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
This commit is contained in:
Phillip Kühne 2023-04-26 18:08:03 +02:00
parent adebf35d08
commit 865df5d588
Signed by: phillip
GPG Key ID: E4C1C4D2F90902AA
5 changed files with 96 additions and 6 deletions

View File

@ -138,6 +138,7 @@ def songs():
@basic_auth.required @basic_auth.required
def update_songs(): def update_songs():
database.delete_all_entries() database.delete_all_entries()
helpers.reset_current_event_id(app)
status = database.import_songs( status = database.import_songs(
helpers.get_songs(helpers.get_catalog_url())) helpers.get_songs(helpers.get_catalog_url()))
print(status) print(status)
@ -149,7 +150,6 @@ def update_songs():
def get_song_completions(input_string=""): def get_song_completions(input_string=""):
input_string = request.args.get('search', input_string) input_string = request.args.get('search', input_string)
if input_string != "": if input_string != "":
print(input_string)
result = [list(x) for x in database.get_song_completions(input_string=input_string)] result = [list(x) for x in database.get_song_completions(input_string=input_string)]
return jsonify(result) return jsonify(result)
@ -157,10 +157,29 @@ def get_song_completions(input_string=""):
return 400 return 400
@app.route("/api/entries/delete/<entry_id>") @app.route("/api/entries/delete/<entry_id>", methods=['GET'])
@nocache @nocache
@basic_auth.required @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/<entry_id>", 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): if database.delete_entry(entry_id):
return Response('{"status": "OK"}', mimetype='text/json') return Response('{"status": "OK"}', mimetype='text/json')
else: else:
@ -235,6 +254,7 @@ def clear_played_songs():
@basic_auth.required @basic_auth.required
def delete_all_entries(): def delete_all_entries():
if database.delete_all_entries(): if database.delete_all_entries():
helpers.reset_current_event_id(app)
return Response('{"status": "OK"}', mimetype='text/json') return Response('{"status": "OK"}', mimetype='text/json')
else: else:
return Response('{"status": "FAIL"}', mimetype='text/json') return Response('{"status": "FAIL"}', mimetype='text/json')
@ -246,6 +266,12 @@ def admin():
return redirect("/", code=303) 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 @app.before_first_request
def activate_job(): def activate_job():
helpers.load_dbconfig(app) helpers.load_dbconfig(app)

View File

@ -4,6 +4,7 @@ from sqlalchemy import create_engine, engine, text
import pandas import pandas
from io import StringIO from io import StringIO
from flask import current_app from flask import current_app
import uuid
song_table = "songs" song_table = "songs"
entry_table = "entries" entry_table = "entries"
@ -16,7 +17,6 @@ sql_engine = None
def get_db_engine() -> engine.base.Engine: def get_db_engine() -> engine.base.Engine:
global sql_engine global sql_engine
if (not sql_engine): if (not sql_engine):
print(current_app.config.get("DBCONNSTRING"))
sql_engine = create_engine( sql_engine = create_engine(
current_app.config.get("DBCONNSTRING")) # type: ignore current_app.config.get("DBCONNSTRING")) # type: ignore
return sql_engine return sql_engine
@ -189,6 +189,26 @@ def clear_played_songs():
return True 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): def delete_entry(id):
with get_db_engine().connect() as conn: with get_db_engine().connect() as conn:
conn.execute(text("DELETE FROM entries WHERE id= :par_id"), { conn.execute(text("DELETE FROM entries WHERE id= :par_id"), {
@ -260,3 +280,18 @@ def check_config_table() -> bool:
return False return False
else: else:
return False 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")

View File

@ -98,6 +98,7 @@ def setup_config(app: Flask):
for key, value in default_config.items(): for key, value in default_config.items():
database.set_config(key, value) database.set_config(key, value)
print("Created new config") print("Created new config")
database.init_event_id()
config = database.get_config_list() config = database.get_config_list()
app.config['BASIC_AUTH_USERNAME'] = config['username'] app.config['BASIC_AUTH_USERNAME'] = config['username']
app.config['BASIC_AUTH_PASSWORD'] = config['password'] app.config['BASIC_AUTH_PASSWORD'] = config['password']
@ -105,6 +106,7 @@ def setup_config(app: Flask):
app.config['MAX_QUEUE'] = config['maxqueue'] app.config['MAX_QUEUE'] = config['maxqueue']
app.config['ENTRIES_ALLOWED'] = bool(config['entries_allowed']) app.config['ENTRIES_ALLOWED'] = bool(config['entries_allowed'])
app.config['THEME'] = config['theme'] app.config['THEME'] = config['theme']
app.config['EVENT_ID'] = database.get_event_id()
# set queue admittance # set queue admittance
@ -153,6 +155,15 @@ def set_theme(app: Flask, theme: str):
print("Theme not found, not setting theme.") 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): def nocache(view):
@wraps(view) @wraps(view)
def no_cache(*args, **kwargs): def no_cache(*args, **kwargs):

View File

@ -108,7 +108,7 @@
{% block extrajs %}{% endblock %} {% block extrajs %}{% endblock %}
<script> <script>
$(document).ready(function () { $(document).ready(function () {
loadOrGenerateClientId() checkEventID()
// get current URL path and assign 'active' class // get current URL path and assign 'active' class
var pathname = window.location.pathname; var pathname = window.location.pathname;
$('.navbar-nav > li > a[href="' + pathname + '"]').parent().addClass('active'); $('.navbar-nav > li > a[href="' + pathname + '"]').parent().addClass('active');
@ -130,6 +130,23 @@
localStorage.setItem("clientId", create_UUID()) localStorage.setItem("clientId", create_UUID())
} }
} }
function getClientId() {
return localStorage.getItem("clientId")
}
async function checkEventID() {
const localEventID = localStorage.getItem("eventID")
const resp = await fetch("/api/events/current")
const respJson = await resp.json()
const remoteEventID = respJson.event
if (localEventID == null || localEventID != remoteEventID) {
localStorage.clear()
localStorage.setItem("eventID", remoteEventID)
loadOrGenerateClientId()
}
}
</script> </script>
</body> </body>

View File

@ -79,7 +79,7 @@
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/api/enqueue', url: '/api/enqueue',
data: JSON.stringify(data), // or JSON.stringify ({name: 'jonas'}), data: JSON.stringify(data),
success: success_callback, success: success_callback,
statusCode: { statusCode: {
423: blocked_callback 423: blocked_callback
@ -99,6 +99,7 @@
enqueue(localStorage.getItem("clientId"),id, name, function () { enqueue(localStorage.getItem("clientId"),id, name, function () {
$("#enqueueModal").modal('hide'); $("#enqueueModal").modal('hide');
window.location.href = '/#end'; window.location.href = '/#end';
}, function (response) { }, function (response) {
bootbox.alert({ bootbox.alert({
message: "Deine Eintragung konnte leider nicht vorgenommen werden.\nGrund: "+response.responseJSON.status, message: "Deine Eintragung konnte leider nicht vorgenommen werden.\nGrund: "+response.responseJSON.status,