Merge pull request #2 from Fluffy-Bean/beta

Beta
This commit is contained in:
Michał Gdula 2023-06-23 14:48:42 +01:00 committed by GitHub
commit 2a1c83a44e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 164 additions and 34 deletions

View file

@ -1,3 +1,4 @@
Pillow
Gunicorn
psycopg2-binary
shortuuid

View file

@ -1,11 +1,20 @@
import uuid
import re
import os
from PIL import Image
from flask import Blueprint, request, render_template, flash, redirect, url_for
from flask_login import login_required, current_user, logout_user
from werkzeug.security import generate_password_hash, check_password_hash
from .config import USER_REGEX, USER_EMAIL_REGEX
from .config import (
USER_REGEX,
USER_EMAIL_REGEX,
UPLOAD_EXTENSIONS,
UPLOAD_MAX_SIZE,
UPLOAD_DIR,
UPLOAD_RESOLUTION,
)
from .models import Users, Sessions, Scores, ProfileTags, PasswordReset
from .extensions import db
@ -29,7 +38,36 @@ def settings():
if not check_password_hash(user.password, password):
flash("Password is incorrect!", "error")
return redirect(url_for('account.settings'))
return redirect(url_for("account.settings"))
if "file" in request.files and request.files['file'].filename:
picture = request.files["file"]
file_ext = picture.filename.split(".")[-1]
file_name = f"{user.id}.{file_ext}"
if file_ext not in UPLOAD_EXTENSIONS:
error.append("Picture is not a valid image!")
if picture.content_length > UPLOAD_MAX_SIZE:
error.append(f"Picture must be less than {UPLOAD_EXTENSIONS / 1000000}MB!")
image = Image.open(picture.stream)
image_x, image_y = image.size
image.thumbnail((
min(image_x, UPLOAD_RESOLUTION),
min(image_y, UPLOAD_RESOLUTION)
))
if error:
for err in error:
flash(err, "error")
return redirect(url_for("account.settings"))
if user.picture:
os.remove(os.path.join(UPLOAD_DIR, user.picture))
user.picture = file_name
image.save(os.path.join(UPLOAD_DIR, file_name))
image.close()
if username:
if user_regex.match(username):
@ -79,7 +117,9 @@ def password_reset():
if not check_password_hash(user.password, current):
error.append("Current password is incorrect!")
if len(new) < 8:
error.append("New password is too short! Must be at least 8 characters long.")
error.append(
"New password is too short! Must be at least 8 characters long."
)
if new != confirm:
error.append("New passwords do not match!")

View file

@ -1,9 +1,10 @@
import re
import shortuuid
from flask import Blueprint, request, jsonify
from flask import Blueprint, request, jsonify, send_from_directory
from flask_login import login_required, current_user
from werkzeug.security import check_password_hash
from werkzeug.utils import secure_filename
from .models import Scores, Sessions, Users
from .extensions import db
@ -11,12 +12,19 @@ from .config import (
GAME_DIFFICULTIES,
MAX_SEARCH_RESULTS,
USER_REGEX,
UPLOAD_DIR,
)
blueprint = Blueprint("api", __name__, url_prefix="/api")
@blueprint.route("/uploads/<filename>", methods=["GET"])
def upload_dir(filename):
filename = secure_filename(filename)
return send_from_directory(UPLOAD_DIR, filename)
@blueprint.route("/tokens", methods=["POST"])
@login_required
def tokens():
@ -58,6 +66,10 @@ def post():
if int(difficulty) not in GAME_DIFFICULTIES:
return "Invalid difficulty!"
# This is a fix for a bug in the game that we dunno how to actually fix
# Yupeeeeeeeeee
if score < 10:
return "Score is impossible!"
session_data = Sessions.query.filter_by(auth_key=session_key).first()
if not session_data:

View file

@ -1,6 +1,11 @@
import os
from os import getenv
UPLOAD_DIR = "/data/uploads"
UPLOAD_EXTENSIONS = ["png", "jpg", "jpeg", "gif"]
UPLOAD_RESOLUTION = 512
UPLOAD_MAX_SIZE = 3 * 1024 * 1024 # 3MB
GAME_VERSION = "alpha"
GAME_VERSIONS = ["alpha"]
GAME_DIFFICULTIES = [0, 1, 2, 3, 4]
@ -12,12 +17,12 @@ MAX_TOP_SCORES = 15
MAX_SEARCH_RESULTS = 5
# Postgres
SECRET_KEY = os.getenv("FLASK_KEY")
SECRET_KEY = getenv("FLASK_KEY")
user = os.getenv("DB_USER")
password = os.getenv("DB_PASSWORD")
host = os.getenv("DB_HOST")
db = os.getenv("DB_NAME")
user = getenv("DB_USER")
password = getenv("DB_PASSWORD")
host = getenv("DB_HOST")
db = getenv("DB_NAME")
SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{user}:{password}@{host}:5432/{db}"
SQLALCHEMY_TRACK_MODIFICATIONS = False

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View file

