Randomizer Button für den DisplayName. Seiten flashen nicht mehr weiß beim Neu laden. Discord Login nur noch wenn man auf dem Westside Diceghost Server "Diceghost" oder "Friend" ist.

This commit is contained in:
Daniel Nagel 2026-03-08 16:23:39 +01:00
parent 84410a49b6
commit 3936a0b53b
8 changed files with 60 additions and 22 deletions

View File

@ -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"}
{"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"}

View File

@ -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
"""

View File

@ -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()
gui_style.apply_design()
if app.storage.user.get('authenticated', False):
ui.card().classes("w-full")

View File

@ -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')
ui.label('Fehler beim Login!').classes('text-red-500')

View File

@ -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)

View File

@ -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?

View File

@ -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')

View File

@ -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()