2018-06-16 18:52:46 -04:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
"""
|
|
|
|
Database tools and functions.
|
|
|
|
"""
|
2018-06-20 13:07:11 -04:00
|
|
|
import time
|
2018-06-16 18:52:46 -04:00
|
|
|
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.
|
|
|
|
"""
|
2018-06-20 13:07:11 -04:00
|
|
|
ident_title, _, extra = quest_title.partition("/")
|
|
|
|
data = db.get_quest_meta(ident_title)
|
2018-06-16 18:52:46 -04:00
|
|
|
if not data:
|
|
|
|
abort(404)
|
2018-06-20 13:07:11 -04:00
|
|
|
quest_id, quest_title, _, owner_id = data
|
|
|
|
quest_posts = db.get_quest_data(quest_id)
|
2018-06-17 21:10:41 -04:00
|
|
|
messages = db.get_chat_messages(quest_id)
|
2018-06-16 18:52:46 -04:00
|
|
|
return render_template('quest.html',
|
|
|
|
quest_title=quest_title,
|
2018-06-20 13:07:11 -04:00
|
|
|
quest_posts=quest_posts,
|
2018-06-19 17:00:49 -04:00
|
|
|
owner_id=owner_id,
|
2018-06-16 18:52:46 -04:00
|
|
|
room_id=quest_id,
|
|
|
|
messages=messages)
|
|
|
|
|
|
|
|
|
2018-06-21 11:00:24 -04:00
|
|
|
@views.route("/profile/<path:username>")
|
|
|
|
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))
|
|
|
|
|
|
|
|
|
2018-06-16 18:52:46 -04:00
|
|
|
@views.route("/create_quest", methods=["GET", "POST"])
|
2018-06-21 09:06:23 -04:00
|
|
|
@login_required(".login")
|
2018-06-16 18:52:46 -04:00
|
|
|
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 />")
|
|
|
|
|
2018-06-19 17:00:49 -04:00
|
|
|
owner_id = session.get("user_id")
|
2018-06-20 13:07:11 -04:00
|
|
|
timestamp = int(time.time())
|
|
|
|
|
|
|
|
quest_id = db.insert_quest(canon_title, ident_title, owner_id)
|
|
|
|
db.insert_quest_post(quest_id, quest_body, timestamp)
|
2018-06-19 17:00:49 -04:00
|
|
|
|
2018-06-21 09:06:23 -04:00
|
|
|
return redirect(url_for('.quest', quest_title=ident_title))
|
2018-06-16 18:52:46 -04:00
|
|
|
|
|
|
|
|
2018-06-19 17:00:49 -04:00
|
|
|
@views.route("/edit_quest")
|
|
|
|
def edit_quest():
|
|
|
|
"""
|
|
|
|
Allows the quest owner to edit the quest.
|
|
|
|
"""
|
|
|
|
return "lol"
|
|
|
|
|
|
|
|
|
2018-06-20 22:21:22 -04:00
|
|
|
@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 ""
|
|
|
|
|
|
|
|
|
2018-06-16 18:52:46 -04:00
|
|
|
@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
|
2018-06-21 09:06:23 -04:00
|
|
|
return redirect(url_for(".index"))
|
2018-06-16 18:52:46 -04:00
|
|
|
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:
|
2018-06-21 11:00:24 -04:00
|
|
|
return "username_too_long"
|
2018-06-16 18:52:46 -04:00
|
|
|
elif len(username) < 3:
|
2018-06-21 11:00:24 -04:00
|
|
|
return "username_too_short"
|
2018-06-16 18:52:46 -04:00
|
|
|
chrs = [c not in string.ascii_letters + string.digits for c in username]
|
|
|
|
if any(chrs):
|
2018-06-21 11:00:24 -04:00
|
|
|
return "username_bad_chars"
|
2018-06-16 18:52:46 -04:00
|
|
|
if db.verify_username(username):
|
2018-06-21 11:00:24 -04:00
|
|
|
return "username_taken"
|
2018-06-16 18:52:46 -04:00
|
|
|
|
|
|
|
if len(password) > 1024:
|
2018-06-21 11:00:24 -04:00
|
|
|
return "password_too_long"
|
2018-06-16 18:52:46 -04:00
|
|
|
elif len(password) < 8:
|
2018-06-21 11:00:24 -04:00
|
|
|
return "password_too_short"
|
2018-06-16 18:52:46 -04:00
|
|
|
|
|
|
|
if password != password_verify:
|
2018-06-21 11:00:24 -04:00
|
|
|
return "passwords_dont_match"
|
2018-06-16 18:52:46 -04:00
|
|
|
|
2018-06-21 11:00:24 -04:00
|
|
|
timestamp = int(time.time())
|
|
|
|
res = db.add_user(username, password, timestamp)
|
2018-06-21 09:06:23 -04:00
|
|
|
return redirect(url_for(".index"))
|
2018-06-16 18:52:46 -04:00
|
|
|
|
|
|
|
|
|
|
|
@views.route("/")
|
|
|
|
def index():
|
|
|
|
"""
|
|
|
|
The index page.
|
|
|
|
"""
|
|
|
|
return render_template("index.html")
|