Liga-System/data/data_api.py

633 lines
18 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import random
from wood import logger
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 = db_connection()
cursor = connection.cursor()
cursor.execute("SELECT discord_id FROM players WHERE id = %s", (db_id,))
result = cursor.fetchone()
cursor.close()
connection.close()
if result is None:
logger.log(f"Player not found in database. Discord:{discord_id}")
return False
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
return True
def change_display_name(player_id, new_name):
connection = db_connection()
cursor = connection.cursor()
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"]
return f"{random.choice(adjectives)} {random.choice(nouns)}"
def get_or_create_player(discord_id, discord_name, avatar_url):
connection = db_connection()
cursor = connection.cursor(dictionary=True)
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:
silly_name = generate_silly_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()
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:
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 = %s",
(discord_id,)
)
player = cursor.fetchone()
cursor.close()
connection.close()
return player
# -----------------------------------------------------
# Player-Listen
# -----------------------------------------------------
def get_all_players():
"""Alle Spieler Basisdaten."""
connection = db_connection()
cursor = connection.cursor(dictionary=True)
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()
return rows
def get_all_players_from_system(system_name):
connection = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT DISTINCT
p.id AS player_id,
p.display_name,
p.discord_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 = %s
ORDER BY p.display_name ASC
"""
cursor.execute(query, (system_name,))
rows = cursor.fetchall()
cursor.close()
connection.close()
return rows
def get_gamesystem_id_by_name(system_name):
connection = db_connection()
cursor = connection.cursor()
cursor.execute("SELECT id FROM gamesystems WHERE name = %s", (system_name,))
row = cursor.fetchone()
cursor.close()
connection.close()
return row[0] if row else None
# -----------------------------------------------------
# Player Statistics
# -----------------------------------------------------
def get_player_statistics(player_id):
connection = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT
sys.id AS gamesystem_id,
sys.name AS gamesystem_name,
sys.*,
stat.mmr,
stat.games_in_system,
stat.points,
stat.avv_points,
stat.last_played,
stat.win_rate,
stat.trend,
stat.tyrann_id,
stat.pushover_id,
stat.nemesis_id
FROM gamesystems sys
LEFT JOIN player_game_statistic stat
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
def get_player_statistic(player_id, system_id):
connection = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT
sys.id AS gamesystem_id,
sys.name AS gamesystem_name,
sys.*,
stat.mmr,
stat.games_in_system,
stat.points,
stat.avv_points,
stat.last_played,
stat.win_rate,
stat.trend,
stat.tyrann_id,
stat.pushover_id,
stat.nemesis_id
FROM gamesystems sys
LEFT JOIN player_game_statistic stat
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 row
def join_league(player_id, gamesystem_id):
connection = db_connection()
cursor = connection.cursor()
query = """
INSERT INTO player_game_statistic (player_id, gamesystem_id)
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 = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT
m.id AS match_id,
sys.name AS gamesystem_name,
m.player1_id,
p1.display_name AS p1_display,
p1.discord_name AS p1_discord,
m.score_player1,
m.player2_id,
p2.display_name AS p2_display,
p2.discord_name AS p2_discord,
m.score_player2,
m.played_at
FROM matches m
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 = %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()
return rows
def add_new_match(system_name, player1_id, player2_id, score_p1, score_p2):
connection = db_connection()
cursor = connection.cursor()
cursor.execute("SELECT id FROM gamesystems WHERE name = %s", (system_name,))
sys_row = cursor.fetchone()
if not sys_row:
cursor.close()
connection.close()
return None
sys_id = sys_row[0]
query = """
INSERT INTO matches (gamesystem_id, player1_id, player2_id, score_player1, score_player2)
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. "
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 = db_connection()
cursor = connection.cursor()
try:
match_id = calc_results["match_id"]
winner_id = calc_results["winner_id"]
looser_id = calc_results["looser_id"]
cursor.execute(
"SELECT player1_id, player2_id, gamesystem_id FROM matches WHERE id = %s",
(match_id,)
)
row = cursor.fetchone()
if not row:
raise ValueError(f"Match ID {match_id} nicht in der Datenbank gefunden.")
player1_id, player2_id, gamesystem_id = row
p1 = calc_results[player1_id]
p2 = calc_results[player2_id]
match_query = """
UPDATE matches
SET
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 = %s
"""
cursor.execute(match_query, (
p1["base"], p1["khorne"], p1["slaanesh"], p1["tzeentch"], p1["total"],
p2["base"], p2["khorne"], p2["slaanesh"], p2["tzeentch"], p2["total"],
calc_results["rust_factor"], calc_results["elo_factor"], calc_results["point_inflation"],
match_id
))
cursor.execute(
"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)
stat_query = """
UPDATE player_game_statistic
SET
mmr = mmr + %s,
games_in_system = games_in_system + 1,
points = points + %s,
avv_points = (points + %s) / (games_in_system + 1),
last_played = CURRENT_TIMESTAMP
WHERE player_id = %s AND gamesystem_id = %s
"""
cursor.execute(stat_query, (
p1["total"], score_p1, score_p1, player1_id, gamesystem_id
))
cursor.execute(stat_query, (
p2["total"], score_p2, score_p2, player2_id, gamesystem_id
))
connection.commit()
logger.log(f"Match ID:{match_id} calculated.")
return True
except Exception as e:
connection.rollback()
logger.log(f"KRITISCHER FEHLER beim Speichern des Matches: {e}")
return False
finally:
cursor.close()
connection.close()
# -----------------------------------------------------
# Get Data Funktionen
# -----------------------------------------------------
def get_gamesystem_data(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 row
def get_gamesystems_data():
connection = db_connection()
cursor = connection.cursor(dictionary=True)
cursor.execute("SELECT * FROM gamesystems")
rows = cursor.fetchall()
cursor.close()
connection.close()
return rows
def get_leaderboard(system_name):
"""Holt alle Spieler eines Systems sortiert nach MMR für die Rangliste."""
connection = db_connection()
cursor = connection.cursor(dictionary=True)
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 = %s AND stat.games_in_system > 0
ORDER BY stat.mmr DESC
"""
cursor.execute(query, (system_name,))
rows = cursor.fetchall()
cursor.close()
connection.close()
return rows
def get_match_by_id(match_id: int) -> dict | None:
"""Gibt alle Match-Daten inkl. Gamesystem-Name als Dict zurück."""
connection = db_connection()
cursor = connection.cursor(dictionary=True)
try:
cursor.execute("""
SELECT
m.id,
m.gamesystem_id,
g.name AS gamesystem_name,
m.player1_id,
m.score_player1,
m.player2_id,
m.score_player2,
m.played_at
FROM matches m
JOIN gamesystems g ON m.gamesystem_id = g.id
WHERE m.id = %s
""", (match_id,))
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."""
if player_id is None:
return "Unbekannter Spieler"
connection = db_connection()
cursor = connection.cursor()
cursor.execute("SELECT display_name, discord_name FROM players WHERE id = %s", (player_id,))
row = cursor.fetchone()
cursor.close()
connection.close()
if row:
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 = db_connection()
cursor = connection.cursor()
cursor.execute("SELECT name FROM gamesystems WHERE id = %s", (sys_id,))
row = cursor.fetchone()
cursor.close()
connection.close()
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 = db_connection()
cursor = connection.cursor()
# MariaDB: DATEDIFF statt julianday()
query = """
SELECT DATEDIFF(NOW(), last_played)
FROM player_game_statistic
WHERE player_id = %s AND gamesystem_id = %s
"""
cursor.execute(query, (player_id, gamesystem_id))
result = cursor.fetchone()
cursor.close()
connection.close()
if result and result[0] is not None:
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 = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT m.id AS match_id, m.score_player1, m.score_player2, m.played_at,
sys.name AS system_name,
p1.display_name AS p1_name
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 = %s AND m.player2_check = 0
"""
cursor.execute(query, (player_id,))
rows = cursor.fetchall()
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 = db_connection()
cursor = connection.cursor()
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 = db_connection()
cursor = connection.cursor()
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 = db_connection()
cursor = connection.cursor()
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."""
connection = db_connection()
cursor = connection.cursor(dictionary=True)
query = """
SELECT m.id AS match_id, m.score_player1, m.score_player2, m.played_at,
sys.name AS system_name,
p2.display_name AS p2_name
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 = %s AND m.player2_check = 0
"""
cursor.execute(query, (player_id,))
rows = cursor.fetchall()
cursor.close()
connection.close()
return rows
def get_match_history_log(player_id):
"""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,
m.player1_id, p1.display_name AS p1_display, p1.discord_name AS p1_discord,
m.score_player1, m.player1_mmr_change,
m.player1_khorne, m.player1_tzeentch, m.player1_slaanesh, m.player1_base_change,
m.player2_id, p2.display_name AS p2_display, p2.discord_name AS p2_discord,
m.score_player2, m.player2_mmr_change,
m.player2_khorne, m.player2_tzeentch, m.player2_slaanesh, m.player2_base_change,
m.elo_factor, m.rust_factor,
m.player2_check, m.match_is_counted
FROM matches m
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 = %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 rows