mirror of
https://github.com/Project-Redacted/Highscores-Server.git
synced 2025-05-28 22:13:14 +00:00
Add templates and many other things
This commit is contained in:
parent
330201be3a
commit
62945c943d
414 changed files with 14758 additions and 4145 deletions
|
@ -1,12 +1,21 @@
|
|||
from flask import Flask
|
||||
from server.extensions import db, migrate, cache
|
||||
from server.views import blueprint
|
||||
from flask_assets import Bundle
|
||||
from server.extensions import db, migrate, cache, assets
|
||||
from server import views, auth
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
db.init_app(app)
|
||||
migrate.init_app(app, db)
|
||||
cache.init_app(app)
|
||||
|
||||
app.register_blueprint(blueprint)
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
|
||||
assets.init_app(app)
|
||||
styles = Bundle("style.sass", filters="libsass, cssmin", output="gen/styles.css", depends="style.sass")
|
||||
assets.register("styles", styles)
|
||||
|
||||
cache.init_app(app)
|
||||
app.register_blueprint(views.blueprint)
|
||||
app.register_blueprint(auth.blueprint)
|
||||
|
|
25
server/auth.py
Normal file
25
server/auth.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
from flask import Blueprint, jsonify, request, render_template
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, IntegerField
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
from server.models import Scores, Users, Tokens
|
||||
from server.extensions import db, cache
|
||||
from server.config import BEARER_TOKEN
|
||||
|
||||
|
||||
blueprint = Blueprint('auth', __name__)
|
||||
|
||||
|
||||
class ScoreForm(FlaskForm):
|
||||
playerName = StringField('Player Name', validators=[DataRequired()])
|
||||
playerId = StringField('Player ID', validators=[DataRequired()])
|
||||
score = IntegerField('Score', validators=[DataRequired()])
|
||||
difficulty = StringField('Difficulty', validators=[DataRequired()])
|
||||
achievements = StringField('Achievements', validators=[DataRequired()])
|
||||
|
||||
|
||||
@blueprint.route('/auth', methods=['GET'])
|
||||
@cache.cached(timeout=60)
|
||||
def auth():
|
||||
return render_template('auth.html')
|
|
@ -1,4 +1,5 @@
|
|||
SECRET_KEY = 'dev'
|
||||
SECRET_KEY = "dev"
|
||||
BEARER_TOKEN = 1234
|
||||
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///db.sqlite'
|
||||
SQLALCHEMY_DATABASE_URI = f"sqlite:///db.sqlite"
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_migrate import Migrate
|
||||
from flask_assets import Environment
|
||||
from flask_caching import Cache
|
||||
|
||||
db = SQLAlchemy()
|
||||
migrate = Migrate()
|
||||
cache = Cache()
|
||||
assets = Environment()
|
||||
cache = Cache(config={'CACHE_TYPE': 'simple'})
|
||||
|
|
|
@ -1,28 +1,33 @@
|
|||
"""
|
||||
Database models for the server
|
||||
"""
|
||||
from uuid import uuid4
|
||||
from server.extensions import db
|
||||
|
||||
|
||||
class Scores(db.Model):
|
||||
"""
|
||||
Post table
|
||||
Scores supports anonymous posting, and instead just wants to post a score,
|
||||
then the username must be provided.Otherwise, it's grabbed from the user table
|
||||
"""
|
||||
__tablename__ = "scores"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
score = db.Column(db.Integer, nullable=False)
|
||||
difficulty = db.Column(db.String, nullable=False)
|
||||
achievements = db.Column(db.String, nullable=False)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||
anonymous = db.Column(db.Boolean, nullable=False, default=False)
|
||||
username = db.Column(db.String(32), nullable=True)
|
||||
|
||||
score = db.Column(db.Float, nullable=False)
|
||||
difficulty = db.Column(db.String, nullable=False)
|
||||
scored_at = db.Column(
|
||||
db.DateTime,
|
||||
nullable=False,
|
||||
server_default=db.func.now(),
|
||||
server_default=db.func.utcnow(),
|
||||
)
|
||||
|
||||
scorer = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
|
||||
|
||||
class Users(db.Model):
|
||||
"""
|
||||
|
@ -31,13 +36,35 @@ class Users(db.Model):
|
|||
__tablename__ = "users"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
steam_uuid = db.Column(db.String, unique=True, nullable=False)
|
||||
steam_name = db.Column(db.String, nullable=False)
|
||||
alt_id = db.Column(db.String, nullable=False, unique=True, default=str(uuid4()))
|
||||
|
||||
scores = db.relationship('Scores', backref='user', lazy=True)
|
||||
|
||||
creation_data = db.Column(
|
||||
username = db.Column(db.String(32), unique=True, nullable=False)
|
||||
email = db.Column(db.String, unique=True, nullable=False)
|
||||
password = db.Column(db.String(128), nullable=False)
|
||||
joined_at = db.Column(
|
||||
db.DateTime,
|
||||
nullable=False,
|
||||
server_default=db.func.now(),
|
||||
server_default=db.func.utcnow(), # pylint: disable=E1102
|
||||
)
|
||||
|
||||
scores = db.relationship('Scores', backref='user', lazy=True)
|
||||
tokens = db.relationship('Tokens', backref='user', lazy=True)
|
||||
|
||||
def get_id(self):
|
||||
return str(self.alt_id)
|
||||
|
||||
|
||||
class Tokens(db.Model):
|
||||
"""
|
||||
Token table
|
||||
"""
|
||||
__tablename__ = "tokens"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
token = db.Column(db.String, nullable=False, unique=True, default=str(uuid4()))
|
||||
created_at = db.Column(
|
||||
db.DateTime,
|
||||
nullable=False,
|
||||
server_default=db.func.utcnow(), # pylint: disable=E1102
|
||||
)
|
||||
holder = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||
|
|
BIN
server/static/bg.png
Normal file
BIN
server/static/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 MiB |
1
server/static/gen/styles.css
Normal file
1
server/static/gen/styles.css
Normal file
|
@ -0,0 +1 @@
|
|||
@import url("https://fonts.googleapis.com/css2?family=Merriweather:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700&display=swap");:root{--black:21,21,21;--white:232,227,227;--primary:213,214,130;--secondary:185,77,77;--gold:255,222,70;--silver:229,220,206;--bronze:193,145,69;--darkBlue:9,9,39}*{box-sizing:border-box;font-family:'Merriweather',serif}html{margin:0;padding:0}body{margin:0;padding:0;display:flex;flex-direction:row;background-color:RGB(var(--darkBlue));color:RGB(var(--white))}.background{width:100%;height:100%;object-fit:cover;position:absolute;z-index:1}.app{margin:0 auto;padding:2rem;width:800px;min-height:100vh;position:relative;display:flex;flex-direction:column;background-color:rgba(var(--darkBlue),0.9);z-index:2}.app>table{width:100%}.app .center-text{height:100%;display:flex;flex-direction:column;justify-content:center;align-items:center}.app .center-text>h2{margin:0;text-align:center;font-size:2em;color:RGB(var(--white))}.app .center-text>p{margin:0;text-align:center;font-size:1em;color:RGB(var(--white))}.app .auth{margin:auto 1rem;padding:1rem;display:flex;flex-direction:column;background-color:rgba(var(--darkBlue),0.5);border-radius:2px}.app .auth>h2{margin:0 0 1rem 0;font-size:1.3em;color:RGB(var(--white))}.title{margin-bottom:2rem;width:100%;height:auto;text-align:center}.subtitle{margin-bottom:1rem;padding:0;text-align:center;font-weight:bolder;font-size:1.2em;color:RGB(var(--secondary))}.subtitle>span{padding:0 .1rem;color:transparent;background:RGB(var(--secondary))}nav{margin:0;padding:0;height:3rem;display:flex;flex-direction:row;justify-content:center}nav>span{width:100%}nav>a{margin:auto .25rem;padding:.5rem 1rem;text-decoration:none;white-space:nowrap;color:RGB(var(--primary))}nav>a.button{text-decoration:none;background-color:transparent;color:RGB(var(--white));border-radius:2px;transition:background-color .2s ease-in-out,box-shadow .2s ease-in-out,transform .2s ease-in-out}nav>a.button:hover{background-color:RGBA(var(--white),0.3);transform:translateY(-0.1rem)}nav>a.button.primary{text-decoration:none;background-color:transparent;color:RGB(var(--primary));border-radius:2px;transition:background-color .2s ease-in-out,box-shadow .2s ease-in-out,transform .2s ease-in-out}nav>a.button.primary:hover{background-color:RGBA(var(--primary),0.3);transform:translateY(-0.1rem)}nav>a.button.secondary{text-decoration:none;background-color:transparent;color:RGB(var(--secondary));border-radius:2px;transition:background-color .2s ease-in-out,box-shadow .2s ease-in-out,transform .2s ease-in-out}nav>a.button.secondary:hover{background-color:RGBA(var(--secondary),0.3);transform:translateY(-0.1rem)}form{display:flex;flex-direction:column}form>input{margin:0 0 1rem 0;padding:.5rem 1rem;border:1px solid RGB(var(--white));border-radius:2px;background-color:RGB(var(--darkBlue));color:RGB(var(--white))}form>input:focus{outline:none;border-color:RGB(var(--primary))}form>input.error{border-color:RGB(var(--secondary))}form>button{margin:0;padding:.5rem 1rem;font-weight:bolder;border:transparent;border-radius:2px;background-color:RGB(var(--primary));color:RGB(var(--black))}form>button:focus-visible,form>button:hover{outline:none;background-color:RGBA(var(--primary),0.3);color:RGB(var(--primary))}form>button.disabled{pointer-events:none;opacity:.5}form>button.secondary{background-color:RGB(var(--secondary));color:RGB(var(--black))}form>button.secondary:focus-visible,form>button.secondary:hover{background-color:RGBA(var(--secondary),0.3);color:RGB(var(--secondary))}
|
212
server/static/style.sass
Normal file
212
server/static/style.sass
Normal file
|
@ -0,0 +1,212 @@
|
|||
$black: var(--black)
|
||||
$white: var(--white)
|
||||
$primary: var(--primary)
|
||||
$secondary: var(--secondary)
|
||||
$gold: var(--gold)
|
||||
$silver: var(--silver)
|
||||
$bronze: var(--bronze)
|
||||
$darkBlue: var(--darkBlue)
|
||||
|
||||
@mixin button($color)
|
||||
text-decoration: none
|
||||
background-color: transparent
|
||||
color: RGB($color)
|
||||
border-radius: 2px
|
||||
// box-shadow: 0 0 0 0 RGBA($color, 0)
|
||||
transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out, transform 0.2s ease-in-out
|
||||
|
||||
&:hover
|
||||
background-color: RGBA($color, 0.3)
|
||||
transform: translateY(-0.1rem)
|
||||
// box-shadow: 0 0.1rem 0.4rem 0.1rem RGBA($color, 0.2)
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Merriweather:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700&display=swap')
|
||||
|
||||
\:root
|
||||
--black: 21, 21, 21
|
||||
--white: 232, 227, 227
|
||||
--primary: 213, 214, 130
|
||||
--secondary: 185, 77, 77
|
||||
--gold: 255, 222, 70
|
||||
--silver: 229, 220, 206
|
||||
--bronze: 193, 145, 69
|
||||
--darkBlue: 9, 9, 39
|
||||
|
||||
*
|
||||
box-sizing: border-box
|
||||
font-family: 'Merriweather', serif
|
||||
|
||||
html
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
body
|
||||
margin: 0
|
||||
padding: 0
|
||||
display: flex
|
||||
flex-direction: row
|
||||
background-color: RGB($darkBlue)
|
||||
color: RGB($white)
|
||||
|
||||
.background
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
object-fit: cover
|
||||
position: absolute
|
||||
z-index: 1
|
||||
|
||||
.app
|
||||
margin: 0 auto
|
||||
padding: 2rem
|
||||
|
||||
width: 800px
|
||||
min-height: 100vh
|
||||
|
||||
position: relative
|
||||
display: flex
|
||||
flex-direction: column
|
||||
|
||||
background-color: rgba($darkBlue, 0.9)
|
||||
z-index: 2
|
||||
|
||||
> table
|
||||
width: 100%
|
||||
|
||||
.center-text
|
||||
height: 100%
|
||||
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
align-items: center
|
||||
|
||||
> h2
|
||||
margin: 0
|
||||
text-align: center
|
||||
font-size: 2em
|
||||
color: RGB($white)
|
||||
|
||||
> p
|
||||
margin: 0
|
||||
text-align: center
|
||||
font-size: 1em
|
||||
color: RGB($white)
|
||||
|
||||
.auth
|
||||
margin: auto 1rem
|
||||
padding: 1rem
|
||||
|
||||
display: flex
|
||||
flex-direction: column
|
||||
|
||||
background-color: rgba($darkBlue, 0.5)
|
||||
border-radius: 2px
|
||||
|
||||
> h2
|
||||
margin: 0 0 1rem 0
|
||||
font-size: 1.3em
|
||||
color: RGB($white)
|
||||
|
||||
.title
|
||||
margin-bottom: 2rem
|
||||
width: 100%
|
||||
height: auto
|
||||
text-align: center
|
||||
|
||||
.subtitle
|
||||
margin-bottom: 1rem
|
||||
padding: 0
|
||||
|
||||
text-align: center
|
||||
font-weight: bolder
|
||||
font-size: 1.2em
|
||||
|
||||
color: RGB($secondary)
|
||||
|
||||
> span
|
||||
padding: 0 0.1rem
|
||||
|
||||
color: transparent
|
||||
background: RGB($secondary)
|
||||
|
||||
nav
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
height: 3rem
|
||||
|
||||
display: flex
|
||||
flex-direction: row
|
||||
justify-content: center
|
||||
|
||||
> span
|
||||
width: 100%
|
||||
|
||||
> a
|
||||
margin: auto 0.25rem
|
||||
padding: 0.5rem 1rem
|
||||
|
||||
text-decoration: none
|
||||
white-space: nowrap
|
||||
|
||||
color: RGB($primary)
|
||||
|
||||
&.button
|
||||
@include button($white)
|
||||
|
||||
&.primary
|
||||
@include button($primary)
|
||||
|
||||
&.secondary
|
||||
@include button($secondary)
|
||||
|
||||
form
|
||||
display: flex
|
||||
flex-direction: column
|
||||
|
||||
> input
|
||||
margin: 0 0 1rem 0
|
||||
padding: 0.5rem 1rem
|
||||
|
||||
border: 1px solid RGB($white)
|
||||
border-radius: 2px
|
||||
|
||||
background-color: RGB($darkBlue)
|
||||
color: RGB($white)
|
||||
|
||||
&:focus
|
||||
outline: none
|
||||
border-color: RGB($primary)
|
||||
|
||||
&.error
|
||||
border-color: RGB($secondary)
|
||||
|
||||
> button
|
||||
margin: 0
|
||||
padding: 0.5rem 1rem
|
||||
|
||||
font-weight: bolder
|
||||
|
||||
border: transparent
|
||||
border-radius: 2px
|
||||
|
||||
background-color: RGB($primary)
|
||||
color: RGB($black)
|
||||
|
||||
&:focus-visible, &:hover
|
||||
outline: none
|
||||
background-color: RGBA($primary, 0.3)
|
||||
color: RGB($primary)
|
||||
|
||||
&.disabled
|
||||
pointer-events: none
|
||||
opacity: 0.5
|
||||
|
||||
&.secondary
|
||||
background-color: RGB($secondary)
|
||||
color: RGB($black)
|
||||
|
||||
&:focus-visible, &:hover
|
||||
background-color: RGBA($secondary, 0.3)
|
||||
color: RGB($secondary)
|
BIN
server/static/title.png
Normal file
BIN
server/static/title.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 152 KiB |
23
server/templates/auth.html
Normal file
23
server/templates/auth.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="auth">
|
||||
<h2>Login</h2>
|
||||
<form action="" method="POST">
|
||||
<input type="text" name="username" placeholder="Username | Email" required>
|
||||
<input type="password" name="password" placeholder="Password" required>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p style="text-align: center;">or</p>
|
||||
|
||||
<div class="auth">
|
||||
<h2>Register</h2>
|
||||
<form action="" method="POST">
|
||||
<input type="text" name="username" placeholder="Username" required>
|
||||
<input type="email" name="email" placeholder="Email - Optional">
|
||||
<input type="password" name="password" placeholder="Password" required>
|
||||
<button type="submit" class="secondary">Register</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
31
server/templates/base.html
Normal file
31
server/templates/base.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Front Rooms Highscores</title>
|
||||
{% assets "styles" %}
|
||||
<link rel="stylesheet" href="{{ ASSET_URL }}" type="text/css">
|
||||
{% endassets %}
|
||||
</head>
|
||||
<body>
|
||||
<img src="{{ url_for("static", filename="bg.png") }}" alt="The Front Rooms pause menu" class="background">
|
||||
<div class="app">
|
||||
<img src="{{ url_for("static", filename="title.png") }}" alt="The Front Rooms logo" class="title">
|
||||
<nav>
|
||||
<a href="{{ url_for('views.index', diff=0) }}" class="button">Level 1</a>
|
||||
<a href="{{ url_for('views.index', diff=1) }}" class="button">Level 2</a>
|
||||
<a href="{{ url_for('views.index', diff=2) }}" class="button">Level 3</a>
|
||||
<a href="{{ url_for('views.index', diff=3) }}" class="button">Normal</a>
|
||||
<a href="{{ url_for('views.index', diff=4) }}" class="button">Hard</a>
|
||||
|
||||
<span></span> <!-- This is a spacer -->
|
||||
|
||||
<a href="{{ url_for('auth.auth') }}" class="button secondary">Login</a>
|
||||
</nav>
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
30
server/templates/scores.html
Normal file
30
server/templates/scores.html
Normal file
|
@ -0,0 +1,30 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
{% if scores %}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Position</th>
|
||||
<th>Player</th>
|
||||
<th>Difficulty</th>
|
||||
<th>Score</th>
|
||||
</tr>
|
||||
{% for score in top_scores %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
{% if score.anonymous %}
|
||||
<td>{{ score.username }}</td>
|
||||
{% else %}
|
||||
<td>{{ score.scorer.username }}</td>
|
||||
{% endif %}
|
||||
<td>{{ score.difficulty }}</td>
|
||||
<td>{{ score.score }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="center-text">
|
||||
<h2>No scores yet</h2>
|
||||
<p>Set some!</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
105
server/views.py
105
server/views.py
|
@ -1,10 +1,12 @@
|
|||
from flask import Blueprint, jsonify, render_template_string, request, abort
|
||||
from flask import Blueprint, jsonify, request, render_template
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, IntegerField
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
from server.models import Scores, Users
|
||||
from server.models import Scores, Users, Tokens
|
||||
from server.extensions import db, cache
|
||||
from server.config import BEARER_TOKEN
|
||||
|
||||
|
||||
blueprint = Blueprint('views', __name__)
|
||||
|
||||
|
@ -17,44 +19,18 @@ class ScoreForm(FlaskForm):
|
|||
achievements = StringField('Achievements', validators=[DataRequired()])
|
||||
|
||||
|
||||
@blueprint.route('/', methods=['GET'])
|
||||
@blueprint.route('/')
|
||||
@cache.cached(timeout=60)
|
||||
def index():
|
||||
top_scores = Scores.query.order_by(Scores.score.desc()).limit(10).all()
|
||||
users = Users.query.all()
|
||||
return render_template_string('''
|
||||
<h1>Top Scores</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Score</th>
|
||||
<th>Difficulty</th>
|
||||
<th>Achievements</th>
|
||||
<th>Player</th>
|
||||
</tr>
|
||||
{% for score in top_scores %}
|
||||
<tr>
|
||||
<td>{{ score.score }}</td>
|
||||
<td>{{ score.difficulty }}</td>
|
||||
<td>{{ score.achievements }}</td>
|
||||
<td>{{ score.user.steam_name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<h1>Players</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Steam ID</th>
|
||||
<th>Steam Name</th>
|
||||
</tr>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{ user.steam_uuid }}</td>
|
||||
<td>{{ user.steam_name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
''', top_scores=top_scores, users=users)
|
||||
difficulty = request.args.get('diff', 0)
|
||||
|
||||
top_scores = (Scores.query
|
||||
.order_by(Scores.score.desc())
|
||||
.filter_by(difficulty=difficulty)
|
||||
.limit(10)
|
||||
.all())
|
||||
return render_template('scores.html', top_scores=top_scores)
|
||||
|
||||
|
||||
|
||||
@blueprint.route('/post', methods=['POST'])
|
||||
|
@ -63,33 +39,50 @@ def post():
|
|||
|
||||
if not form:
|
||||
return "Invalid form", 400
|
||||
if request.headers.get('Authentication') != 'Bearer 1234':
|
||||
if not request.headers.get('Authentication'):
|
||||
return "Invalid authentication", 401
|
||||
|
||||
if not isinstance(form.score.data, int):
|
||||
return "Score must be an integer", 400
|
||||
if form.score.data < 0:
|
||||
return "Score must be greater than 0", 400
|
||||
if form.difficulty.data not in ['easy', 'medium', 'hard']:
|
||||
if form.difficulty.data not in [0, 1, 2, 3, 4]:
|
||||
# 0 = Easy, Level 1
|
||||
# 1 = Easy, Level 2
|
||||
# 2 = Easy, Level 3
|
||||
# 3 = Normal
|
||||
# 4 = Hard
|
||||
return "Invalid difficulty", 400
|
||||
|
||||
user = Users.query.filter_by(steam_uuid=form.playerId.data).first()
|
||||
if not user:
|
||||
user = Users(
|
||||
steam_uuid=form.playerId.data,
|
||||
steam_name=form.playerName.data,
|
||||
if request.headers.get('Authentication') == BEARER_TOKEN:
|
||||
# User is not authenticated, but has the correct token
|
||||
# This is an anonymous user
|
||||
|
||||
if not form.playerName.data or len(form.playerId.data) != 4:
|
||||
return "Invalid player name", 400
|
||||
|
||||
score = Scores(
|
||||
anonymous=True,
|
||||
username=form.playerName.data,
|
||||
score=form.score.data,
|
||||
difficulty=form.difficulty.data,
|
||||
)
|
||||
db.session.add(user)
|
||||
db.session.add(score)
|
||||
db.session.commit()
|
||||
return "Success!", 200
|
||||
elif Tokens.query.filter_by(token=request.headers.get('Authentication')).first():
|
||||
# User is authenticated
|
||||
# This is a registered user
|
||||
|
||||
score = Scores(
|
||||
score=form.score.data,
|
||||
difficulty=form.difficulty.data,
|
||||
achievements=form.achievements.data,
|
||||
user_id=user.id,
|
||||
)
|
||||
db.session.add(score)
|
||||
db.session.commit()
|
||||
return jsonify({'message': 'Success!'})
|
||||
|
||||
user = Tokens.query.filter_by(token=request.headers.get('Authentication')).first().holder
|
||||
score = Scores(
|
||||
score=form.score.data,
|
||||
difficulty=form.difficulty.data,
|
||||
achievements=form.achievements.data,
|
||||
user_id=user.id,
|
||||
)
|
||||
db.session.add(score)
|
||||
db.session.commit()
|
||||
return "Success!", 200
|
||||
|
||||
return "Authentication failed", 401
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue