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, )