From 865df5d58866ff0c1f2f17e505943fe4df2de89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Phillip=20K=C3=BChne?= Date: Wed, 26 Apr 2023 18:08:03 +0200 Subject: [PATCH] Implement EventID to scope ClientIDs and Entry IDs Implement an EventID saved in settings. Currently this is used to scope clientIDs and entryIDs to an event. The client checks the event currently going on on the server, and discards its localstorage (containing the clientID) if it has changed --- backend/app.py | 32 +++++++++++++++++++++++++--- backend/database.py | 37 ++++++++++++++++++++++++++++++++- backend/helpers.py | 11 ++++++++++ backend/templates/base.html | 19 ++++++++++++++++- backend/templates/songlist.html | 3 ++- 5 files changed, 96 insertions(+), 6 deletions(-) diff --git a/backend/app.py b/backend/app.py index 6ea7dab..b3ebe97 100644 --- a/backend/app.py +++ b/backend/app.py @@ -138,6 +138,7 @@ def songs(): @basic_auth.required def update_songs(): database.delete_all_entries() + helpers.reset_current_event_id(app) status = database.import_songs( helpers.get_songs(helpers.get_catalog_url())) print(status) @@ -149,7 +150,6 @@ def update_songs(): def get_song_completions(input_string=""): input_string = request.args.get('search', input_string) if input_string != "": - print(input_string) result = [list(x) for x in database.get_song_completions(input_string=input_string)] return jsonify(result) @@ -157,10 +157,29 @@ def get_song_completions(input_string=""): return 400 -@app.route("/api/entries/delete/") +@app.route("/api/entries/delete/", methods=['GET']) @nocache @basic_auth.required -def delete_entry(entry_id): +def delete_entry_admin(entry_id): + if database.delete_entry(entry_id): + return Response('{"status": "OK"}', mimetype='text/json') + else: + return Response('{"status": "FAIL"}', mimetype='text/json') + + +@app.route("/api/entries/delete/", methods=['POST']) +@nocache +def delete_entry_user(entry_id): + if not request.json: + print(request.data) + abort(400) + client_id = request.json['client_id'] + if not helpers.is_valid_uuid(client_id): + print(request.data) + abort(400) + if database.get_raw_entry(entry_id)['client_id'] != client_id: # type: ignore + print(request.data) + abort(403) if database.delete_entry(entry_id): return Response('{"status": "OK"}', mimetype='text/json') else: @@ -235,6 +254,7 @@ def clear_played_songs(): @basic_auth.required def delete_all_entries(): if database.delete_all_entries(): + helpers.reset_current_event_id(app) return Response('{"status": "OK"}', mimetype='text/json') else: return Response('{"status": "FAIL"}', mimetype='text/json') @@ -246,6 +266,12 @@ def admin(): return redirect("/", code=303) +@app.route("/api/events/current") +@nocache +def get_current_event(): + return Response('{"status": "OK", "event": "' + helpers.get_current_event_id(app) + '"}', mimetype='text/json') + + @app.before_first_request def activate_job(): helpers.load_dbconfig(app) diff --git a/backend/database.py b/backend/database.py index fdf6d86..68e264a 100644 --- a/backend/database.py +++ b/backend/database.py @@ -4,6 +4,7 @@ from sqlalchemy import create_engine, engine, text import pandas from io import StringIO from flask import current_app +import uuid song_table = "songs" entry_table = "entries" @@ -16,7 +17,6 @@ sql_engine = None def get_db_engine() -> engine.base.Engine: global sql_engine if (not sql_engine): - print(current_app.config.get("DBCONNSTRING")) sql_engine = create_engine( current_app.config.get("DBCONNSTRING")) # type: ignore return sql_engine @@ -189,6 +189,26 @@ def clear_played_songs(): return True +def get_entry(id): + try: + with get_db_engine().connect() as conn: + cur = conn.execute(text("SELECT * FROM Liste WHERE entry_ID = :par_id"), + {"par_id": id}) # type: ignore + return cur.fetchall()[0] + except Exception: + return None + + +def get_raw_entry(id): + try: + with get_db_engine().connect() as conn: + cur = conn.execute(text("SELECT * FROM entries WHERE ID = :par_id"), + {"par_id": id}) # type: ignore + return cur.fetchall()[0] + except Exception: + return None + + def delete_entry(id): with get_db_engine().connect() as conn: conn.execute(text("DELETE FROM entries WHERE id= :par_id"), { @@ -260,3 +280,18 @@ def check_config_table() -> bool: return False else: return False + + +def init_event_id() -> bool: + if not get_config("EventID"): + set_config("EventID", str(uuid.uuid4())) + return True + + +def reset_event_id() -> bool: + set_config("EventID", str(uuid.uuid4())) + return True + + +def get_event_id() -> str: + return get_config("EventID") diff --git a/backend/helpers.py b/backend/helpers.py index fff6b8d..9dab0a5 100644 --- a/backend/helpers.py +++ b/backend/helpers.py @@ -98,6 +98,7 @@ def setup_config(app: Flask): for key, value in default_config.items(): database.set_config(key, value) print("Created new config") + database.init_event_id() config = database.get_config_list() app.config['BASIC_AUTH_USERNAME'] = config['username'] app.config['BASIC_AUTH_PASSWORD'] = config['password'] @@ -105,6 +106,7 @@ def setup_config(app: Flask): app.config['MAX_QUEUE'] = config['maxqueue'] app.config['ENTRIES_ALLOWED'] = bool(config['entries_allowed']) app.config['THEME'] = config['theme'] + app.config['EVENT_ID'] = database.get_event_id() # set queue admittance @@ -153,6 +155,15 @@ def set_theme(app: Flask, theme: str): print("Theme not found, not setting theme.") +def get_current_event_id(app: Flask): + return app.config['EVENT_ID'] + + +def reset_current_event_id(app: Flask): + database.reset_event_id() + app.config['EVENT_ID'] = database.get_event_id() + + def nocache(view): @wraps(view) def no_cache(*args, **kwargs): diff --git a/backend/templates/base.html b/backend/templates/base.html index 852d0eb..26d0ec2 100644 --- a/backend/templates/base.html +++ b/backend/templates/base.html @@ -108,7 +108,7 @@ {% block extrajs %}{% endblock %} diff --git a/backend/templates/songlist.html b/backend/templates/songlist.html index b1fb95a..1225a90 100644 --- a/backend/templates/songlist.html +++ b/backend/templates/songlist.html @@ -79,7 +79,7 @@ $.ajax({ type: 'POST', url: '/api/enqueue', - data: JSON.stringify(data), // or JSON.stringify ({name: 'jonas'}), + data: JSON.stringify(data), success: success_callback, statusCode: { 423: blocked_callback @@ -99,6 +99,7 @@ enqueue(localStorage.getItem("clientId"),id, name, function () { $("#enqueueModal").modal('hide'); window.location.href = '/#end'; + }, function (response) { bootbox.alert({ message: "Deine Eintragung konnte leider nicht vorgenommen werden.\nGrund: "+response.responseJSON.status,