Compare commits

..

No commits in common. "7c39b542152bb90640b98bcb5ca3d2431eec26ec" and "15c2bd6a1bcbb223ac97dfb99e6a814f841a9aa3" have entirely different histories.

4 changed files with 204 additions and 222 deletions

View File

@ -12,8 +12,11 @@ file_access_temp = []
app_config = auth.return_app_config() app_config = auth.return_app_config()
# Example database name; you can change to whatever you want:
DB_NAME = 'access_log.db'
# Create a single global connection to SQLite # Create a single global connection to SQLite
log_db = sqlite3.connect("access_log.db", check_same_thread=False) log_db = sqlite3.connect(DB_NAME, check_same_thread=False)
search_db = sqlite3.connect("search.db", check_same_thread=False) search_db = sqlite3.connect("search.db", check_same_thread=False)
# geo location # geo location
@ -141,7 +144,6 @@ def return_file_access():
return [] return []
def songs_dashboard(): def songs_dashboard():
# — SESSION & PARAM HANDLING (unchanged) —
if 'songs_dashboard_timeframe' not in session: if 'songs_dashboard_timeframe' not in session:
session['songs_dashboard_timeframe'] = "30" session['songs_dashboard_timeframe'] = "30"
timeframe_param = request.args.get("timeframe", session['songs_dashboard_timeframe']) timeframe_param = request.args.get("timeframe", session['songs_dashboard_timeframe'])
@ -157,73 +159,50 @@ def songs_dashboard():
site = request.args.get("site", session['songs_dashboard_site']) site = request.args.get("site", session['songs_dashboard_site'])
session['songs_dashboard_site'] = site session['songs_dashboard_site'] = site
# — DETERMINE CUTOFF + TODAY STRINGS — # Determine cutoff_date based on the days parameter
now = datetime.now() if timeframe_param == "all":
params = [category, site] cutoff_date = None # No date filtering when analyzing all time
date_clauses = [] timeframe = "all" # Pass the string to the template if needed
if timeframe_param != "all": else:
cutoff = now - timedelta(days=int(timeframe_param)) timeframe = int(timeframe_param)
date_clauses.append("performance_date >= ?") now = datetime.now()
params.append(cutoff.strftime("%Y-%m-%d")) cutoff_date = now - timedelta(days=timeframe)
# filter out any future-dated rows at the DB level
date_clauses.append("performance_date <= ?")
params.append(now.strftime("%Y-%m-%d"))
where_sql = " AND ".join(["category = ?", "site = ?"] + date_clauses)
cursor = search_db.cursor() cursor = search_db.cursor()
cursor.execute( # Query rows with category "Gemeinsamer Gesang"
f"SELECT titel, performance_date FROM files WHERE {where_sql}", query = "SELECT titel, performance_date FROM files WHERE category = ? and site = ?"
params cursor.execute(query, (category, site))
)
rows = cursor.fetchall() rows = cursor.fetchall()
# — AGGREGATE COUNTS + LAST-PERFORMED, WITH ERROR LOGGING — # Group and count performances per titel (only if performance_date is within the timeframe,
performance_counts = defaultdict(int) # or count all if cutoff_date is None)
last_performed_dates = {} performance_counts = defaultdict(int)
for titel, performance_date in rows:
if performance_date:
try:
# Convert date from "dd.mm.yyyy" format
date_obj = datetime.strptime(performance_date, "%d.%m.%Y")
except ValueError:
continue
# If cutoff_date is None, count all dates; otherwise, filter by cutoff_date.
if cutoff_date is None or date_obj >= cutoff_date:
performance_counts[titel] += 1
for titel, perf_date_str in rows: # Create a list of tuples: (count, titel), sorted in descending order by count.
if not perf_date_str: performance_data = [(count, titel) for titel, count in performance_counts.items()]
continue performance_data.sort(reverse=True, key=lambda x: x[0])
perf_date_str = perf_date_str.strip()
try:
perf_date = datetime.strptime(perf_date_str, "%Y-%m-%d")
except ValueError:
print(f"[songs_dashboard] bad date format for “{titel}”: “{perf_date_str}")
continue
performance_counts[titel] += 1
prev = last_performed_dates.get(titel)
if prev is None or perf_date > prev:
last_performed_dates[titel] = perf_date
# — BUILD LIST FOR TEMPLATE —
performance_data = []
for titel, count in performance_counts.items():
last_str = last_performed_dates[titel].strftime("%d.%m.%Y")
performance_data.append({
"titel": titel,
"count": count,
"last_performed": last_str
})
performance_data.sort(key=lambda x: x["count"], reverse=True)
# — RENDER —
return render_template(
'songs_dashboard.html',
timeframe=timeframe_param,
performance_data=performance_data,
site=site,
category=category,
admin_enabled=auth.is_admin(),
title_short=app_config.get('TITLE_SHORT', 'Default Title'),
title_long= app_config.get('TITLE_LONG', 'Default Title'),
)
title_short = app_config.get('TITLE_SHORT', 'Default Title')
title_long = app_config.get('TITLE_LONG' , 'Default Title')
return render_template('songs_dashboard.html',
timeframe=timeframe_param,
performance_data=performance_data,
site=site,
category=category,
admin_enabled=auth.is_admin(),
title_short=title_short,
title_long=title_long)
@require_secret @require_secret
def connections(): def connections():

