From 3936a0b53b538834bfcf393d30ff762497cae7b6 Mon Sep 17 00:00:00 2001 From: Daniel Nagel Date: Sun, 8 Mar 2026 16:23:39 +0100 Subject: [PATCH] =?UTF-8?q?Randomizer=20Button=20f=C3=BCr=20den=20DisplayN?= =?UTF-8?q?ame.=20Seiten=20flashen=20nicht=20mehr=20wei=C3=9F=20beim=20Neu?= =?UTF-8?q?=20laden.=20Discord=20Login=20nur=20noch=20wenn=20man=20auf=20d?= =?UTF-8?q?em=20Westside=20Diceghost=20Server=20"Diceghost"=20oder=20"Frie?= =?UTF-8?q?nd"=20ist.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-47e8cea6-65ad-4725-abd9-23cf84587a03.json | 2 +- data/data_api.py | 18 ++++----- gui/admin_gui.py | 6 ++- gui/discord_login.py | 40 ++++++++++++++++--- gui/gui_style.py | 2 + gui/league_statistic.py | 2 +- gui/main_gui.py | 10 ++++- gui/match_gui.py | 2 +- 8 files changed, 60 insertions(+), 22 deletions(-) diff --git a/.nicegui/storage-user-47e8cea6-65ad-4725-abd9-23cf84587a03.json b/.nicegui/storage-user-47e8cea6-65ad-4725-abd9-23cf84587a03.json index 6b89cb8..90a427a 100644 --- a/.nicegui/storage-user-47e8cea6-65ad-4725-abd9-23cf84587a03.json +++ b/.nicegui/storage-user-47e8cea6-65ad-4725-abd9-23cf84587a03.json @@ -1 +1 @@ -{"authenticated":true,"discord_id":"277898241750859776","discord_name":"mrteels","db_id":2,"display_name":"r","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":"Stolpernder Meta-Chaser","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 771787c..dd2a4df 100644 --- a/data/data_api.py +++ b/data/data_api.py @@ -11,7 +11,12 @@ def change_display_name(player_id, new_name): connection.commit() connection.close() - +def generate_silly_name(): + adjectives = ["Verwirrter", "Blinder", "Heulender", "Zorniger", "Chaos", "Verzweifelter", "Schreiender", "Stolpernder", "Schwitzender"] + nouns = ["Grot", "Kultist", "Servitor", "Snotling", "Guardmen", "Würfellecker", "Regelvergesser", "Meta-Chaser", "Klebschnüffler"] + adj = random.choice(adjectives) + noun = random.choice(nouns) + return f"{adj} {noun}" def get_or_create_player(discord_id, discord_name, avatar_url): @@ -25,12 +30,6 @@ def get_or_create_player(discord_id, discord_name, avatar_url): if player is None: # Random Silly Name Generator für neue Spieler. Damit sie angeregt werden ihren richtigen Namen einzutragen. - def generate_silly_name(): - adjectives = ["Verwirrter", "Blinder", "Heulender", "Zorniger", "Chaos", "Verzweifelter", "Schreiender", "Stolpernder", "Schwitzender"] - nouns = ["Grot", "Kultist", "Servitor", "Snotling", "Guardmen", "Würfellecker", "Regelvergesser", "Meta-Chaser", "Klebschnüffler"] - adj = random.choice(adjectives) - noun = random.choice(nouns) - return f"{adj} {noun}" 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)) @@ -456,13 +455,14 @@ def get_leaderboard(system_name): connection.row_factory = sqlite3.Row cursor = connection.cursor() - # Wir holen ID, Namen, Discord und MMR, sortiert vom höchsten MMR zum niedrigsten + # WIR HABEN HIER EINE BEDINGUNG HINZUGEFÜGT: AND stat.games_in_system > 0 + # Dadurch filtert die Datenbank direkt auf dem Server schon alle "0-Spiele"-Accounts raus. query = """ SELECT p.id, p.display_name, p.discord_name, stat.mmr FROM players p JOIN player_game_statistic stat ON p.id = stat.player_id JOIN gamesystems sys ON stat.gamesystem_id = sys.id - WHERE sys.name = ? + WHERE sys.name = ? AND stat.games_in_system > 0 ORDER BY stat.mmr DESC """ diff --git a/gui/admin_gui.py b/gui/admin_gui.py index 4636cb9..7a30fa8 100644 --- a/gui/admin_gui.py +++ b/gui/admin_gui.py @@ -3,6 +3,8 @@ from data import database, data_api from gui import gui_style def setup_routes(): - @ui.page('/admin') + @ui.page('/admin', dark=True) def home_page(): - gui_style.apply_design() \ No newline at end of file + gui_style.apply_design() + if app.storage.user.get('authenticated', False): + ui.card().classes("w-full") \ No newline at end of file diff --git a/gui/discord_login.py b/gui/discord_login.py index 2ca768f..712e123 100644 --- a/gui/discord_login.py +++ b/gui/discord_login.py @@ -11,8 +11,9 @@ def get_auth_url(): redirect_uri = f"{app_url}/login/discord" encoded_redirect_uri = urllib.parse.quote(redirect_uri, safe="") - # NEU: scope=identify%20guilds fragt Profilbild UND Server ab - return f"https://discord.com/api/oauth2/authorize?client_id={client_id}&redirect_uri={encoded_redirect_uri}&response_type=code&scope=identify%20guilds" + # NEU: guilds.members.read erlaubt uns, die Rollen des Users in einem bestimmten Server abzufragen + return f"https://discord.com/api/oauth2/authorize?client_id={client_id}&redirect_uri={encoded_redirect_uri}&response_type=code&scope=identify%20guilds.members.read" + def setup_login_routes(): client_id = os.getenv("DISCORD_CLIENT_ID") @@ -20,7 +21,7 @@ def setup_login_routes(): app_url = os.getenv("APP_URL") redirect_uri = f"{app_url}/login/discord" - @ui.page('/login/discord') + @ui.page('/login/discord', dark=True) def discord_callback(code: str = None): if not code: ui.label('Fehler: Kein Code erhalten.').classes('text-red-500') @@ -39,8 +40,35 @@ def setup_login_routes(): if 'access_token' in token_json: access_token = token_json['access_token'] - user_headers = {'Authorization': f"Bearer {access_token}"} + + # 1. Die IDs aus der .env laden (Passe die Namen an, falls sie bei dir anders heißen!) + guild_id = os.getenv("DISCORD_SERVER_ID") + role_diceghosts = os.getenv("DISCORD_SERVER_DICEGHOST_ID") + role_friend = os.getenv("DISCORD_SERVER_FRIEND_ID") + + # 2. Prüfen: Ist der Nutzer überhaupt auf unserem Server? + # Wir fragen Discord gezielt nach dem Profil des Nutzers auf DEINEM Server. + member_response = requests.get(f'https://discord.com/api/users/@me/guilds/{guild_id}/member', headers=user_headers) + + # Ein HTTP Status-Code 200 bedeutet "OK". Alles andere (z.B. 404 Not Found) bedeutet: Er ist nicht auf dem Server! + if member_response.status_code != 200: + ui.label('Zugriff verweigert: Du bist nicht auf dem Diceghosts Server!').classes('text-red-500 text-xl font-bold p-4') + return # Bricht die Funktion hier ab. Kein Login! + + # 3. Prüfen: Hat er die richtige Rolle? + member_json = member_response.json() + # Wir holen die Liste aller Rollen des Nutzers. Wenn er keine hat, nehmen wir eine leere Liste [] + user_roles = member_json.get('roles', []) + + # Wir prüfen, ob mindestens eine der beiden Rollen-IDs in seiner Liste auftaucht + if role_diceghosts not in user_roles and role_friend not in user_roles: + ui.label('Zugriff verweigert: Du hast nicht die benötigte Rolle (Diceghosts oder Friend)!').classes('text-red-500 text-xl font-bold p-4') + return # Bricht die Funktion hier ab. Kein Login! + + # --- AB HIER: ZUGANG GEWÄHRT! --- + + # Jetzt laden wir noch seine allgemeinen Discord-Daten (für Name und Profilbild) user_response = requests.get('https://discord.com/api/users/@me', headers=user_headers) user_json = user_response.json() @@ -63,8 +91,8 @@ def setup_login_routes(): app.storage.user['discord_name'] = discord_name app.storage.user['db_id'] = player[0] app.storage.user['display_name'] = player[2] - app.storage.user['discord_avatar_url'] = player[3] # Bild speichern! + app.storage.user['discord_avatar_url'] = player[3] ui.navigate.to('/') else: - ui.label('Fehler beim Login!').classes('text-red-500') \ No newline at end of file + ui.label('Fehler beim Login!').classes('text-red-500') diff --git a/gui/gui_style.py b/gui/gui_style.py index 29f8b7b..11873a9 100644 --- a/gui/gui_style.py +++ b/gui/gui_style.py @@ -1,6 +1,8 @@ from nicegui import ui def apply_design(): + ui.add_css('body { background-color: #18181b; }') + # 1. Dark Mode aktivieren ui.dark_mode(True) diff --git a/gui/league_statistic.py b/gui/league_statistic.py index ca9856b..a5d5317 100644 --- a/gui/league_statistic.py +++ b/gui/league_statistic.py @@ -4,7 +4,7 @@ from data import data_api def setup_routes(): # 1. Die {}-Klammern definieren eine dynamische Variable in der URL - @ui.page('/statistic/{systemname}') + @ui.page('/statistic/{systemname}', dark=True) def gamesystem_statistic_page(systemname: str): # <--- WICHTIG: Hier fangen wir das Wort aus der URL auf! # Sicherheitscheck: Ist der User eingeloggt? diff --git a/gui/main_gui.py b/gui/main_gui.py index e4d48af..731118d 100644 --- a/gui/main_gui.py +++ b/gui/main_gui.py @@ -4,7 +4,7 @@ from gui import discord_login, gui_style from match_calculations import calc_match def setup_routes(admin_discord_id): - @ui.page('/') + @ui.page('/', dark=True) def home_page(): gui_style.apply_design() @@ -48,7 +48,7 @@ def setup_routes(admin_discord_id): ui.button(icon='edit', color='primary', on_click=toggle_edit_mode).props('round dense') # --- ANSICHT 2: Das Eingabefeld (startet unsichtbar!) --- - with ui.row().classes('items-center gap-2') as edit_row: + with ui.row().classes('items-center gap-5') as edit_row: edit_row.visible = False # Am Anfang verstecken def save_new_name(): @@ -65,8 +65,14 @@ def setup_routes(admin_discord_id): # Wenn nichts geändert wurde, einfach wieder einklappen toggle_edit_mode() + def generate_random_silly_name(): + silly_name = data_api.generate_silly_name() + name_input.value=silly_name + + name_input = ui.input('Neuer Name', value=display_name).on('keydown.enter', save_new_name) ui.button(icon='save', color='positive', on_click=save_new_name).props('round dense') + ui.button(icon='casino', on_click=generate_random_silly_name).props('round dense') ui.button(icon='close', color='negative', on_click=toggle_edit_mode).props('round dense') avatar = app.storage.user.get('avatar_url') diff --git a/gui/match_gui.py b/gui/match_gui.py index 65a4d7a..6413df8 100644 --- a/gui/match_gui.py +++ b/gui/match_gui.py @@ -6,7 +6,7 @@ from match_calculations import calc_match def setup_routes(): # 1. Die {}-Klammern definieren eine dynamische Variable in der URL - @ui.page('/add-match/{systemname}') + @ui.page('/add-match/{systemname}', dark=True) def match_form_page(systemname: str): # <--- WICHTIG: Hier fangen wir das Wort aus der URL auf! gui_style.apply_design()