diff --git a/.nicegui/storage-user-253576f7-9827-4994-a103-e67a11c8053c.json b/.nicegui/storage-user-253576f7-9827-4994-a103-e67a11c8053c.json index 9963eea..cfdc4d2 100644 --- a/.nicegui/storage-user-253576f7-9827-4994-a103-e67a11c8053c.json +++ b/.nicegui/storage-user-253576f7-9827-4994-a103-e67a11c8053c.json @@ -1 +1 @@ -{"authenticated":true,"discord_id":"277898241750859776","discord_name":"mrteels","db_id":2,"display_name":"Daniel Nagel","discord_avatar_url":"https://cdn.discordapp.com/avatars/277898241750859776/7c3446bb51fafd72b1b4c21124b4994f.png"} \ No newline at end of file +{"authenticated":true,"discord_id":"277898241750859776","discord_name":"mrteels","db_id":2,"display_name":"Daniel N.","discord_avatar_url":"https://cdn.discordapp.com/avatars/277898241750859776/7c3446bb51fafd72b1b4c21124b4994f.png"} \ No newline at end of file diff --git a/data/data_api.py b/data/data_api.py index 7f341f7..6421c93 100644 --- a/data/data_api.py +++ b/data/data_api.py @@ -15,10 +15,12 @@ def validate_user_session(db_id, discord_id): # 1. Fall: Die ID gibt es gar nicht mehr in der Datenbank if result is None: + logger.log(f"Player not found in database. Discord:{discord_id}") return False # 2. Fall: Die ID gehört jetzt einem anderen Discord-Account (Datenbank wurde resettet) if str(result[0]) != str(discord_id): + logger.log(f"Player with false coockies logged in! {discord_id} doesnt belong to {db_id}") return False # 3. Fall: Alles ist korrekt! @@ -54,7 +56,7 @@ def get_or_create_player(discord_id, discord_name, avatar_url): # Random Silly Name Generator für neue Spieler. Damit sie angeregt werden ihren richtigen Namen einzutragen. silly_name = generate_silly_name() cursor.execute("INSERT INTO players (discord_id, discord_name, display_name, discord_avatar_url) VALUES (?, ?, ?, ?)", (discord_id, discord_name, silly_name, avatar_url)) - logger.log("data_api.get_or_create_player", str("Ein neuer Spieler wurde angelegt - " + discord_name)) + logger.log(f"new player added. Discord:{discord_name}") connection.commit() cursor.execute("SELECT id, discord_name, display_name, discord_avatar_url FROM players WHERE discord_id = ?", (discord_id,)) player = cursor.fetchone() @@ -184,7 +186,7 @@ def join_league(player_id, gamesystem_id): INSERT INTO player_game_statistic (player_id, gamesystem_id) VALUES (?, ?) """ - logger.log("data_api.join_league", f"{get_player_name(player_id)} joined {gamesystem_id}", player_id) + logger.log(f"{get_player_name(player_id)} joined {gamesystem_id}") cursor.execute(query, (player_id, gamesystem_id)) connection.commit() @@ -256,7 +258,7 @@ def add_new_match(system_name, player1_id, player2_id, score_p1, score_p2): cursor.execute(query, (sys_id, player1_id, player2_id, score_p1, score_p2)) new_match_id = cursor.lastrowid - logger.log("data_api.add_new_match", f"{get_player_name(player1_id)}:({score_p1}) posted Match. System: {system_name}, {get_player_name(player2_id)}:({score_p2})", player1_id) + logger.log(f"{get_player_name(player1_id)}:({score_p1}) posted Match. System: {system_name}, {get_player_name(player2_id)}:({score_p2})", player1_id) connection.commit() connection.close() @@ -341,12 +343,12 @@ def save_calculated_match(calc_results: dict): )) connection.commit() - logger.log("pi.save_calculated_match", f"Match ID:{match_id} berechnet.") + logger.log(f"Match ID:{match_id} calculated.") return True except Exception as e: connection.rollback() - logger.log("data_api.save_calculated_match", f"KRITISCHER FEHLER beim Speichern des Matches: {e}") + logger.log(f"KRITISCHER FEHLER beim Speichern des Matches: {e}") return False finally: @@ -445,7 +447,7 @@ def get_match_by_id(match_id: int) -> dict | None: return dict(zip(columns, row)) except Exception as e: - print(f"Fehler beim Laden des Matches: {e}") + logger.log(f"Fehler beim Laden des Matches: {e}") return None finally: @@ -552,7 +554,7 @@ def delete_match(match_id, player_id): # DELETE FROM löscht die gesamte Zeile, bei der die ID übereinstimmt. cursor.execute("DELETE FROM matches WHERE id = ?", (match_id,)) - logger.log("data_api.delete_match", f"Match mit ID{match_id} von User gelöscht.", f"{player_id}") + logger.log(f"Match ID{match_id} deleted from user {get_player_name(player_id)}(ID:{player_id})") connection.commit() connection.close() @@ -563,7 +565,7 @@ def confirm_match(match_id): # Ändert nur die Spalte player2_check auf 1 (True) cursor.execute("UPDATE matches SET player2_check = 1 WHERE id = ?", (match_id,)) - logger.log("data_api.confirm_match", f"Match mit ID{match_id} von Player2 bestätigt.") + logger.log(f"Match mit ID{match_id} von Player2 bestätigt.") connection.commit() connection.close() @@ -670,7 +672,7 @@ def create_random_dummy_match(player_id): dummy_name = get_player_name(dummy_id) sys_name = get_system_name(1) - logger.log("TEST_MATCH", f"Zufallsspiel generiert. [{sys_name}]: {p1_name} ({score_p1}) vs. {dummy_name} ({score_p2})", player_id) + logger.log(f"Zufallsspiel generiert. [{sys_name}]: {p1_name} ({score_p1}) vs. {dummy_name} ({score_p2})") return True diff --git a/gui/admin_gui.py b/gui/admin_gui.py index a9cdd25..5b609ad 100644 --- a/gui/admin_gui.py +++ b/gui/admin_gui.py @@ -12,12 +12,11 @@ def setup_routes(): with ui.header().classes('items-center justify-between bg-zinc-900 p-4 shadow-lg'): ui.button("Zurück", on_click= lambda: ui.navigate.to("/") ) - if app.storage.user.get('authenticated', False): - with ui.card().classes("w-full"): - with ui.row().classes("w-full"): + if app.storage.user.get('authenticated', False): + with ui.row().classes("w-full"): ui.button(text= "test", on_click=lambda: data_api.create_random_dummy_match(2)) - ui.button(icon="refresh", on_click=lambda: ui.navigate.reload) - + ui.button(icon="refresh", on_click= lambda: ui.navigate.to("/admin") ) + with ui.card().classes("w-full"): ui.label("System Audit Log").classes('text-2xl font-bold text-white mb-4') # Daten abrufen @@ -25,18 +24,16 @@ def setup_routes(): # Tabelle aufbauen columns = [ - {'name': 'time', 'label': 'Zeitstempel', 'field': 'timestamp', 'align': 'left', 'sortable': True}, - {'name': 'user', 'label': 'Auslöser', 'field': 'player_name', 'align': 'left'}, - {'name': 'action', 'label': 'Aktion', 'field': 'action', 'align': 'left', 'sortable': True}, + {'name': 'time', 'label': 'Time', 'field': 'timestamp', 'align': 'left', 'sortable': True}, + {'name': 'file', 'label': 'Datei', 'field': 'file', 'align': 'left'}, + {'name': 'source', 'label': 'Quelle', 'field': 'source', 'align': 'left'}, {'name': 'details', 'label': 'Details', 'field': 'details', 'align': 'left'} ] if len(log_data) > 0: - # Wir schneiden bei den Millisekunden vom Zeitstempel wieder etwas ab [:19] + # Millisekunden vom Zeitstempel abschneiden [:19] for row in log_data: row['timestamp'] = str(row['timestamp'])[:19] - - # Tabelle zeichnen ui.table(columns=columns, rows=log_data, row_key='id').classes('w-full bg-zinc-900 text-gray-300') else: ui.label("Das Logbuch ist leer.").classes('text-gray-500 italic') \ No newline at end of file diff --git a/gui/info_text/info_system.py b/gui/info_text/info_system.py index b584714..0187ef5 100644 --- a/gui/info_text/info_system.py +++ b/gui/info_text/info_system.py @@ -2,11 +2,11 @@ import json import os from nicegui import ui -# 1. Pfad zur JSON Datei berechnen +# Pfad zur JSON Datei berechnen BASE_DIR = os.path.dirname(os.path.abspath(__file__)) JSON_PATH = os.path.join(BASE_DIR, "info_texts.json") -# 2. JSON Datei in den Speicher laden +# JSON Datei in den Speicher laden def load_info_texts(): if os.path.exists(JSON_PATH): # encoding="utf-8" ist wichtig für deutsche Umlaute (ä, ö, ü)! @@ -19,7 +19,6 @@ def load_info_texts(): # Wir laden das Wörterbuch genau 1x beim Serverstart TEXT_DICTIONARY = load_info_texts() -# 3. Unser neuer Baustein für die Webseite def create_info_button(topic_key): # Den Text aus dem Wörterbuch holen. Falls nicht vorhanden wird eine Fehlermeldung geworfen. texts = TEXT_DICTIONARY.get(topic_key, ["Hilfetext nicht gefunden!"]) diff --git a/gui/info_text/info_texts.json b/gui/info_text/info_texts.json index 034cce9..182e91f 100644 --- a/gui/info_text/info_texts.json +++ b/gui/info_text/info_texts.json @@ -12,6 +12,10 @@ "**ACHTUNG:** Ein Spieler ist nur als Gegner auswählbar wenn er sich in der Liga angemeldet hat!", "Solltest du einen Fehler machen kannst du das 'falsche' Match auf der Hauptseite noch löschen bevor es bestätigt wurde." ], + "khorne": ["Khorne will Blut und Schädel!"], + "tzeentch": ["tzeentch Pläne gehen auf!"], + "basis_mmr": ["Berechnet mit dem MMR Unterschied."], + "tyrann_info": [], "prügelknabe_info": [] } \ No newline at end of file diff --git a/match_calculations/calc_match.py b/match_calculations/calc_match.py index 1a42ab4..433cd04 100644 --- a/match_calculations/calc_match.py +++ b/match_calculations/calc_match.py @@ -93,8 +93,8 @@ def calculate_match (match_id): } } - logger.log(f"calc_match ID:{match_id}", f"Winner {data_api.get_player_name(winner_id)}: Base {w_base} + Khorne({w_khorne}) + Slaanesh({slaanesh}) + Tzeentch({tzeentch}) = {calc_results[winner_id]["total"]}") - logger.log(f"calc_match ID:{match_id}", f"Looser {data_api.get_player_name(looser_id)}: -Base({l_base}) + Khorne({l_khorne}) - Slaanesh({slaanesh}) - Tzeentch({tzeentch}) = {calc_results[looser_id]["total"]}") + logger.log(f"Match{match_id}: Winner {data_api.get_player_name(winner_id)}: Base {w_base} + Khorne({w_khorne}) + Slaanesh({slaanesh}) + Tzeentch({tzeentch}) = {calc_results[winner_id]["total"]}") + logger.log(f"Match{match_id}: Looser {data_api.get_player_name(looser_id)}: -Base({l_base}) + Khorne({l_khorne}) - Slaanesh({slaanesh}) - Tzeentch({tzeentch}) = {calc_results[looser_id]["total"]}") data_api.save_calculated_match(calc_results) diff --git a/wood/logger.py b/wood/logger.py index c50652d..9c51bd5 100644 --- a/wood/logger.py +++ b/wood/logger.py @@ -1,22 +1,39 @@ import sqlite3 import os +import inspect from data.setup_database import DB_PATH DB_FILE = "wood/log.db" -def log(action, details, player_id = None): - """Schreibt ein Ereignis (Audit Trail) in das System-Log.""" - connection = sqlite3.connect(DB_FILE) - cursor = connection.cursor() +def log(details): + # Arbeitsdaten der aktuellen Funktion (log) holen + this_frame = inspect.currentframe() + try: + # Einen Schritt "nach oben" zum Aufrufer gehen + caller_frame = this_frame.f_back + # 3. Lesbare Infos aus dem Aufrufer-Frame extrahieren + info = inspect.getframeinfo(caller_frame) + file = f"{info.filename}" + source = f"{info.function}() L:{info.lineno}" - cursor.execute( - "INSERT INTO system_log (player_id, action, details) VALUES (?, ?, ?)", - (player_id, action, details) - ) + # 5. Datenbank-Verbindung aufbauen (DB_FILE muss vorher definiert sein) + connection = sqlite3.connect(DB_FILE) + cursor = connection.cursor() + + # 6. Daten in die Datenbank schreiben + cursor.execute( + "INSERT INTO system_log (file, source, details) VALUES (?, ?, ?)", + (file, source, details) + ) + + connection.commit() + connection.close() + + finally: + del this_frame + del caller_frame - connection.commit() - connection.close() def setup_log_db(): @@ -34,8 +51,8 @@ def setup_log_db(): CREATE TABLE IF NOT EXISTS system_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - player_id INTEGER, - action TEXT, + file TEXT, + source TEXT, details TEXT ) ''') @@ -57,19 +74,4 @@ def get_full_log(): logs = [dict(row) for row in log_cursor.fetchall()] log_conn.close() - # 2. Spielernamen aus der Haupt-DB holen - main_conn = sqlite3.connect(DB_PATH) - main_cursor = main_conn.cursor() - main_cursor.execute("SELECT id, display_name, discord_name FROM players") - players_dict = {row[0]: f"{row[1]} ({row[2]})" for row in main_cursor.fetchall()} - main_conn.close() - - # 3. Die IDs in den Logs durch Namen ersetzen - for log_entry in logs: - p_id = log_entry['player_id'] - if p_id is not None and p_id in players_dict: - log_entry['player_name'] = players_dict[p_id] - else: - log_entry['player_name'] = "System / Unbekannt" - return logs \ No newline at end of file