Fuck so much to comment on
Renamed the folders and containers to something more reasonable Using .env file for secretes so I can better hide them from git Mostly it, I think
9
.env
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
GAME_EXPO_DOMAIN = expo.leggy.dev
|
||||||
|
GAME_EXPO_SECRETE_KEY = leggy
|
||||||
|
|
||||||
|
POSTGRES_USER = leggy
|
||||||
|
POSTGRES_PASSWORD = leggy
|
||||||
|
POSTGRES_DB = leggy
|
||||||
|
|
||||||
|
THE_FRONT_ROOMS_DOMAIN = tfr.leggy.dev
|
||||||
|
THE_FRONT_ROOMS_SECRETE_KEY = leggy
|
6
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
||||||
.idea/
|
/.idea/
|
||||||
.vscode/
|
/.vscode/
|
||||||
|
|
||||||
.uuid
|
.uuid
|
||||||
|
.env
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{$DOMAIN_HIGHSCORE} {
|
{$THE_FRONT_ROOMS_DOMAIN} {
|
||||||
reverse_proxy highscore:8000
|
reverse_proxy tfr:8000
|
||||||
encode gzip
|
encode gzip
|
||||||
}
|
}
|
||||||
|
|
||||||
{$DOMAIN_EXPO} {
|
{$GAME_EXPO_DOMAIN} {
|
||||||
reverse_proxy expo:5000
|
reverse_proxy expo:5000
|
||||||
encode gzip
|
encode gzip
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
function keepRatio(){let games=document.querySelectorAll(".game-box");games.forEach((game)=>{game.style.height=(game.offsetWidth*1.5)+"px";});}
|
|
||||||
window.onscroll=()=>{scrollFunction();checkSection();};window.onload=()=>{keepRatio()
|
|
||||||
resizeNav();scrollFunction();checkSection();};window.onresize=()=>{keepRatio()
|
|
||||||
resizeNav();checkSection();};const defaultTitle="DV8 Game Expo <span>2023</span>";let navSpacing=(5*16);let prevElement=null;function resizeNav(){if(window.innerWidth>600){navSpacing=(5*16);}else{navSpacing=(8*16);}}
|
|
||||||
function scrollFunction(){let nav=document.querySelector("nav");let scrollHeight=0;if(document.body.scrollTop>scrollHeight||document.documentElement.scrollTop>scrollHeight){nav.classList.add("scrolled");}else{nav.classList.remove("scrolled");}}
|
|
||||||
function checkSection(){let navTitle=document.querySelector(".title > p");let sections=document.querySelectorAll("section");if((window.pageYOffset+navSpacing)<sections[0].offsetTop||window.pageYOffset===0){if(prevElement===null)return;navTitle.innerHTML=defaultTitle;navTitle.style.animation="title-change 0.2s ease-in-out";prevElement=null;setTimeout(()=>{navTitle.style.animation="";},200);return;}
|
|
||||||
sections.forEach((section)=>{let top=section.offsetTop;let bottom=section.offsetTop+section.offsetHeight;if((window.pageYOffset+navSpacing)>=top&&window.pageYOffset<(bottom-navSpacing)){if(prevElement===section)return;navTitle.innerHTML=section.id.split("_").join(" ");navTitle.style.animation="title-change 0.2s ease-in-out";prevElement=section;setTimeout(()=>{navTitle.style.animation="";},200);}});}
|
|
||||||
document.querySelectorAll("nav > ul > li > a").forEach((element)=>{element.onclick=()=>{let anchor=location.hash.split("#")[1].toString();let element=document.getElementById(anchor);if(element===null){window.scrollTo({top:0,behavior:"smooth"});}else{window.scrollTo({top:(element.offsetTop+navSpacing),behavior:"smooth"});}}});
|
|
0
DV8-Expo/.gitignore → GameExpo/.gitignore
vendored
|
@ -6,11 +6,11 @@ from website.config import INSTANCE_DIR, MIGRATION_DIR
|
||||||
from website import routes
|
from website import routes
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__) # instance_path=INSTANCE_DIR
|
app = Flask(__name__, instance_path=INSTANCE_DIR)
|
||||||
app.config.from_pyfile("config.py")
|
app.config.from_pyfile("config.py")
|
||||||
|
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
migrate.init_app(app, db) # directory=MIGRATION_DIR
|
migrate.init_app(app, db, directory=MIGRATION_DIR)
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
@ -1,24 +0,0 @@
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
# Purely to make the code a bit more readable
|
|
||||||
def env(key):
|
|
||||||
return os.getenv(key)
|
|
||||||
|
|
||||||
|
|
||||||
SECRET_KEY = env("FLASK_KEY")
|
|
||||||
BEARER_TOKEN = env("BEARER_TOKEN")
|
|
||||||
|
|
||||||
user = env("DB_USER")
|
|
||||||
password = env("DB_PASSWORD")
|
|
||||||
host = env("DB_HOST")
|
|
||||||
database = env("DB_NAME")
|
|
||||||
|
|
||||||
SQLALCHEMY_DATABASE_URI = (
|
|
||||||
f"postgresql+psycopg2://{user}:{password}@{host}:5432/{database}"
|
|
||||||
)
|
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
||||||
SQLALCHEMY_POOL_RECYCLE = 621
|
|
||||||
|
|
||||||
MIGRATION_DIR = "/data/storage/migrations"
|
|
||||||
INSTANCE_DIR = "/data/storage/instance"
|
|
0
Highscore-Server/.gitignore → TFR/.gitignore
vendored
|
@ -26,4 +26,4 @@ fi
|
||||||
|
|
||||||
# Start server!!!!
|
# Start server!!!!
|
||||||
echo "Starting server..."
|
echo "Starting server..."
|
||||||
gunicorn --bind highscore:8000 server:app
|
gunicorn --bind tfr:8000 server:app
|
|
@ -5,7 +5,6 @@ from flask_login import login_required, current_user
|
||||||
|
|
||||||
from server.models import Tokens, Scores
|
from server.models import Tokens, Scores
|
||||||
from server.extensions import db
|
from server.extensions import db
|
||||||
from server.config import BEARER_TOKEN
|
|
||||||
|
|
||||||
|
|
||||||
blueprint = Blueprint("api", __name__, url_prefix="/api")
|
blueprint = Blueprint("api", __name__, url_prefix="/api")
|
||||||
|
@ -40,20 +39,30 @@ def tokens():
|
||||||
return jsonify({"success": "Token added!"}), 200
|
return jsonify({"success": "Token added!"}), 200
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/post", methods=["POST"])
|
@blueprint.route("/post", methods=["GET", "POST"])
|
||||||
def post():
|
def post():
|
||||||
|
if request.method == "GET":
|
||||||
|
return """
|
||||||
|
<form method="POST">
|
||||||
|
<input name="score">
|
||||||
|
<input name="difficulty">
|
||||||
|
<input name="token">
|
||||||
|
<button type="submit">Sub</button>
|
||||||
|
</form>
|
||||||
|
"""
|
||||||
|
|
||||||
form = request.form
|
form = request.form
|
||||||
|
|
||||||
if not form:
|
if not form:
|
||||||
return "Invalid form", 400
|
return "Invalid form", 400
|
||||||
if not request.headers.get("Authentication"):
|
if not form["token"]:
|
||||||
return "Invalid authentication", 401
|
return "Invalid authentication", 401
|
||||||
|
|
||||||
if not isinstance(form["score"], int):
|
# if not isinstance(form["score"], int):
|
||||||
return "Score must be an integer", 400
|
# return "Score must be an integer", 400
|
||||||
if int(form["score"]) < 0:
|
if int(form["score"]) < 0:
|
||||||
return "Score must be greater than 0", 400
|
return "Score must be greater than 0", 400
|
||||||
if form["difficulty"] not in [0, 1, 2, 3, 4]:
|
if int(form["difficulty"]) not in [0, 1, 2, 3, 4]:
|
||||||
# 0 = Easy, Level 1
|
# 0 = Easy, Level 1
|
||||||
# 1 = Easy, Level 2
|
# 1 = Easy, Level 2
|
||||||
# 2 = Easy, Level 3
|
# 2 = Easy, Level 3
|
||||||
|
@ -61,38 +70,17 @@ def post():
|
||||||
# 4 = Hard
|
# 4 = Hard
|
||||||
return "Invalid difficulty", 400
|
return "Invalid difficulty", 400
|
||||||
|
|
||||||
if token_data := Tokens.query.filter_by(
|
if token := Tokens.query.filter_by(token=form["token"]).first():
|
||||||
token=request.headers.get("Authentication")
|
# Yupeee, authenticated
|
||||||
).first():
|
|
||||||
# User is authenticated
|
|
||||||
# This is a registered user
|
|
||||||
|
|
||||||
score = Scores(
|
score = Scores(
|
||||||
score=form["score"],
|
score=int(form["score"]),
|
||||||
difficulty=form["difficulty"],
|
difficulty=int(form["difficulty"]),
|
||||||
achievements=form["achievements"],
|
scorer=token.holder,
|
||||||
user_id=token_data.holder,
|
|
||||||
)
|
|
||||||
db.session.add(score)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return "Success!", 200
|
|
||||||
elif request.headers.get("Authentication") == BEARER_TOKEN:
|
|
||||||
# User is not authenticated, but has the correct token
|
|
||||||
# This is an anonymous user
|
|
||||||
|
|
||||||
if not form["playerName"] or len(form["playerId"]) != 4:
|
|
||||||
return "Invalid player name", 400
|
|
||||||
|
|
||||||
score = Scores(
|
|
||||||
anonymous=True,
|
|
||||||
username=form["playerName"],
|
|
||||||
score=form["score"],
|
|
||||||
difficulty=form["difficulty"],
|
|
||||||
)
|
)
|
||||||
db.session.add(score)
|
db.session.add(score)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return "Success!", 200
|
return "Success!", 200
|
||||||
|
|
||||||
|
# L no authentication :3
|
||||||
return "Authentication failed", 401
|
return "Authentication failed", 401
|
15
TFR/server/config.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
SECRET_KEY = os.getenv("FLASK_KEY")
|
||||||
|
|
||||||
|
user = os.getenv("DB_USER")
|
||||||
|
password = os.getenv("DB_PASSWORD")
|
||||||
|
host = os.getenv("DB_HOST")
|
||||||
|
db = os.getenv("DB_NAME")
|
||||||
|
|
||||||
|
SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{user}:{password}@{host}:5432/{db}"
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
SQLALCHEMY_POOL_RECYCLE = 621
|
||||||
|
|
||||||
|
MIGRATION_DIR = "/data/storage/migrations"
|
||||||
|
INSTANCE_DIR = "/data/storage/instance"
|
|
@ -17,9 +17,6 @@ class Scores(db.Model):
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
|
||||||
anonymous = db.Column(db.Boolean, nullable=False, default=False)
|
|
||||||
username = db.Column(db.String(32), nullable=True)
|
|
||||||
|
|
||||||
score = db.Column(db.Float, nullable=False)
|
score = db.Column(db.Float, nullable=False)
|
||||||
difficulty = db.Column(db.Integer, nullable=False)
|
difficulty = db.Column(db.Integer, nullable=False)
|
||||||
scored_at = db.Column(
|
scored_at = db.Column(
|
||||||
|
@ -28,7 +25,7 @@ class Scores(db.Model):
|
||||||
server_default=db.func.now(),
|
server_default=db.func.now(),
|
||||||
)
|
)
|
||||||
|
|
||||||
scorer = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
|
scorer = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class Users(db.Model, UserMixin):
|
class Users(db.Model, UserMixin):
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 400 KiB After Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 165 KiB |
Before Width: | Height: | Size: 708 KiB After Width: | Height: | Size: 708 KiB |
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
|
@ -34,7 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<img src="{{ url_for('static', filename='title.png') }}" alt="The Front Rooms logo" class="title" height="60px">
|
<img src="{{ url_for('static', filename='title.png') }}" alt="The Front Rooms logo" class="title" height="82px">
|
||||||
<nav>
|
<nav>
|
||||||
<a href="{{ url_for('views.index') }}" class="button">Scores</a>
|
<a href="{{ url_for('views.index') }}" class="button">Scores</a>
|
||||||
<a href="{{ url_for('views.about') }}" class="button"><i class="ph ph-info"></i></a>
|
<a href="{{ url_for('views.about') }}" class="button"><i class="ph ph-info"></i></a>
|
|
@ -20,14 +20,10 @@
|
||||||
<th>Difficulty</th>
|
<th>Difficulty</th>
|
||||||
<th>Score</th>
|
<th>Score</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for score in top_scores %}
|
{% for score in scores %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ loop.index }}</td>
|
<td>{{ loop.index }}</td>
|
||||||
{% if score.anonymous %}
|
<td>{{ score.scorer.username }}</td>
|
||||||
<td>{{ score.username }}</td>
|
|
||||||
{% else %}
|
|
||||||
<td>{{ score.scorer.username }}</td>
|
|
||||||
{% endif %}
|
|
||||||
<td>{{ score.difficulty }}</td>
|
<td>{{ score.difficulty }}</td>
|
||||||
<td>{{ score.score }}</td>
|
<td>{{ score.score }}</td>
|
||||||
</tr>
|
</tr>
|
|
@ -10,13 +10,13 @@ blueprint = Blueprint("views", __name__)
|
||||||
def index():
|
def index():
|
||||||
difficulty = request.args.get("diff", 0)
|
difficulty = request.args.get("diff", 0)
|
||||||
|
|
||||||
top_scores = (
|
scores = (
|
||||||
Scores.query.order_by(Scores.score.desc())
|
Scores.query.filter_by(difficulty=difficulty)
|
||||||
.filter_by(difficulty=difficulty)
|
.order_by(Scores.score.desc())
|
||||||
.limit(10)
|
.limit(10)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
return render_template("scores.html", top_scores=top_scores)
|
return render_template("scores.html", scores=scores)
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/about")
|
@blueprint.route("/about")
|
|
@ -12,45 +12,44 @@ services:
|
||||||
- ./Caddy/data:/data
|
- ./Caddy/data:/data
|
||||||
- ./Caddy/config:/config
|
- ./Caddy/config:/config
|
||||||
environment:
|
environment:
|
||||||
DOMAIN_HIGHSCORE: tfr.leggy.dev
|
THE_FRONT_ROOMS_DOMAIN: ${THE_FRONT_ROOMS_DOMAIN}
|
||||||
DOMAIN_EXPO: expo.leggy.dev
|
GAME_EXPO_DOMAIN: ${GAME_EXPO_DOMAIN}
|
||||||
links:
|
links:
|
||||||
- highscore
|
- tfr
|
||||||
- expo
|
- expo
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:alpine
|
image: postgres:alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
ports:
|
||||||
# - "5432:5432"
|
- "5432:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- ./Postgres/data:/var/lib/postgresql/data
|
- ./Postgres/data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: pguser
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
POSTGRES_PASSWORD: secret
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
POSTGRES_DB: database
|
POSTGRES_DB: ${POSTGRES_DB}
|
||||||
links:
|
links:
|
||||||
- highscore
|
- tfr
|
||||||
|
|
||||||
highscore:
|
tfr:
|
||||||
build: ./Highscore-Server
|
build: TFR
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./Highscore-Server/storage:/data/storage
|
- ./TFR/storage:/data/storage
|
||||||
- ./Highscore-Server/logs:/data/logs
|
- ./TFR/logs:/data/logs
|
||||||
environment:
|
environment:
|
||||||
FLASK_KEY: secret
|
FLASK_KEY: ${THE_FRONT_ROOMS_SECRETE_KEY}
|
||||||
BEARER_TOKEN: 1234
|
DB_USER: ${POSTGRES_USER}
|
||||||
DB_USER: pguser
|
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
DB_PASSWORD: secret
|
|
||||||
DB_HOST: db
|
DB_HOST: db
|
||||||
DB_NAME: database
|
DB_NAME: ${POSTGRES_DB}
|
||||||
|
|
||||||
expo:
|
expo:
|
||||||
build: ./DV8-Expo
|
build: GameExpo
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./DV8-Expo/storage:/data/storage
|
- ./GameExpo/storage:/data/storage
|
||||||
- ./DV8-Expo/logs:/data/logs
|
- ./GameExpo/logs:/data/logs
|
||||||
environment:
|
environment:
|
||||||
FLASK_KEY: secret
|
FLASK_KEY: ${GAME_EXPO_SECRETE_KEY}
|
||||||
|
|