View File

@ -41,9 +41,9 @@
<span> | </span> <span> | </span>
<a href="{{ url_for('connections') }}">Verbindungen</a> <a href="{{ url_for('connections') }}">Verbindungen</a>
<span> | </span> <span> | </span>
<a href="{{ url_for('dashboard') }}">Dashbord</a> <a href="{{ url_for('dashboard') }}">Auswertung-Downloads</a>
<span> | </span> <span> | </span>
<a href="{{ url_for('songs_dashboard') }}">Wiederholungen</a> <a href="{{ url_for('songs_dashboard') }}">Auswertung-Wiederholungen</a>
{% if admin_enabled %} {% if admin_enabled %}
<span> | </span> <span> | </span>
<a href="{{ url_for('folder_secret_config_editor') }}" id="edit-folder-config">Ordnerkonfiguration</a> <a href="{{ url_for('folder_secret_config_editor') }}" id="edit-folder-config">Ordnerkonfiguration</a>

View File

@ -6,10 +6,8 @@
{# pagespecific content #} {# pagespecific content #}
{% block content %} {% block content %}
<!-- Main Container -->
<div class="container"> <div class="container">
<h2>Übersicht deiner Links</h2> <h2>Übersicht deiner gültigen Links</h2>
<div class="row"> <div class="row">
{% if valid_secrets %} {% if valid_secrets %}
{% for secret in valid_secrets %} {% for secret in valid_secrets %}
@ -19,7 +17,7 @@
class="card-img-top qr-code p-3" class="card-img-top qr-code p-3"
alt="QR Code for secret"> alt="QR Code for secret">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Secret Link:</h5> <h5 class="card-title">Geheimnis: {{ secret }}</h5>
<p class="card-text"> <p class="card-text">
<small class="text-muted">Gültig bis: {{ secret_valid_to[secret] }}</small> <small class="text-muted">Gültig bis: {{ secret_valid_to[secret] }}</small>
</p> </p>
@ -31,14 +29,16 @@
<button type="submit" class="btn btn-danger btn-sm">Link entfernen</button> <button type="submit" class="btn btn-danger btn-sm">Link entfernen</button>
</form> </form>
{% if secret_folders[secret] %} {% if secret_folders[secret] %}
<h5 class="mt-3">Ordner:</h5> <h6 class="mt-3">Ordner</h6>
<div class="list-group"> <ul class="list-group list-group-flush">
{% for folder in secret_folders[secret] %} {% for folder in secret_folders[secret] %}
<a class="btn btn-outline-secondary" style="margin: 5px;" href="/path/{{ folder.foldername }}">{{ folder.foldername }}</a> <li class="list-group-item">
<strong>{{ folder.foldername }}</strong>
</li>
{% endfor %} {% endfor %}
</div> </ul>
{% else %} {% else %}
<p class="text-muted">Keine Ordner für dieses Secret hinterlegt.</p> <p class="text-muted">Keine Ordner für dieses Gemeimnis hinterlegt.</p>
{% endif %} {% endif %}
</div> </div>
</div> </div>
@ -66,14 +66,16 @@
<button type="submit" class="btn btn-danger btn-sm">Link entfernen</button> <button type="submit" class="btn btn-danger btn-sm">Link entfernen</button>
</form> </form>
{% if token_folders[token] %} {% if token_folders[token] %}
<h5 class="mt-3">Ordner:</h5> <h6 class="mt-3">Ordner</h6>
<div class="list-group"> <ul class="list-group list-group-flush">
{% for folder in token_folders[token] %} {% for folder in token_folders[token] %}
<a class="btn btn-outline-secondary" style="margin: 5px;" href="/path/{{ folder.foldername }}">{{ folder.foldername }}</a> <li class="list-group-item">
<strong>{{ folder.foldername }}</strong>
</li>
{% endfor %} {% endfor %}
</div> </ul>
{% else %} {% else %}
<p class="text-muted">Keine Ordner für diesen Token hinterlegt.</p> <p class="text-muted">Keine Ordner für dieses Gemeimnis hinterlegt.</p>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -7,146 +7,147 @@
{# page content #} {# page content #}
{% block content %} {% block content %}
<!-- Main Container --> <!-- Main Container -->
<div class="container-fluid px-4"> <div class="container-fluid px-4">
<h2>Analyse Wiederholungen</h2> <h2>Analyse Wiederholungen</h2>
<!-- Dropdown Controls --> <!-- Dropdown Controls -->
<div class="mb-4 d-flex flex-wrap gap-2"> <div class="mb-4 d-flex flex-wrap gap-2">
<!-- Site Dropdown -->
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle"
type="button" id="siteDropdown" data-bs-toggle="dropdown" aria-expanded="false">
{% if session['songs_dashboard_site'] == 'Speyer' %}
Speyer
{% elif session['songs_dashboard_site'] == 'Schwegenheim' %}
Schwegenheim
{% else %}
Select Site
{% endif %}
</button>
<ul class="dropdown-menu" aria-labelledby="siteDropdown">
<li>
<a class="dropdown-item {% if session['songs_dashboard_site'] == 'Speyer' %}active{% endif %}"
href="{{ url_for('songs_dashboard', site='Speyer') }}">
Speyer
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_site'] == 'Schwegenheim' %}active{% endif %}"
href="{{ url_for('songs_dashboard', site='Schwegenheim') }}">
Schwegenheim
</a>
</li>
</ul>
</div>
<!-- Timeframe Dropdown --> <!-- Site Dropdown -->
<div class="dropdown"> <div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" <button class="btn btn-secondary dropdown-toggle"
type="button" id="timeframeDropdown" data-bs-toggle="dropdown" aria-expanded="false"> type="button" id="siteDropdown" data-bs-toggle="dropdown" aria-expanded="false">
{% if session['songs_dashboard_timeframe'] == '7' %} {% if session['songs_dashboard_site'] == 'Speyer' %}
Last 7 Days Speyer
{% elif session['songs_dashboard_timeframe'] == '30' %} {% elif session['songs_dashboard_site'] == 'Schwegenheim' %}
Last 30 Days Schwegenheim
{% elif session['songs_dashboard_timeframe'] == '90' %} {% else %}
Last 90 Days Select Site
{% elif session['songs_dashboard_timeframe'] == '365' %} {% endif %}
Last 365 Days </button>
{% elif session['songs_dashboard_timeframe'] == 'all' %} <ul class="dropdown-menu" aria-labelledby="siteDropdown">
All Data <li>
{% else %} <a class="dropdown-item {% if session['songs_dashboard_site'] == 'Speyer' %}active{% endif %}"
Select Timeframe href="{{ url_for('songs_dashboard', site='Speyer') }}">
{% endif %} Speyer
</button> </a>
<ul class="dropdown-menu" aria-labelledby="timeframeDropdown"> </li>
<li> <li>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == '7' %}active{% endif %}" <a class="dropdown-item {% if session['songs_dashboard_site'] == 'Schwegenheim' %}active{% endif %}"
href="{{ url_for('songs_dashboard', timeframe='7') }}"> href="{{ url_for('songs_dashboard', site='Schwegenheim') }}">
Last 7 Days Schwegenheim
</a> </a>
</li> </li>
<li> </ul>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == '30' %}active{% endif %}" </div>
href="{{ url_for('songs_dashboard', timeframe='30') }}">
Last 30 Days
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == '90' %}active{% endif %}"
href="{{ url_for('songs_dashboard', timeframe='90') }}">
Last 90 Days
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == '365' %}active{% endif %}"
href="{{ url_for('songs_dashboard', timeframe='365') }}">
Last 365 Days
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == 'all' %}active{% endif %}"
href="{{ url_for('songs_dashboard', timeframe='all') }}">
All Data
</a>
</li>
</ul>
</div>
<!-- category Dropdown --> <!-- Timeframe Dropdown -->
<div class="dropdown"> <div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="categoryDropdown" data-bs-toggle="dropdown" aria-expanded="false"> <button class="btn btn-secondary dropdown-toggle"
{% if session['songs_dashboard_category'] == 'Gemeinsamer Gesang' %} type="button" id="timeframeDropdown" data-bs-toggle="dropdown" aria-expanded="false">
Gemeinsamer Gesang {% if session['songs_dashboard_timeframe'] == '7' %}
{% elif session['songs_dashboard_category'] == 'Chor' %} Last 7 Days
Chor {% elif session['songs_dashboard_timeframe'] == '30' %}
{% elif session['songs_dashboard_category'] == 'Gruppenlied' %} Last 30 Days
Gruppenlied {% elif session['songs_dashboard_timeframe'] == '90' %}
{% else %} Last 90 Days
Select Category {% elif session['songs_dashboard_timeframe'] == '365' %}
{% endif %} Last 365 Days
</button> {% elif session['songs_dashboard_timeframe'] == 'all' %}
<ul class="dropdown-menu" aria-labelledby="categoryDropdown"> All Data
<li> {% else %}
<a class="dropdown-item {% if session['songs_dashboard_category'] == 'Gemeinsamer Gesang' %}active{% endif %}" Select Timeframe
href="{{ url_for('songs_dashboard', category='Gemeinsamer Gesang') }}"> {% endif %}
</button>
<ul class="dropdown-menu" aria-labelledby="timeframeDropdown">
<li>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == '7' %}active{% endif %}"
href="{{ url_for('songs_dashboard', timeframe='7') }}">
Last 7 Days
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == '30' %}active{% endif %}"
href="{{ url_for('songs_dashboard', timeframe='30') }}">
Last 30 Days
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == '90' %}active{% endif %}"
href="{{ url_for('songs_dashboard', timeframe='90') }}">
Last 90 Days
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == '365' %}active{% endif %}"
href="{{ url_for('songs_dashboard', timeframe='365') }}">
Last 365 Days
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_timeframe'] == 'all' %}active{% endif %}"
href="{{ url_for('songs_dashboard', timeframe='all') }}">
All Data
</a>
</li>
</ul>
</div>
<!-- category Dropdown -->
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="categoryDropdown" data-bs-toggle="dropdown" aria-expanded="false">
{% if session['songs_dashboard_category'] == 'Gemeinsamer Gesang' %}
Gemeinsamer Gesang Gemeinsamer Gesang
</a> {% elif session['songs_dashboard_category'] == 'Chor' %}
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_category'] == 'Chor' %}active{% endif %}"
href="{{ url_for('songs_dashboard', category='Chor') }}">
Chor Chor
</a> {% elif session['songs_dashboard_category'] == 'Gruppenlied' %}
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_category'] == 'Gruppenlied' %}active{% endif %}"
href="{{ url_for('songs_dashboard', category='Gruppenlied') }}">
Gruppenlied Gruppenlied
</a> {% else %}
</li> Select Category
</ul> {% endif %}
</div> </button>
</div> <ul class="dropdown-menu" aria-labelledby="categoryDropdown">
<li>
<a class="dropdown-item {% if session['songs_dashboard_category'] == 'Gemeinsamer Gesang' %}active{% endif %}"
href="{{ url_for('songs_dashboard', category='Gemeinsamer Gesang') }}">
Gemeinsamer Gesang
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_category'] == 'Chor' %}active{% endif %}"
href="{{ url_for('songs_dashboard', category='Chor') }}">
Chor
</a>
</li>
<li>
<a class="dropdown-item {% if session['songs_dashboard_category'] == 'Gruppenlied' %}active{% endif %}"
href="{{ url_for('songs_dashboard', category='Gruppenlied') }}">
Gruppenlied
</a>
</li>
</ul>
</div>
</div>
<!-- Table Output --> <!-- Table Output -->
<table class="table table-bordered"> <table class="table table-bordered">
<thead> <thead>
<tr>
<th>Anzahl</th>
<th>Titel</th>
<th>Zuletzt gesungen</th>
</tr>
</thead>
<tbody>
{% for item in performance_data %}
<tr> <tr>
<td>{{ item['count'] }}</td> <th>Anzahl</th>
<td>{{ item['titel'] }}</td> <th>Titel</th>
<td>{{ item['last_performed'] }}</td>
</tr> </tr>
{% endfor %} </thead>
</tbody> <tbody>
</table> {% for count, titel in performance_data %}
</div> <tr>
<td>{{ count }}</td>
<td>{{ titel }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
{% endblock %} {% endblock %}