#!/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/", strict_slashes=False) @views.route("/quest///") def quest(quest_id, page_num=1): """ An arbituary quest page. """ data = db.get_quest_meta(quest_id) if not data: abort(404) quest_id = room_id = data[0] quest_title = data[1] owner_id = data[2] open_post_id = data[2] ip_address = request.remote_addr pages = db.get_quest_pages(quest_id) quest_posts = db.get_quest_data(quest_id, page_num) dice_rolls_raw = db.get_dice_rolls(quest_id) dice_rolls = {roll[2]: [] for roll in dice_rolls_raw} _ = [dice_rolls[roll[2]].append(roll) for roll in dice_rolls_raw] del dice_rolls_raw options_raw = db.get_poll_options(quest_id=quest_id) options = {opt[1]: [] for opt in options_raw} _ = [options[opt[1]].append(opt) for opt in options_raw] del options_raw poll_votes_raw = db.get_poll_votes(quest_id) poll_votes = {vote[0]: [] for vote in poll_votes_raw} _ = [poll_votes[vote[0]].append(vote[1]) for vote in poll_votes_raw] del poll_votes_raw messages = db.get_chat_messages(quest_id) return render_template('quest.html', **locals()) @views.route("/quest//edit_quest", methods=["GET", "POST"]) def edit_quest(quest_id): """ Allows the quest owner to edit the quest. """ data = db.get_quest_meta(quest_id) 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, quest_id=quest_id) return redirect(url_for(".quest", quest_id=quest_id)) @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") quest_title = request.form.get("quest_title") quest_body = request.form.get("quest_body") quest_body = bleach.clean(quest_body.strip()) quest_body = quest_body.replace("\n", "
") owner_id = session.get("user_id") timestamp = int(time.time()) page_num = 1 quest_id = db.insert_quest(quest_title, owner_id) db.insert_quest_page(quest_id, page_num, "Page 1") db.insert_quest_post(quest_id, page_num, "text", quest_body, timestamp) return redirect(url_for('.quest', quest_id=quest_id)) @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")