mirror of
https://github.com/Fluffy-Bean/GameExpo23.git
synced 2025-05-14 14:22:16 +00:00
commit
2a3dfc5f99
12 changed files with 181 additions and 177 deletions
|
@ -1,14 +1,15 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
FROM alpine:latest
|
||||
FROM alpine:3.18.2
|
||||
|
||||
EXPOSE 8000
|
||||
RUN apk update && apk add python3 py3-pip postgresql-client
|
||||
WORKDIR /data
|
||||
RUN mkdir /storage&& \
|
||||
apk update && \
|
||||
apk --no-cache add python3 py3-pip postgresql-client
|
||||
|
||||
COPY requirements.txt requirements.txt
|
||||
RUN pip install -r requirements.txt
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
RUN mkdir /storage
|
||||
COPY ./server ./server
|
||||
COPY ./run.sh ./run.sh
|
||||
RUN chmod +x ./run.sh
|
||||
|
|
10
TFR/run.sh
10
TFR/run.sh
|
@ -1,15 +1,15 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Wait for database to start
|
||||
until pg_isready -d $DB_NAME -h $DB_HOST -U $DB_USER
|
||||
until pg_isready -d "$DB_NAME" -h "$DB_HOST" -U "$DB_USER"
|
||||
do
|
||||
echo "Waiting for database to start... (5s)"
|
||||
sleep 5
|
||||
echo "Waiting for database to start... (3s)"
|
||||
sleep 3
|
||||
done
|
||||
|
||||
echo "Database is ready!"
|
||||
|
||||
# Check if migrastions folder exists
|
||||
# Check if migrations folder exists
|
||||
if [ ! -d "/data/storage/migrations" ];
|
||||
then
|
||||
echo "Creating tables..."
|
||||
|
@ -17,7 +17,7 @@ then
|
|||
fi
|
||||
|
||||
# Check if there are any changes to the database
|
||||
if ! $(flask --app server db check | grep -q "No changes in schema detected.");
|
||||
if ! flask --app server db check | grep "No changes in schema detected.";
|
||||
then
|
||||
echo "Database changes detected! Migrating..."
|
||||
flask --app server db migrate
|
||||
|
|
|
@ -21,10 +21,23 @@ from .extensions import db
|
|||
blueprint = Blueprint("account", __name__, url_prefix="/account")
|
||||
|
||||
|
||||
@blueprint.route("/settings", methods=["GET", "POST"])
|
||||
@blueprint.route("/settings", methods=["GET"])
|
||||
@login_required
|
||||
def settings():
|
||||
if request.method == "POST":
|
||||
def get_settings():
|
||||
action = request.args.get("action", None)
|
||||
|
||||
if action == "logout":
|
||||
logout_user()
|
||||
flash("Successfully logged out!", "success")
|
||||
return redirect(url_for("views.index"))
|
||||
|
||||
sessions = Sessions.query.filter_by(user_id=current_user.id).all()
|
||||
return render_template("views/account_settings.html", sessions=sessions)
|
||||
|
||||
|
||||
@blueprint.route("/settings", methods=["POST"])
|
||||
@login_required
|
||||
def post_settings():
|
||||
username = request.form.get("username", "").strip()
|
||||
email = request.form.get("email", "").strip()
|
||||
password = request.form.get("password", "").strip()
|
||||
|
@ -44,9 +57,7 @@ def settings():
|
|||
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!"
|
||||
)
|
||||
error.append(f"Picture must be less than {UPLOAD_MAX_SIZE}MB!")
|
||||
|
||||
image = Image.open(picture.stream)
|
||||
|
||||
|
@ -94,22 +105,17 @@ def settings():
|
|||
|
||||
flash("Successfully updated account!", "success")
|
||||
return redirect(url_for("account.settings"))
|
||||
else:
|
||||
action = request.args.get("action", None)
|
||||
|
||||
if action == "logout":
|
||||
logout_user()
|
||||
flash("Successfully logged out!", "success")
|
||||
return redirect(url_for("views.index"))
|
||||
|
||||
sessions = Sessions.query.filter_by(user_id=current_user.id).all()
|
||||
return render_template("views/account_settings.html", sessions=sessions)
|
||||
|
||||
|
||||
@blueprint.route("/reset-password", methods=["GET", "POST"])
|
||||
@blueprint.route("/password", methods=["GET"])
|
||||
@login_required
|
||||
def password_reset():
|
||||
if request.method == "POST":
|
||||
def get_password_reset():
|
||||
return render_template("views/reset_password.html")
|
||||
|
||||
|
||||
@blueprint.route("/password", methods=["POST"])
|
||||
@login_required
|
||||
def post_password_reset():
|
||||
current = request.form.get("current", "").strip()
|
||||
new = request.form.get("new", "").strip()
|
||||
confirm = request.form.get("confirm", "").strip()
|
||||
|
@ -122,9 +128,7 @@ 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!")
|
||||
|
||||
|
@ -140,14 +144,17 @@ def password_reset():
|
|||
flash("Successfully changed password!", "success")
|
||||
logout_user()
|
||||
return redirect(url_for("auth.auth"))
|
||||
else:
|
||||
return render_template("views/reset_password.html")
|
||||
|
||||
|
||||
@blueprint.route("/delete-account", methods=["GET", "POST"])
|
||||
@blueprint.route("/delete-account", methods=["GET"])
|
||||
@login_required
|
||||
def delete_account():
|
||||
if request.method == "POST":
|
||||
def get_delete_account():
|
||||
return render_template("views/delete_account.html")
|
||||
|
||||
|
||||
@blueprint.route("/delete", methods=["POST"])
|
||||
@login_required
|
||||
def post_delete_account():
|
||||
username = request.form.get("username", "").strip()
|
||||
password = request.form.get("password", "").strip()
|
||||
error = []
|
||||
|
@ -176,5 +183,3 @@ def delete_account():
|
|||
flash("Successfully deleted account!", "success")
|
||||
logout_user()
|
||||
return redirect(url_for("auth.auth"))
|
||||
else:
|
||||
return render_template("views/delete_account.html")
|
||||
|
|
|
@ -6,7 +6,7 @@ SECRET_KEY = getenv("FLASK_KEY")
|
|||
|
||||
UPLOAD_DIR = "/data/uploads"
|
||||
UPLOAD_EXTENSIONS = ["png", "jpg", "jpeg", "gif", "webp"]
|
||||
UPLOAD_RESOLUTION = 512
|
||||
UPLOAD_RESOLUTION = 169
|
||||
UPLOAD_MAX_SIZE = 3 * 1024 * 1024 # 3MB
|
||||
|
||||
GAME_VERSION = "alpha"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
function addFlashMessage(message, type='success') {
|
||||
let flask = document.createElement('p');
|
||||
const flask = document.createElement('p');
|
||||
flask.onclick = () => flask.remove();
|
||||
flask.classList.add(type);
|
||||
flask.innerHTML = message;
|
||||
|
||||
let close = document.createElement('span');
|
||||
const close = document.createElement('span');
|
||||
close.innerHTML = '<i class="ph-bold ph-x"></i>';
|
||||
|
||||
flask.appendChild(close);
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
function showHint() {
|
||||
let search = document.querySelector('#search');
|
||||
let searchPos = search.getBoundingClientRect();
|
||||
let hint = document.querySelector('.search-hint');
|
||||
const search = document.querySelector('#search');
|
||||
const searchPos = search.getBoundingClientRect();
|
||||
const hint = document.querySelector('.search-hint');
|
||||
|
||||
hint.style.width = search.offsetWidth + 'px';
|
||||
hint.style.left = searchPos.left + 'px';
|
||||
hint.style.top = searchPos.bottom + 'px';
|
||||
hint.style.width = `${search.offsetWidth}px`;
|
||||
hint.style.left = `${searchPos.left}px`;
|
||||
hint.style.top = `${searchPos.bottom}px`;
|
||||
|
||||
hint.style.display = 'flex';
|
||||
}
|
||||
|
||||
|
||||
function hideHint() {
|
||||
let hint = document.querySelector('.search-hint');
|
||||
const hint = document.querySelector('.search-hint');
|
||||
hint.style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
function updateHint() {
|
||||
let search = document.querySelector('#search');
|
||||
let searchPos = search.getBoundingClientRect();
|
||||
let hint = document.querySelector('.search-hint');
|
||||
const search = document.querySelector('#search');
|
||||
const searchPos = search.getBoundingClientRect();
|
||||
const hint = document.querySelector('.search-hint');
|
||||
|
||||
hint.style.width = search.offsetWidth + 'px';
|
||||
hint.style.left = searchPos.left + 'px';
|
||||
hint.style.top = searchPos.bottom + 'px';
|
||||
hint.style.width = `${search.offsetWidth}px`;
|
||||
hint.style.left = `${searchPos.left}px`;
|
||||
hint.style.top = `${searchPos.bottom}px`;
|
||||
}
|
||||
|
||||
|
||||
function getSearch() {
|
||||
let search = document.querySelector('#search').value;
|
||||
let hint = document.querySelector('.search-hint');
|
||||
const hint = document.querySelector('.search-hint');
|
||||
|
||||
if (search.length === 0) {
|
||||
hint.innerHTML = '<p>Start typing to see results...</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/api/search?q=' + search.toString(), {
|
||||
fetch(`/api/search?q=${search}`, {
|
||||
method: 'GET',
|
||||
})
|
||||
.then(response => response.json())
|
||||
|
@ -50,12 +50,11 @@ function getSearch() {
|
|||
hint.innerHTML = '';
|
||||
|
||||
data.forEach(user => {
|
||||
let el = document.createElement('button');
|
||||
const el = document.createElement('button');
|
||||
el.innerHTML = user;
|
||||
el.onmousedown = function (event) {
|
||||
event.preventDefault();
|
||||
search = document.querySelector('#search');
|
||||
search.value = user.toString();
|
||||
search = user.toString();
|
||||
search.blur();
|
||||
}
|
||||
hint.appendChild(el);
|
||||
|
@ -69,7 +68,7 @@ function getSearch() {
|
|||
|
||||
window.onload = () => {
|
||||
let typingTimer;
|
||||
let search = document.querySelector('#search');
|
||||
const search = document.querySelector('#search');
|
||||
|
||||
if (search === null) {
|
||||
return;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
function yeetSession(id) {
|
||||
let form = new FormData();
|
||||
form.append('session_id', id);
|
||||
const form = new FormData();
|
||||
form.append('session', id);
|
||||
|
||||
fetch('/api/tokens', {
|
||||
method: 'POST',
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<span class="spacer"></span>
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<a href="{{ url_for('account.settings') }}" class="button primary">
|
||||
<a href="{{ url_for('account.get_settings') }}" class="button primary">
|
||||
{{ current_user.username }}
|
||||
{% if not current_user.email %}<i class="ph ph-warning" style="margin-left: 0.2rem !important;"></i>{% endif %}
|
||||
</a>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{% block content %}
|
||||
<div class="block">
|
||||
<h2 style="margin-bottom: 1rem;">Profile Settings</h2>
|
||||
<form action="{{ url_for('account.settings') }}" method="POST" enctype="multipart/form-data">
|
||||
<form action="{{ url_for('account.post_settings') }}" method="POST" enctype="multipart/form-data">
|
||||
<div class="profile-settings">
|
||||
<div class="picture">
|
||||
{% if current_user.picture %}
|
||||
|
@ -34,7 +34,7 @@
|
|||
<div class="table">
|
||||
<table>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Options</th>
|
||||
<th>Device</th>
|
||||
<th>Created</th>
|
||||
<th>Last Used</th>
|
||||
|
@ -44,7 +44,7 @@
|
|||
<td><button onclick="yeetSession({{ session.id }})" class="button secondary"><i class="ph ph-trash"></i></button></td>
|
||||
<td>{{ session.device_type }}</td>
|
||||
<td>{{ session.created_at.strftime('%Y-%m-%d') }}</td>
|
||||
<td>{{ session.last_used.strftime('%Y-%m-%d') }}</td>
|
||||
<td>{{ session.last_used|timesince }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
@ -54,9 +54,9 @@
|
|||
<div class="block secondary">
|
||||
<h2>Danger Zone</h2>
|
||||
<p>Be careful!</p>
|
||||
<a href="{{ url_for('account.delete_account') }}" class="button secondary" style="margin-bottom: 0.5rem">Delete Account</a>
|
||||
<a href="{{ url_for('account.password_reset') }}" class="button secondary" style="margin-bottom: 0.5rem">Reset Password</a>
|
||||
<a href="{{ url_for('account.settings', action='logout') }}" class="button secondary">Logout</a>
|
||||
<a href="{{ url_for('account.get_delete_account') }}" class="button secondary" style="margin-bottom: 0.5rem">Delete Account</a>
|
||||
<a href="{{ url_for('account.get_password_reset') }}" class="button secondary" style="margin-bottom: 0.5rem">Reset Password</a>
|
||||
<a href="{{ url_for('account.get_settings', action='logout') }}" class="button secondary">Logout</a>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -67,8 +67,7 @@
|
|||
|
||||
// Adjusted from https://stackoverflow.com/a/3814285/14885829
|
||||
document.getElementById('profile-picture').onchange = (event) => {
|
||||
let tgt = event.target || window.event.srcElement,
|
||||
files = tgt.files;
|
||||
let files = event.target.files;
|
||||
|
||||
if (FileReader && files && files.length) {
|
||||
let fr = new FileReader();
|
||||
|
@ -78,7 +77,7 @@
|
|||
fr.readAsDataURL(files[0]);
|
||||
}
|
||||
else {
|
||||
addFlashMessage("Your browser could not show a preview of your profile picture!", "error")
|
||||
addFlashMessage("Your browser could not show a preview of your profile picture!", "error");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
Deleting your account will delete <span style="color: rgb(var(--secondary)) !important;">EVERYTHING</span> on your account, including <span style="color: rgb(var(--secondary)) !important;">ALL</span> your ever submitted scores.
|
||||
There is <span style="color: rgb(var(--secondary)) !important;">NO WAY</span> to recover your account from this, are you sure you want todo this?
|
||||
</p>
|
||||
<form action="{{ url_for('account.delete_account') }}" method="POST">
|
||||
<form action="{{ url_for('account.post_delete_account') }}" method="POST">
|
||||
{{ text(id="username", name="username", required=True) }}
|
||||
{{ text(id="password", name="password", type="password", required=True) }}
|
||||
<button type="submit" class="button secondary">Delete account forever</button>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="block secondary">
|
||||
<h2>Password Reset</h2>
|
||||
<p>Forgotten your current password? Go here [insert password reset tool link]</p>
|
||||
<form action="{{ url_for('account.password_reset') }}" method="POST">
|
||||
<form action="{{ url_for('account.post_password_reset') }}" method="POST">
|
||||
{{ text(id="current-password", name="current", type="password", required=True) }}
|
||||
{{ text(id="new-password", name="new", type="password", required=True) }}
|
||||
{{ text(id="confirm-password", name="confirm", type="password", required=True) }}
|
||||
|
|
|
@ -9,7 +9,7 @@ from .extensions import db
|
|||
blueprint = Blueprint("views", __name__)
|
||||
|
||||
|
||||
@blueprint.route("/")
|
||||
@blueprint.route("/", methods=["GET"])
|
||||
def index():
|
||||
diff_arg = request.args.get("diff", 0)
|
||||
ver_arg = request.args.get("ver", GAME_VERSION).strip()
|
||||
|
@ -45,6 +45,6 @@ def index():
|
|||
)
|
||||
|
||||
|
||||
@blueprint.route("/about")
|
||||
@blueprint.route("/about", methods=["GET"])
|
||||
def about():
|
||||
return render_template("views/about.html")
|
||||
|
|
Loading…
Add table
Reference in a new issue