155 lines
3.7 KiB
Python
155 lines
3.7 KiB
Python
|
#!/usr/bin/env python3
|
||
|
"""
|
||
|
Database tools and functions.
|
||
|
"""
|
||
|
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
|
||
|
|
||
|
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
|
||
|
|
||
|
|
||
|
def sanitize_title(canon_title):
|
||
|
"""
|
||
|
Sanitizes the given canonical title for a quest and returns a
|
||
|
url-friendly version.
|
||
|
"""
|
||
|
ident_title = canon_title.lower().replace(" ", "-")
|
||
|
ident_title = urllib.parse.quote(ident_title)
|
||
|
return ident_title
|
||
|
|
||
|
|
||
|
@views.route("/quest/<path:quest_title>")
|
||
|
def quest(quest_title):
|
||
|
"""
|
||
|
An arbituary quest page.
|
||
|
"""
|
||
|
quest_title, _, extra = quest_title.partition("/")
|
||
|
res = db._DB.execute("SELECT * FROM `quests` WHERE `ident_title` = %s",
|
||
|
(quest_title,))
|
||
|
data = res.fetchone()
|
||
|
if not data:
|
||
|
abort(404)
|
||
|
quest_id, quest_title, _, owner_id, quest_data = data
|
||
|
|
||
|
res = db._DB.execute("SELECT * FROM `chat_messages` WHERE `room_id` = '%s'",
|
||
|
(quest_id,))
|
||
|
messages = res.fetchall()
|
||
|
return render_template('quest.html',
|
||
|
quest_title=quest_title,
|
||
|
quest_body=quest_data,
|
||
|
room_id=quest_id,
|
||
|
messages=messages)
|
||
|
|
||
|
|
||
|
@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 = sanitize_title(canon_title)
|
||
|
quest_body = bleach.clean(quest_body.strip())
|
||
|
quest_body = quest_body.replace("\n", "<br />")
|
||
|
|
||
|
db._DB.execute(
|
||
|
"INSERT INTO `quests` (`canon_title`, `ident_title`, `quest_data`) " \
|
||
|
"VALUES (%s, %s, %s)", (canon_title, ident_title, quest_body))
|
||
|
return redirect(url_for('views.quest', quest_title=ident_title))
|
||
|
|
||
|
|
||
|
@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("views.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:
|
||
|
"username_too_long"
|
||
|
elif len(username) < 3:
|
||
|
"username_too_short"
|
||
|
chrs = [c not in string.ascii_letters + string.digits for c in username]
|
||
|
if any(chrs):
|
||
|
"username_bad_chars"
|
||
|
if db.verify_username(username):
|
||
|
"username_taken"
|
||
|
|
||
|
if len(password) > 1024:
|
||
|
"password_too_long"
|
||
|
elif len(password) < 8:
|
||
|
"password_too_short"
|
||
|
|
||
|
if password != password_verify:
|
||
|
"passwords_dont_match"
|
||
|
|
||
|
res = db.add_user(username, password)
|
||
|
return redirect(url_for("views.index"))
|
||
|
|
||
|
|
||
|
@views.route("/")
|
||
|
def index():
|
||
|
"""
|
||
|
The index page.
|
||
|
"""
|
||
|
return render_template("index.html")
|