From e7fbb4a76eb22ecbe2b81165fd0c583b1fdefcf6 Mon Sep 17 00:00:00 2001 From: sqozz Date: Wed, 21 Jan 2015 13:42:08 +0100 Subject: [PATCH] initial commit --- settings.py | 11 +++++ templates/new_paste.html | 2 + urlshort.db | Bin 0 -> 41984 bytes urlshort.py | 90 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 settings.py create mode 100644 templates/new_paste.html create mode 100644 urlshort.db create mode 100644 urlshort.py diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..bbf6c2a --- /dev/null +++ b/settings.py @@ -0,0 +1,11 @@ +#!/usr/bin/python3 +DEBUG = True +DATABASE = "urlshort.db" +FOOBAR = "PONG" +DEFAULT_SCHEMA = ''' +CREATE TABLE IF NOT EXISTS pastes (id INT PRIMARY KEY, paste_url TEXT NOT NULL, target TEXT NOT NULL, method_id INT NOT NULL, ip TEXT NOT NULL, timestamp TEXT NOT NULL); + +CREATE TABLE IF NOT EXISTS methods (id INT PRIMARY KEY, name TEXT NOT NULL); + +CREATE TABLE IF NOT EXISTS access (id INT PRIMARY KEY NOT NULL, paste_id TEXT NOT NULL, ip TEXT NOT NULL, user_agent TEXT NOT NULL); +''' diff --git a/templates/new_paste.html b/templates/new_paste.html new file mode 100644 index 0000000..fa314b7 --- /dev/null +++ b/templates/new_paste.html @@ -0,0 +1,2 @@ + +http://localhost:5000/{{paste_id}} diff --git a/urlshort.db b/urlshort.db new file mode 100644 index 0000000000000000000000000000000000000000..57aceec7e4f8cf548ecdd5d0c40e01ee9eb3667d GIT binary patch literal 41984 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 F{u}o2l&Amz literal 0 HcmV?d00001 diff --git a/urlshort.py b/urlshort.py new file mode 100644 index 0000000..bf87ca3 --- /dev/null +++ b/urlshort.py @@ -0,0 +1,90 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +from flask import Flask, g, request, render_template, redirect +import sqlite3 +import random +import string +import math +import time +from flask_limiter import Limiter +from contextlib import closing +from urllib.parse import urlparse + +app = Flask(__name__) +app.config.from_object("settings") +limiter = Limiter(app, global_limits=["2 per minute", "100 per day"]) + +@app.before_request +def before_request(): + g.db = connect_db() + +@app.teardown_request +def teardown_request(exception): + db = getattr(g, "db", None) + if db is not None: + db.close() + +@app.route("/") +@limiter.exempt +def root(): + return "Welcome to root!" + +@app.route("/") +@limiter.exempt +def paste(pasteID): + target = query_db("SELECT target FROM pastes WHERE paste_url = ?", [pasteID], one=True) + if target is None: + return "Shorturl not found!" + else: + url = urlparse(target["target"]) + if url.scheme is "": + target = "http://" + url.path + else: + target = url.scheme + "://" + url.netloc + url.path + return redirect(target, 301) + +@app.route("/new") +@limiter.exempt +def new_paste(): + target_url = request.args.get("target", "") + paste_id = add_redirect(target_url, 1) + return render_template("new_paste.html", paste_id=paste_id) + +def add_redirect(target_url, method_id): + paste_id = gen_new_id(5) + ip = request.remote_addr + timestamp = int(time.time()) + db = getattr(g, "db", None) + if db is not None: + query = "INSERT INTO pastes (paste_url, target, method_id, ip, timestamp) VALUES (:paste_url, :target, :method_id, :ip, :timestamp);" + args = {"paste_url" : paste_id, "target" : target_url, "method_id" : "1", "ip" : ip, "timestamp" : timestamp} + db.cursor().execute(query, args) + db.commit() + db.close() + return paste_id + +def gen_new_id(length): + while True: + new_id = "".join([random.choice(string.ascii_letters + string.digits) for n in range(length)]) + if query_db("SELECT * FROM pastes WHERE paste_url = ?", [new_id], one=True) is None: + break + return new_id + +def query_db(query, args=(), one=False): + with closing(connect_db()) as db: + db.row_factory = sqlite3.Row + cur = db.cursor().execute(query, args) + rv = cur.fetchall() + cur.close() + return (rv[0] if rv else None) if one else rv + +def init_db(): + with closing(connect_db()) as db: + db.cursor().executescript(app.config["DEFAULT_SCHEMA"]) + db.commit() + +def connect_db(): + return sqlite3.connect(app.config["DATABASE"]) + +if __name__ == "__main__": + app.run(debug=app.config["DEBUG"])