diff --git a/analytics.py b/analytics.py index 65c6c50..8c6cbf1 100644 --- a/analytics.py +++ b/analytics.py @@ -12,11 +12,8 @@ file_access_temp = [] 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 -log_db = sqlite3.connect(DB_NAME, check_same_thread=False) +log_db = sqlite3.connect("access_log.db", check_same_thread=False) search_db = sqlite3.connect("search.db", check_same_thread=False) # geo location @@ -144,65 +141,89 @@ def return_file_access(): return [] def songs_dashboard(): + # — SESSION & PARAM HANDLING (unchanged) — if 'songs_dashboard_timeframe' not in session: session['songs_dashboard_timeframe'] = "30" timeframe_param = request.args.get("timeframe", session['songs_dashboard_timeframe']) session['songs_dashboard_timeframe'] = timeframe_param - + if 'songs_dashboard_category' not in session: session['songs_dashboard_category'] = "Gemeinsamer Gesang" category = request.args.get("category", session['songs_dashboard_category']) session['songs_dashboard_category'] = category - + if 'songs_dashboard_site' not in session: session['songs_dashboard_site'] = "Speyer" site = request.args.get("site", session['songs_dashboard_site']) session['songs_dashboard_site'] = site - - # Determine cutoff_date based on the days parameter - if timeframe_param == "all": - cutoff_date = None # No date filtering when analyzing all time - timeframe = "all" # Pass the string to the template if needed - else: - timeframe = int(timeframe_param) - now = datetime.now() - cutoff_date = now - timedelta(days=timeframe) - + + # — DETERMINE CUTOFF + TODAY STRINGS — + now = datetime.now() + params = [category, site] + date_clauses = [] + if timeframe_param != "all": + cutoff = now - timedelta(days=int(timeframe_param)) + date_clauses.append("performance_date >= ?") + params.append(cutoff.strftime("%Y-%m-%d")) + # 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() - # Query rows with category "Gemeinsamer Gesang" - query = "SELECT titel, performance_date FROM files WHERE category = ? and site = ?" - cursor.execute(query, (category, site)) + cursor.execute( + f"SELECT titel, performance_date FROM files WHERE {where_sql}", + params + ) rows = cursor.fetchall() - - # Group and count performances per titel (only if performance_date is within the timeframe, - # or count all if cutoff_date is None) - 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 - - # Create a list of tuples: (count, titel), sorted in descending order by count. - performance_data = [(count, titel) for titel, count in performance_counts.items()] - performance_data.sort(reverse=True, key=lambda x: x[0]) - - 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) + + # — AGGREGATE COUNTS + LAST-PERFORMED, WITH ERROR LOGGING — + performance_counts = defaultdict(int) + last_performed_dates = {} + + for titel, perf_date_str in rows: + if not perf_date_str: + continue + + 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'), + ) + + @require_secret def connections(): diff --git a/templates/songs_dashboard.html b/templates/songs_dashboard.html index c283047..99001b6 100644 --- a/templates/songs_dashboard.html +++ b/templates/songs_dashboard.html @@ -134,13 +134,15 @@ Anzahl Titel + Zuletzt gesungen - {% for count, titel in performance_data %} + {% for item in performance_data %} - {{ count }} - {{ titel }} + {{ item['count'] }} + {{ item['titel'] }} + {{ item['last_performed'] }} {% endfor %}