WyR/app/routes.py

163 lines
3.5 KiB
Python

import hashlib
from datetime import date, datetime, time, timedelta
from flask import Blueprint, redirect, render_template, request, url_for
from .database import get_db
bp = Blueprint("public", __name__)
VOTE_COOKIE_NAME = "wyr_daily_vote"
def get_todays_question():
db = get_db()
today = date.today().isoformat()
return db.execute(
"""
SELECT id, question, option_a, option_b, date
FROM questions
WHERE date = ?
LIMIT 1
""",
(today,),
).fetchone()
def get_question_version(question):
parts = (
str(question["id"]),
question["date"],
question["question"],
question["option_a"],
question["option_b"],
)
fingerprint = "\x1f".join(parts)
return hashlib.sha256(fingerprint.encode()).hexdigest()
def get_vote_cookie_value(question):
return f"{question['date']}:{question['id']}:{get_question_version(question)}"
def get_seconds_until_tomorrow():
now = datetime.now()
tomorrow = datetime.combine(date.today() + timedelta(days=1), time.min)
return max(1, int((tomorrow - now).total_seconds()))
def has_voted_for_question(question):
return request.cookies.get(VOTE_COOKIE_NAME) == get_vote_cookie_value(question)
def set_vote_cookie(response, question):
response.set_cookie(
VOTE_COOKIE_NAME,
get_vote_cookie_value(question),
max_age=get_seconds_until_tomorrow(),
httponly=True,
samesite="Lax",
)
return response
@bp.route("/")
def home():
question = get_todays_question()
return render_template(
"public/index.html",
question=question,
)
@bp.route("/vote", methods=["POST"])
def vote():
qid = request.form.get("qid")
selected_vote = request.form.get("vote")
if not qid or selected_vote not in {"A", "B"}:
return redirect(url_for("public.home"))
db = get_db()
question = get_todays_question()
if question is None or str(question["id"]) != str(qid):
return redirect(url_for("public.home"))
if has_voted_for_question(question):
return redirect(url_for("public.results"))
db.execute(
"""
INSERT INTO votes (question_id, vote, voter_hash)
VALUES (?, ?, ?)
""",
(qid, selected_vote, "cookie"),
)
db.commit()
response = redirect(url_for("public.results"))
return set_vote_cookie(response, question)
@bp.route("/results")
def results():
question = get_todays_question()
if question is None:
return render_template(
"public/results.html",
question=None,
votes_a=0,
votes_b=0,
percent_a=0,
percent_b=0,
total=0,
)
db = get_db()
votes_a = db.execute(
"""
SELECT COUNT(*)
FROM votes
WHERE question_id = ?
AND vote = 'A'
""",
(question["id"],),
).fetchone()[0]
votes_b = db.execute(
"""
SELECT COUNT(*)
FROM votes
WHERE question_id = ?
AND vote = 'B'
""",
(question["id"],),
).fetchone()[0]
total = votes_a + votes_b
if total == 0:
percent_a = 0
percent_b = 0
else:
percent_a = round(votes_a / total * 100)
percent_b = round(votes_b / total * 100)
return render_template(
"public/results.html",
question=question,
votes_a=votes_a,
votes_b=votes_b,
percent_a=percent_a,
percent_b=percent_b,
total=total,
)