From 384874d4f5999b41c9397451995f86b067d5ade9 Mon Sep 17 00:00:00 2001 From: lelo Date: Sat, 3 May 2025 14:01:24 +0200 Subject: [PATCH 1/8] implement folder config for admin --- .gitignore | 2 +- analytics.py | 8 +- app.py | 11 +- auth.py | 23 +- folder_secret_config_editor.py | 63 ++++ templates/app.html | 5 + templates/base.html | 71 +++++ templates/connections.html | 335 ++++++++------------- templates/dashboard.html | 56 +--- templates/folder_secret_config_editor.html | 187 ++++++++++++ templates/mylinks.html | 220 +++++++------- templates/songs_dashboard.html | 51 +--- 12 files changed, 614 insertions(+), 418 deletions(-) create mode 100644 folder_secret_config_editor.py create mode 100644 templates/base.html create mode 100644 templates/folder_secret_config_editor.html diff --git a/.gitignore b/.gitignore index 26464f9..e12ff74 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ /search.db /access_log.db /access_log.db.bak -/folder_permission_config.json +/folder_secret_config.json /folder_mount_config.json /.env /app_config.json diff --git a/analytics.py b/analytics.py index d10d8dc..4d562aa 100644 --- a/analytics.py +++ b/analytics.py @@ -6,6 +6,7 @@ from auth import require_secret from collections import defaultdict import json import os +import auth file_access_temp = [] @@ -189,11 +190,11 @@ def songs_dashboard(): performance_data = [(count, titel) for titel, count in performance_counts.items()] performance_data.sort(reverse=True, key=lambda x: x[0]) - return render_template('songs_dashboard.html', timeframe=timeframe_param, performance_data=performance_data, site=site, category=category) + return render_template('songs_dashboard.html', timeframe=timeframe_param, performance_data=performance_data, site=site, category=category, admin_enabled=auth.is_admin()) @require_secret def connections(): - return render_template('connections.html') + return render_template('connections.html', admin_enabled=auth.is_admin()) @require_secret def dashboard(): @@ -476,7 +477,8 @@ def dashboard(): unique_files=unique_files, unique_user=unique_user, cached_percentage=cached_percentage, - timeframe_data=timeframe_data + timeframe_data=timeframe_data, + admin_enabled=auth.is_admin() ) def export_to_excel(): diff --git a/app.py b/app.py index a9a0e8a..2de3d22 100755 --- a/app.py +++ b/app.py @@ -22,11 +22,12 @@ import base64 import search import auth import analytics as a +import folder_secret_config_editor as fsce with open("app_config.json", 'r') as file: app_config = json.load(file) -with open('folder_permission_config.json') as file: +with open('folder_secret_config.json') as file: folder_config = json.load(file) cache_audio = diskcache.Cache('./filecache_audio', size_limit= app_config['filecache_size_limit_audio'] * 1024**3) @@ -53,6 +54,9 @@ app.add_url_rule('/searchcommand', view_func=search.searchcommand, methods=['POS app.add_url_rule('/songs_dashboard', view_func=a.songs_dashboard) +app.add_url_rule('/admin/folder_secret_config_editor', view_func=auth.require_admin(fsce.folder_secret_config_editor), methods=['GET', 'POST']) +app.add_url_rule('/admin/folder_secret_config_editor/data', view_func=auth.require_admin(fsce.folder_secret_config_data)) +app.add_url_rule('/admin/folder_secret_config_editor/action', view_func=auth.require_admin(fsce.folder_secret_config_action), methods=['POST']) # Grab the HOST_RULE environment variable host_rule = os.getenv("HOST_RULE", "") @@ -548,14 +552,11 @@ def handle_request_initial_data(): def index(path): title_short = app_config.get('TITLE_SHORT', 'Default Title') title_long = app_config.get('TITLE_LONG' , 'Default Title') - admin_enabled = False - if 'admin' in session: - admin_enabled = session['admin'] return render_template("app.html", title_short=title_short, title_long=title_long, - admin_enabled=admin_enabled, + admin_enabled=auth.is_admin() ) if __name__ == '__main__': diff --git a/auth.py b/auth.py index d0ed94c..f207c5b 100644 --- a/auth.py +++ b/auth.py @@ -17,9 +17,24 @@ import hashlib with open("app_config.json", 'r') as file: app_config = json.load(file) -with open('folder_permission_config.json') as file: +with open('folder_secret_config.json') as file: folder_config = json.load(file) +def is_admin(): + """ + Check if the user is an admin based on the session. + """ + return session.get('admin', False) + +def require_admin(f): + @wraps(f) + @require_secret + def decorated_function(*args, **kwargs): + if is_admin(): + return f(*args, **kwargs) + else: + return "You don't have admin permission", 403 + return decorated_function def require_secret(f): @wraps(f) @@ -104,8 +119,10 @@ def require_secret(f): if args_admin and config_admin: if args_admin == config_admin: + print(f"Admin access granted with key: {args_admin}") session['admin'] = True else: + print(f"Admin access denied with key: {args_admin}") session['admin'] = False # 6) If we have folders, proceed; otherwise show index @@ -129,6 +146,7 @@ def require_secret(f): header_text_color=header_text_color, main_text_color=main_text_color, background_color=background_color, + admin_enabled=is_admin() ) return decorated_function @@ -197,7 +215,8 @@ def mylinks(): token_qr_codes=token_qr_codes, token_folders=token_folders, token_url=token_url, - token_valid_to=token_valid_to + token_valid_to=token_valid_to, + admin_enabled=is_admin() ) diff --git a/folder_secret_config_editor.py b/folder_secret_config_editor.py new file mode 100644 index 0000000..de07349 --- /dev/null +++ b/folder_secret_config_editor.py @@ -0,0 +1,63 @@ +from flask import Flask, request, jsonify, render_template +import json +import os +from datetime import datetime +import secrets +import string +import auth + + +DATA_FILE = 'folder_secret_config.json' + +# Secret alphabet +ALPHABET = string.ascii_letters + string.digits + +@auth.require_admin +def load_data(): + with open(DATA_FILE) as f: + try: + data = json.load(f) + print(f"Loaded {len(data)} records from {DATA_FILE}.") + return data + except: + print(f"Error loading {DATA_FILE}. File may be empty or corrupted.") + return [] + +@auth.require_admin +def save_data(data): + with open(DATA_FILE, 'w') as f: + json.dump(data, f, indent=4) + +@auth.require_admin +def folder_secret_config_editor(): + return render_template('folder_secret_config_editor.html', alphabet=ALPHABET, admin_enabled=auth.is_admin()) + +@auth.require_admin +def folder_secret_config_data(): + return jsonify(load_data()) + +@auth.require_admin +def folder_secret_config_action(): + p = request.get_json() + data = load_data() + action = p.get('action') + if action == 'delete': + data = [r for r in data if r['secret'] != p['secret']] + elif action == 'update': + old = p['oldSecret']; new = p['newSecret'] + for i, r in enumerate(data): + if r['secret'] == old: + r['secret'] = new + r['validity'] = datetime.strptime(p['validity'], '%Y-%m-%d').strftime('%d.%m.%Y') + r['folders'] = p['folders'] + break + else: + # append if not found + data.append({ + 'secret': new, + 'validity': datetime.strptime(p['validity'], '%Y-%m-%d').strftime('%d.%m.%Y'), + 'folders': p['folders'] + }) + save_data(data) + return jsonify(success=True) + diff --git a/templates/app.html b/templates/app.html index 767b99e..2838b00 100644 --- a/templates/app.html +++ b/templates/app.html @@ -55,6 +55,11 @@ + {% if admin_enabled %} +
+ admin +
+ {% endif %} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..52550cd --- /dev/null +++ b/templates/base.html @@ -0,0 +1,71 @@ + + + + + + + {% block title %}Meine Links{% endblock %} + + + + + + {% block head_extra %}{% endblock %} + + + + + + + + {% block content %}{% endblock %} + + {% block scripts %}{% endblock %} + + + + diff --git a/templates/connections.html b/templates/connections.html index 3573830..6daa255 100644 --- a/templates/connections.html +++ b/templates/connections.html @@ -1,218 +1,139 @@ - - - - - - Recent Connections - - - - - - +{# templates/connections.html #} +{% extends 'base.html' %} -
-
- - - - - - - - - - - - - - - -
TimestampLocationUser AgentFile PathFile SizeMIME-TypCached
-
+{% block title %}Recent Connections{% endblock %} + +{% block nav_brand %}Downloads der letzten 10 Minuten{% endblock %} + +{% block nav_extra %} + + Anzahl Verbindungen: 0 + +{% endblock %} + +{% block head_extra %} + +{% endblock %} + +{% block content %} +
+
+ + + + + + + + + + + + + + {# dynamically populated via Socket.IO #} + +
TimestampLocationUser AgentFile PathFile SizeMIME-TypCached
+
+{% endblock %} - - - + - - - + + tbody.innerHTML = ""; + tbody.appendChild(frag); + } + + function animateTableWithNewRow(data) { + const tbody = document.getElementById("connectionsTableBody"); + const currentTs = new Set([...tbody.children].map(r => r.dataset.timestamp)); + const newRecs = data.filter(r => !currentTs.has(r.timestamp)); + + if (newRecs.length) { + const temp = createRow(newRecs[0], false); + temp.style.visibility = "hidden"; + tbody.appendChild(temp); + const h = temp.getBoundingClientRect().height; + temp.remove(); + + tbody.style.transform = `translateY(${h}px)`; + setTimeout(() => { + updateTable(data); + tbody.style.transition = "none"; + tbody.style.transform = "translateY(0)"; + void tbody.offsetWidth; + tbody.style.transition = "transform 0.5s ease-out"; + }, 500); + } else { + updateTable(data); + } + } + + socket.on("recent_connections", data => { + updateStats(data); + animateTableWithNewRow(data); + }); + +{% endblock %} diff --git a/templates/dashboard.html b/templates/dashboard.html index edfa580..51ee5fd 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -1,42 +1,14 @@ - - - - - - Dashboard - Verbindungsanalyse - - - - - - +{# templates/dashboard.html #} +{% extends 'base.html' %} + +{# page title #} +{% block title %}Dashboard{% endblock %} + +{# override navbar text: #} +{% block nav_brand %}Auswertung-Downloads{% endblock %} + +{# page content #} +{% block content %}
@@ -271,8 +243,9 @@
+ {% endblock %} - + {% block scripts %} - - +{% endblock %} diff --git a/templates/folder_secret_config_editor.html b/templates/folder_secret_config_editor.html new file mode 100644 index 0000000..5d171b0 --- /dev/null +++ b/templates/folder_secret_config_editor.html @@ -0,0 +1,187 @@ +{# templates/mylinks.html #} +{% extends 'base.html' %} + +{# page title #} +{% block title %}Edit Folder Config{% endblock %} + +{# override navbar text: #} +{% block nav_brand %}Folder Config Editor{% endblock %} + +{# page content #} +{% block content %} +
+

Edit Folder Config

+
+ +
+ + + +{% endblock %} + +{% block scripts %} + + + + + {% endblock %} diff --git a/templates/mylinks.html b/templates/mylinks.html index 9400509..7c534d3 100644 --- a/templates/mylinks.html +++ b/templates/mylinks.html @@ -1,123 +1,105 @@ - - - - - - Meine Links - - - - - - - +{# templates/mylinks.html #} +{% extends 'base.html' %} -
-
- {% if valid_secrets %} - {% for secret in valid_secrets %} -
-
- QR Code for secret -
-
Geheimnis: {{ secret }}
-

- Gültig bis: {{ secret_valid_to[secret] }} -

- Link öffnen - -
-
- - -
- {% if secret_folders[secret] %} -
Ordner
-
    - {% for folder in secret_folders[secret] %} -
  • - {{ folder.foldername }} -
  • - {% endfor %} -
- {% else %} -

Keine Ordner für dieses Gemeimnis hinterlegt.

- {% endif %} -
-
+{# page title #} +{% block title %}Meine Links{% endblock %} + +{# override navbar text: #} +{# +{% block nav_brand %} + Übersicht deiner gültigen Links +{% endblock %} +#} + +{# page‐specific content #} +{% block content %} +
+
+ {% if valid_secrets %} + {% for secret in valid_secrets %} +
+
+ QR Code for secret +
+
Geheimnis: {{ secret }}
+

+ Gültig bis: {{ secret_valid_to[secret] }} +

+ Link öffnen + +
+
+ + +
+ {% if secret_folders[secret] %} +
Ordner
+
    + {% for folder in secret_folders[secret] %} +
  • + {{ folder.foldername }} +
  • + {% endfor %} +
+ {% else %} +

Keine Ordner für dieses Gemeimnis hinterlegt.

+ {% endif %}
- {% endfor %} - {% endif %} - {% if valid_tokens %} - {% for token in valid_tokens %} -
-
- QR Code for token -
-
Token-Link:
-

- Gültig bis: {{ token_valid_to[token] }} -

- Link öffnen - -
-
- - -
- {% if token_folders[token] %} -
Ordner
-
    - {% for folder in token_folders[token] %} -
  • - {{ folder.foldername }} -
  • - {% endfor %} -
- {% else %} -

Keine Ordner für dieses Gemeimnis hinterlegt.

- {% endif %} -
-
-
- {% endfor %} - {% endif %} - {% if not valid_secrets and not valid_tokens %} - - {% endif %} +
+ {% endfor %} + {% endif %} + + {% if valid_tokens %} + {% for token in valid_tokens %} +
+
+ QR Code for token +
+
Token-Link:
+

+ Gültig bis: {{ token_valid_to[token] }} +

+ Link öffnen + +
+
+ + +
+ {% if token_folders[token] %} +
Ordner
+
    + {% for folder in token_folders[token] %} +
  • + {{ folder.foldername }} +
  • + {% endfor %} +
+ {% else %} +

Keine Ordner für dieses Gemeimnis hinterlegt.

+ {% endif %} +
+
+
+ {% endfor %} + {% endif %} + + {% if not valid_secrets and not valid_tokens %} + -
- - - + {% endif %} +
+
+{% endblock %} diff --git a/templates/songs_dashboard.html b/templates/songs_dashboard.html index 5a7936d..f5aa56e 100644 --- a/templates/songs_dashboard.html +++ b/templates/songs_dashboard.html @@ -1,42 +1,14 @@ - - - - - - Dashboard - Verbindungsanalyse - - - - - - +{# templates/songs_dashboard.html #} +{% extends 'base.html' %} + +{# page title #} +{% block title %}Edit Folder Config{% endblock %} + +{# override navbar text: #} +{% block nav_brand %}Dashboard - Analyse Wiederholungen{% endblock %} + +{# page content #} +{% block content %}
@@ -180,3 +152,4 @@ +{% endblock %} \ No newline at end of file From 8f6cf3d7b83195efb9da64cd5abdfedfc5dce0b4 Mon Sep 17 00:00:00 2001 From: lelo Date: Sat, 3 May 2025 15:41:11 +0000 Subject: [PATCH 2/8] improve visual --- templates/folder_secret_config_editor.html | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/templates/folder_secret_config_editor.html b/templates/folder_secret_config_editor.html index 5d171b0..26db61b 100644 --- a/templates/folder_secret_config_editor.html +++ b/templates/folder_secret_config_editor.html @@ -56,20 +56,23 @@ const isEdit = editing.has(key); const cls = isEdit ? 'unlocked' : 'locked'; let html = `
`; - html += `
Record
`; + html += `
Link
`; html += `
Secret:
`; html += `
Validity:
`; - html += `
Folders
`; + html += `
Ordner
`; rec.folders.forEach((f,i) => { - html += `
`; + html += `
`; + html += `Ordnername:
`; html += ``; if(isEdit) html += ``; html += `
`; - html += ``; + html += `Ordnerpfad: `; + html += `
`; }); if(isEdit) html += ``; html += `
`; // Change Delete button to a class + data-secret + if (!isEdit) html += `Link öffnen`; html += ``; html += ``; if(isEdit) html += ``; From 849cdf575666e0d526deb20143c155b6e6319bd2 Mon Sep 17 00:00:00 2001 From: lelo Date: Sun, 4 May 2025 11:52:57 +0000 Subject: [PATCH 3/8] display expired links --- templates/folder_secret_config_editor.html | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/templates/folder_secret_config_editor.html b/templates/folder_secret_config_editor.html index 26db61b..41f3e2d 100644 --- a/templates/folder_secret_config_editor.html +++ b/templates/folder_secret_config_editor.html @@ -55,10 +55,17 @@ const key = rec.secret; const isEdit = editing.has(key); const cls = isEdit ? 'unlocked' : 'locked'; + + // Determine if entry has expired + const validityISO = formatISO(rec.validity); + const expired = validityISO ? (new Date(validityISO) < new Date()) : false; + + // Build card HTML let html = `
`; - html += `
Link
`; + // Show exclamation if expired + html += `
Link${expired ? ' ! abgelaufen !' : ''}
`; html += `
Secret:
`; - html += `
Validity:
`; + html += `
Validity:
`; html += `
Ordner
`; rec.folders.forEach((f,i) => { html += `
`; @@ -71,7 +78,6 @@ }); if(isEdit) html += ``; html += `
`; - // Change Delete button to a class + data-secret if (!isEdit) html += `Link öffnen`; html += ``; html += ``; @@ -187,4 +193,4 @@ render(); }); - {% endblock %} +{% endblock %} From cb634476295b0b757e247dc7bbd470712654062b Mon Sep 17 00:00:00 2001 From: lelo Date: Sun, 4 May 2025 11:57:49 +0000 Subject: [PATCH 4/8] move header --- templates/base.html | 6 +++--- templates/folder_secret_config_editor.html | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/templates/base.html b/templates/base.html index 52550cd..a882162 100644 --- a/templates/base.html +++ b/templates/base.html @@ -55,12 +55,12 @@ {% endif %}
- - {% block nav_brand %}Übersicht deiner gültigen Links{% endblock %} - {% block nav_extra %}{% endblock %}
+
+

{% block nav_brand %}Übersicht deiner gültigen Links{% endblock %}

+
{% block content %}{% endblock %} diff --git a/templates/folder_secret_config_editor.html b/templates/folder_secret_config_editor.html index 41f3e2d..964be38 100644 --- a/templates/folder_secret_config_editor.html +++ b/templates/folder_secret_config_editor.html @@ -10,7 +10,6 @@ {# page content #} {% block content %}
-

Edit Folder Config

From 80e3b1abb5181f315f35c696413feb21c73584f7 Mon Sep 17 00:00:00 2001 From: lelo Date: Sun, 4 May 2025 12:10:35 +0000 Subject: [PATCH 5/8] add links for admin --- templates/app.html | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/templates/app.html b/templates/app.html index 2838b00..00363f1 100644 --- a/templates/app.html +++ b/templates/app.html @@ -44,6 +44,15 @@
+ {% if admin_enabled %} + + {% endif %}
@@ -55,11 +64,6 @@
- {% if admin_enabled %} -
- admin -
- {% endif %}
From fceeabe652746c72d856b6ba283626d246e3f638 Mon Sep 17 00:00:00 2001 From: lelo Date: Sun, 4 May 2025 17:24:04 +0000 Subject: [PATCH 6/8] central config --- app.py | 14 +++--- auth.py | 55 +++++++++++++++++----- folder_secret_config_editor.py | 25 +--------- templates/app.html | 16 ++++--- templates/base.html | 2 +- templates/folder_secret_config_editor.html | 4 +- templates/mylinks.html | 2 +- templates/view_token.html | 4 +- 8 files changed, 67 insertions(+), 55 deletions(-) diff --git a/app.py b/app.py index 2de3d22..e79b22f 100755 --- a/app.py +++ b/app.py @@ -9,7 +9,6 @@ import mimetypes from datetime import datetime, date, timedelta import diskcache import threading -import json import time from flask_socketio import SocketIO, emit import geoip2.database @@ -24,11 +23,7 @@ import auth import analytics as a import folder_secret_config_editor as fsce -with open("app_config.json", 'r') as file: - app_config = json.load(file) - -with open('folder_secret_config.json') as file: - folder_config = json.load(file) +app_config = auth.return_app_config() cache_audio = diskcache.Cache('./filecache_audio', size_limit= app_config['filecache_size_limit_audio'] * 1024**3) cache_image = diskcache.Cache('./filecache_image', size_limit= app_config['filecache_size_limit_image'] * 1024**3) @@ -55,7 +50,7 @@ app.add_url_rule('/searchcommand', view_func=search.searchcommand, methods=['POS app.add_url_rule('/songs_dashboard', view_func=a.songs_dashboard) app.add_url_rule('/admin/folder_secret_config_editor', view_func=auth.require_admin(fsce.folder_secret_config_editor), methods=['GET', 'POST']) -app.add_url_rule('/admin/folder_secret_config_editor/data', view_func=auth.require_admin(fsce.folder_secret_config_data)) +app.add_url_rule('/admin/folder_secret_config_editor/data', view_func=auth.require_admin(auth.load_folder_config)) app.add_url_rule('/admin/folder_secret_config_editor/action', view_func=auth.require_admin(fsce.folder_secret_config_action), methods=['POST']) # Grab the HOST_RULE environment variable @@ -104,6 +99,7 @@ def list_directory_contents(directory, subpath): """ directories = [] files = [] + folder_config = auth.return_folder_config() transcription_dir = os.path.join(directory, "Transkription") transcription_exists = os.path.isdir(transcription_dir) @@ -438,9 +434,10 @@ def get_transcript(subpath): def create_share(subpath): scheme = request.scheme # current scheme (http or https) host = request.host - if 'admin ' not in session and not session.get('admin'): + if 'admin' not in session and not session.get('admin'): return "Unauthorized", 403 + folder_config = auth.return_folder_config() paths = {} for item in folder_config: for folder in item['folders']: @@ -550,6 +547,7 @@ def handle_request_initial_data(): @app.route('/') @auth.require_secret def index(path): + app_config = auth.return_app_config() title_short = app_config.get('TITLE_SHORT', 'Default Title') title_long = app_config.get('TITLE_LONG' , 'Default Title') diff --git a/auth.py b/auth.py index f207c5b..01d27aa 100644 --- a/auth.py +++ b/auth.py @@ -12,29 +12,42 @@ import zlib import hmac import hashlib +FOLDER_CONFIG_FILENAME = 'folder_secret_config.json' +APP_CONFIG_FILENAME = 'app_config.json' - -with open("app_config.json", 'r') as file: +# initial read of the config files +with open(APP_CONFIG_FILENAME, 'r') as file: app_config = json.load(file) -with open('folder_secret_config.json') as file: +with open(FOLDER_CONFIG_FILENAME) as file: folder_config = json.load(file) +# functions to be used by other modules +def load_folder_config(): + global folder_config + with open(FOLDER_CONFIG_FILENAME) as file: + folder_config = json.load(file) + return folder_config + +def load_app_config(): + global app_config + with open(APP_CONFIG_FILENAME, 'r') as file: + app_config = json.load(file) + return app_config + +def return_folder_config(): + return folder_config + +def return_app_config(): + return app_config + + def is_admin(): """ Check if the user is an admin based on the session. """ return session.get('admin', False) -def require_admin(f): - @wraps(f) - @require_secret - def decorated_function(*args, **kwargs): - if is_admin(): - return f(*args, **kwargs) - else: - return "You don't have admin permission", 403 - return decorated_function def require_secret(f): @wraps(f) @@ -150,6 +163,24 @@ def require_secret(f): ) return decorated_function +def require_admin(f): + @wraps(f) + @require_secret + def decorated_function(*args, **kwargs): + if is_admin(): + return f(*args, **kwargs) + else: + return "You don't have admin permission", 403 + return decorated_function + +@require_admin +def save_folder_config(data): + global folder_config + folder_config = data + with open(FOLDER_CONFIG_FILENAME, 'w') as file: + json.dump(folder_config, file, indent=4) + return folder_config + @require_secret def mylinks(): scheme = request.scheme # current scheme (http or https) diff --git a/folder_secret_config_editor.py b/folder_secret_config_editor.py index de07349..7e93f2d 100644 --- a/folder_secret_config_editor.py +++ b/folder_secret_config_editor.py @@ -7,39 +7,18 @@ import string import auth -DATA_FILE = 'folder_secret_config.json' - # Secret alphabet ALPHABET = string.ascii_letters + string.digits -@auth.require_admin -def load_data(): - with open(DATA_FILE) as f: - try: - data = json.load(f) - print(f"Loaded {len(data)} records from {DATA_FILE}.") - return data - except: - print(f"Error loading {DATA_FILE}. File may be empty or corrupted.") - return [] - -@auth.require_admin -def save_data(data): - with open(DATA_FILE, 'w') as f: - json.dump(data, f, indent=4) @auth.require_admin def folder_secret_config_editor(): return render_template('folder_secret_config_editor.html', alphabet=ALPHABET, admin_enabled=auth.is_admin()) -@auth.require_admin -def folder_secret_config_data(): - return jsonify(load_data()) - @auth.require_admin def folder_secret_config_action(): p = request.get_json() - data = load_data() + data = auth.return_folder_config() action = p.get('action') if action == 'delete': data = [r for r in data if r['secret'] != p['secret']] @@ -58,6 +37,6 @@ def folder_secret_config_action(): 'validity': datetime.strptime(p['validity'], '%Y-%m-%d').strftime('%d.%m.%Y'), 'folders': p['folders'] }) - save_data(data) + auth.save_folder_config(data) return jsonify(success=True) diff --git a/templates/app.html b/templates/app.html index 00363f1..ab39453 100644 --- a/templates/app.html +++ b/templates/app.html @@ -45,12 +45,16 @@
{% if admin_enabled %} -
- App · - Meine Links · - Verbindungen · - Auswertung · - Folder Config Editor + {% endif %} diff --git a/templates/base.html b/templates/base.html index a882162..3a5edae 100644 --- a/templates/base.html +++ b/templates/base.html @@ -51,7 +51,7 @@ {% if admin_enabled %} - + {% endif %}
diff --git a/templates/folder_secret_config_editor.html b/templates/folder_secret_config_editor.html index 964be38..6eee2e6 100644 --- a/templates/folder_secret_config_editor.html +++ b/templates/folder_secret_config_editor.html @@ -2,10 +2,10 @@ {% extends 'base.html' %} {# page title #} -{% block title %}Edit Folder Config{% endblock %} +{% block title %}Ordnerkonfiguration{% endblock %} {# override navbar text: #} -{% block nav_brand %}Folder Config Editor{% endblock %} +{% block nav_brand %}Ordnerkonfiguration{% endblock %} {# page content #} {% block content %} diff --git a/templates/mylinks.html b/templates/mylinks.html index 7c534d3..b003fcf 100644 --- a/templates/mylinks.html +++ b/templates/mylinks.html @@ -27,7 +27,7 @@

Gültig bis: {{ secret_valid_to[secret] }}

- Link öffnen + Link öffnen + Link öffnen +

Gültig bis:

From f7137e2d4c2c45a9e95ea63348e9bda4b89f959f Mon Sep 17 00:00:00 2001 From: lelo Date: Sun, 4 May 2025 18:30:34 +0000 Subject: [PATCH 7/8] fix bootstrap implementation --- templates/base.html | 9 +++------ templates/dashboard.html | 3 +-- templates/folder_secret_config_editor.html | 5 ++--- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/templates/base.html b/templates/base.html index 3a5edae..7e4994d 100644 --- a/templates/base.html +++ b/templates/base.html @@ -6,10 +6,7 @@ {% block title %}Meine Links{% endblock %} - + {% block head_extra %}{% endblock %} -