Compare commits

..

1 Commits

7 changed files with 231 additions and 531 deletions

View File

@ -1,100 +1,120 @@
import sqlite3
import random
from wood import logger
from data.setup_database import DB_PATH
from data.database import db_connection
# -----------------------------------------------------
# User / Session
# -----------------------------------------------------
def validate_user_session(db_id, discord_id):
"""Prüft, ob das Cookie noch zur aktuellen Datenbank passt."""
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
cursor.execute("SELECT discord_id FROM players WHERE id = ?", (db_id,))
cursor.execute("SELECT discord_id FROM players WHERE id = %s", (db_id,))
result = cursor.fetchone()
cursor.close()
connection.close()
# 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!
return True
def change_display_name(player_id, new_name):
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
cursor.execute("UPDATE players SET display_name = ? WHERE id = ?", (new_name, player_id))
cursor.execute("UPDATE players SET display_name = %s WHERE id = %s", (new_name, player_id))
connection.commit()
cursor.close()
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}"
adjectives = ["Verwirrter", "Blinder", "Heulender", "Zorniger", "Chaos",
"Verzweifelter", "Schreiender", "Stolpernder", "Schwitzender"]
nouns = ["Grot", "Kultist", "Servitor", "Snotling", "Guardmen",
"Würfellecker", "Regelvergesser", "Meta-Chaser", "Klebschnüffler"]
return f"{random.choice(adjectives)} {random.choice(nouns)}"
def get_or_create_player(discord_id, discord_name, avatar_url):
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
connection = db_connection()
cursor = connection.cursor(dictionary=True)
# fragen 4 Dinge ab (id, discord_name, display_name, discord_avatar_url)
cursor.execute("SELECT id, discord_name, display_name, discord_avatar_url FROM players WHERE discord_id = ?", (discord_id,))
cursor.execute(
"SELECT id, discord_name, display_name, discord_avatar_url FROM players WHERE discord_id = %s",
(discord_id,)
)
player = cursor.fetchone()
if player is None:
# 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(f"new player added. Discord:{discord_name}")
cursor.execute(
"INSERT INTO players (discord_id, discord_name, display_name, discord_avatar_url) "
"VALUES (%s, %s, %s, %s)",
(discord_id, discord_name, silly_name, avatar_url)
)
connection.commit()
cursor.execute("SELECT id, discord_name, display_name, discord_avatar_url FROM players WHERE discord_id = ?", (discord_id,))
logger.log(f"new player added. Discord:{discord_name}")
cursor.execute(
"SELECT id, discord_name, display_name, discord_avatar_url FROM players WHERE discord_id = %s",
(discord_id,)
)
player = cursor.fetchone()
else:
# Falls sich Name oder Bild auf Discord geändert haben, machen wir ein Update
cursor.execute("UPDATE players SET discord_name = ?, discord_avatar_url = ? WHERE discord_id = ?", (discord_name, avatar_url, discord_id))
cursor.execute(
"UPDATE players SET discord_name = %s, discord_avatar_url = %s WHERE discord_id = %s",
(discord_name, avatar_url, discord_id)
)
connection.commit()
cursor.execute("SELECT id, discord_name, display_name, discord_avatar_url FROM players WHERE discord_id = ?", (discord_id,))
cursor.execute(
"SELECT id, discord_name, display_name, discord_avatar_url FROM players WHERE discord_id = %s",
(discord_id,)
)
player = cursor.fetchone()
cursor.close()
connection.close()
return player
# -----------------------------------------------------
# Player-Listen
# -----------------------------------------------------
def get_all_players():
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
"""Alle Spieler Basisdaten."""
connection = db_connection()
cursor = connection.cursor(dictionary=True)
# Alle Spieler laden, absteigend sortiert nach MMR
cursor.execute("SELECT id, name, mmr, points, games FROM players ORDER BY mmr DESC")
players = cursor.fetchall()
cursor.execute(
"SELECT id, display_name, discord_name, discord_avatar_url FROM players "
"ORDER BY display_name ASC"
)
rows = cursor.fetchall()
cursor.close()
connection.close()
# Die Daten für das Web-GUI in eine lesbare Form umwandeln (Liste von Dictionaries)
result = []
return result
return rows
def get_all_players_from_system(system_name):
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
connection = db_connection()
cursor = connection.cursor(dictionary=True)
# ID und Namen der Spieler.
# DISTINCT stellt sicher, dass jeder Spieler nur einmal vorkommt.
query = """
SELECT DISTINCT
p.id AS player_id,
@ -103,47 +123,37 @@ def get_all_players_from_system(system_name):
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 = %s
ORDER BY p.display_name ASC
"""
cursor.execute(query, (system_name,))
rows = cursor.fetchall()
cursor.close()
connection.close()
result = []
for row in rows:
result.append(dict(row))
return result
return rows
def get_gamesystem_id_by_name(system_name):
"""Holt die interne ID eines Spielsystems anhand seines Namens (z.B. 'Warhammer 40k' -> 1)."""
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
# Wir suchen exakt nach dem Namen
cursor.execute("SELECT id FROM gamesystems WHERE name = ?", (system_name,))
cursor.execute("SELECT id FROM gamesystems WHERE name = %s", (system_name,))
row = cursor.fetchone()
cursor.close()
connection.close()
# Wenn wir einen Treffer haben, geben wir die erste Spalte (die ID) zurück
if row:
return row[0]
# Wenn das System nicht existiert
return None
return row[0] if row else None
# -----------------------------------------------------
# Player Statistics
# -----------------------------------------------------
def get_player_statistics(player_id):
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
connection = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT
@ -162,22 +172,19 @@ def get_player_statistics(player_id):
stat.nemesis_id
FROM gamesystems sys
LEFT JOIN player_game_statistic stat
ON sys.id = stat.gamesystem_id AND stat.player_id = ?
ON sys.id = stat.gamesystem_id AND stat.player_id = %s
"""
cursor.execute(query, (player_id,))
rows = cursor.fetchall()
cursor.close()
connection.close()
return rows
result = []
for row in rows:
result.append(dict(row))
return result
def get_player_statistic(player_id, system_id):
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
connection = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT
@ -196,38 +203,40 @@ def get_player_statistic(player_id, system_id):
stat.nemesis_id
FROM gamesystems sys
LEFT JOIN player_game_statistic stat
ON sys.id = stat.gamesystem_id AND stat.player_id = ?
WHERE sys.id = ?
ON sys.id = stat.gamesystem_id AND stat.player_id = %s
WHERE sys.id = %s
"""
cursor.execute(query, (player_id, system_id))
row = cursor.fetchone()
cursor.close()
connection.close()
return dict(row) if row else None
return row
def join_league(player_id, gamesystem_id):
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
# Wir fügen nur die beiden IDs ein, der Rest wird von den DEFAULT-Werten der DB erledigt
query = """
INSERT INTO player_game_statistic (player_id, gamesystem_id)
VALUES (?, ?)
VALUES (%s, %s)
"""
logger.log(f"{get_player_name(player_id)} joined {gamesystem_id}")
cursor.execute(query, (player_id, gamesystem_id))
connection.commit()
cursor.close()
connection.close()
# -----------------------------------------------------
# Matches: Lesen
# -----------------------------------------------------
def get_recent_matches_for_player(player_id):
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
connection = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT
@ -246,69 +255,62 @@ def get_recent_matches_for_player(player_id):
JOIN gamesystems sys ON m.gamesystem_id = sys.id
JOIN players p1 ON m.player1_id = p1.id
JOIN players p2 ON m.player2_id = p2.id
WHERE m.player1_id = ? OR m.player2_id = ?
WHERE m.player1_id = %s OR m.player2_id = %s
ORDER BY m.played_at DESC
LIMIT 10
"""
cursor.execute(query, (player_id, player_id))
rows = cursor.fetchall()
cursor.close()
connection.close()
result = []
for row in rows:
result.append(dict(row))
return result
return rows
def add_new_match(system_name, player1_id, player2_id, score_p1, score_p2):
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
# 1. Wir suchen die interne ID des Spielsystems anhand des Namens (z.B. "Warhammer 40k" -> 1)
cursor.execute("SELECT id FROM gamesystems WHERE name = ?", (system_name,))
cursor.execute("SELECT id FROM gamesystems WHERE name = %s", (system_name,))
sys_row = cursor.fetchone()
# Sicherheitscheck (sollte eigentlich nie passieren)
if not sys_row:
cursor.close()
connection.close()
return None
return None
sys_id = sys_row[0]
# 2. Das Match eintragen! (Datum 'played_at' macht SQLite durch DEFAULT CURRENT_TIMESTAMP automatisch)
query = """
INSERT INTO matches (gamesystem_id, player1_id, player2_id, score_player1, score_player2)
VALUES (?, ?, ?, ?, ?)
VALUES (%s, %s, %s, %s, %s)
"""
cursor.execute(query, (sys_id, player1_id, player2_id, score_p1, score_p2))
new_match_id = cursor.lastrowid
logger.log(f"{get_player_name(player1_id)}:({score_p1}) posted Match. System: {system_name}, {get_player_name(player2_id)}:({score_p2})")
logger.log(
f"{get_player_name(player1_id)}:({score_p1}) posted Match. "
f"System: {system_name}, {get_player_name(player2_id)}:({score_p2})"
)
connection.commit()
cursor.close()
connection.close()
return new_match_id
def save_calculated_match(calc_results: dict):
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
try:
match_id = calc_results["match_id"]
winner_id = calc_results["winner_id"]
looser_id = calc_results["looser_id"]
match_id = calc_results["match_id"]
winner_id = calc_results["winner_id"]
looser_id = calc_results["looser_id"]
# Match aus DB lesen
cursor.execute(
"SELECT player1_id, player2_id, gamesystem_id FROM matches WHERE id = ?",
"SELECT player1_id, player2_id, gamesystem_id FROM matches WHERE id = %s",
(match_id,)
)
row = cursor.fetchone()
@ -317,21 +319,19 @@ def save_calculated_match(calc_results: dict):
player1_id, player2_id, gamesystem_id = row
# Daten der Spieler aus calc_results holen (Key = player_id als int/str)
p1 = calc_results[player1_id]
p2 = calc_results[player2_id]
# 1. Match-Tabelle updaten
match_query = """
UPDATE matches
SET
player1_base_change = ?, player1_khorne = ?, player1_slaanesh = ?,
player1_tzeentch = ?, player1_mmr_change = ?,
player2_base_change = ?, player2_khorne = ?, player2_slaanesh = ?,
player2_tzeentch = ?, player2_mmr_change = ?,
rust_factor = ?, elo_factor = ?, point_inflation = ?,
player1_base_change = %s, player1_khorne = %s, player1_slaanesh = %s,
player1_tzeentch = %s, player1_mmr_change = %s,
player2_base_change = %s, player2_khorne = %s, player2_slaanesh = %s,
player2_tzeentch = %s, player2_mmr_change = %s,
rust_factor = %s, elo_factor = %s, point_inflation = %s,
match_is_counted = 1
WHERE id = ?
WHERE id = %s
"""
cursor.execute(match_query, (
p1["base"], p1["khorne"], p1["slaanesh"], p1["tzeentch"], p1["total"],
@ -340,36 +340,29 @@ def save_calculated_match(calc_results: dict):
match_id
))
# 2. Scores holen
cursor.execute(
"SELECT score_player1, score_player2 FROM matches WHERE id = ?",
"SELECT score_player1, score_player2 FROM matches WHERE id = %s",
(match_id,)
)
score_row = cursor.fetchone()
score_p1, score_p2 = score_row if score_row else (0, 0)
# 3. Statistik-Query
stat_query = """
UPDATE player_game_statistic
SET
mmr = mmr + ?,
mmr = mmr + %s,
games_in_system = games_in_system + 1,
points = points + ?,
avv_points = (points + ?) / (games_in_system + 1),
points = points + %s,
avv_points = (points + %s) / (games_in_system + 1),
last_played = CURRENT_TIMESTAMP
WHERE player_id = ? AND gamesystem_id = ?
WHERE player_id = %s AND gamesystem_id = %s
"""
# 4. Statistik Spieler 1
cursor.execute(stat_query, (
p1["total"], score_p1, score_p1,
player1_id, gamesystem_id
p1["total"], score_p1, score_p1, player1_id, gamesystem_id
))
# 5. Statistik Spieler 2
cursor.execute(stat_query, (
p2["total"], score_p2, score_p2,
player2_id, gamesystem_id
p2["total"], score_p2, score_p2, player2_id, gamesystem_id
))
connection.commit()
@ -382,76 +375,63 @@ def save_calculated_match(calc_results: dict):
return False
finally:
cursor.close()
connection.close()
# -----------------------------------------------------
# Get Data Funktionen
# -----------------------------------------------------
# -----------------------------------------------------
def get_gamesystem_data(system_id):
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
cursor.execute("SELECT * FROM gamesystems WHERE id = ?", (system_id,))
connection = db_connection()
cursor = connection.cursor(dictionary=True)
cursor.execute("SELECT * FROM gamesystems WHERE id = %s", (system_id,))
row = cursor.fetchone()
cursor.close()
connection.close()
return dict(zip([col[0] for col in cursor.description], row)) if row else None
return row
def get_gamesystems_data():
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
connection = db_connection()
cursor = connection.cursor(dictionary=True)
cursor.execute("SELECT * FROM gamesystems")
rows = cursor.fetchall()
cursor.close()
connection.close()
# SQLite-Rows in normale Python-Dictionaries um
result = []
for row in rows:
result.append(dict(row))
return result
return rows
def get_leaderboard(system_name):
"""Holt alle Spieler eines Systems sortiert nach MMR für die Rangliste."""
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
connection = db_connection()
cursor = connection.cursor(dictionary=True)
# 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 = ? AND stat.games_in_system > 0
WHERE sys.name = %s AND stat.games_in_system > 0
ORDER BY stat.mmr DESC
"""
cursor.execute(query, (system_name,))
rows = cursor.fetchall()
cursor.close()
connection.close()
result = []
for row in rows:
result.append(dict(row))
return result
return rows
def get_match_by_id(match_id: int) -> dict | None:
"""Gibt alle Match-Daten inkl. Gamesystem-Name als Dict zurück."""
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
connection = db_connection()
cursor = connection.cursor(dictionary=True)
try:
cursor.execute("""
@ -466,99 +446,86 @@ def get_match_by_id(match_id: int) -> dict | None:
m.played_at
FROM matches m
JOIN gamesystems g ON m.gamesystem_id = g.id
WHERE m.id = ?
WHERE m.id = %s
""", (match_id,))
row = cursor.fetchone()
if not row:
return None
columns = [desc[0] for desc in cursor.description]
return dict(zip(columns, row))
return cursor.fetchone()
except Exception as e:
logger.log(f"Fehler beim Laden des Matches: {e}")
return None
finally:
cursor.close()
connection.close()
def get_player_name(player_id):
"""Gibt den Namen eines Spielers im Format 'Anzeigename (Discordname)' zurück."""
# Sicherheits-Check: Falls aus Versehen gar keine ID übergeben wird
if player_id is None:
return "Unbekannter Spieler"
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
cursor.execute("SELECT display_name, discord_name FROM players WHERE id = ?", (player_id,))
cursor.execute("SELECT display_name, discord_name FROM players WHERE id = %s", (player_id,))
row = cursor.fetchone()
cursor.close()
connection.close()
# Wenn die Datenbank den Spieler gefunden hat:
if row:
display_name = row[0]
discord_name = row[1]
return f"{display_name} ({discord_name})"
else:
return "Gelöschter Spieler"
return f"{row[0]} ({row[1]})"
return "Gelöschter Spieler"
def get_system_name(sys_id):
if sys_id is None:
return "Unbekanntes System"
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
cursor.execute("SELECT name FROM gamesystems WHERE id = ?", (sys_id,))
connection = db_connection()
cursor = connection.cursor()
cursor.execute("SELECT name FROM gamesystems WHERE id = %s", (sys_id,))
row = cursor.fetchone()
cursor.close()
connection.close()
if row:
return row[0]
else:
return "Gelöschtes System"
return row[0] if row else "Gelöschtes System"
def get_days_since_last_system_game(player_id, gamesystem_id):
"""Gibt zurück, wie viele Tage das letzte Spiel in einem bestimmten System her ist."""
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
# Julianday() berechnet in SQLite die Differenz in Tagen zwischen zwei Daten
# MariaDB: DATEDIFF statt julianday()
query = """
SELECT CAST(julianday('now') - julianday(last_played) AS INTEGER)
SELECT DATEDIFF(NOW(), last_played)
FROM player_game_statistic
WHERE player_id = ? AND gamesystem_id = ?
WHERE player_id = %s AND gamesystem_id = %s
"""
cursor.execute(query, (player_id, gamesystem_id))
result = cursor.fetchone()
cursor.close()
connection.close()
# Wenn er gefunden wurde und ein Datum hat, gib die Tage zurück. Sonst (Erstes Spiel) 0.
if result and result[0] is not None:
return result[0]
return int(result[0])
return 0
# -----------------------------------------------------
# Matches Bestätigen, Löschen, Berechnen, ...
# -----------------------------------------------------
# -----------------------------------------------------
def get_unconfirmed_matches(player_id):
"""Holt alle offenen Matches, die der Spieler noch bestätigen muss."""
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
connection = db_connection()
cursor = connection.cursor(dictionary=True)
# Wir joinen players (für den Namen des Gegners) und gamesystems (für den Systemnamen)
query = """
SELECT m.id AS match_id, m.score_player1, m.score_player2, m.played_at,
sys.name AS system_name,
@ -566,58 +533,58 @@ def get_unconfirmed_matches(player_id):
FROM matches m
JOIN gamesystems sys ON m.gamesystem_id = sys.id
JOIN players p1 ON m.player1_id = p1.id
WHERE m.player2_id = ? AND m.player2_check = 0
WHERE m.player2_id = %s AND m.player2_check = 0
"""
cursor.execute(query, (player_id,))
rows = cursor.fetchall()
connection.close()
# Wir geben eine Liste mit Dictionaries zurück
return [dict(row) for row in rows]
cursor.close()
connection.close()
return rows
def delete_match(match_id, player_id):
"""Löscht ein Match anhand seiner ID komplett aus der Datenbank."""
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
# DELETE FROM löscht die gesamte Zeile, bei der die ID übereinstimmt.
cursor.execute("DELETE FROM matches WHERE id = ?", (match_id,))
cursor.execute("DELETE FROM matches WHERE id = %s", (match_id,))
logger.log(f"Match ID{match_id} deleted from user {get_player_name(player_id)}(ID:{player_id})")
connection.commit()
cursor.close()
connection.close()
def confirm_match(match_id):
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
# Ändert nur die Spalte player2_check auf 1 (True)
cursor.execute("UPDATE matches SET player2_check = 1 WHERE id = ?", (match_id,))
cursor.execute("UPDATE matches SET player2_check = 1 WHERE id = %s", (match_id,))
logger.log(f"Match mit ID{match_id} von Player2 bestätigt.")
connection.commit()
cursor.close()
connection.close()
def set_match_counted(match_id):
"""Setzt den Haken (1), dass das Match erfolgreich in die MMR eingeflossen ist."""
connection = sqlite3.connect(DB_PATH)
connection = db_connection()
cursor = connection.cursor()
# Ändert nur die Spalte match_is_counted auf 1 (True)
cursor.execute("UPDATE matches SET match_is_counted = 1 WHERE id = ?", (match_id,))
cursor.execute("UPDATE matches SET match_is_counted = 1 WHERE id = %s", (match_id,))
connection.commit()
cursor.close()
connection.close()
def get_submitted_matches(player_id):
"""Holt alle offenen Matches, die der Spieler selbst eingetragen hat, aber vom Gegner noch nicht bestätigt wurden."""
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
"""Holt alle offenen Matches, die der Spieler selbst eingetragen hat."""
connection = db_connection()
cursor = connection.cursor(dictionary=True)
# ACHTUNG: Wir joinen hier p2 (player2), weil wir den Namen des Gegners anzeigen wollen!
query = """
SELECT m.id AS match_id, m.score_player1, m.score_player2, m.played_at,
sys.name AS system_name,
@ -625,21 +592,20 @@ def get_submitted_matches(player_id):
FROM matches m
JOIN gamesystems sys ON m.gamesystem_id = sys.id
JOIN players p2 ON m.player2_id = p2.id
WHERE m.player1_id = ? AND m.player2_check = 0
WHERE m.player1_id = %s AND m.player2_check = 0
"""
cursor.execute(query, (player_id,))
rows = cursor.fetchall()
connection.close()
return [dict(row) for row in rows]
cursor.close()
connection.close()
return rows
def get_match_history_log(player_id):
"""Holt ALLE Matches eines Spielers inklusive der MMR-Änderungen und Faktoren für das Log."""
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
"""Holt ALLE Matches eines Spielers inkl. MMR-Änderungen und Faktoren."""
connection = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT m.played_at, sys.name AS gamesystem_name,
@ -655,54 +621,12 @@ def get_match_history_log(player_id):
JOIN gamesystems sys ON m.gamesystem_id = sys.id
JOIN players p1 ON m.player1_id = p1.id
JOIN players p2 ON m.player2_id = p2.id
WHERE m.player1_id = ? OR m.player2_id = ?
WHERE m.player1_id = %s OR m.player2_id = %s
ORDER BY m.played_at DESC
"""
cursor.execute(query, (player_id, player_id))
rows = cursor.fetchall()
cursor.close()
connection.close()
return [dict(row) for row in rows]
# -----------------------------------------------------
# Testing and Prototyping
# -----------------------------------------------------
def create_random_dummy_match(player_id):
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
# 1. Die ID des Dummys suchen (Wir suchen einfach nach dem Namen 'Dummy')
cursor.execute("SELECT id FROM players WHERE display_name LIKE '%Dummy%' OR discord_name LIKE '%Dummy%' LIMIT 1")
dummy_row = cursor.fetchone()
if not dummy_row:
connection.close()
print("Fehler: Kein Dummy in der Datenbank gefunden!")
return False
dummy_id = dummy_row[0]
# 2. Zufällige Punkte generieren (z.B. zwischen 0 und 100)
score_p1 = random.randint(0, 100)
score_p2 = random.randint(0, 100)
# 3. Das Match hart in System 1 (gamesystem_id = 1) eintragen
query = """
INSERT INTO matches (gamesystem_id, player2_id, player1_id, score_player1, score_player2, player2_check)
VALUES (?, ?, ?, ?, ?, 0)
"""
cursor.execute(query, (1, player_id, dummy_id, score_p1, score_p2))
connection.commit()
connection.close()
p1_name = get_player_name(player_id)
dummy_name = get_player_name(dummy_id)
sys_name = get_system_name(1)
logger.log(f"Zufallsspiel generiert. [{sys_name}]: {p1_name} ({score_p1}) vs. {dummy_name} ({score_p2})")
return True
return rows

View File

@ -1,27 +1,23 @@
import sqlite3
import mariadb
import os
from data import setup_database, data_api
from dotenv import load_dotenv
from data.setup_database import DB_PATH
load_dotenv()
def db_connection():
try:
connection = mariadb.connect(
host=os.getenv("DB_HOST", "localhost"),
port=int(os.getenv("DB_PORT", 3306)),
user=os.getenv("DB_USER"),
password=os.getenv("DB_PASSWORD"),
database=os.getenv("DB_NAME")
)
return connection
except mariadb.Error as e:
raise RuntimeError(f"Fehler beim Verbinden mit DB: {e}")
if __name__ == "__main__":
setup_database.init_db()
def check_db():
# Prüfen, ob die Datei existiert
db_file = DB_PATH
if not os.path.exists(db_file):
print(f"WARNUNG: '{db_file}' nicht gefunden!")
print("Starte Datenbank-Einrichtung...")
# 1. Erstellt die leere Datei und alle Tabellen-Strukturen
setup_database.init_db()
print("Datenbank aufgebaut!")
else:
print(f"OK: Datenbank '{db_file}' gefunden. Lade System...")

View File

@ -1,225 +0,0 @@
import sqlite3
import os
import json
from dotenv import load_dotenv
load_dotenv()
DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "league_database.db")
dummy_is_in = True
def init_db():
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
# Fremdschlüssel (Foreign Keys) in SQLite aktivieren
cursor.execute('PRAGMA foreign_keys = ON;')
# 1. Tabelle: players (Stammdaten)
cursor.execute('''
CREATE TABLE IF NOT EXISTS players (
id INTEGER PRIMARY KEY AUTOINCREMENT,
discord_id TEXT UNIQUE,
discord_name TEXT NOT NULL,
discord_avatar_url TEXT,
display_name TEXT
)
''')
# 2. Tabelle: gamesystems (Globale Spielsysteme)
cursor.execute('''
CREATE TABLE IF NOT EXISTS gamesystems (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
picture TEXT,
description TEXT,
active_players INTEGER DEFAULT 0,
min_score INTEGER DEFAULT 0,
max_score INTEGER DEFAULT 100
)
''')
# 3. Tabelle: player_game_statistic (Welcher Spieler hat in welchem System welche Stats?)
cursor.execute('''
CREATE TABLE IF NOT EXISTS player_game_statistic (
id INTEGER PRIMARY KEY AUTOINCREMENT,
player_id INTEGER,
gamesystem_id INTEGER,
mmr INTEGER DEFAULT 1000,
games_in_system INTEGER DEFAULT 0,
points INTEGER DEFAULT 0,
avv_points INTEGER DEFAULT 0,
last_played TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
win_rate REAL DEFAULT 0,
win_streak INTEGER DEFAULT 0,
wins INTEGER DEFAULT 0,
losses INTEGER DEFAULT 0,
draws INTEGER DEFAULT 0,
trend INTEGER DEFAULT 0,
tyrann_id INTEGER,
pushover_id INTEGER,
nemesis_id INTEGER,
FOREIGN KEY (player_id) REFERENCES players (id),
FOREIGN KEY (tyrann_id) REFERENCES players (id),
FOREIGN KEY (pushover_id) REFERENCES players (id),
FOREIGN KEY (nemesis_id) REFERENCES players (id),
FOREIGN KEY (gamesystem_id) REFERENCES gamesystems (id)
)
''')
# 4. Tabelle: matches (Wer hat wann gegen wen in welchem System gespielt?)
cursor.execute('''
CREATE TABLE IF NOT EXISTS matches (
id INTEGER PRIMARY KEY AUTOINCREMENT,
gamesystem_id INTEGER,
player1_id INTEGER,
score_player1 INTEGER,
player2_id INTEGER,
score_player2 INTEGER,
played_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
player1_base_change INTEGER,
player1_khorne INTEGER,
player1_slaanesh INTEGER,
player1_tzeentch INTEGER,
player1_mmr_change INTEGER,
player2_base_change INTEGER,
player2_khorne INTEGER,
player2_slaanesh INTEGER,
player2_tzeentch INTEGER,
player2_mmr_change INTEGER,
rust_factor REAL,
elo_factor REAL,
point_inflation REAL,
player2_check INTEGER DEFAULT 0,
match_is_counted INTEGER DEFAULT 0,
FOREIGN KEY (gamesystem_id) REFERENCES gamesystems (id),
FOREIGN KEY (player1_id) REFERENCES players (id),
FOREIGN KEY (player2_id) REFERENCES players (id)
)
''')
# 5. Tabelle: achievements (Der globale Katalog aller möglichen Erfolge - Stammdaten)
cursor.execute('''
CREATE TABLE IF NOT EXISTS achievements (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
description TEXT NOT NULL,
icon TEXT
)
''')
# 6. Tabelle: player_achievements. Wer hat welchen Erfolg wann bekommen
cursor.execute('''
CREATE TABLE IF NOT EXISTS player_achievements (
id INTEGER PRIMARY KEY AUTOINCREMENT,
player_id INTEGER,
achievement_id INTEGER,
earned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
earned_in INTEGER,
FOREIGN KEY (earned_in) REFERENCES gamesystems (id),
FOREIGN KEY (player_id) REFERENCES players (id),
FOREIGN KEY (achievement_id) REFERENCES achievements (id)
)
''')
connection.commit()
connection.close()
print("Datenbank Struktur aufgebaut")
#nächster Schritt: Standard Spielsysteme eintragen
seed_gamesystems()
# --------------------
# --- Start Setup der DB Daten. Damit sie nicht GANZ leer sind.
# --------------------
def seed_gamesystems():
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
systems = [
("Warhammer 40k", "40k_logo.png", "Die Schlacht um die Galaxie in einer entfernten Zukunft.", 0, 100),
("Warhammer Age of Sigmar", "aos_logo.png", "Der ewige Krieg um die Reiche der Sterblichen in einer epischen Fantasy-Welt.", 0, 50),
("Spearhead", "aos_logo.png", "Schnelle und taktische Scharmützel für actiongeladene Kämpfe.", 0, 50)
]
# executemany ist eine extrem schnelle SQL For-Schleife für Inserts
cursor.executemany("INSERT INTO gamesystems (name, picture, description, min_score, max_score) VALUES (?, ?, ?, ?, ?)", systems)
connection.commit()
connection.close()
print("Spielsysteme angelegt!")
#Nächster Schritt: Standard Achievments eintragen.
seed_achievements()
def seed_achievements():
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
# Unsere Start-Stückliste an Erfolgen (Name, Beschreibung, Icon)
achievements = [
("Kingslayer", "Hat den Spieler auf Platz 1 besiegt!", "👑"),
("Unstoppable", "3 Spiele in Folge gewonnen.", "🔥"),
("First Blood", "Das allererste Ligaspiel absolviert.", "🩸")
]
cursor.executemany("INSERT INTO achievements (name, description, icon) VALUES (?, ?, ?)", achievements)
connection.commit()
connection.close()
print("Achievements angelegt.")
if dummy_is_in:
seed_dummy_player()
def seed_dummy_player():
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
# 1. Dummy-Spieler anlegen (falls noch nicht vorhanden)
query_player = """
INSERT OR IGNORE INTO players
(discord_id, discord_name, display_name, discord_avatar_url)
VALUES (?, ?, ?, ?)
"""
cursor.execute(query_player, ("dummy_001", "dummy_user", "Dummy Mc DummDumm", ""))
# 2. Wir holen uns die ID des Dummys (egal ob neu oder alt)
cursor.execute("SELECT id FROM players WHERE discord_id = 'dummy_001'")
dummy_row = cursor.fetchone()
if dummy_row:
dummy_id = dummy_row[0]
# 3. Wir holen alle IDs der aktuellen Spielsysteme
cursor.execute("SELECT id FROM gamesystems")
systems = cursor.fetchall()
# 4. Wir gehen jedes System durch und prüfen, ob er schon drin ist
for sys in systems:
sys_id = sys[0]
cursor.execute("SELECT id FROM player_game_statistic WHERE player_id = ? AND gamesystem_id = ?", (dummy_id, sys_id))
is_in_league = cursor.fetchone()
if not is_in_league:
# Er ist noch nicht drin -> Eintragen! (MMR startet durch DEFAULT automatisch bei 1000)
cursor.execute("""
INSERT INTO player_game_statistic (player_id, gamesystem_id)
VALUES (?, ?)
""", (dummy_id, sys_id))
connection.commit()
connection.close()
print("Test-Gegner 'Dummy Mc DummDumm' ist bereit und in allen Ligen angemeldet!")

View File

@ -89,9 +89,16 @@ def setup_login_routes():
app.storage.user['authenticated'] = True
app.storage.user['discord_id'] = discord_id
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]
# Kompatibel mit dict (MariaDB) UND tuple (SQLite)
if isinstance(player, dict):
app.storage.user['db_id'] = player['id'] # oder der echte Spaltenname
app.storage.user['display_name'] = player['display_name']
app.storage.user['discord_avatar_url'] = player['discord_avatar_url']
else:
app.storage.user['db_id'] = player[0]
app.storage.user['display_name'] = player[2]
app.storage.user['discord_avatar_url'] = player['discord_avatar_url']
ui.navigate.to('/')
else:

View File

@ -23,10 +23,8 @@ client_secret = os.getenv("DISCORD_CLIENT_SECRET")
admin_discord_id = os.getenv("ADMIN")
url = os.getenv("APP_URL")
database.check_db()
logger.setup_log_db()
# 3. Seitenrouten aufbauen
main_gui.setup_routes(admin_discord_id)
discord_login.setup_login_routes()

View File

@ -1,3 +1,4 @@
nicegui
requests
python-dotenv
mariadb

View File

@ -2,7 +2,6 @@ import sqlite3
import os
import inspect
from data.setup_database import DB_PATH
DB_FILE = "wood/log.db"