mirror of
https://github.com/PhoenixTwoFive/karaoqueue.git
synced 2025-05-19 02:51:48 +02:00
Merge pull request #55 from PhoenixTwoFive/feature/legacy/53-löschung-von-eigenen-einträgen-erlauben
Feature/legacy/53 löschung von eigenen einträgen erlauben
This commit is contained in:
commit
c9cbd24569
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -10,5 +10,8 @@
|
|||||||
"python.testing.pytestEnabled": false,
|
"python.testing.pytestEnabled": false,
|
||||||
"python.testing.unittestEnabled": true,
|
"python.testing.unittestEnabled": true,
|
||||||
"python.linting.pylintEnabled": false,
|
"python.linting.pylintEnabled": false,
|
||||||
"python.linting.flake8Enabled": true
|
"python.linting.flake8Enabled": true,
|
||||||
|
"emmet.includeLanguages": {
|
||||||
|
"django-html": "html"
|
||||||
|
}
|
||||||
}
|
}
|
@ -40,8 +40,8 @@ def enqueue():
|
|||||||
name = request.json['name']
|
name = request.json['name']
|
||||||
song_id = request.json['id']
|
song_id = request.json['id']
|
||||||
if request.authorization:
|
if request.authorization:
|
||||||
database.add_entry(name, song_id, client_id)
|
entry_id = database.add_entry(name, song_id, client_id)
|
||||||
return Response('{"status":"OK"}', mimetype='text/json')
|
return Response(f"""{{"status":"OK", "entry_id":{entry_id}}}""", mimetype='text/json')
|
||||||
else:
|
else:
|
||||||
if helpers.get_accept_entries(app):
|
if helpers.get_accept_entries(app):
|
||||||
if not request.json:
|
if not request.json:
|
||||||
@ -55,8 +55,8 @@ def enqueue():
|
|||||||
song_id = request.json['id']
|
song_id = request.json['id']
|
||||||
if database.check_queue_length() < int(app.config['MAX_QUEUE']):
|
if database.check_queue_length() < int(app.config['MAX_QUEUE']):
|
||||||
if database.check_entry_quota(client_id) < int(app.config['ENTRY_QUOTA']):
|
if database.check_entry_quota(client_id) < int(app.config['ENTRY_QUOTA']):
|
||||||
database.add_entry(name, song_id, client_id)
|
entry_id = database.add_entry(name, song_id, client_id)
|
||||||
return Response('{"status":"OK"}', mimetype='text/json')
|
return Response(f"""{{"status":"OK", "entry_id":{entry_id}}}""", mimetype='text/json')
|
||||||
else:
|
else:
|
||||||
return Response('{"status":"Du hast bereits ' + str(database.check_entry_quota(client_id)) + ' Songs eingetragen, dies ist das Maximum an Einträgen die du in der Warteliste haben kannst."}', mimetype='text/json', status=423)
|
return Response('{"status":"Du hast bereits ' + str(database.check_entry_quota(client_id)) + ' Songs eingetragen, dies ist das Maximum an Einträgen die du in der Warteliste haben kannst."}', mimetype='text/json', status=423)
|
||||||
else:
|
else:
|
||||||
@ -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)[3] != 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)
|
||||||
|
@ -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
|
||||||
@ -134,11 +134,11 @@ def get_song_completions(input_string):
|
|||||||
def add_entry(name, song_id, client_id):
|
def add_entry(name, song_id, client_id):
|
||||||
with get_db_engine().connect() as conn:
|
with get_db_engine().connect() as conn:
|
||||||
stmt = text(
|
stmt = text(
|
||||||
"INSERT INTO entries (Song_Id,Name,Client_Id) VALUES (:par_song_id,:par_name,:par_client_id);")
|
"INSERT INTO entries (Song_Id,Name,Client_Id) VALUES (:par_song_id,:par_name,:par_client_id) RETURNING entries.ID;")
|
||||||
conn.execute(stmt, {"par_song_id": song_id, "par_name": name,
|
cur = conn.execute(stmt, {"par_song_id": song_id, "par_name": name,
|
||||||
"par_client_id": client_id}) # type: ignore
|
"par_client_id": client_id}) # type: ignore
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return True
|
return cur.fetchone()[0] # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def add_sung_song(entry_id):
|
def add_sung_song(entry_id):
|
||||||
@ -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")
|
||||||
|
@ -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):
|
||||||
|
@ -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,46 @@
|
|||||||
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEntry(entryId) {
|
||||||
|
entryArray = JSON.parse(localStorage.getItem("ownedEntries"))
|
||||||
|
if (entryArray == null) {
|
||||||
|
entryArray = []
|
||||||
|
}
|
||||||
|
entryArray.push(entryId)
|
||||||
|
localStorage.setItem("ownedEntries", JSON.stringify(entryArray))
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeEntry(entryId) {
|
||||||
|
entryArray = JSON.parse(localStorage.getItem("ownedEntries"))
|
||||||
|
if (entryArray == null) {
|
||||||
|
entryArray = []
|
||||||
|
}
|
||||||
|
entryArray = entryArray.filter(function(value, index, arr){ return value != entryId;});
|
||||||
|
localStorage.setItem("ownedEntries", JSON.stringify(entryArray))
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOwnedEntries() {
|
||||||
|
return JSON.parse(localStorage.getItem("ownedEntries"))
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
<th data-field="Name">Name</th>
|
<th data-field="Name">Name</th>
|
||||||
<th data-field="Title">Song</th>
|
<th data-field="Title">Song</th>
|
||||||
<th data-field="Artist">Künstler</th>
|
<th data-field="Artist">Künstler</th>
|
||||||
|
<th scope="col" data-formatter="TableActionsFormatter"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
@ -34,5 +35,37 @@ $.getJSON("/api/entries/accept", (data) => {
|
|||||||
$('[data-toggle="tooltip"]').tooltip()
|
$('[data-toggle="tooltip"]').tooltip()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function TableActionsFormatter(value,row,index) {
|
||||||
|
console.log("Value: " + value + ", Row: " + row + ", Index: " + index)
|
||||||
|
console.log(row)
|
||||||
|
if (getOwnedEntries().includes(row.entry_ID)) {
|
||||||
|
return "<button type='button' class='btn btn-danger' data-toggle='tooltip' data-placement='top' title='Eintrag zurückziehen' onclick=\"event.stopPropagation();$(this).tooltip('dispose');requestDeletionAsUser("+row["entry_ID"]+")\"><i class='fas fa-trash'></i></button>"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestDeletionAsUser(id) {
|
||||||
|
bootbox.confirm("Wirklich den Eintrag zurückziehen? Das könnte zu einer langen Wartezeit führen!", function (result) {
|
||||||
|
if (result) {
|
||||||
|
payload = {
|
||||||
|
"client_id": localStorage.getItem("clientId"),
|
||||||
|
"entry_id": id
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/entries/delete/"+id,
|
||||||
|
type: "POST",
|
||||||
|
data: JSON.stringify(payload),
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
|
dataType: "json",
|
||||||
|
success: function(result) {
|
||||||
|
bootbox.alert("Eintrag zurückgezogen!")
|
||||||
|
location.reload()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -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
|
||||||
@ -96,7 +96,14 @@
|
|||||||
function submitModal() {
|
function submitModal() {
|
||||||
var name = $("#singerNameInput").val();
|
var name = $("#singerNameInput").val();
|
||||||
var id = $("#selectedId").attr("value");
|
var id = $("#selectedId").attr("value");
|
||||||
enqueue(localStorage.getItem("clientId"),id, name, function () {
|
enqueue(localStorage.getItem("clientId"),id, name, function (response) {
|
||||||
|
console.log(response);
|
||||||
|
entryID = response["entry_id"];
|
||||||
|
bootbox.alert({
|
||||||
|
message: "Deine Eintragung wurde erfolgreich vorgenommen.",
|
||||||
|
});
|
||||||
|
console.log("Entry ID: " + entryID);
|
||||||
|
addEntry(entryID);
|
||||||
$("#enqueueModal").modal('hide');
|
$("#enqueueModal").modal('hide');
|
||||||
window.location.href = '/#end';
|
window.location.href = '/#end';
|
||||||
}, function (response) {
|
}, function (response) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user