Login Funktioniert. Dark Mode. Match Formular Seite erstellt.
This commit is contained in:
parent
296d170442
commit
01256cba0d
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# 1. Datenbanken
|
||||
*.db
|
||||
*.sqlite3
|
||||
|
||||
# 2. Python Caches
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# 3. Virtuelle Umgebungen
|
||||
venv/
|
||||
.venv/
|
||||
env/
|
||||
|
||||
# 4. Geheime Konfigurationen (Umgebungsvariablen)
|
||||
.env
|
||||
|
||||
# 5. IDE / Editor Einstellungen
|
||||
.vscode/
|
||||
.idea/
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"authenticated":true,"discord_id":"277898241750859776","discord_name":"mrteels","db_id":1}
|
||||
91
database.py
Normal file
91
database.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import sqlite3
|
||||
|
||||
def init_db():
|
||||
# Neue englische Datenbank-Datei
|
||||
connection = sqlite3.connect("warhammer_league.db")
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Fremdschlüssel (Foreign Keys) in SQLite aktivieren
|
||||
cursor.execute('PRAGMA foreign_keys = ON;')
|
||||
|
||||
# Tabelle: players (ehemals spieler)
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS players (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
discord_id TEXT UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
mmr INTEGER DEFAULT 1000,
|
||||
points INTEGER DEFAULT 0,
|
||||
games INTEGER DEFAULT 0
|
||||
)
|
||||
''')
|
||||
|
||||
# Tabelle: matches (ehemals spiele)
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS matches (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
player1_id INTEGER,
|
||||
score_player1 INTEGER,
|
||||
player2_id INTEGER,
|
||||
score_player2 INTEGER,
|
||||
FOREIGN KEY (player1_id) REFERENCES players (id),
|
||||
FOREIGN KEY (player2_id) REFERENCES players (id)
|
||||
)
|
||||
''')
|
||||
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
print("Warhammer database successfully initialized!")
|
||||
|
||||
def get_or_create_player(discord_id, discord_name):
|
||||
# 1. Verbindung öffnen
|
||||
connection = sqlite3.connect("warhammer_league.db")
|
||||
cursor = connection.cursor()
|
||||
|
||||
# 2. Suchen, ob der Spieler schon existiert
|
||||
cursor.execute("SELECT id, name, mmr, points, games FROM players WHERE discord_id = ?", (discord_id,))
|
||||
player = cursor.fetchone()
|
||||
|
||||
# 3. Wenn der Spieler nicht gefunden wurde (ist "None")
|
||||
if player is None:
|
||||
# Neu anlegen
|
||||
cursor.execute("INSERT INTO players (discord_id, name) VALUES (?, ?)", (discord_id, discord_name))
|
||||
connection.commit()
|
||||
|
||||
# Den frisch angelegten Spieler direkt wieder auslesen, um seine neue ID zu bekommen
|
||||
cursor.execute("SELECT id, name, mmr, points, games FROM players WHERE discord_id = ?", (discord_id,))
|
||||
player = cursor.fetchone()
|
||||
|
||||
# 4. Verbindung schließen
|
||||
connection.close()
|
||||
|
||||
# 5. Daten zurückgeben
|
||||
return player
|
||||
|
||||
if __name__ == "__main__":
|
||||
init_db()
|
||||
|
||||
|
||||
def get_all_players():
|
||||
connection = sqlite3.connect("warhammer_league.db")
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Alle Spieler laden, absteigend sortiert nach MMR
|
||||
cursor.execute("SELECT id, name, mmr, points, games FROM players ORDER BY mmr DESC")
|
||||
players = cursor.fetchall()
|
||||
|
||||
connection.close()
|
||||
|
||||
# Die Daten für das Web-GUI in eine lesbare Form umwandeln (Liste von Dictionaries)
|
||||
result = []
|
||||
for player in players:
|
||||
result.append({
|
||||
'id': player[0],
|
||||
'name': player[1],
|
||||
'mmr': player[2],
|
||||
'points': player[3],
|
||||
'games': player[4]
|
||||
})
|
||||
|
||||
return result
|
||||
110
gui/main_gui.py
110
gui/main_gui.py
|
|
@ -0,0 +1,110 @@
|
|||
import os
|
||||
import urllib.parse
|
||||
import requests
|
||||
from nicegui import ui, app
|
||||
|
||||
# NEU: Wir importieren unsere eigene Datenbank-Datei
|
||||
import database
|
||||
|
||||
def setup_routes():
|
||||
client_id = os.getenv("DISCORD_CLIENT_ID")
|
||||
client_secret = os.getenv("DISCORD_CLIENT_SECRET")
|
||||
app_url = os.getenv("APP_URL")
|
||||
|
||||
redirect_uri = f"{app_url}/login/discord"
|
||||
encoded_redirect_uri = urllib.parse.quote(redirect_uri, safe="")
|
||||
|
||||
discord_auth_url = f"https://discord.com/api/oauth2/authorize?client_id={client_id}&redirect_uri={encoded_redirect_uri}&response_type=code&scope=identify"
|
||||
|
||||
# --- HOME PAGE ---
|
||||
@ui.page('/')
|
||||
|
||||
def home_page():
|
||||
ui.dark_mode(True)
|
||||
with ui.card().classes('w-full items-center mt-10'):
|
||||
ui.label('Warhammer League').classes('text-2xl font-bold')
|
||||
|
||||
# --- LOGIN BEREICH ---
|
||||
if app.storage.user.get('authenticated', False):
|
||||
discord_name = app.storage.user.get('discord_name')
|
||||
db_id = app.storage.user.get('db_id')
|
||||
|
||||
ui.label(f'Welcome back, {discord_name}!').classes('text-green-500 font-bold')
|
||||
|
||||
ui.button('Enter Match', on_click=lambda: ui.navigate.to('/add-match')).classes('mt-4 bg-blue-500 text-white')
|
||||
|
||||
def logout():
|
||||
app.storage.user.clear()
|
||||
ui.navigate.to('/')
|
||||
|
||||
ui.button('Logout', on_click=logout).classes('mt-4 bg-red-500 text-white')
|
||||
else:
|
||||
ui.button('Login with Discord', on_click=lambda: ui.navigate.to(discord_auth_url))
|
||||
|
||||
# --- LEADERBOARD BEREICH ---
|
||||
with ui.card().classes('w-full items-center mt-6'):
|
||||
ui.label('Leaderboard').classes('text-xl font-bold mb-4')
|
||||
|
||||
# 1. Spalten (Columns) für die Tabelle definieren
|
||||
table_columns = [
|
||||
{'name': 'name', 'label': 'Player', 'field': 'name', 'align': 'left'},
|
||||
{'name': 'mmr', 'label': 'MMR', 'field': 'mmr', 'sortable': True},
|
||||
{'name': 'points', 'label': 'Points', 'field': 'points', 'sortable': True},
|
||||
{'name': 'games', 'label': 'Games Played', 'field': 'games', 'sortable': True},
|
||||
]
|
||||
|
||||
# 2. Daten (Rows) aus der Datenbank holen
|
||||
player_data = database.get_all_players()
|
||||
|
||||
# 3. Tabelle zeichnen
|
||||
ui.table(columns=table_columns, rows=player_data, row_key='name').classes('w-full max-w-4xl')
|
||||
|
||||
|
||||
|
||||
# --- DISCORD CALLBACK PAGE ---
|
||||
@ui.page('/login/discord')
|
||||
def discord_callback(code: str = None):
|
||||
if not code:
|
||||
ui.label('Fehler: Kein Code erhalten.').classes('text-red-500')
|
||||
return
|
||||
|
||||
token_data = {
|
||||
'client_id': client_id,
|
||||
'client_secret': client_secret,
|
||||
'grant_type': 'authorization_code',
|
||||
'code': code,
|
||||
'redirect_uri': redirect_uri
|
||||
}
|
||||
|
||||
token_response = requests.post('https://discord.com/api/oauth2/token', data=token_data)
|
||||
token_json = token_response.json()
|
||||
|
||||
if 'access_token' in token_json:
|
||||
access_token = token_json['access_token']
|
||||
|
||||
user_headers = {
|
||||
'Authorization': f"Bearer {access_token}"
|
||||
}
|
||||
user_response = requests.get('https://discord.com/api/users/@me', headers=user_headers)
|
||||
user_json = user_response.json()
|
||||
|
||||
# --- NEU: DATENBANK INTEGRATION ---
|
||||
discord_id = user_json['id']
|
||||
discord_name = user_json['username']
|
||||
|
||||
# 1. Spieler in der DB suchen oder neu anlegen
|
||||
player = database.get_or_create_player(discord_id, discord_name)
|
||||
|
||||
# 2. Session-Daten aktualisieren
|
||||
app.storage.user['authenticated'] = True
|
||||
app.storage.user['discord_id'] = discord_id
|
||||
app.storage.user['discord_name'] = discord_name
|
||||
|
||||
# player ist ein Tuple aus der DB, z.B.: (1, "123456", "Daniel", 1000, 0, 0)
|
||||
# player[0] ist die interne Datenbank-ID. Diese merken wir uns in der Session!
|
||||
app.storage.user['db_id'] = player[0]
|
||||
|
||||
ui.navigate.to('/')
|
||||
else:
|
||||
ui.label('Fehler beim Login!').classes('text-red-500')
|
||||
ui.label(str(token_json))
|
||||
23
gui/match_gui.py
Normal file
23
gui/match_gui.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from nicegui import ui, app
|
||||
|
||||
def setup_match_routes():
|
||||
|
||||
# Unsere neue Unterseite für das Eintragen der Spiele
|
||||
@ui.page('/add-match')
|
||||
def add_match_page():
|
||||
with ui.card().classes('w-full items-center mt-10'):
|
||||
ui.label('Enter New Match').classes('text-2xl font-bold')
|
||||
|
||||
# --- SICHERHEITS-CHECK ---
|
||||
# Prüfen, ob der User wirklich eingeloggt ist.
|
||||
# Wenn nicht, brechen wir hier sofort ab!
|
||||
if not app.storage.user.get('authenticated', False):
|
||||
ui.label('Access Denied. Please log in first.').classes('text-red-500')
|
||||
ui.button('Back to Home', on_click=lambda: ui.navigate.to('/'))
|
||||
return
|
||||
|
||||
# --- PLATZHALTER ---
|
||||
ui.label('Hier kommt im nächsten Schritt das Eingabe-Formular hin!').classes('text-gray-500 my-4')
|
||||
|
||||
# Ein Button, um wieder zurück zur Startseite zu kommen
|
||||
ui.button('Cancel', on_click=lambda: ui.navigate.to('/')).classes('bg-gray-500 text-white')
|
||||
19
main.py
19
main.py
|
|
@ -0,0 +1,19 @@
|
|||
import os
|
||||
from dotenv import load_dotenv
|
||||
from nicegui import ui
|
||||
from gui import main_gui
|
||||
from gui import match_gui
|
||||
|
||||
# 1. Lade die geheimen Variablen aus der .env Datei in den Speicher
|
||||
load_dotenv()
|
||||
|
||||
# 2. Variablen abrufen
|
||||
client_id = os.getenv("DISCORD_CLIENT_ID")
|
||||
client_secret = os.getenv("DISCORD_CLIENT_SECRET")
|
||||
|
||||
# 3. Wir rufen unsere Funktion aus der main_gui.py auf
|
||||
main_gui.setup_routes()
|
||||
match_gui.setup_match_routes()
|
||||
|
||||
# 4. Wir starten die NiceGUI App
|
||||
ui.run(title="Warhammer Liga", port=9000, storage_secret="ein_sehr_geheimes_passwort_fuer_die_cookies")
|
||||
Loading…
Reference in New Issue
Block a user