Add highscores server

This commit is contained in:
Michał Gdula 2023-05-03 20:08:09 +03:00
parent 0d28b50944
commit b6dc53dfaa
10 changed files with 192 additions and 6 deletions

View file

@ -1,8 +1,13 @@
# Expo Website
:5000 {
<!-- # Expo Website
expo.example.com {
reverse_proxy 127.0.0.1:5000
}
# Highscore Server
:6000 {
highscore.example.com {
reverse_proxy 127.0.0.1:6000
} -->
# Highscore Server
expo.leggy.dev:443 {
reverse_proxy localhost:5000
file_server
}

View file

@ -0,0 +1,8 @@
# syntax=docker/dockerfile:1
FROM python:3.10
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY server server
CMD ["flask", "run", "--port=5000", "--host=localhost"]

View file

@ -0,0 +1,2 @@
# Highscores-Server
Server (and website) to store and display Highscores of the players who completed the game

View file

@ -0,0 +1,5 @@
Flask
Flask-SQLAlchemy
Flask-Migrate
Flask-Caching
Flask-wtf

View file

@ -0,0 +1,14 @@
from flask import Flask
from server.extensions import db, migrate, cache
from server.views import blueprint
app = Flask(__name__)
app.config.from_pyfile('config.py')
db.init_app(app)
migrate.init_app(app, db)
cache.init_app(app)
db.create_all(app=app)
app.register_blueprint(blueprint)

View file

@ -0,0 +1,4 @@
SECRET_KEY = 'dev'
SQLALCHEMY_DATABASE_URI = 'sqlite:///db.sqlite'
SQLALCHEMY_TRACK_MODIFICATIONS = False

View file

@ -0,0 +1,7 @@
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_caching import Cache
db = SQLAlchemy()
migrate = Migrate()
cache = Cache()

View file

@ -0,0 +1,43 @@
"""
Database models for the server
"""
from server.extensions import db
class Scores(db.Model):
"""
Post 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)
scored_at = db.Column(
db.DateTime,
nullable=False,
server_default=db.func.now(),
)
class Users(db.Model):
"""
User table
"""
__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)
scores = db.relationship('Scores', backref='user', lazy=True)
creation_data = db.Column(
db.DateTime,
nullable=False,
server_default=db.func.now(),
)

View file

@ -0,0 +1,95 @@
from flask import Blueprint, jsonify, render_template_string, request, abort
from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField
from wtforms.validators import DataRequired
from server.models import Scores, Users
from server.extensions import db, cache
blueprint = Blueprint('views', __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('/', methods=['GET'])
@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)
@blueprint.route('/post', methods=['POST'])
def post():
form = ScoreForm()
if not form:
return "Invalid form", 400
if request.headers.get('Authentication') != 'Bearer 1234':
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']:
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,
)
db.session.add(user)
db.session.commit()
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!'})

View file

@ -1,14 +1,17 @@
version: "3.8"
services:
highscores:
build: ./Highscore-Server/
# restart: unless-stopped
ports:
- "5000:5000"
caddy:
image: caddy:latest
# restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "5000:5000"
- "6000:6000"
volumes:
- ./Caddy/Caddyfile:/etc/caddy/Caddyfile
- ./Caddy/data:/data