Add admin "login" and functionality, fix Umlauts in search

This commit is contained in:
Phillip Kühne 2019-05-26 00:28:26 +02:00
parent 28ff0ecf06
commit 3adea7b46a
7 changed files with 178 additions and 49 deletions

18
.vscode/launch.json vendored
View File

@ -5,8 +5,26 @@
"version": "0.2.0",
"configurations": [
{"name":"Python: Flask","type":"python","request":"launch","module":"flask","env":{"FLASK_APP":"main.py","FLASK_ENV":"development","FLASK_DEBUG":"1"},"args":["run","--no-debugger","--no-reload"],"jinja":true},
{"name":"Python: Flask (with reload)","type":"python","request":"launch","module":"flask","env":{"FLASK_APP":"main.py","FLASK_ENV":"development","FLASK_DEBUG":"1"},"args":["run","--no-debugger"],"jinja":true},
{
"name": "Python: Flask (with reload, externally reachable)",
"type": "python",
"request": "launch",
"module": "flask",
"env": {
"FLASK_APP": "main.py",
"FLASK_ENV": "development",
"FLASK_DEBUG": "1"
},
"args": [
"run",
"--no-debugger",
"--host='0.0.0.0'"
],
"jinja": true
},
{
"name": "Python: Current File (Integrated Terminal)",
"type": "python",

View File

@ -1,3 +1,5 @@
# -*- coding: utf_8 -*-
import sqlite3
import pandas
from io import StringIO
@ -8,6 +10,7 @@ index_label = "Id"
def open_db():
conn = sqlite3.connect("test.db")
conn.execute('PRAGMA encoding = "UTF-8";')
return conn
def import_songs(song_csv):
@ -16,6 +19,7 @@ def import_songs(song_csv):
df.to_sql(song_table, conn, if_exists='replace',
index=False)
conn.close()
print("Imported songs")
return
def create_entry_table():
@ -25,6 +29,22 @@ def create_entry_table():
' (ID INTEGER PRIMARY KEY NOT NULL, Song_Id INTEGER NOT NULL, Name VARCHAR(255))')
conn.close()
def create_song_table():
conn = open_db()
t = (entry_table,)
conn.execute("CREATE TABLE IF NOT EXISTS \""+song_table+"""\" (
"Id" INTEGER,
"Title" TEXT,
"Artist" TEXT,
"Year" INTEGER,
"Duo" INTEGER,
"Explicit" INTEGER,
"Date Added" TEXT,
"Styles" TEXT,
"Languages" TEXT
)""")
conn.close()
def create_list_view():
conn = open_db()
conn.execute("""CREATE VIEW IF NOT EXISTS [Liste] AS
@ -48,7 +68,9 @@ def get_song_list():
def get_song_completions(input_string):
conn = open_db()
cur = conn.cursor()
cur.execute("SELECT Title || \" - \" || Artist AS Song, Id FROM songs WHERE Song LIKE '%"+input_string+"%'")
# Don't look, it burns...
cur.execute(
"SELECT Title || \" - \" || Artist AS Song, Id FROM songs WHERE Song LIKE REPLACE(REPLACE(REPLACE(REPLACE(UPPER('%"+input_string+"%'),'ö','Ö'),'ü','Ü'),'ä','Ä'),'ß','')")
return cur.fetchall()
def add_entry(name,song_id):
@ -67,3 +89,12 @@ def delete_entry(id):
conn.commit()
conn.close()
return True
def delete_all_entries():
conn = open_db()
cur = conn.cursor()
cur.execute("DELETE FROM entries")
conn.commit()
conn.close()
return True

37
main.py
View File

@ -37,12 +37,24 @@ def songs():
list = database.get_song_list()
return Response(json.dumps(list, ensure_ascii=False).encode('utf-8'), mimetype='text/json')
@app.route("/api/songs/update")
def update_songs():
database.delete_all_entries()
database.import_songs(helpers.get_songs(helpers.get_catalog_url()))
return Response('{"status":"OK"}', mimetype='text/json')
@app.route("/api/songs/compl/<input_string>")
def get_song_completions(input_string):
@app.route("/api/songs/compl")
def get_song_completions(input_string=""):
input_string = request.args.get('search',input_string)
if input_string!="":
print(input_string)
list = database.get_song_completions(input_string=input_string)
return Response(json.dumps(list, ensure_ascii=False).encode('utf-8'), mimetype='text/json')
else:
return 400
@app.route("/api/entries/delete/<entry_id>")
@basic_auth.required
@ -52,19 +64,24 @@ def delete_entry(entry_id):
else:
return Response('{"status": "FAIL"}', mimetype='text/json')
@app.route("/api/entries/delete_all")
@basic_auth.required
def delete_all_entries():
if database.delete_all_entries():
return Response('{"status": "OK"}', mimetype='text/json')
else:
return Response('{"status": "FAIL"}', mimetype='text/json')
@app.route("/login")
@basic_auth.required
def admin():
return redirect("/", code=303)
if __name__ == "__main__":
"""try:
os.remove("test.db")
print("removed database")
except OSError:
print("failed to remove database")
pass"""
@app.before_first_request
def activate_job():
database.create_entry_table()
database.create_song_table()
database.create_list_view()
database.import_songs(helpers.get_songs(helpers.get_catalog_url()))
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0')

View File

@ -6,11 +6,6 @@ html, body {
height: 100%;
}
footer a, footer span{
display: inline-flex;
vertical-align: middle;
}
.site {
height: auto;
min-height: 100%;

View File

@ -52,11 +52,14 @@
</div>
<!-- Footer -->
<footer class="footer">
<div class="container text-center py-3">
<div class="container text-center py-3 d-flex flex-row mx-auto">
{% if not auth %}
<a href="/login"><i class='material-icons'>launch</i>&nbsp;Login</a>
<a href="/login" class="d-flex justify-content-center align-content-between ml-1 mr-1"><i
class='material-icons mr-1'>launch</i><span>Login</span></a>
{% endif %}
<a href="https://github.com/PhoenixTwoFive/karaoqueue"><i class='material-icons'>code</i>&nbsp;Github</a>
<a href="https://github.com/PhoenixTwoFive/karaoqueue"
class="d-flex justify-content-center align-content-between ml-1 mr-1"><i
class='material-icons mr-1'>code</i><span>Github</span></a>
<span class="text-muted">KaraoQueue -&nbsp;<span
style="display:inline-block;transform: rotate(180deg);">&copy</span>&nbsp;2019 - Phillip
Kühne</span>

View File

@ -3,7 +3,25 @@
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
<table class="table">
<div class="container">
<div class="row">
<div class="card" style="width: 100%">
<div class="card-body d-flex flex-row">
<button type="button" class="btn btn-danger d-flex justify-content-center align-content-between m-2"
onclick="confirmDeleteAllEntries()"><i
class="material-icons mr-1">
delete_forever
</i>&nbsp;Alle Einträge löschen</button>
<button type="button" class="btn btn-danger d-flex justify-content-center align-content-between m-2"
onclick="confirmUpdateSongDatabase()"><i
class="material-icons mr-1">
cloud_download
</i>&nbsp;Song-Datenbank aktualisieren</button>
</div>
</div>
</div>
<div class="row">
<table class="table">
<tr>
<th scope="col">Name</th>
<th scope="col">Song</th>
@ -22,16 +40,43 @@
{{ entry[2] }}
</td>
<td>
<button type='button' class='btn btn-danger' onclick='deleteEntry({{ entry[3] }})'><i
<button type='button' class='btn btn-danger d-flex justify-content-center align-content-between'
onclick='confirmDeleteEntry("{{ entry[0] }}",{{ entry[3] }})'><i
class='material-icons'>delete</i></button>
</td>
</tr>
{% endfor %}
</table>
<a name="end"></a>
</table>
<a name="end"></a>
</div>
</div>
{% endblock %}
{% block extrajs %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"
integrity="sha256-4F7e4JsAJyLUdpP7Q8Sah866jCOhv72zU5E8lIRER4w=" crossorigin="anonymous"></script>
<script>
function confirmDeleteEntry(name, entry_id) {
bootbox.confirm("Wirklich den Eintrag von "+name+" löschen?", function(result){
if (result) {
deleteEntry(entry_id)
}
})
}
function confirmDeleteAllEntries() {
bootbox.confirm("Wirklich alle Eintragungen löschen?", function(result){
if (result) {
deleteAllEntries()
}
})
}
function confirmUpdateSongDatabase() {
bootbox.confirm("Wirklich die Song-Datenbank aktualisieren?<br>Dies lädt die Aktuelle Song-Liste von <a href='https://www.karafun.de/karaoke-song-list.html'>KaraFun</a> herunter, <b>und wird alle Eintragungen löschen!</b>" ,
function(result){
if (result) {
updateSongDatabase()
}
})
}
function deleteEntry(entry_id) {
$.ajax({
type: 'GET',
@ -41,5 +86,23 @@
});
location.reload();
}
function deleteAllEntries() {
$.ajax({
type: 'GET',
url: '/api/entries/delete_all',
contentType: "application/json",
dataType: 'json'
});
location.reload();
}
function updateSongDatabase() {
$.ajax({
type: 'GET',
url: '/api/songs/update',
contentType: "application/json",
dataType: 'json'
});
location.reload();
}
</script>
{% endblock %}

View File

@ -51,11 +51,13 @@
var value = $(this).val().toLowerCase();
//alert(value);
if(value.length >= 3) {
$.getJSON("/api/songs/compl/" + value, function (data) {
$.getJSON("/api/songs/compl", { search: value }, function (data) {
var items = [];
$.each(data, function (key, val) {
items.push("<tr><td>"+val[0]+`</td>
<td><button type='button' class='btn btn-primary' data-toggle='modal'
<td><button type='button'
class='btn btn-primary d-flex justify-content-center align-content-between'
data-toggle='modal'
data-target='#enqueueModal' onclick='setSelectedId(`+val[1]+`)'><i
class='material-icons'>queue_music</i></button></td>
</tr>`)