diff --git a/LICENSE b/LICENSE index 204b93d..327e069 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -MIT License Copyright (c) +MIT License Copyright (c) 2020 Armin Friedl Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 5ceb16b..955d1f1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,75 @@ -# snip +# Snip +[![Build Status](https://drone.friedl.net/api/badges/incubator/snip/status.svg)](https://drone.friedl.net/incubator/snip) -Self-hosted, url-based redirection service \ No newline at end of file +No-fuzz link shortener. + +![Snip Screenshot](snip_screen.png) + +## Getting started +Snip is a self-hosted link shortener. It provides an API and a web interface. +Dependencies are managed with [pipenv](https://pipenv.pypa.io/en/latest/) and +[npm](https://www.npmjs.com/). Snip runs on +[flask](https://flask.palletsprojects.com/) the frontend is assembled with +[webpack](https://webpack.js.org/). All this is rather simple in practice. + +### Run from docker +The simplest way to get started is to run snip from the regularily [published +docker containers](https://hub.docker.com/repository/docker/arminfriedl/snip). + +```shell +docker run -p5000 arminfriedl/snip:latest +``` + +Then navigate your browser to http://localhost:5000. Alternatively, you can also +query the REST API. For an example see the [querysheet.http](querysheet.http) in +this repository. If you want to run it manually you can also install snip and +its dependencies yourself. + +### Install Dependencies +To install the dependencies for snip, you need +[pipenv](https://pipenv.pypa.io/en/latest/) and [npm](https://www.npmjs.com/) +installed on your system. Then run: + +```shell +pipenv install --dev +npm install --dev +``` + +### Build Snip +The snip backend itself needs no separate build step. However, the frontend +needs to be assembled by webpack. + + +```shell +# Run a development build with continuous update +npm run watch + +# Run a production build +npm run publish +``` + +### Run Snip +From the repository root run: + +```shell +export FLASK_ENV=production # or development +export FLASK_APP=snip + +pipenv run flask run +``` + +Flask will tell you where you can reach snip, per default http://localhost:5000. + +# Contribute +If you want to contribute to `snip` feel free to send patches to +dev[at]friedl[dot]net. Alternatviely, you can issue a pull request on GitHub +which will be cherry picked into my tree. If you plan significant long-term +contributions drop me a mail for access to the incubator repository. + +# Github Users +If you are visiting this repository on GitHub, you are on a mirror of +https://git.friedl.net/incubator/snip. This mirror is regularily updated +with my other GitHub mirrors. + +Like with my other incubator projects, once I consider `snip` reasonable +stable the main tree will move to GitHub. diff --git a/TODO.org b/TODO.org index 38edeaf..be87676 100644 --- a/TODO.org +++ b/TODO.org @@ -1,19 +1,28 @@ #+TODO: TODO NEXT HOLD | DONE CANCELLED -* URL Shortener [22%] +* URL Shortener [57%] ** DONE Landing Page Endpoint CLOSED: [2020-10-25 Sun 04:50] ** DONE Snip Endpoint CLOSED: [2020-10-25 Sun 05:22] -** TODO Shorten URL -** TODO Save Shortened URLs -** TODO Unsnip Shortened URLs -** TODO Landing Page Template -** TODO Rediret +** DONE Shorten URL + CLOSED: [2020-11-06 Fri 00:48] +** DONE Save Shortened URLs + CLOSED: [2020-11-06 Fri 00:48] +** DONE Unsnip Shortened URLs + CLOSED: [2020-11-06 Fri 00:48] +** DONE Landing Page Template + CLOSED: [2020-11-06 Fri 00:48] +** DONE Redirect + CLOSED: [2020-11-06 Fri 00:48] ** TODO Stats Endpoint ** TODO Store Stats ** TODO Stats Template ** TODO Externalize config -** TODO Deploy script -** TODO Improvement: Pronouncable short urls +** DONE Deploy script + CLOSED: [2020-11-06 Fri 00:49] +** HOLD Improvement: Pronouncable short urls with markov chain? + see womblies + +** TODO Better persistence concept diff --git a/package.json b/package.json index da7af3b..6868351 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build_scss": "node-sass --include-path node_modules/foundation-sites/scss --include-path node_modules/motion-ui/src -o snip/static snip/templates", "build_webpack": "webpack --config webpack.dev.js", "watch": "npm-watch", - "publish": "node-sass --include-path node_modules/foundation-sites/scss -o snip/static snip/templates && webpack --config webpack.prod.js" + "publish": "node-sass --include-path node_modules/foundation-sites/scss --include-path node_modules/motion-ui/src -o snip/static snip/templates && webpack --config webpack.prod.js" }, "repository": { "type": "git", diff --git a/querysheet.http b/querysheet.http new file mode 100644 index 0000000..d4c2570 --- /dev/null +++ b/querysheet.http @@ -0,0 +1,11 @@ +:host = http://localhost:5000 + +# Create a new shortlink +POST :host/api/snip +-> jq-set-var :snip .snip +{ + "url": "https://example.com" +} + +# Unsnip shortlink +GET :host/api/:snip \ No newline at end of file diff --git a/snip/api.py b/snip/api.py index 1e7312e..09cd55d 100644 --- a/snip/api.py +++ b/snip/api.py @@ -38,7 +38,7 @@ def snip(): return {"url": url, "snip": snip} -@app.route("/api/unsnip/", methods=['GET']) +@app.route("/api/", methods=['GET']) def unsnip(snip): url = snipper.unsnip(snip) if not url: diff --git a/snip_screen.png b/snip_screen.png new file mode 100644 index 0000000..fd09776 Binary files /dev/null and b/snip_screen.png differ