Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Post to highscores #1

Merged
merged 2 commits into from
Sep 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/typefight/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from typefight.db import get_db
from typefight.utils import validate_country
# from datetime import datetime
import functools
import secrets
# import hashlib

Expand All @@ -18,7 +19,6 @@ def auth():

@bp.route("/register", methods=["POST"])
def register():
# when method is POST, user is sending the register form
player_name = request.form["username"]
password = request.form["password"]
country = validate_country(request.form["country"])
Expand All @@ -33,6 +33,8 @@ def register():
error = "Username is required."
elif not password:
error = "Password is required."
elif not country:
error = "Not a valid country."
else:
cur.execute(
"SELECT player_uid FROM players WHERE player_name = %s;", (player_name,)
Expand Down Expand Up @@ -116,3 +118,15 @@ def load_logged_in_user():
)
g.user = cur.fetchone()
cur.close()

def login_required(view):
@functools.wraps(view)
def wrapped_view(**kwargs):

if g.user is not None:
return view(**kwargs)
else:
#TODO redirect to a login page or something
return "You need to be logged in to access this content"

return wrapped_view
133 changes: 118 additions & 15 deletions src/typefight/game.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
from flask import render_template, Blueprint, jsonify
from flask import (
render_template, Blueprint, jsonify, request, g, session
)
from psycopg2.extras import RealDictCursor

from typefight.db import get_db
from typefight.utils import make_serializable
from typefight.auth import login_required

import contextlib

bp = Blueprint("game", __name__)

Expand All @@ -12,37 +17,135 @@ def index():

@bp.route("/highscores")
def get_highscores():
# add POST method here so highscore will be updated if its higher than
# their previous one.

db = get_db()
cur = db.cursor(cursor_factory=RealDictCursor)

cur.execute(
"""
SELECT scores.score, players.player_name, players.country FROM scores
LEFT JOIN players
ON players.player_uid = scores.player_uid;
"""
)
quote_id = g.quote_id
scores_table = []

try:
cur.execute(
"""
SELECT scores.score, players.player_name, players.country
FROM scores
LEFT JOIN players
ON players.player_uid = scores.player_uid
WHERE scores.quote_uid = %s;
""",
(quote_id,)
)
scores_table = cur.fetchall()

except Exception as e:
print(f"An exception has occured during {request}:", e)
print("Exception TYPE: ", type(e))

scores_table = cur.fetchall()
cur.close()

return jsonify(make_serializable(scores_table))

@bp.route("/highscores/<float:score>", methods=["POST"])
@login_required
def set_highscore(score):
#TODO make sure "score" doesn't contain slash (/)
db = get_db()

server_response = {
"success": False,
"message": None
}

player_name = g.user["player_name"]
quote_id = g.quote_id
existing_score = None

with contextlib.closing(db.cursor(cursor_factory=RealDictCursor)) as cur:
cur.execute(
"""
SELECT player_uid
FROM players
WHERE player_name = %s;
""",
(player_name, )
)
player_uid = cur.fetchone()["player_uid"]

try:
cur.execute(
"""
SELECT players.player_uid, scores.score
FROM scores
LEFT JOIN players
ON players.player_uid = scores.player_uid
WHERE player_name = %s
AND quote_uid = %s;
""",
(player_name, quote_id)
)
existing_score = cur.fetchone()

except Exception as e:
server_response["message"] = e
print(f"An exception has occured during {request}:", e)
print("Exception TYPE:", type(e))

if existing_score is None:
cur.execute(
"""
INSERT INTO scores(player_uid, quote_uid, score)
VALUES (%s, %s, %s);
""",
(player_uid, quote_id, score)
)
db.commit()

server_response["success"] = True
server_response["message"] = f"Your new score {score} has been saved."

elif score < existing_score["score"]:
cur.execute(
"""
UPDATE scores
SET score = %s
WHERE player_uid = %s
AND quote_uid = %s;
""",
(score, player_uid, quote_id)
)
db.commit()

server_response["success"] = True
server_response["message"] = f"New record! Your new score was faster than your previous one. Old score: {existing_score['score']} New score: {score}"
else:
server_response["success"] = True
server_response["message"] = f"Too slow! Best score: {existing_score['score']} Current score: {score}"

return server_response

@bp.route("/quote")
def get_quote():
db = get_db()
cur = db.cursor(cursor_factory=RealDictCursor)

cur.execute(
"""
SELECT quote FROM quotes ORDER BY RANDOM() LIMIT 1;
SELECT quote, quote_uid AS quote_id
FROM quotes
ORDER BY RANDOM()
LIMIT 1;
"""
)

quote = cur.fetchone()
session["quote"] = quote
cur.close()

return jsonify(quote)
return jsonify(quote)

@bp.before_app_request
def load_current_quote():
quote = session.get("quote")

if quote is None:
g.quote_id = None
else:
g.quote_id = quote["quote_id"]
Loading