#!/usr/bin/env python3 """ Database tools and functions. """ import time import string import urllib import functools import bleach from flask import session, request, abort, redirect, url_for, render_template from flask import Blueprint import database as db import tools views = Blueprint("views", __name__) def login_required(url=None): """ A decorator function to protect certain endpoints by requiring the user to either pass a valid session cookie, or pass thier username and password along with the request to login. """ def actual_decorator(func): @functools.wraps(func) def _nop(*args, **kwargs): username = session.get("username") if db.verify_username(username): return func(*args, **kwargs) username = request.form.get("user") password = request.form.get("pass") if db.verify_password(username, password): return func(*args, **kwargs) if url: return redirect(url_for(url)) else: abort(401) return _nop return actual_decorator @views.route("/quest/") def quest(quest_title): """ An arbituary quest page. """ ident_title, _, extra = quest_title.partition("/") data = db.get_quest_meta(ident_title=ident_title) if not data: abort(404) quest_id = data[0] quest_title = data[1] owner_id = data[3] quest_posts = db.get_quest_data(quest_id) messages = db.get_chat_messages(quest_id) return render_template('quest.html', quest_title=quest_title, ident_title=ident_title, quest_posts=quest_posts, owner_id=owner_id, room_id=quest_id, messages=messages) @views.route("/profile/") def profile(username): """ Shows the profile page of the specified user. """ data = db.get_user_info(username) if not data: return "user_not_found" user_id, signup_date = data quests = db.get_user_quests(user_id) return render_template("profile.html", username=username, signup_date=signup_date, num_quests=len(quests)) @views.route("/create_quest", methods=["GET", "POST"]) @login_required(".login") def create_quest(): """ Starts a new quest. """ if request.method == "GET": return render_template("create_quest.html") canon_title = request.form.get("quest_title") quest_body = request.form.get("quest_body") ident_title = tools.sanitize_title(canon_title) quest_body = bleach.clean(quest_body.strip()) quest_body = quest_body.replace("\n", "
") owner_id = session.get("user_id") timestamp = int(time.time()) quest_id = db.insert_quest(canon_title, ident_title, owner_id) db.insert_quest_post(quest_id, quest_body, timestamp) return redirect(url_for('.quest', quest_title=ident_title)) @views.route("/quest//edit_quest", methods=["GET", "POST"]) def edit_quest(quest_title): """ Allows the quest owner to edit the quest. """ ident_title = quest_title data = db.get_quest_meta(ident_title=ident_title) if not data: abort(404) quest_id = data[0] quest_title = data[1] if request.method == "GET": return render_template("edit_quest.html", quest_title=quest_title, ident_title=ident_title) return redirect(url_for(".quest", quest_title=ident_title)) @views.route("/set_session") def set_session(): """ Allows certain session values to be set by the client. """ hide_header = request.args.get("hide_header") if hide_header == "on": session["hide_header"] = True elif hide_header == "off": session["hide_header"] = False return "" @views.route("/login", methods=["GET", "POST"]) def login(): """ Logs the user in. """ if request.method == "GET": return render_template("login.html") username = request.form.get("user") password = request.form.get("pass") if db.verify_password(username, password): session["username"] = username return redirect(url_for(".index")) else: abort(401) @views.route("/signup", methods=["GET", "POST"]) def signup(): """ Create a new account. """ if request.method == "GET": return render_template("signup.html") username = request.form.get("user") password = request.form.get("pass") password_verify = request.form.get("pass_verify") if len(username) > 20: return "username_too_long" elif len(username) < 3: return "username_too_short" chrs = [c not in string.ascii_letters + string.digits for c in username] if any(chrs): return "username_bad_chars" if db.verify_username(username): return "username_taken" if len(password) > 1024: return "password_too_long" elif len(password) < 8: return "password_too_short" if password != password_verify: return "passwords_dont_match" timestamp = int(time.time()) res = db.add_user(username, password, timestamp) return redirect(url_for(".index")) @views.route("/") def index(): """ The index page. """ return render_template("index.html")