@ -7,7 +7,7 @@
background-color: rgba($black, 0.5)
border-radius: 2px
border: 1px solid RGBA(var(--white),0.05)
border: 1px solid RGBA($white, 0.05)
> h2
margin: 0 0 0.2rem 0
@ -28,3 +28,59 @@
display: flex
flex-direction: column
gap: 0.5rem
.account-block
margin-bottom: 1rem
padding: 1rem
display: flex
flex-direction: row
gap: 1rem
background-color: rgba($black, 0.5)
border-radius: 2px
border: 1px solid RGBA($white, 0.05)
> img
height: 10rem
width: 10rem
background-color: RGBA($white, 0.02)
border: 1px solid RGBA($white, 0.1)
border-radius: 2px
object-fit: cover
.other
width: 100%
display: flex
flex-direction: column
justify-content: flex-start
gap: 0.5rem
h2
margin: 0
font-size: 1.3rem
color: RGB($white)
p
margin: 0
font-size: 1rem
color: RGB($white)
hr
margin: 0
width: 100%
border: 0 solid transparent
border-bottom: 1px solid RGBA($white, 0.1)
@media (max-width: 621px)
.account-block
flex-direction: column
> img
margin: 0 auto
width: 15rem
height: 15rem

View file

@ -48,7 +48,7 @@
> label
padding: 0.5rem 0.7rem
min-width: 6rem
min-width: 7rem
text-decoration: none
text-align: end

View file

@ -1,7 +1,7 @@
.profile-settings
display: flex
flex-direction: row
gap: 0.5rem
gap: 1rem
.picture
margin: 0
@ -11,6 +11,8 @@
display: flex
flex-direction: column
border: 1px solid RGBA($white, 0.1)
> img
height: 10rem
width: 10rem
@ -59,16 +61,17 @@
.other
width: 100%
height: 100%
display: flex
flex-direction: column
justify-content: flex-start
justify-content: space-between
gap: 0.5rem
> .text-input
margin: 0 !important
@media (max-width: 621px)
.profile-settings
flex-direction: column
gap: 1rem
.picture
margin: 0 auto

View file

@ -4,20 +4,27 @@
{% block content %}
<div class="block">
<h2 style="margin-bottom: 1rem;">Profile Settings</h2>
<form action="{{ url_for('account.settings') }}" method="POST">
<form action="{{ url_for('account.settings') }}" method="POST" enctype="multipart/form-data">
<div class="profile-settings">
<div class="picture">
<img src="{{ url_for('static', filename='images/error/2.jpg') }}" alt="Profile picture">
{% if current_user.picture %}
<img src="{{ url_for('api.upload_dir', filename=current_user.picture) }}" alt="Profile picture">
{% else %}
<img src="{{ url_for('static', filename='images/pfp.png') }}" alt="Profile picture">
{% endif %}
<label for="profile-picture">Profile Picture</label>
<input type="file" name="picture" id="profile-picture">
<input type="file" name="file" id="profile-picture">
</div>
<div class="other">
{{ text(id="profile-username", name="username", value=current_user.username) }}
{{ text(id="profile-email", name="email") }}
{{ text(id="profile-password", name="password", type="password", required=True, minlength=8) }}
<span style="height: 100%"></span>
<button type="submit" class="button primary">Save changes</button>
</div>
</div>
<button type="submit" class="button primary">Save changes</button>
</form>
</div>

View file

@ -37,8 +37,20 @@
{% endblock %}
{% block content %}
{% if user %}
<div class="block">
<h2 style="margin-bottom: 0;">{{ user.username }}</h2>
<div class="account-block">
{% if user.picture %}
<img src="{{ url_for('api.upload_dir', filename=user.picture) }}" alt="Profile picture">
{% else %}
<img src="{{ url_for('static', filename='images/pfp.png') }}" alt="Profile picture">
{% endif %}
<div class="other">
<h2>{{ user.username }}</h2>
<p>Joined {{ user.joined_at.strftime('%Y-%m-%d') }}</p>
<hr>
<p>Best score: {{ scores[0].score | format_result }}</p>
</div>
</div>
{% endif %}
@ -50,7 +62,6 @@
<th>Name</th>
<th>Time Set</th>
<th>Submitted</th>
<!-- <th>Game</th> -->
</tr>
{% for score in scores %}
<tr>
@ -72,7 +83,6 @@
<td>{{ score.score | format_result }}</td>
<td>{{ score.scored_at.strftime('%Y-%m-%d') }}</td>
<!-- <td>{{ score.version }}</td> -->
</tr>
{% endfor %}
</table>

View file

@ -19,7 +19,7 @@ def index():
scores = db.session.query(Scores).filter_by(difficulty=diff_arg)
subquery = (
db.session.query(Scores.user_id, func.min(Scores.score).label('min'))
db.session.query(Scores.user_id, func.min(Scores.score).label("min"))
.group_by(Scores.user_id)
.subquery()
)
@ -28,9 +28,8 @@ def index():
scores = scores.filter_by(version=ver_arg)
if not user_arg:
scores = (
scores.join(subquery, Scores.user_id == subquery.c.user_id)
.filter(Scores.score == subquery.c.min)
scores = scores.join(subquery, Scores.user_id == subquery.c.user_id).filter(
Scores.score == subquery.c.min
)
else:
user = Users.query.filter_by(username=user_arg).first()
@ -42,11 +41,7 @@ def index():
scores = scores.order_by(Scores.score.asc()).limit(MAX_TOP_SCORES).all()
return render_template(
"views/scores.html",
scores=scores,
diff=int(diff_arg),
ver=ver_arg,
user=user
"views/scores.html", scores=scores, diff=int(diff_arg), ver=ver_arg, user=user
)

View file

@ -37,6 +37,7 @@ services:
restart: unless-stopped
volumes:
- ./TFR/storage/migrations:/data/migrations
- ./TFR/storage/uploads:/data/uploads
environment:
FLASK_KEY: ${THE_FRONT_ROOMS_SECRETE_KEY}
DB_USER: ${POSTGRES_USER}