Impressums Seite. Datenschutzerklärung. Servitor Basic Test funktion.
This commit is contained in:
parent
b707dd96d6
commit
b7f9e7a6bb
15
bot/servitor.py
Normal file
15
bot/servitor.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
import requests
|
||||
|
||||
webhook_url = "https://liga-n8n.au-fab.eu/webhook/21066d30-2757-4d64-9c72-e439ecd70f94"
|
||||
|
||||
discord_tokken = "MTQ3NTg1ODU5OTQwNTQyNDcwMQ.GRo63W.1erAk0janBqS8NlHB6FHEbXM1bolIOPH2Uc4vs"
|
||||
|
||||
def send_message(event, text):
|
||||
data = {
|
||||
event: "Neuer Spieler",
|
||||
text: "mr_teels"
|
||||
}
|
||||
|
||||
response = requests.post(webhook_url, json=data)
|
||||
|
||||
124
gui/imprint.json
Normal file
124
gui/imprint.json
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
{
|
||||
"version": 1,
|
||||
"default_locale": "de",
|
||||
"locales": {
|
||||
"de": {
|
||||
"page": {
|
||||
"title": "Info"
|
||||
},
|
||||
"sections": [
|
||||
{
|
||||
"id": "rules",
|
||||
"order": 10,
|
||||
"title": "Allgemeine Regeln",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "markdown",
|
||||
"content": [
|
||||
"Mit der Anmeldung in der Liga stimmst du folgenden Richtlinien und Regeln zu:\n",
|
||||
"* Freundliches und Respektvolles Verhalten gegenüber anderen Mitspielern.",
|
||||
"* Kein Cheating / absichtliches Falschmelden in die Liga! Fehler können passieren.",
|
||||
"* Es giltet ein Gentleman's Agreement: 'Wir schreiben keine absichtlichen Konterlisten. Schlecht geschriebene Regeln werden nicht zu unserem Vorteil ausgenutzt!'.",
|
||||
"* Wir spielen mit **Intent**. Sprich: Es werden keine Regeln der eigenen Armee dem Gegner verheimlicht um Überraschungen zu produzieren."
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "imprint",
|
||||
"order": 20,
|
||||
"title": "Impressum",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "markdown",
|
||||
"content": "**Verantwortlich:** Daniel Nagel (Privatperson) \n**Adresse:** PRIVAT \n**Kontakt:** admin@danielnagel.at"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "privacy",
|
||||
"order": 30,
|
||||
"title": "Datenschutz",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "markdown",
|
||||
"content": [
|
||||
"Die Daten die für den Betrieb der Liga nötig sind werden auf einem privaten Server in Österreich gespeichert. Das bezieht ein: \n",
|
||||
"* Spieler Namen (Automatisch generiert oder Selbst eingetragen)",
|
||||
"* Spieler ID in form der Discord Nutzer ID.",
|
||||
"* Discord Nutzernamen",
|
||||
"* Discord url Pfad zum Profilfoto",
|
||||
"\nDiese Daten werden **keinem** anderen Dienst, Service, Anbieter oder Drittem zur Verfügung gestellt!",
|
||||
"\nEine Löschung der eigenen Daten kann jederzeit beantragt werden wenn man nicht mehr an der Liga teilnehmen will. \n",
|
||||
"Bestimmte Ereignisse oder Eingaben in die App werden in eine Log Funktion geschrieben (mit Zeitstempel) für die Qualitätssicherung und störungsfreie Funktion der App. Unter anderem: \n",
|
||||
"* Alle Eingaben vom Match Formular. Inkl. Spieler der es eingegeben hat.",
|
||||
"* Wenn ein Match abgelehnt oder gelöscht wird. Inkl. Spieler der es gelöscht/abgelehnt hat.",
|
||||
"* Genaue Aufschlüsselung der MMR Punkte Berechnung pro eingetragenem Match.",
|
||||
"* Neu angelegte Spieler und ihren Discord Namen."
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"en": {
|
||||
"page": {
|
||||
"title": "Info"
|
||||
},
|
||||
"sections": [
|
||||
{
|
||||
"id": "rules",
|
||||
"order": 10,
|
||||
"title": "General Rules",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "markdown",
|
||||
"content": [
|
||||
"By registering for the league you agree to the following guidelines and rules:\n",
|
||||
"* Friendly and respectful behaviour towards all other players.",
|
||||
"* No cheating or intentional misreporting of match results! Honest mistakes can happen.",
|
||||
"* A Gentleman's Agreement applies: 'We do not write intentional counter-lists. Poorly written rules are not exploited for our own advantage!'.",
|
||||
"* We play with **Intent**. This means: no rules of your own army are hidden from your opponent in order to create surprises."
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "imprint",
|
||||
"order": 20,
|
||||
"title": "Imprint",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "markdown",
|
||||
"content": "**Responsible:** Daniel Nagel (Private individual) \n**Address:** PRIVATE \n**Contact:** admin@danielnagel.at"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "privacy",
|
||||
"order": 30,
|
||||
"title": "Privacy Policy",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "markdown",
|
||||
"content": [
|
||||
"Data required to operate the league is stored on a private server located in Austria. This includes: \n",
|
||||
"* Player names (automatically generated or manually entered).",
|
||||
"* Player ID in the form of the Discord user ID.",
|
||||
"* Discord usernames.",
|
||||
"* Discord URL path to the profile picture.",
|
||||
"\nThis data is **not** shared with any other service, provider, or third party.",
|
||||
"\nDeletion of your own data can be requested at any time if you no longer wish to participate in the league. \n",
|
||||
"Certain events or inputs within the app are written to a log function (with timestamp) to ensure quality and stable operation of the app. This includes: \n",
|
||||
"* All inputs from the match form, including the player who submitted it.",
|
||||
"* When a match is rejected or deleted, including the player who rejected/deleted it.",
|
||||
"* Detailed breakdown of the MMR point calculation per submitted match.",
|
||||
"* Newly created players and their Discord names."
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
75
gui/imprint_gui.py
Normal file
75
gui/imprint_gui.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import json
|
||||
from pathlib import Path
|
||||
from nicegui import ui
|
||||
from fastapi import Request
|
||||
from gui import gui_style
|
||||
|
||||
# JSON laden - liegt laut Screenshot direkt in gui/
|
||||
_JSON_PATH = Path(__file__).resolve().parent / 'imprint.json'
|
||||
|
||||
with open(_JSON_PATH, encoding='utf-8') as f:
|
||||
imprint_data: dict = json.load(f)
|
||||
|
||||
# -------------------------------------------------------
|
||||
|
||||
SECTION_TITLES_FALLBACK = {
|
||||
"howto": "Kurzanleitung",
|
||||
"rules": "Allgemeine Regeln",
|
||||
"imprint": "Impressum",
|
||||
"privacy": "Datenschutz",
|
||||
}
|
||||
|
||||
def _get_locale(request: Request) -> str:
|
||||
default = imprint_data.get('default_locale', 'de')
|
||||
lang = request.query_params.get('lang', default)
|
||||
if lang not in imprint_data.get('locales', {}):
|
||||
lang = default
|
||||
return lang
|
||||
|
||||
def _get_locale_options() -> list[str]:
|
||||
return list(imprint_data.get('locales', {}).keys())
|
||||
|
||||
def setup_routes():
|
||||
@ui.page('/info', dark=True)
|
||||
def info_page(request: Request):
|
||||
gui_style.apply_design()
|
||||
|
||||
lang = _get_locale(request)
|
||||
locale_data = imprint_data['locales'][lang]
|
||||
|
||||
page_title = locale_data.get('page', {}).get('title', 'Info')
|
||||
sections = sorted(locale_data.get('sections', []), key=lambda s: s.get('order', 0))
|
||||
|
||||
with ui.row().classes("w-full items-center justify-between"):
|
||||
ui.button(text="Zurück", on_click=lambda: ui.navigate.to('/'))
|
||||
ui.label(page_title).classes("text-xl font-bold")
|
||||
ui.select(
|
||||
options=_get_locale_options(),
|
||||
value=lang,
|
||||
label='Sprache',
|
||||
on_change=lambda e: ui.navigate.to(f'/info?lang={e.value}'),
|
||||
).classes("min-w-[8rem]")
|
||||
|
||||
ui.separator().classes("my-4")
|
||||
|
||||
with ui.column().classes("w-full gap-4"):
|
||||
for section in sections:
|
||||
title = section.get('title', SECTION_TITLES_FALLBACK.get(section.get('id', ''), ''))
|
||||
blocks = section.get('blocks', [])
|
||||
|
||||
with ui.card().classes("w-full"):
|
||||
if title:
|
||||
ui.label(title).classes("text-lg font-semibold mb-2")
|
||||
|
||||
for block in blocks:
|
||||
btype = block.get('type', 'markdown')
|
||||
if btype == 'markdown':
|
||||
raw = block.get('content', '')
|
||||
# Unterstützt sowohl String als auch Array
|
||||
if isinstance(raw, list):
|
||||
content = '\n'.join(raw)
|
||||
else:
|
||||
content = raw
|
||||
ui.markdown(content).classes("prose max-w-none")
|
||||
elif btype == 'divider':
|
||||
ui.separator().classes("my-2")
|
||||
|
|
@ -16,19 +16,17 @@ def setup_routes(admin_discord_id):
|
|||
|
||||
# Fehlt die Discord-ID (altes Cookie) ODER sagt die Datenbank, dass da was nicht stimmt?
|
||||
if not discord_id or not data_api.validate_user_session(db_id, discord_id):
|
||||
# Ausweis ungültig! Wir vernichten das Cookie sofort.
|
||||
app.storage.user.clear()
|
||||
ui.notify("Deine Sitzung ist ungültig oder abgelaufen. Bitte neu einloggen!", color="negative")
|
||||
|
||||
ui.navigate.reload()
|
||||
return
|
||||
# -----------------------------------------
|
||||
|
||||
# ---------------------------
|
||||
# --- NAVIGATIONSLEISTE (HEADER) ---
|
||||
# --- NAVIGATIONSLEISTE (HEADER)
|
||||
# ---------------------------
|
||||
|
||||
with ui.header().classes('items-center justify-between bg-zinc-900 shadow-lg').props("reveal reveal-offset=1"):
|
||||
with ui.header(fixed=False).classes('items-center justify-between bg-zinc-900 shadow-lg'):
|
||||
|
||||
# --- LINKE SEITE ---
|
||||
# Vereinslogo und den Titel in einer eigenen Reihe (Reihe 1)
|
||||
|
|
@ -291,3 +289,5 @@ def setup_routes(admin_discord_id):
|
|||
else:
|
||||
ui.label("Noch keine Spiele absolviert.").classes("text-infotext italic")
|
||||
|
||||
with ui.footer(fixed=False).classes('items-center justify-between bg-zinc-900 shadow-lg'):
|
||||
ui.button(icon="description", on_click=lambda: ui.navigate.to('/info'))
|
||||
|
|
@ -5,10 +5,9 @@ from match_calculations import calc_match
|
|||
from gui.info_text import info_system
|
||||
|
||||
def setup_routes():
|
||||
|
||||
# 1. Die {}-Klammern definieren eine dynamische Variable in der URL
|
||||
@ui.page('/add-match/{system_name}', dark=True)
|
||||
def match_form_page(system_name: str): # <--- WICHTIG: Hier fangen wir das Wort aus der URL auf!
|
||||
def match_form_page(system_name: str): # <-- Hier wird der Name des Spielsystems gefiltert.
|
||||
gui_style.apply_design()
|
||||
|
||||
# --- SICHERHEITS-CHECK ---
|
||||
|
|
|
|||
6
main.py
6
main.py
|
|
@ -3,7 +3,7 @@ from dotenv import load_dotenv
|
|||
from nicegui import ui, app
|
||||
|
||||
from data import database
|
||||
from gui import main_gui, match_gui, discord_login, league_statistic, admin_gui, match_history_gui
|
||||
from gui import main_gui, match_gui, discord_login, league_statistic_gui, admin_gui, match_history_gui, imprint_gui
|
||||
from wood import logger
|
||||
from gui.info_text import info_system
|
||||
|
||||
|
|
@ -30,11 +30,11 @@ logger.setup_log_db()
|
|||
# 3. Seitenrouten aufbauen
|
||||
main_gui.setup_routes(admin_discord_id)
|
||||
discord_login.setup_login_routes()
|
||||
league_statistic.setup_routes()
|
||||
league_statistic_gui.setup_routes()
|
||||
match_gui.setup_routes()
|
||||
admin_gui.setup_routes()
|
||||
match_history_gui.setup_routes()
|
||||
|
||||
imprint_gui.setup_routes()
|
||||
|
||||
# 4. Wir starten die NiceGUI App
|
||||
ui.run(title="Westside Diceghost Liga", port=9000, storage_secret="EIN_super-geheimes_Pa$$wort#!", favicon="gui/pictures/wsdg.png")
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user