From f23dbee2ead7c9c8925a84313ed81814af658342 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Sun, 4 Jan 2026 14:21:52 +0100 Subject: [PATCH 1/8] FEAT: pyproject.toml --- .gitignore | 4 +- README.md | 1037 ++++++++++++----- __init__.py | 1 + docs/index.rst | 1 + docs/plugins/index.rst | 21 + docs/plugins/own_plugins/index.rst | 68 ++ pyproject.toml | 137 +++ {DevTools => src/DevTools}/__init__.py | 0 .../DevTools}/backend/__init__.py | 0 .../DevTools}/backend/config/__init__.py | 0 .../DevTools}/backend/config/links.py | 0 .../DevTools}/backend/config/permission.py | 0 .../DevTools}/backend/database/Stats_db.py | 0 .../DevTools}/backend/database/__init__.py | 0 .../backend/database/autodelete_db.py | 0 .../DevTools}/backend/database/autorole_db.py | 0 .../backend/database/globalchat_db.py | 0 .../DevTools}/backend/database/lang_db.py | 0 .../backend/database/levelsystem_db.py | 0 .../DevTools}/backend/database/logging_db.py | 0 .../DevTools}/backend/database/notes_db.py | 0 .../DevTools}/backend/database/spam_db.py | 0 .../DevTools}/backend/database/vc_db.py | 0 .../DevTools}/backend/database/warn_db.py | 0 .../DevTools}/backend/database/welcome_db.py | 0 {DevTools => src/DevTools}/backend/logging.py | 0 .../DevTools}/backend/utils/__init__.py | 0 {DevTools => src/DevTools}/ui/__init__.py | 0 {DevTools => src/DevTools}/ui/emojis.py | 0 src/__init__.py | 2 + {handler => src/handler}/__init__.py | 0 .../handler}/translation_handler.py | 0 {handler => src/handler}/update_checker.py | 0 src/managerx/cli.py | 45 + 34 files changed, 1003 insertions(+), 313 deletions(-) create mode 100644 __init__.py create mode 100644 docs/plugins/index.rst create mode 100644 docs/plugins/own_plugins/index.rst create mode 100644 pyproject.toml rename {DevTools => src/DevTools}/__init__.py (100%) rename {DevTools => src/DevTools}/backend/__init__.py (100%) rename {DevTools => src/DevTools}/backend/config/__init__.py (100%) rename {DevTools => src/DevTools}/backend/config/links.py (100%) rename {DevTools => src/DevTools}/backend/config/permission.py (100%) rename {DevTools => src/DevTools}/backend/database/Stats_db.py (100%) rename {DevTools => src/DevTools}/backend/database/__init__.py (100%) rename {DevTools => src/DevTools}/backend/database/autodelete_db.py (100%) rename {DevTools => src/DevTools}/backend/database/autorole_db.py (100%) rename {DevTools => src/DevTools}/backend/database/globalchat_db.py (100%) rename {DevTools => src/DevTools}/backend/database/lang_db.py (100%) rename {DevTools => src/DevTools}/backend/database/levelsystem_db.py (100%) rename {DevTools => src/DevTools}/backend/database/logging_db.py (100%) rename {DevTools => src/DevTools}/backend/database/notes_db.py (100%) rename {DevTools => src/DevTools}/backend/database/spam_db.py (100%) rename {DevTools => src/DevTools}/backend/database/vc_db.py (100%) rename {DevTools => src/DevTools}/backend/database/warn_db.py (100%) rename {DevTools => src/DevTools}/backend/database/welcome_db.py (100%) rename {DevTools => src/DevTools}/backend/logging.py (100%) rename {DevTools => src/DevTools}/backend/utils/__init__.py (100%) rename {DevTools => src/DevTools}/ui/__init__.py (100%) rename {DevTools => src/DevTools}/ui/emojis.py (100%) create mode 100644 src/__init__.py rename {handler => src/handler}/__init__.py (100%) rename {handler => src/handler}/translation_handler.py (100%) rename {handler => src/handler}/update_checker.py (100%) create mode 100644 src/managerx/cli.py diff --git a/.gitignore b/.gitignore index cd03cab..38bdde6 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,6 @@ docs/_build/html/_sources/ furo.js.LICENSE.txt fontawesome.js.LICENSE.txt .map -docs/_build/* \ No newline at end of file +docs/_build/* +ManagerX.egg-info/ +dist/ \ No newline at end of file diff --git a/README.md b/README.md index 3bf5801..e952827 100644 --- a/README.md +++ b/README.md @@ -2,46 +2,103 @@ ![ManagerX Banner](assets/img/ManagerX_banner.png) -

๐Ÿค– ManagerX Discord Bot

+# ๐Ÿค– ManagerX Discord Bot -

Der ultimative All-in-One Discord Bot fรผr deine Community

+### *Der ultimative All-in-One Bot fรผr professionelles Community Management*
- +

- Version - Next Release - Last Commit - License + + Version + + + Next Release + + + Last Commit + + + License +

+

Python Pycord + SQLite Issues Stars + Forks


```ascii -โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— -โ•‘ โ•‘ -โ•‘ ๐Ÿค– Der professionelle Discord Bot fรผr deine Community ๐Ÿš€ โ•‘ -โ•‘ โ•‘ -โ•‘ Moderation โ€ข Leveling โ€ข Welcome โ€ข TempVC โ€ข Globalchat โ•‘ -โ•‘ โ•‘ -โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— +โ•‘ โ•‘ +โ•‘ ๐Ÿค– Professionelles Discord Bot Framework fรผr Communities ๐Ÿš€ โ•‘ +โ•‘ โ•‘ +โ•‘ Moderation โ€ข Leveling โ€ข Welcome โ€ข TempVC โ€ข Globalchat โ€ข Stats โ•‘ +โ•‘ โ•‘ +โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ```
-**Entwickelt von** [**OPPRO.NET Development**](https://github.com/Oppro-net-Development) **|** **ยฉ OPPRO.NET Networkโ„ข** +**Entwickelt von** [**OPPRO.NET Development**](https://github.com/Oppro-net-Development) **|** โšก **Powered by OPPRO.NET Networkโ„ข**
-[๐Ÿ“ฅ Installation](#-installation) โ€ข [โœจ Features](#-features) โ€ข [๐Ÿ“– Docs](https://docs.oppro-network.de) โ€ข [๐Ÿ’ฌ Support](#-support--community) +--- + +## ๐Ÿ“ฆ Quick Install + + + + + + +
+ +### ๐ŸŽฏ Fรผr End-User + +```bash +# Bot direkt nutzen +pip install ManagerX +``` + +**Mit Dokumentation:** +```bash +pip install ManagerX[docs] +``` + + + +### ๐Ÿ‘จโ€๐Ÿ’ป Fรผr Entwickler + +```bash +# Development Setup +pip install ManagerX[dev] +``` + +**Vollstรคndige Installation:** +```bash +pip install ManagerX[all] +``` + +
+ +
+ +

+ ๐Ÿ“ฅ Detaillierte Installation โ€ข + โœจ Features โ€ข + ๐Ÿ“– Dokumentation โ€ข + ๐Ÿ’ฌ Support +

@@ -49,45 +106,85 @@ --- +
+ ## ๐ŸŽฏ Was ist ManagerX? +
+ - - @@ -98,89 +195,175 @@ Active Modules: --- +
+ ## โœจ Feature-รœbersicht +*Entdecke die leistungsstarken Module von ManagerX* + +
+ +
+
+ + +**ManagerX** ist ein hochmoderner, leistungsstarker Discord-Bot, der speziell fรผr professionelles Community-Management entwickelt wurde. Mit modernster Architektur und einer Vielzahl an Features bietet ManagerX alles, was anspruchsvolle Discord-Server benรถtigen. -**ManagerX** ist ein hochmoderner, leistungsstarker Discord-Bot, der speziell fรผr professionelles Community-Management entwickelt wurde. Mit einer Vielzahl an Features von automatisierter Moderation รผber interaktive Levelsysteme bis hin zu globaler Kommunikation bietet ManagerX alles, was moderne Discord-Server benรถtigen. +
-### ๐ŸŒŸ Warum ManagerX wรคhlen? +### ๐ŸŒŸ Warum ManagerX? -- โšก **Performance** โ€“ Optimierte Datenbank-Architektur mit SQLite -- ๐Ÿ›ก๏ธ **Sicherheit** โ€“ Integriertes Anti-Spam und umfassende Moderationstools -- ๐ŸŽจ **Flexibilitรคt** โ€“ Vollstรคndig konfigurierbare Module fรผr jeden Server -- ๐ŸŒ **Konnektivitรคt** โ€“ Globalchat verbindet Communities weltweit -- ๐Ÿ“ˆ **Aktive Entwicklung** โ€“ RegelmรครŸige Updates und neue Features -- ๐Ÿ†“ **Open Source** โ€“ Transparent und community-driven + + + + + + + + + + + + + + + + + + + + + + + + + +
โšกBlazing Fast
Optimierte SQLite-Architektur fรผr maximale Performance
๐Ÿ›ก๏ธEnterprise Security
Anti-Spam, Moderation-Logs und umfassende Sicherheitsfeatures
๐ŸŽจHochgradig Anpassbar
Jedes Modul vollstรคndig konfigurierbar fรผr deine Bedรผrfnisse
๐ŸŒGlobal Connected
Verbinde deine Community mit Servern weltweit via Globalchat
๐Ÿ“ˆAktive Entwicklung
RegelmรครŸige Updates mit neuen Features und Verbesserungen
๐Ÿ†“100% Open Source
Transparent, community-driven und kostenlos verfรผgbar
+ ```yaml -Quick Stats: - Status: Production Ready - Version: 2.0.0 - Python: 3.10+ - Framework: py-cord + ezcord - Database: SQLite3 - Hosting: Linux Compatible - License: GPL-3.0 - -Active Modules: - - Moderation System - - Level & XP System - - Welcome System - - Temporary Voice Channels - - Global Chat - - Weather Integration - - Wikipedia Search - - Stats & Analytics +โš™๏ธ Technical Specifications +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” +Status: Production Ready โœ“ +Current: v2.0.0 +Next Release: v2.1.0 (Q1 2025) + +๐Ÿ”ง Technology Stack +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” +Language: Python 3.10+ +Framework: py-cord + ezcord +Database: SQLite3 +API: Discord API v10 +Architecture: Modular Cogs System + +๐ŸŒ Deployment +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” +Platforms: Linux, Windows, macOS +Hosting: Cloud-Ready +Requirements: 512MB RAM (1GB+ rec.) +Uptime: 99.9%+ Verfรผgbarkeit + +๐Ÿ“ฆ Active Modules +โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” +โœ“ Advanced Moderation System +โœ“ Dynamic Leveling & XP Engine +โœ“ Smart Welcome Automation +โœ“ Temporary Voice Channels +โœ“ Global Cross-Server Chat +โœ“ Real-Time Weather Data +โœ“ Wikipedia Integration +โœ“ Comprehensive Statistics +โœ“ Custom Command Framework ```
@@ -190,228 +373,426 @@ Active Modules: --- -## ๐Ÿš€ Installation +
+ +## ๐Ÿš€ Installation & Setup + +*Starte ManagerX in wenigen Minuten* + +
+ +
### ๐Ÿ“‹ Systemanforderungen +
### ๐Ÿ›ก๏ธ Moderation & Sicherheit -**Advanced Moderation Tools** -- โœ… Ban, Kick, Mute, Warn Befehle -- โœ… Intelligentes Anti-Spam System -- โœ… Automatisches Warning-Management -- โœ… Detaillierte Moderation-Logs -- โœ… Temporรคre Strafen (Timeout) -- โœ… Reason-Tracking fรผr alle Actions - -**Konfigurierbare Schwellenwerte** -- Nachrichten pro Zeiteinheit -- Duplicate Message Detection -- Mention Spam Protection -- Link Spam Filter -- Custom Regex Patterns +
+ +**๐Ÿ”’ Advanced Moderation Toolkit** + +
+ +```yaml +Moderation Commands: + /ban - Permanenter Server-Ausschluss + /kick - User vom Server entfernen + /mute - Temporรคres Timeout verhรคngen + /warn - Verwarnungen aussprechen + /timeout - Zeitlich begrenzte Stummschaltung + /purge - Massen-Nachrichtenlรถschung + +Anti-Spam Engine: + โœ“ Intelligente Spam-Erkennung + โœ“ Duplicate Message Detection + โœ“ Mention Spam Protection + โœ“ Link & URL Filter + โœ“ Custom Regex Patterns + โœ“ Configurable Thresholds + +Moderation Logs: + โœ“ Vollstรคndige Action History + โœ“ Reason Tracking + โœ“ Moderator Attribution + โœ“ Automatic Evidence Collection + โœ“ Appeal System Ready +```
### ๐Ÿ“Š Community Engagement -**Levelsystem** -- โœ… Vollstรคndig anpassbares XP-System -- โœ… Rollenbelohnungen fรผr Level-Ups -- โœ… Server & Global Leaderboards -- โœ… Individuelle Level-Up Notifications -- โœ… XP-Multiplikatoren & Boosts -- โœ… Voice-Channel XP-Tracking - -**Welcome-System** -- โœ… Automatische BegrรผรŸungsnachrichten -- โœ… Custom Embed Designs -- โœ… Regel- & Informationsnachrichten -- โœ… Automatische Autorollen -- โœ… User-Counter Integration +
+ +**๐ŸŽฎ Gamification & Engagement** + +
+ +```yaml +Levelsystem Features: + XP System: + - Vollstรคndig anpassbare XP-Raten + - Text & Voice Channel XP + - XP-Multiplier & Boosts + - Daily/Weekly Bonuses + + Rewards: + - Automatische Rollenbelohnungen + - Custom Level-Up Messages + - Achievement System + - Milestone Rewards + + Leaderboards: + - Server Top Rankings + - Global Leaderboards + - Category-Specific Rankings + - Historical Statistics + +Welcome System: + โœ“ Benutzerdefinierte Embed-Designs + โœ“ Auto-Role Assignment + โœ“ Regel- & Info-Nachrichten + โœ“ User Counter Integration + โœ“ Custom Welcome Images + โœ“ Join/Leave Logging +```
-### ๐ŸŒ Social & Information +### ๐ŸŒ Social & Communication -**Globalchat System** -- โœ… Echtzeit-Chat mit anderen Servern -- โœ… Moderierte und sichere Kommunikation -- โœ… Blacklist-System fรผr Content-Filterung -- โœ… Server-รผbergreifende Reputation -- โœ… Report & Block Funktionen -- โœ… Admin-Kontrolle & Moderation +
-**Wikipedia Integration** -- โœ… Direkte Wikipedia-Suche -- โœ… Formatierte Artikel-Previews -- โœ… Mehrsprachige Unterstรผtzung -- โœ… Schnelle Informationsabfrage +**๐Ÿ’ฌ Cross-Server Communication** -**Weather System** -- โœ… Live-Wetterinformationen -- โœ… Detaillierte Vorhersagen -- โœ… Temperatur, Luftfeuchtigkeit, Wind -- โœ… Automatische Standorterkennung +
+ +```yaml +Globalchat System: + Core Features: + - Echtzeit Cross-Server Chat + - Moderierte Kommunikation + - Server-รผbergreifende Community + - Report & Block Funktionen + - User Reputation System + + Safety Features: + โœ“ Content-Filterung + โœ“ Blacklist System + โœ“ Admin-Kontrolle + โœ“ Spam Prevention + โœ“ Moderation Queue + โœ“ Appeal Process + +Information Tools: + Wikipedia Integration: + - Direkte Artikelsuche + - Formatierte Previews + - Multi-Language Support + - Related Articles + - Quick Summaries + + Weather System: + - Live-Wetterdaten + - 5-Tage Vorhersage + - Detaillierte Metriken + - Location Auto-Detection + - Weather Alerts +```
### ๐ŸŽฎ Interaktive Features -**Temporary Voice Channels** -- โœ… User erstellen eigene Voice-Channel -- โœ… Individuelle Kanalverwaltung -- โœ… User-Limit & Permissions -- โœ… Auto-Delete bei Inaktivitรคt -- โœ… Custom Namen & Kategorien +
+ +**๐ŸŽ™๏ธ Dynamic Voice & Analytics** + +
-**Stats & Analytics** -- โœ… Server-Statistiken in Echtzeit -- โœ… User-Activity Tracking -- โœ… Command-Usage Analytics -- โœ… Performance Metriken +```yaml +Temporary Voice Channels: + User Control: + โœ“ Eigene Voice-Channel erstellen + โœ“ Custom Namen & Beschreibung + โœ“ User-Limit Management + โœ“ Permission Control + โœ“ Channel Transfer + + Automation: + - Auto-Delete bei Inaktivitรคt + - Category Organization + - Template System + - VIP Channel Options + +Stats & Analytics: + Real-Time Metrics: + - Server Activity Tracking + - User Engagement Stats + - Command Usage Analytics + - Voice Channel Statistics + - Growth Metrics + + Reports: + โœ“ Daily/Weekly Summaries + โœ“ Performance Dashboards + โœ“ Member Insights + โœ“ Trend Analysis +```
+ + + + +
+ +**Minimum Requirements** + +```yaml +Operating System: + - Linux (Ubuntu 20.04+) + - Windows 10/11 + - macOS 11+ + +Software: + - Python 3.10 oder hรถher + - pip (Python Package Manager) + - Git 2.0+ + +Resources: + - RAM: 512 MB minimum + - Storage: 200 MB freier Speicher + - Network: Stabile Internetverbindung +``` + + + +**Empfohlene Konfiguration** + ```yaml -Minimum Requirements: - OS: Linux / Windows / macOS - Python: 3.10 oder hรถher - RAM: 512 MB (empfohlen: 1 GB+) - Storage: 200 MB freier Speicher - Network: Stabile Internetverbindung - -Benรถtigte Services: - Discord Bot Token: discord.com/developers/applications - Database: SQLite3 (vorinstalliert) +Production Environment: + - Linux Server (Ubuntu 22.04 LTS) + - Python 3.11+ + - 1 GB+ RAM + - SSD Storage + - 24/7 Uptime Hosting + +Optional Services: + - Discord Bot Token (Required) + - Weather API Key (Optional) + - Custom Domain (Optional) + - SSL Certificate (Optional) ``` +
+
-### โšก Quick Start Guide +### โšก Installation Guide + +
+๐Ÿง Linux / macOS Installation (Click to expand) + +
-**Linux / macOS:** ```bash -# 1. Repository klonen +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 1: Repository klonen +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ git clone https://github.com/Oppro-net-Development/ManagerX.git cd ManagerX -# 2. Python Virtual Environment erstellen (empfohlen) +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 2: Virtual Environment erstellen (empfohlen) +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ python3 -m venv venv source venv/bin/activate -# 3. Dependencies installieren +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 3: Dependencies installieren +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +pip install --upgrade pip pip install -r requirements.txt -# 4. Konfiguration erstellen +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 4: Konfiguration erstellen +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ cp .env.example .env -nano .env # TOKEN und andere Einstellungen anpassen +nano .env # Passe TOKEN und andere Einstellungen an + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 5: Erste Datenbankinitialisierung +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +python -c "from utils.database import init_db; init_db()" -# 5. Bot starten +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 6: Bot starten +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ python main.py + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Optional: Systemd Service erstellen (fรผr 24/7 Betrieb) +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +sudo nano /etc/systemd/system/managerx.service +# Fรผge Service-Konfiguration hinzu (siehe Dokumentation) +sudo systemctl enable managerx +sudo systemctl start managerx ``` -**Windows:** +
+ +
+๐ŸชŸ Windows Installation (Click to expand) + +
+ ```powershell -# 1. Repository klonen +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 1: Repository klonen +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ git clone https://github.com/Oppro-net-Development/ManagerX.git cd ManagerX -# 2. Virtual Environment erstellen +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 2: Virtual Environment erstellen +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ python -m venv venv venv\Scripts\activate -# 3. Dependencies installieren +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 3: Dependencies installieren +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +python -m pip install --upgrade pip pip install -r req.txt -# 4. Konfiguration +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 4: Konfiguration erstellen +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ copy .env.example .env -notepad .env # TOKEN anpassen +notepad .env # TOKEN und Einstellungen anpassen + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 5: Datenbank initialisieren +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +python -c "from utils.database import init_db; init_db()" -# 5. Bot starten +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Step 6: Bot starten +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ python main.py + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Optional: Als Windows Service einrichten +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# Siehe Dokumentation fรผr NSSM Setup ``` +
+
-### ๐Ÿ”ง Konfiguration (.env) +### ๐Ÿ”ง Konfiguration + + + + + + +
+ +**Environment Variables (.env)** ```bash +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• # Discord Bot Configuration +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• DISCORD_TOKEN=your_bot_token_here -WEATHER_API=your_Weather_API_Key DISCORD_CLIENT_ID=your_client_id DISCORD_CLIENT_SECRET=your_client_secret -DISCORD_REDIRECT_URI=your_redirect_uri +DISCORD_REDIRECT_URI=http://localhost:8080/callback + +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# Optional API Keys +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +WEATHER_API=your_openweathermap_api_key + +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# Bot Settings +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +BOT_PREFIX=! +DEBUG_MODE=false +LOG_LEVEL=INFO + +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# Database Configuration +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +DATABASE_PATH=./data/managerx.db +BACKUP_ENABLED=true +BACKUP_INTERVAL=24h ``` -
+
---- +**๐Ÿ“ Token erstellen** -## ๐Ÿ“‹ Version History & Changelog +1. Besuche [Discord Developer Portal](https://discord.com/developers/applications) +2. Klicke auf "New Application" +3. Gehe zu "Bot" โ†’ "Add Bot" +4. Kopiere den Token +5. Fรผge ihn in `.env` ein -
+**๐Ÿ”‘ Wichtige Berechtigungen** -| Version | Status | Highlights | -|---------|--------|------------| -| **v2.1.0** | ๐Ÿ”œ In Development | Bug Fixes, Performance Improvements | -| **v2.0.0** | โœ… Current | Refactored Codebase, Enhanced Stats, Globalchat v2 | -| **v1.7.1** | ๐Ÿ“ฆ Stable | Enhanced Features, Bug Fixes | -| **v1.7.0** | ๐Ÿ“ฆ Archived | TempVC System Implementation | -| **v1.6.0** | ๐Ÿ“ฆ Archived | Levelsystem Launch | -| **v1.5.0** | ๐Ÿ“ฆ Archived | Welcome System | +```yaml +Required Intents: + โœ“ Server Members Intent + โœ“ Message Content Intent + โœ“ Presence Intent + +Bot Permissions: + โœ“ Manage Roles + โœ“ Manage Channels + โœ“ Kick Members + โœ“ Ban Members + โœ“ Send Messages + โœ“ Embed Links + โœ“ Attach Files + โœ“ Manage Messages + โœ“ Read Message History +``` -[๐Ÿ“– View Full Changelog โ†’](CHANGELOG.md) +**๐ŸŒฆ๏ธ Weather API** -
+Kostenloser API-Key: [OpenWeatherMap](https://openweathermap.org/api) + +

--- -## ๐Ÿค Contributing & Development +
-### ๐Ÿ’ป Werde Teil des Projekts! +## ๐Ÿ“‹ Version History & Roadmap -Wir freuen uns รผber Contributions von der Community. Hier sind unsere Commit-Konventionen: +*Entwicklungsgeschichte und zukรผnftige Features* + +
+ +
+ +### ๐Ÿ”„ Release Timeline + +```mermaid +gantt + title ManagerX Development Timeline + dateFormat YYYY-MM-DD + section Releases + v1.0.0 Initial Release :done, 2023-01-01, 30d + v1.5.0 Welcome System :done, 2023-05-01, 45d + v1.6.0 Levelsystem :done, 2023-08-01, 60d + v1.7.0 TempVC System :done, 2023-11-01, 45d + v2.0.0 Major Refactor :done, 2024-06-01, 90d + v2.1.0 Enhancements :active, 2025-01-01, 60d + v2.5.0 Advanced Features :2025-04-01, 90d +``` + +
- - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + + - - - + + + +
PrรคfixBeschreibungBeispielVersionStatusDatumKey Features
FEATURE:Neue Funktion hinzugefรผgtFEATURE: Add weather commandv2.1.0๐Ÿ”œ In DevQ1 2025 +โ€ข Performance Optimierungen
+โ€ข Bug Fixes & Stability
+โ€ข Enhanced Error Handling
+โ€ข UI/UX Improvements +
UPDATE:Bestehende Funktion aktualisiertUPDATE: Improve levelsystem performancev2.0.0โœ… Current2024-12 +โ€ข Komplettes Code Refactoring
+โ€ข Globalchat v2 Launch
+โ€ข Enhanced Statistics Module
+โ€ข Improved Database Architecture +
BUGFIX:Normaler Fehler behobenBUGFIX: Fix welcome message formattingv1.7.1๐Ÿ“ฆ Stable2024-08 +โ€ข Feature Enhancements
+โ€ข Critical Bug Fixes
+โ€ข Security Updates +
HOTFIX:Kritischer Fehler behobenHOTFIX: Resolve database connection issuesv1.7.0๐Ÿ“ฆ Archived2024-05 +โ€ข TempVC System Implementation
+โ€ข Dynamic Voice Channel Management
+โ€ข User Control Features +
DOCS:Dokumentation geรคndertDOCS: Update installation guidev1.6.0๐Ÿ“ฆ Archived2024-02 +โ€ข Advanced Levelsystem
+โ€ข XP & Rewards Engine
+โ€ข Leaderboard System +
DELETE:Datei oder Feature entferntDELETE: Remove deprecated commandv1.5.0๐Ÿ“ฆ Archived2023-11 +โ€ข Welcome System Launch
+โ€ข Auto-Role Assignment
+โ€ข Custom Embeds +

-### ๐Ÿ”ง Development Workflow - -```bash -# 1. Repository forken & klonen -git clone https://github.com/YOUR_USERNAME/ManagerX.git -cd ManagerX +### ๐Ÿ—บ๏ธ Roadmap -# 2. Development Branch erstellen -git checkout -b feature/amazing-feature - -# 3. ร„nderungen vornehmen und testen -python main.py # Testen - -# 4. Committen mit Konvention -git commit -m "FEATURE: Add amazing new feature" + + + + + + +
-# 5. Pushen -git push origin feature/amazing-feature +**๐ŸŽฏ v2.1.0 - Q1 2025** -# 6. Pull Request erstellen auf GitHub +```yaml +Focus: Stability & Polish + +Features: + - Performance Tuning + - Memory Optimization + - Enhanced Logging + - Bug Fixes + +Improvements: + - Error Recovery + - Database Indexing + - Command Response Time + - Resource Management ``` -
- ---- - -## ๐Ÿ’ฌ Support & Community - -
+
-### ๐Ÿ†˜ Brauchst du Hilfe? +**๐Ÿš€ v2.2.0 - Q2 2025** -
+```yaml +Focus: New Features + +Planned Features: + - Ticket System + - Advanced Polls + - Music Module + - Custom Commands 2.0 + +Enhancements: + - AI Integration + - Multi-Language Support + - Enhanced Analytics + - API Webhooks +``` -[![Discord Server](https://img.shields.io/badge/Discord-Join_Community-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/tmz673WAnV) -[![Documentation](https://img.shields.io/badge/Docs-Read_More-00D9FF?style=for-the-badge&logo=gitbook&logoColor=white)](https://docs.oppro-network.de) -[![GitHub Issues](https://img.shields.io/badge/Issues-Report_Bug-EA4335?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Oppro-net-Development/ManagerX/issues) -[![Email](https://img.shields.io/badge/Email-Contact_Us-00D26A?style=for-the-badge&logo=gmail&logoColor=white)](mailto:development@oppro-network.de) +
-
+**๐Ÿ’ซ v2.3.0 - Q4 2025** -| Support-Kanal | Beschreibung | Antwortzeit | -|---------------|--------------|-------------| -| ๐Ÿ’ฌ **Discord** | Community Support & Diskussion | < 1 Stunde | -| ๐Ÿ“– **Docs** | Umfassende Anleitungen | Sofort | -| ๐Ÿ› **GitHub Issues** | Bug Reports & Feature Requests | < 24 Stunden | -| ๐Ÿ“ง **E-Mail** | Direkter Support | < 48 Stunden | +```yaml +Focus: Major Upgrade + +Revolutionary Features: + - Web Dashboard + - Mobile App Support + - Plugin System + - Advanced AI Features + +Architecture: + - Microservices + - Cloud-Native + - Horizontal Scaling + - GraphQL API +``` - +

---- - -## ๐Ÿข Empfohlener Hosting Partner -
-### ๐Ÿš€ Professionelles Hosting fรผr ManagerX - -
- - - DeinServerHost - Premium Hosting - - -

- -**Zuverlรคssiges, deutsches Hosting fรผr Discord Bots** - -โœ… **24/7 Support** โ€ข โœ… **99.9% Uptime** โ€ข โœ… **DDoS Protection** โ€ข โœ… **SSD Storage** - -
- -[![Jetzt buchen](https://img.shields.io/badge/Hosting-Jetzt_buchen-00D9FF?style=for-the-badge&logo=server&logoColor=white)](https://deinserverhost.de/store/aff.php?aff=5609) +[๐Ÿ“– **Vollstรคndiges Changelog anzeigen** โ†’](CHANGELOG.md)
@@ -419,119 +800,151 @@ git push origin feature/amazing-feature --- -## ๐Ÿ“Š GitHub Statistics -
-![Contributors](https://img.shields.io/github/contributors/Oppro-net-Development/ManagerX?style=for-the-badge&logo=github&logoColor=white&color=5865F2) -![Forks](https://img.shields.io/github/forks/Oppro-net-Development/ManagerX?style=for-the-badge&logo=github&logoColor=white&color=00D26A) -![Stars](https://img.shields.io/github/stars/Oppro-net-Development/ManagerX?style=for-the-badge&logo=github&logoColor=white&color=FFD700) -![Issues](https://img.shields.io/github/issues/Oppro-net-Development/ManagerX?style=for-the-badge&logo=github&logoColor=white&color=EA4335) -![Last Commit](https://img.shields.io/github/last-commit/Oppro-net-Development/ManagerX?style=for-the-badge&logo=github&logoColor=white) - -
- -
- ---- - -## ๐Ÿ“„ Lizenz & Urheberrecht - -
- -``` -โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— -โ•‘ โ•‘ -โ•‘ This project is licensed under the GNU GPL-3.0 License โ•‘ -โ•‘ โ•‘ -โ•‘ Copyright ยฉ 2024 OPPRO.NET Development โ•‘ -โ•‘ Copyright ยฉ 2025-present OPPRO.NET Networkโ„ข โ•‘ -โ•‘ โ•‘ -โ•‘ All rights reserved. โ•‘ -โ•‘ โ•‘ -โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• -``` - -
- -[![License](https://img.shields.io/badge/License-GPL--3.0-blue?style=for-the-badge&logo=opensourceinitiative&logoColor=white)](LICENSE) +## ๐Ÿค Contributing & Development -**๐Ÿ“– Vollstรคndige Lizenz:** [LICENSE Datei anzeigen โ†’](LICENSE) +*Werde Teil unseres Open-Source Projekts!*

---- - -## ๐Ÿ™ Credits & Danksagungen +### ๐Ÿ’ก Wie kann ich beitragen? -
- -| Team | Community | Frameworks | Hosting | -|:----:|:---------:|:----------:|:-------:| -| **OPPRO.NET
Development** | **Contributors
& Beta Testers** | **py-cord
ezcord** | **DeinServerHost
Premium Partner** | - -
+ + + + + + + +
-**Besonderer Dank an alle, die dieses Projekt unterstรผtzen!** +**๐Ÿ› Bug Reports** - +Fehler gefunden?
+[Issue erstellen โ†’](https://github.com/Oppro-net-Development/ManagerX/issues/new?template=bug_report.md) -
+
---- +**โœจ Feature Requests** -## ๐Ÿ”— Wichtige Links +Idee fรผr ein Feature?
+[Feature vorschlagen โ†’](https://github.com/Oppro-net-Development/ManagerX/issues/new?template=feature_request.md) -
+
-| Link | Beschreibung | -|------|--------------| -| ๐ŸŒ [**Website**](https://development.oppro-network.de/ManagerX/) | Offizielle ManagerX Website | -| ๐Ÿ“š [**Dokumentation**](https://docs.oppro-network.de/en/latest/) | Vollstรคndige Bot-Dokumentation | -| ๐Ÿ  [**OPPRO.NET**](https://oppro-network.de) | OPPRO.NET Networkโ„ข Hauptseite | -| ๐Ÿ’ฌ [**Discord**](https://discord.gg/tmz673WAnV) | Community & Support Server | -| ๐Ÿ“ง [**E-Mail**](mailto:development@oppro-network.de) | Direkter Kontakt | +**๐Ÿ’ป Code Beitrรคge** - +Code beisteuern?
+[Pull Request โ†’](https://github.com/Oppro-net-Development/ManagerX/pulls) -
+
---- +**๐Ÿ“– Dokumentation** -
+Docs verbessern?
+[Docs bearbeiten โ†’](https://github.com/Oppro-net-Development/ManagerX-Docs) -### โญ Hat dir ManagerX geholfen? +

-**Gib uns einen Stern auf GitHub und teile das Projekt!** +### ๐Ÿ“ Commit-Konventionen -
+Wir verwenden standardisierte Commit-Prefixes fรผr bessere Nachvollziehbarkeit: -[![GitHub Stars](https://img.shields.io/github/stars/Oppro-net-Development/ManagerX?style=social)](https://github.com/Oppro-net-Development/ManagerX) -[![GitHub Forks](https://img.shields.io/github/forks/Oppro-net-Development/ManagerX?style=social)](https://github.com/Oppro-net-Development/ManagerX/fork) -[![GitHub Watchers](https://img.shields.io/github/watchers/Oppro-net-Development/ManagerX?style=social)](https://github.com/Oppro-net-Development/ManagerX) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PrรคfixVerwendungBeispiel
โœจ FEATURE:Neue Funktion hinzugefรผgtโœจ FEATURE: Add weather command integration
๐Ÿ”„ UPDATE:Bestehende Funktion verbessert๐Ÿ”„ UPDATE: Improve levelsystem performance by 40%
๐Ÿ› BUGFIX:Bug behoben (normal)๐Ÿ› BUGFIX: Fix welcome message formatting issue
๐Ÿš‘ HOTFIX:Kritischer Bug behoben๐Ÿš‘ HOTFIX: Resolve critical database connection error
๐Ÿ“š DOCS:Dokumentation aktualisiert๐Ÿ“š DOCS: Update installation guide with troubleshooting
๐Ÿ—‘๏ธ DELETE:Code/Feature entfernt๐Ÿ—‘๏ธ DELETE: Remove deprecated legacy commands
๐ŸŽจ STYLE:Code-Style ร„nderungen๐ŸŽจ STYLE: Refactor code to match PEP 8 standards
โ™ป๏ธ REFACTOR:Code-Umstrukturierungโ™ป๏ธ REFACTOR: Restructure database module architecture
โšก PERF:Performance-Verbesserungโšก PERF: Optimize query execution time
๐Ÿงช TEST:Tests hinzugefรผgt/geรคndert๐Ÿงช TEST: Add unit tests for moderation module
-

+
-``` -โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— -โ•‘ โ•‘ -โ•‘ Made with โค๏ธ in Germany โ•‘ -โ•‘ by the OPPRO.NET Development Team โ•‘ -โ•‘ โ•‘ -โ•‘ Bringing communities together, one bot at a time โ•‘ -โ•‘ โ•‘ -โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• -``` +### ๐Ÿ”ง Development Workflow -
+```bash +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# 1. Repository forken & klonen +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +git clone https://github.com/YOUR_USERNAME/ManagerX.git +cd ManagerX -![Made with Love](https://img.shields.io/badge/Made%20with-โค๏ธ-red?style=for-the-badge) -![Powered by Coffee](https://img.shields.io/badge/Powered%20by-โ˜•-brown?style=for-the-badge) -![Made in Germany](https://img.shields.io/badge/Made%20in-๐Ÿ‡ฉ๐Ÿ‡ช%20Germany-black?style=for-the-badge) -![Built with Python](https://img.shields.io/badge/Built%20with-๐Ÿ%20Python-blue?style=for-the-badge) +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# 2. Development Branch erstellen +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +git checkout -b feature/amazing-feature +# Oder fรผr Bugfixes: +git checkout -b bugfix/fix-critical-issue -
\ No newline at end of file +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# 3. Development Environment aufsetzen +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +python -m venv venv +source venv/bin/activate # Windows: venv\Scripts\activate +pip install -r requirements-dev.txt + +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# 4. ร„nderungen vornehmen und testen +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# Code schreiben... +python main.py # Bot testen +pytest tests/ # Unit Tests ausfรผhren + +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# 5. Code Style prรผfen +# \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..3c64cf3 --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +from .src import * \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 52a19c6..4770f20 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -114,6 +114,7 @@ We welcome contributions from the community! Whether it's bug reports, feature r User Guide Developer Guide Changelog & Releases + Plugins --- diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst new file mode 100644 index 0000000..ee7d819 --- /dev/null +++ b/docs/plugins/index.rst @@ -0,0 +1,21 @@ +Available Plugins for ManagerX +================================ + +No Plugins Available ๐Ÿ˜ฅ +------------------------ + +At the moment, there are no plugins available for ManagerX. Please check back later for updates! +We are actively working on developing plugins to enhance the functionality of ManagerX. Stay tuned for future releases! + +Code your Own Plugins +---------------------- + +If you're interested in creating your own plugins for ManagerX, please refer to our Developer Guide for detailed instructions and best practices. +Read the `own Plugins Guide `_ to get started on building custom plugins tailored to your needs! + +.. toctree:: + :maxdepth: 2 + :caption: Plugin Documentation: + :hidden: + + Own Plugins Guide \ No newline at end of file diff --git a/docs/plugins/own_plugins/index.rst b/docs/plugins/own_plugins/index.rst new file mode 100644 index 0000000..5671ce6 --- /dev/null +++ b/docs/plugins/own_plugins/index.rst @@ -0,0 +1,68 @@ +Developing Your Own Plugins for ManagerX +======================================== + +Extend ManagerX with your own custom functionality! This guide helps you create plugins, +whether as local Cogs in the bot or as standalone PyPi projects, from setup to deployment. + +Getting Started +--------------- + +Before you begin, make sure you have: + +- Python 3.8+ installed +- A basic understanding of Python +- Familiarity with the ManagerX bot architecture + +1. Set Up Your Development Environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Install all dependencies required by ManagerX. +- Clone the ManagerX repository from GitHub to get the latest codebase. +- For PyPi plugins, ensure you have `setuptools` and `wheel` installed to package your plugin. + +2. Understand the Plugin Structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- **Local Cogs**: look inside the `cogs` or `plugins` directory. Each plugin is typically a single Python file or module. +- **PyPi Plugins**: structure your project like a standard Python package with a `setup.py` or `pyproject.toml` file. +- Review existing plugins to understand naming conventions, commands, and event listeners. + +3. Create Your Plugin +~~~~~~~~~~~~~~~~~~~~ + +**Local Cog Example:** + +.. code-block:: python + + from discord.ext import commands + + class MyPlugin(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.slash_command(name="hello", description="Say hello!") + async def hello(self, ctx): + await ctx.respond(f"Hello, {ctx.author.mention}!") + + def setup(bot): + bot.add_cog(MyPlugin(bot)) + +**PyPi Plugin Tips:** + +- Wrap your plugin in a package structure (`myplugin/`) +- Include a `setup.py` or `pyproject.toml` for distribution +- Make sure your Cog is loaded automatically when installed + +4. Register Your Plugin +~~~~~~~~~~~~~~~~~~~~~~ + +- **Local Cogs**: add the Cog in your botโ€™s `setup` function or main script. +- **PyPi Plugins**: once installed via `pip`, ensure ManagerX can discover and load your plugin dynamically. + +Best Practices +--------------- + +- Keep your plugin modular, documented, and maintainable. +- Use ManagerXโ€™s `SimpleColoredLogs` for logging plugin events and errors. +- Follow existing naming and coding conventions for compatibility. +- For PyPi plugins, include versioning, dependencies, and metadata in your package. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1797abc --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,137 @@ +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "ManagerX" +version = "2.0.0" +description = "A powerful Discord bot for server management and fun." +readme = "README.md" +requires-python = ">=3.8" +license = {text = "GPL-3.0-or-later"} +authors = [ + {name = "OPPRO.NET Development", email = "development@oppro-network.de"}, + {name = "OPPRO.NET Network", email = "contact@oppro-network.de"} +] +classifiers = [ + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", + "Operating System :: OS Independent" +] + +# Korrigierte Syntax: Direktes Array +dependencies = [ + "ezcord==0.7.4", + "py-cord==2.7.0", + "aiosqlite==0.22.1", + "aiohttp==3.13.2", + "aiocache==0.12.3", + "propcache==0.4.1", + "requests==2.32.5", + "wikipedia==1.4.0", + "beautifulsoup4==4.14.3", + "soupsieve==2.8.1", + "yarl==1.22.0", + "frozenlist==1.8.0", + "h11==0.16.0", + "multidict==6.7.0", + "SimpleColoredLogs==1.3.0", + "FastAPI==0.100.0", + "uvicorn==0.24.0", + "Jinja2==3.1.6", + "MarkupSafe==3.0.3", + "starlette==0.50.0", + "timedelta==2020.12.3" +] + +[project.urls] +Homepage = "https://github.com/Oppro-net-Development/ManagerX" +Documentation = "https://docs.oppro-network.de/" +Changelog = "https://docs.oppro-network.de/en/latest/releases/index.html" +BugTracker = "https://github.com/Oppro-net-Development/ManagerX/issues" + +[project.optional-dependencies] +dev = [ + "python-dotenv==1.2.1", + "click==8.3.1", + "colorama==0.4.6", + "typing_extensions==4.15.0", + "typing-inspection==0.4.2", + "attrs==25.4.0", + "annotated-types==0.7.0", + "anyio==4.12.0", + "certifi==2025.11.12", + "charset-normalizer==3.4.4", + "idna==3.11", + "urllib3==2.6.2", + "build==1.3.0", + "twine==4.2.0" +] + +docs = [ + "sphinx<8,>=6", + "pydata-sphinx-theme", + "sphinx-autodoc-typehints", + "myst-parser<3,>=2", + "sphinx-copybutton" +] + +all = [ + "ezcord==0.7.4", + "py-cord==2.7.0", + "aiosqlite==0.22.1", + "aiohttp==3.13.2", + "aiocache==0.12.3", + "propcache==0.4.1", + "requests==2.32.5", + "wikipedia==1.4.0", + "beautifulsoup4==4.14.3", + "soupsieve==2.8.1", + "yarl==1.22.0", + "frozenlist==1.8.0", + "h11==0.16.0", + "multidict==6.7.0", + "python-dotenv==1.2.1", + "click==8.3.1", + "colorama==0.4.6", + "typing_extensions==4.15.0", + "typing-inspection==0.4.2", + "attrs==25.4.0", + "annotated-types==0.7.0", + "anyio==4.12.0", + "certifi==2025.11.12", + "charset-normalizer==3.4.4", + "idna==3.11", + "urllib3==2.6.2", + "Jinja2==3.1.6", + "MarkupSafe==3.0.3", + "starlette==0.50.0", + "FastAPI==0.100.0", + "uvicorn==0.24.0", + "SimpleColoredLogs==1.3.0", + "timedelta==2020.12.3", + "sphinx<8,>=6", + "pydata-sphinx-theme", + "sphinx-autodoc-typehints", + "myst-parser<3,>=2", + "sphinx-copybutton", + "build==1.3.0", + "twine==4.2.0" +] + +[project.scripts] +# Standard-Weg fรผr CLI-Befehle +managerx-cli = "managerx.cli:main" +managerx = "managerx.__main__:main" + +[tool.setuptools] +# Definiert, wo der Quellcode liegt +package-dir = {"src" = "src"} + +[tool.setuptools.packages.find] +where = ["src"] +include = ["managerx*", "plugins*", "handlers*", "DevTools*", "cogs*"] +exclude = ["tests*"] \ No newline at end of file diff --git a/DevTools/__init__.py b/src/DevTools/__init__.py similarity index 100% rename from DevTools/__init__.py rename to src/DevTools/__init__.py diff --git a/DevTools/backend/__init__.py b/src/DevTools/backend/__init__.py similarity index 100% rename from DevTools/backend/__init__.py rename to src/DevTools/backend/__init__.py diff --git a/DevTools/backend/config/__init__.py b/src/DevTools/backend/config/__init__.py similarity index 100% rename from DevTools/backend/config/__init__.py rename to src/DevTools/backend/config/__init__.py diff --git a/DevTools/backend/config/links.py b/src/DevTools/backend/config/links.py similarity index 100% rename from DevTools/backend/config/links.py rename to src/DevTools/backend/config/links.py diff --git a/DevTools/backend/config/permission.py b/src/DevTools/backend/config/permission.py similarity index 100% rename from DevTools/backend/config/permission.py rename to src/DevTools/backend/config/permission.py diff --git a/DevTools/backend/database/Stats_db.py b/src/DevTools/backend/database/Stats_db.py similarity index 100% rename from DevTools/backend/database/Stats_db.py rename to src/DevTools/backend/database/Stats_db.py diff --git a/DevTools/backend/database/__init__.py b/src/DevTools/backend/database/__init__.py similarity index 100% rename from DevTools/backend/database/__init__.py rename to src/DevTools/backend/database/__init__.py diff --git a/DevTools/backend/database/autodelete_db.py b/src/DevTools/backend/database/autodelete_db.py similarity index 100% rename from DevTools/backend/database/autodelete_db.py rename to src/DevTools/backend/database/autodelete_db.py diff --git a/DevTools/backend/database/autorole_db.py b/src/DevTools/backend/database/autorole_db.py similarity index 100% rename from DevTools/backend/database/autorole_db.py rename to src/DevTools/backend/database/autorole_db.py diff --git a/DevTools/backend/database/globalchat_db.py b/src/DevTools/backend/database/globalchat_db.py similarity index 100% rename from DevTools/backend/database/globalchat_db.py rename to src/DevTools/backend/database/globalchat_db.py diff --git a/DevTools/backend/database/lang_db.py b/src/DevTools/backend/database/lang_db.py similarity index 100% rename from DevTools/backend/database/lang_db.py rename to src/DevTools/backend/database/lang_db.py diff --git a/DevTools/backend/database/levelsystem_db.py b/src/DevTools/backend/database/levelsystem_db.py similarity index 100% rename from DevTools/backend/database/levelsystem_db.py rename to src/DevTools/backend/database/levelsystem_db.py diff --git a/DevTools/backend/database/logging_db.py b/src/DevTools/backend/database/logging_db.py similarity index 100% rename from DevTools/backend/database/logging_db.py rename to src/DevTools/backend/database/logging_db.py diff --git a/DevTools/backend/database/notes_db.py b/src/DevTools/backend/database/notes_db.py similarity index 100% rename from DevTools/backend/database/notes_db.py rename to src/DevTools/backend/database/notes_db.py diff --git a/DevTools/backend/database/spam_db.py b/src/DevTools/backend/database/spam_db.py similarity index 100% rename from DevTools/backend/database/spam_db.py rename to src/DevTools/backend/database/spam_db.py diff --git a/DevTools/backend/database/vc_db.py b/src/DevTools/backend/database/vc_db.py similarity index 100% rename from DevTools/backend/database/vc_db.py rename to src/DevTools/backend/database/vc_db.py diff --git a/DevTools/backend/database/warn_db.py b/src/DevTools/backend/database/warn_db.py similarity index 100% rename from DevTools/backend/database/warn_db.py rename to src/DevTools/backend/database/warn_db.py diff --git a/DevTools/backend/database/welcome_db.py b/src/DevTools/backend/database/welcome_db.py similarity index 100% rename from DevTools/backend/database/welcome_db.py rename to src/DevTools/backend/database/welcome_db.py diff --git a/DevTools/backend/logging.py b/src/DevTools/backend/logging.py similarity index 100% rename from DevTools/backend/logging.py rename to src/DevTools/backend/logging.py diff --git a/DevTools/backend/utils/__init__.py b/src/DevTools/backend/utils/__init__.py similarity index 100% rename from DevTools/backend/utils/__init__.py rename to src/DevTools/backend/utils/__init__.py diff --git a/DevTools/ui/__init__.py b/src/DevTools/ui/__init__.py similarity index 100% rename from DevTools/ui/__init__.py rename to src/DevTools/ui/__init__.py diff --git a/DevTools/ui/emojis.py b/src/DevTools/ui/emojis.py similarity index 100% rename from DevTools/ui/emojis.py rename to src/DevTools/ui/emojis.py diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..b5d7926 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,2 @@ +from .handler import * +from .DevTools import * \ No newline at end of file diff --git a/handler/__init__.py b/src/handler/__init__.py similarity index 100% rename from handler/__init__.py rename to src/handler/__init__.py diff --git a/handler/translation_handler.py b/src/handler/translation_handler.py similarity index 100% rename from handler/translation_handler.py rename to src/handler/translation_handler.py diff --git a/handler/update_checker.py b/src/handler/update_checker.py similarity index 100% rename from handler/update_checker.py rename to src/handler/update_checker.py diff --git a/src/managerx/cli.py b/src/managerx/cli.py new file mode 100644 index 0000000..5cd9696 --- /dev/null +++ b/src/managerx/cli.py @@ -0,0 +1,45 @@ +# src/managerx/cli.py +import click +import os + +FOLDER_STRUCTURE = [ + "src/handler", + "src/DevTools/backend/utils", + "src/DevTools/backend/database", + "src/DevTools/backend/config", + "src/cogs/fun/wikipedia", + "src/cogs/information", + "src/cogs/moderation", + "src/cogs/servermanagement", + "src/managerx", +] + +@click.group() +def managerx(): + """ManagerX CLI Tool""" + pass + +@managerx.command() +def create(): + """Erstellt automatisch die komplette ManagerX-Ordnerstruktur""" + root_folder = "ManagerX" + root_path = os.path.join(os.getcwd(), root_folder) + + if os.path.exists(root_path): + click.echo(f"Ordner '{root_folder}' existiert bereits. Bitte lรถschen oder umbenennen!") + return + + for path in FOLDER_STRUCTURE: + full_path = os.path.join(root_path, path) + os.makedirs(full_path, exist_ok=True) + + # Automatisch __init__.py erstellen, damit Python-Pakete erkannt werden + if path.endswith("managerx") or "DevTools" in path or "cogs" in path: + init_file = os.path.join(full_path, "__init__.py") + with open(init_file, "w") as f: + f.write("# Init for package\n") + + click.echo(f"ManagerX-Ordnerstruktur wurde erfolgreich in '{root_folder}' erstellt!") + +if __name__ == "__main__": + managerx() From 152bea4cfe913193dd8e1541507ae5ac0b81f805 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Sun, 4 Jan 2026 15:34:43 +0100 Subject: [PATCH 2/8] EXAMPLE: UPDATE --- docs/conf.py | 1 + .../own_plugins/create_local_plugin.rst | 111 ++++++++++ .../own_plugins/create_pypi_plugin.rst | 109 ++++++++++ docs/plugins/own_plugins/index.rst | 9 + .../plugins/own_plugins/plugin_guidelines.rst | 190 ++++++++++++++++++ examples/plugins/README.md | 32 +++ examples/plugins/example__init__.py | 18 ++ examples/plugins/example_plugin.py | 55 +++++ examples/plugins/example_pyproject.toml | 29 +++ examples/plugins/functions.py | 28 +++ examples/plugins/utils.py | 17 ++ 11 files changed, 599 insertions(+) create mode 100644 docs/plugins/own_plugins/create_local_plugin.rst create mode 100644 docs/plugins/own_plugins/create_pypi_plugin.rst create mode 100644 docs/plugins/own_plugins/plugin_guidelines.rst create mode 100644 examples/plugins/README.md create mode 100644 examples/plugins/example__init__.py create mode 100644 examples/plugins/example_plugin.py create mode 100644 examples/plugins/example_pyproject.toml create mode 100644 examples/plugins/functions.py create mode 100644 examples/plugins/utils.py diff --git a/docs/conf.py b/docs/conf.py index 6e0d510..5be075d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,6 +7,7 @@ import sys sys.path.insert(0, os.path.abspath('../src')) +sys.setrecursionlimit(1500) # -- Project information ----------------------------------------------------- project = 'ManagerX' diff --git a/docs/plugins/own_plugins/create_local_plugin.rst b/docs/plugins/own_plugins/create_local_plugin.rst new file mode 100644 index 0000000..3567cc8 --- /dev/null +++ b/docs/plugins/own_plugins/create_local_plugin.rst @@ -0,0 +1,111 @@ +Local Plugins (Main GitHub Repository) +===================================== + +In addition to PyPI-based plugins, ManagerX also supports **local plugins** that live directly inside the **main GitHub repository**. + +These plugins are intended for: +- experimental features +- optional extensions +- community contributions +- features that may become core plugins later + +Local plugins are **not enabled or shipped by default**. + +Design Principle +---------------- + +Local plugins follow the same core philosophy as external plugins: + +- โŒ Not part of the default ManagerX installation +- ๐Ÿ”’ Do not affect the core unless explicitly enabled +- ๐Ÿงช Can evolve independently + +This keeps the ManagerX core clean while still allowing flexibility and experimentation. + +Repository Structure +-------------------- + +Local plugins are stored in a dedicated folder inside the main GitHub repository. + +Example structure: + +:: + + plugins/ + โ”œโ”€โ”€ README.md + โ”œโ”€โ”€ example_plugin/ + โ”‚ โ”œโ”€โ”€ plugin.py + โ”‚ โ””โ”€โ”€ README.md + โ”œโ”€โ”€ logging_plugin/ + โ”‚ โ”œโ”€โ”€ plugin.py + โ”‚ โ””โ”€โ”€ README.md + +- Each plugin lives in its own folder +- ``plugin.py`` contains the implementation +- ``README.md`` explains usage, configuration, and behavior + +Local plugins **must not** modify core files directly. + +Enabling Local Plugins +---------------------- + +Local plugins are **disabled by default**. + +To enable a local plugin: +1. Place it inside the ``plugins/`` directory +2. Enable it via the ManagerX configuration +3. Restart ManagerX + +Only explicitly enabled plugins are loaded. + +Differences to PyPI Plugins +--------------------------- + ++-------------------+------------------------+-------------------------+ +| Feature | Local Plugins | PyPI Plugins | ++===================+========================+=========================+ +| Location | Main GitHub repository | External (PyPI) | ++-------------------+------------------------+-------------------------+ +| Installed via pip | No | Yes | ++-------------------+------------------------+-------------------------+ +| Enabled by default| No | No | ++-------------------+------------------------+-------------------------+ +| Naming scheme | Flexible | ``managerx-*`` required | ++-------------------+------------------------+-------------------------+ +| Intended use | Experimental / optional| Public distribution | ++-------------------+------------------------+-------------------------+ + +Promotion to PyPI +----------------- + +A local plugin can later be **promoted to a PyPI plugin** if it: +- proves stable +- has good documentation +- is useful to a wider audience + +In this case, it must follow the PyPI naming scheme: + +:: + + managerx-[plugin-name] + +Conclusion +---------- + +Local plugins provide a **safe space for innovation** without increasing the default footprint of ManagerX. + +They allow contributors to: +- test new ideas +- share optional features +- collaborate inside the main repository + +All without forcing functionality onto every ManagerX user. +Happy coding! ๐Ÿš€ + +.. toctree:: + :maxdepth: 2 + :caption: Next Steps + + Create a PyPi Plugin + + Plugin Guidelines \ No newline at end of file diff --git a/docs/plugins/own_plugins/create_pypi_plugin.rst b/docs/plugins/own_plugins/create_pypi_plugin.rst new file mode 100644 index 0000000..93c4ad5 --- /dev/null +++ b/docs/plugins/own_plugins/create_pypi_plugin.rst @@ -0,0 +1,109 @@ +Create your own PyPI Plugin for ManagerX +======================================= + +ManagerX provides a flexible **plugin system** that allows developers to extend its functionality without modifying the core project. Plugins are developed as **separate Python packages** and distributed via **PyPI**. + +Plugin Philosophy +----------------- + +Plugins are **not included by default** in ManagerX. + +This is an intentional design decision to keep ManagerX: +- lightweight +- secure +- easy to maintain + +Every plugin is installed **explicitly by the user** and lives outside the core project. + +Plugin Naming Convention +------------------------ + +All ManagerX plugins **must** follow this naming scheme: + +:: + + managerx-[your-plugin-name] + +Examples: +- ``managerx-logger`` +- ``managerx-moderation`` +- ``managerx-backup`` + +This naming convention ensures: +- clear identification on PyPI +- no name collisions +- automatic recognition by ManagerX + +Plugin Examples on GitHub +------------------------- + +The official ManagerX GitHub repository contains an **examples folder** to help developers get started. + +Structure: + +:: + + examples/ + โ””โ”€โ”€ plugins/ + โ”œโ”€โ”€ basic_plugin/ + โ”‚ โ”œโ”€โ”€ plugin.py + โ”‚ โ””โ”€โ”€ README.md + โ”œโ”€โ”€ advanced_plugin/ + โ”‚ โ”œโ”€โ”€ plugin.py + โ”‚ โ””โ”€โ”€ README.md + +- ``.py`` files show how to implement plugins +- ``.md`` files explain the plugin logic and structure +- examples are **reference implementations**, not production code + +How Plugins Work +---------------- + +A ManagerX plugin is a **standalone Python package** that: + +- is installed via ``pip`` +- exposes a defined entry point +- is detected and loaded automatically by ManagerX + +Once installed, ManagerX scans for compatible plugins and enables them at runtime. + +Installing a Plugin +------------------- + +Plugins are installed like any other PyPI package: + +:: + + pip install managerx-your-plugin-name + +After installation, restart ManagerX to activate the plugin. + +Creating Your Own Plugin +------------------------ + +1. Create a new Python project +2. Name it using the required prefix: ``managerx-`` +3. Implement the plugin interface +4. Add documentation (README.md) +5. Publish the package to PyPI + +By following standard Python packaging rules, plugins remain: +- easy to install +- easy to update +- easy to remove + +Conclusion +---------- + +The ManagerX plugin system is designed for **modularity and freedom**. +You decide which features you need, and plugins provide them โ€” without bloating the core. + +Build small, focused plugins and share them with the community ๐Ÿš€ +Happy coding! + +.. toctree:: + :maxdepth: 2 + :caption: Next Steps + + Local Cog Development + Plugin Guidelines \ No newline at end of file diff --git a/docs/plugins/own_plugins/index.rst b/docs/plugins/own_plugins/index.rst index 5671ce6..34ceadf 100644 --- a/docs/plugins/own_plugins/index.rst +++ b/docs/plugins/own_plugins/index.rst @@ -66,3 +66,12 @@ Best Practices - Use ManagerXโ€™s `SimpleColoredLogs` for logging plugin events and errors. - Follow existing naming and coding conventions for compatibility. - For PyPi plugins, include versioning, dependencies, and metadata in your package. + + +.. toctree:: + :maxdepth: 2 + :caption: Next Steps + + Create a PyPi Plugin + Local Cog Development + Plugin Guidelines \ No newline at end of file diff --git a/docs/plugins/own_plugins/plugin_guidelines.rst b/docs/plugins/own_plugins/plugin_guidelines.rst new file mode 100644 index 0000000..79e4c1b --- /dev/null +++ b/docs/plugins/own_plugins/plugin_guidelines.rst @@ -0,0 +1,190 @@ +Plugin Policy +============= + +This document defines the official rules and requirements for all ManagerX +plugins, including **Local Plugins** and **PyPI Plugins**. + +The goal of this policy is to keep ManagerX: +- stable +- secure +- modular +- lightweight + +Plugins are never part of the core by default. + +--- + +General Principles +------------------ + +- All plugins are **optional**. +- All plugins are **disabled by default**. +- The ManagerX core must never depend on plugins. +- Plugins must not modify or patch core files. + +--- + +Plugin Types +------------ + +ManagerX supports two types of plugins: + +1. **PyPI Plugins** +2. **Local Plugins** + +**Local Plugins**: +- Live in the main ManagerX repository under the folder: + +:: + + plugins/ + +- Are **not Cogs**, but fully independent plugins +- Can be experimental or optional features +- Are never enabled by default + +**PyPI Plugins**: +- Distributed via PyPI +- Must follow the naming convention: + +:: + + managerx-[plugin-name] + +- Fully independent and always stored in their own GitHub repository + +--- + +License +------- + +- ManagerX itself is licensed under **GPL-3.0**. +- Local Plugins included in the repository **must also be GPL-3.0 compatible**. +- PyPI Plugins can use any license **compatible with GPL-3.0**. +- Plugins without a clear license will **not be accepted**. + +--- + +Source Code Separation Requirement +---------------------------------- + +All plugins, whether Local or PyPI, must have a **dedicated GitHub repository**. + +- The repository in the main ManagerX repo (`plugins/`) is only a mirror or example. +- The **canonical source** is always the plugin's own repo. +- One plugin = one repository. + +--- + +Ownership & Responsibility +-------------------------- + +- Each plugin must have a clearly defined owner or maintainer. +- The owner is responsible for: + - bugs + - security issues + - legal matters +- ManagerX does **not** provide support for third-party plugins. + +--- + +Security Requirements +--------------------- + +Plugins must not: +- contain malicious code +- collect tokens or credentials +- perform hidden network requests +- auto-update without user consent + +--- + +Versioning Rules +---------------- + +- Every plugin must define a version. +- Breaking changes require a major version bump. +- Plugin versions are independent from ManagerX versions. + +--- + +Documentation Requirement +------------------------- + +Each plugin must include a `README.md` that explains: +- what the plugin does +- how to enable or install it +- configuration options +- dependencies + +Plugins without documentation are not accepted. + +--- + +Compatibility Rules +------------------- + +- Plugins must declare supported ManagerX versions. +- Plugins must use only public plugin APIs. +- Plugins must not depend on private core interfaces. + +--- + +Enable / Disable & Removal +-------------------------- + +- Plugins must be safely disableable. +- Plugins must not block ManagerX startup. +- Uninstalling a plugin must not leave persistent data behind. + +--- + +Official Plugin Status +---------------------- + +If a plugin fulfills **all requirements** in this policy, it **may** be: + +- listed in the official ManagerX documentation +- marked as an **Official ManagerX Plugin** + +Official status means: +- recommended by ManagerX +- documented in the main docs +- still optional and not part of the core + +Promotion is evaluated on: +- stability +- code quality +- documentation +- maintenance activity + +--- + +Final Checklist +--------------- + +Before a plugin can be accepted or promoted: + +- [ ] Separate GitHub repository +- [ ] Correct naming (PyPI only) +- [ ] License included (GPL-3.0 compatible for Local Plugins) +- [ ] Version defined +- [ ] README.md present +- [ ] No core modifications +- [ ] Disabled by default + +--- + +Conclusion +---------- + +Local and PyPI plugins provide **modularity and freedom**. +The core remains clean and minimal, while plugins can evolve independently. + +.. toctree:: + :maxdepth: 2 + :caption: Next Steps + + Local Cog Development + + Create a PyPi Plugin \ No newline at end of file diff --git a/examples/plugins/README.md b/examples/plugins/README.md new file mode 100644 index 0000000..15166d4 --- /dev/null +++ b/examples/plugins/README.md @@ -0,0 +1,32 @@ +# ManagerX Plugin-System + +Das Plugin-System von **ManagerX** erlaubt es Entwicklern und der Community, den Bot flexibel zu erweitern. +Jedes Plugin ist eine **Extension**, die neue Funktionen bereitstellt und in den Bot integriert werden kann. + +## Wie Plugins funktionieren + +- **Freiwillige Entwicklung:** Jeder kann Plugins fรผr ManagerX erstellen, sei es fรผr neue Befehle, Automatisierungen oder Utility-Funktionen. +- **Modularer Aufbau:** Plugins sind von Haus aus **separat vom Hauptcode**. Das sorgt fรผr Stabilitรคt und einfache Updates. +- **Manuelles Laden:** Im Gegensatz zu manchen Bot-Systemen werden Plugins in ManagerX manuell in Cogs oder direkt im Bot geladen โ€“ so behรคlt der Betreiber volle Kontrolle. +- **PyPI & Local Plugins:** + - **PyPI Plugins**: Externe Plugins, die รผber PyPI installiert werden kรถnnen. + - **Local Plugins**: Plugins, die lokal im Projekt gespeichert und direkt vom Bot geladen werden. + +## Vorteile des Systems + +1. **Community-getrieben** โ€“ Jeder kann Ideen umsetzen. +2. **Sauber & modular** โ€“ Plugins stรถren den Kern-Bot nicht. +3. **Erweiterbar** โ€“ Neue Funktionen kรถnnen einfach hinzugefรผgt oder entfernt werden. +4. **Sicher** โ€“ Trennung von Kern-Bot und Plugins reduziert das Risiko von Fehlern. + +## Offizielle Plugins + +Damit ein Plugin als offizielle Extension gilt, muss es alle Anforderungen des **ManagerX Plugin Guidelines** erfรผllen. +Nur so kann es in die **offizielle Dokumentation** aufgenommen und vom Bot als โ€žoffizielles Pluginโ€œ behandelt werden. + +--- + +### Mehr dazu + +Weitere Informationen, Beispiele und detaillierte Anleitungen zu Plugins findest du **bald in unseren offiziellen Docs**. +Bleib dran, um zu erfahren, wie du eigene Plugins entwickeln und verรถffentlichen kannst! diff --git a/examples/plugins/example__init__.py b/examples/plugins/example__init__.py new file mode 100644 index 0000000..2b2e17a --- /dev/null +++ b/examples/plugins/example__init__.py @@ -0,0 +1,18 @@ +""" +ManagerX Example Plugin + +This package exposes functions for ManagerX bots. +No automatic bot registration is done here. +""" + +from .functions import hello, add_numbers, multiply_numbers, format_user_message +from .utils import current_time, is_even + +__all__ = [ + "hello", + "add_numbers", + "multiply_numbers", + "format_user_message", + "current_time", + "is_even" +] \ No newline at end of file diff --git a/examples/plugins/example_plugin.py b/examples/plugins/example_plugin.py new file mode 100644 index 0000000..29e2725 --- /dev/null +++ b/examples/plugins/example_plugin.py @@ -0,0 +1,55 @@ +""" +This Cog loads the functions from the PyPI plugin +and exposes them as Discord commands. +""" + +from discord.ext import commands +from managerx_example_plugin import ( + hello, + add_numbers, + multiply_numbers, + format_user_message, + current_time, + is_even +) + +class ExamplePlugin(commands.Cog): + """Example Cog that uses the ManagerX Example Plugin functions.""" + + def __init__(self, bot): + self.bot = bot + + @commands.command(name="sayhello") + async def say_hello(self, ctx): + user = ctx.author.name + result = hello(user) + await ctx.send(result) + + @commands.command(name="add") + async def add(self, ctx, a: int, b: int): + result = add_numbers(a, b) + await ctx.send(f"{a} + {b} = {result}") + + @commands.command(name="multiply") + async def multiply(self, ctx, a: int, b: int): + result = multiply_numbers(a, b) + await ctx.send(f"{a} ร— {b} = {result}") + + @commands.command(name="formatmsg") + async def formatmsg(self, ctx, *, message: str): + user = ctx.author.name + formatted = format_user_message(user, message) + await ctx.send(formatted) + + @commands.command(name="time") + async def time(self, ctx): + await ctx.send(f"Current time: {current_time()}") + + @commands.command(name="iseven") + async def is_even_cmd(self, ctx, number: int): + result = is_even(number) + await ctx.send(f"{number} is even? {result}") + +# Setup function for bot +async def setup(bot): + await bot.add_cog(ExamplePlugin(bot)) \ No newline at end of file diff --git a/examples/plugins/example_pyproject.toml b/examples/plugins/example_pyproject.toml new file mode 100644 index 0000000..fa1f167 --- /dev/null +++ b/examples/plugins/example_pyproject.toml @@ -0,0 +1,29 @@ +[project] +name = "managerx-example-plugin" # Name muss managerx-* sein +version = "0.1.0" # Startversion +description = "An example plugin for ManagerX demonstrating PyPI plugin structure" +readme = "README.md" # Fรผr PyPI / Dokumentation +authors = [ + { name = "Your Name", email = "you@example.com" } +] +license = { text = "GPL-3.0-or-later" } +keywords = ["managerx", "plugin", "example"] +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", + "Operating System :: OS Independent" +] +requires-python = ">=3.10" + +[project.dependencies] +# Beispielabhรคngigkeiten, falls dein Plugin externe Bibliotheken benรถtigt +# requests = ">=2.30.0" +# aiohttp = ">=3.8.0" + +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" + +# Optional: entry points fรผr Plugins, falls spรคter automatische Discovery genutzt wird +[project.scripts] +# hello-plugin = "managerx_example_plugin.functions:hello" diff --git a/examples/plugins/functions.py b/examples/plugins/functions.py new file mode 100644 index 0000000..c880583 --- /dev/null +++ b/examples/plugins/functions.py @@ -0,0 +1,28 @@ +""" +This file contains the main plugin functions. +These functions are independent and can be used in any bot Cog. +""" + +def hello(user: str) -> str: + """ + Example greeting function. + """ + return f"Hello {user}! Welcome to ManagerX Example Plugin." + +def add_numbers(a: int, b: int) -> int: + """ + Example calculation function. + """ + return a + b + +def multiply_numbers(a: int, b: int) -> int: + """ + Another example function for multiplication. + """ + return a * b + +def format_user_message(user: str, message: str) -> str: + """ + Formats a message with the user's name. + """ + return f"{user} says: {message}" \ No newline at end of file diff --git a/examples/plugins/utils.py b/examples/plugins/utils.py new file mode 100644 index 0000000..dd172ff --- /dev/null +++ b/examples/plugins/utils.py @@ -0,0 +1,17 @@ +""" +Utility functions for ManagerX Example Plugin. +""" + +from datetime import datetime + +def current_time() -> str: + """ + Returns the current time as a formatted string. + """ + return datetime.now().strftime("%Y-%m-%d %H:%M:%S") + +def is_even(number: int) -> bool: + """ + Returns True if the number is even, False otherwise. + """ + return number % 2 == 0 \ No newline at end of file From b1871de26f18c54fdf8c5ae3c5c96638063afc69 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Fri, 9 Jan 2026 14:08:18 +0100 Subject: [PATCH 3/8] Updated --- TODO.md | 60 ++ __init__.py | 3 +- api.py | 229 +++-- docs/_static/custom.css | 31 + docs/conf.py | 4 +- docs/dev_guide/architecture/cog_system.rst | 4 +- .../architecture/command_handler.rst | 4 +- .../contributing/coding_standards.rst | 16 + docs/dev_guide/contributing/contributing.rst | 17 + docs/dev_guide/contributing/documentation.rst | 13 + docs/dev_guide/contributing/index.rst | 106 -- docs/dev_guide/contributing/testing.rst | 24 + docs/dev_guide/contributing/workflow.rst | 41 + docs/dev_guide/index.rst | 49 +- docs/dev_guide/installation/index.rst | 11 + .../installation/install_from_source.rst | 105 ++ docs/plugins/index.rst | 42 +- .../official_plugins/managerx_handler.rst | 50 + .../own_plugins/create_local_plugin.rst | 24 +- .../own_plugins/create_pypi_plugin.rst | 23 +- docs/plugins/own_plugins/index.rst | 12 +- .../plugins/own_plugins/plugin_guidelines.rst | 54 +- main.py | 27 +- pyproject.toml | 8 +- requirements/bot_req.txt | 2 + requirements/dev_req.txt | 2 + requirements/req.txt | 5 +- src/DevTools/__init__.py | 3 - src/DevTools/backend/__init__.py | 5 - src/DevTools/backend/config/__init__.py | 3 - src/DevTools/backend/config/links.py | 4 - src/DevTools/backend/config/permission.py | 40 - src/DevTools/backend/database/Stats_db.py | 476 --------- src/DevTools/backend/database/__init__.py | 13 - .../backend/database/autodelete_db.py | 843 ---------------- src/DevTools/backend/database/autorole_db.py | 102 -- .../backend/database/globalchat_db.py | 955 ------------------ src/DevTools/backend/database/lang_db.py | 46 - .../backend/database/levelsystem_db.py | 758 -------------- src/DevTools/backend/database/logging_db.py | 413 -------- src/DevTools/backend/database/notes_db.py | 55 - src/DevTools/backend/database/spam_db.py | 494 --------- src/DevTools/backend/database/vc_db.py | 176 ---- src/DevTools/backend/database/warn_db.py | 121 --- src/DevTools/backend/database/welcome_db.py | 552 ---------- src/DevTools/backend/logging.py | 240 ----- src/DevTools/backend/utils/__init__.py | 1 - src/DevTools/ui/__init__.py | 2 - src/DevTools/ui/emojis.py | 53 - src/__init__.py | 2 - src/cogs/Servermanament/tempvc.py | 1 - src/cogs/Servermanament/welcome.py | 1 - src/cogs/moderation/antispam.py | 17 +- src/cogs/moderation/moderation.py | 2 - src/cogs/moderation/notes.py | 1 - src/cogs/moderation/warningsystem.py | 3 - src/cogs/setlang.py | 26 +- src/handler/__init__.py | 2 - src/handler/translation_handler.py | 89 -- src/handler/update_checker.py | 218 ---- 60 files changed, 676 insertions(+), 6007 deletions(-) create mode 100644 TODO.md create mode 100644 docs/dev_guide/contributing/coding_standards.rst create mode 100644 docs/dev_guide/contributing/contributing.rst create mode 100644 docs/dev_guide/contributing/documentation.rst delete mode 100644 docs/dev_guide/contributing/index.rst create mode 100644 docs/dev_guide/contributing/testing.rst create mode 100644 docs/dev_guide/contributing/workflow.rst create mode 100644 docs/dev_guide/installation/index.rst create mode 100644 docs/dev_guide/installation/install_from_source.rst create mode 100644 docs/plugins/official_plugins/managerx_handler.rst delete mode 100644 src/DevTools/__init__.py delete mode 100644 src/DevTools/backend/__init__.py delete mode 100644 src/DevTools/backend/config/__init__.py delete mode 100644 src/DevTools/backend/config/links.py delete mode 100644 src/DevTools/backend/config/permission.py delete mode 100644 src/DevTools/backend/database/Stats_db.py delete mode 100644 src/DevTools/backend/database/__init__.py delete mode 100644 src/DevTools/backend/database/autodelete_db.py delete mode 100644 src/DevTools/backend/database/autorole_db.py delete mode 100644 src/DevTools/backend/database/globalchat_db.py delete mode 100644 src/DevTools/backend/database/lang_db.py delete mode 100644 src/DevTools/backend/database/levelsystem_db.py delete mode 100644 src/DevTools/backend/database/logging_db.py delete mode 100644 src/DevTools/backend/database/notes_db.py delete mode 100644 src/DevTools/backend/database/spam_db.py delete mode 100644 src/DevTools/backend/database/vc_db.py delete mode 100644 src/DevTools/backend/database/warn_db.py delete mode 100644 src/DevTools/backend/database/welcome_db.py delete mode 100644 src/DevTools/backend/logging.py delete mode 100644 src/DevTools/backend/utils/__init__.py delete mode 100644 src/DevTools/ui/__init__.py delete mode 100644 src/DevTools/ui/emojis.py delete mode 100644 src/__init__.py delete mode 100644 src/handler/__init__.py delete mode 100644 src/handler/translation_handler.py delete mode 100644 src/handler/update_checker.py diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..36dce02 --- /dev/null +++ b/TODO.md @@ -0,0 +1,60 @@ +# ๐Ÿ“ ManagerX Developer Todo-Guide + +> รœbersicht รผber offene Aufgaben, Bugs, Refactors und Dokumentation. +> Dieses Dokument dient der internen Organisation und Contributor-Info. + +--- + +## ๐Ÿ“‚ Kategorien + +### 1๏ธโƒฃ Features +Neue Funktionen, die implementiert werden sollen. + +| Status | Aufgabe | Beschreibung | Prioritรคt | Verantwortlich | +|--------|--------|--------------|-----------|----------------| +| โฌœ | | | | | + +--- + +### 2๏ธโƒฃ Bugs / Fixes +Probleme, die behoben werden mรผssen. + +| Status | Aufgabe | Beschreibung | Prioritรคt | Verantwortlich | +|--------|--------|--------------|-----------|----------------| +| โฌœ | Wikipedia Link Button | Link Button fixen | Hoch | - | + +--- + +### 3๏ธโƒฃ Refactors / Code-Optimierung +Code-Struktur verbessern, Lesbarkeit erhรถhen. + +| Status | Aufgabe | Beschreibung | Prioritรคt | Verantwortlich | +|--------|--------|--------------|-----------|----------------| +| โฌœ | | | | | + +--- + +### 4๏ธโƒฃ Documentation +Alles, was mit Docs zu tun hat. + +| Status | Aufgabe | Beschreibung | Prioritรคt | Verantwortlich | +|--------|--------|--------------|-----------|----------------| +| โฌœ | | | | | + +--- + +### โœ… Status-Markierungen +- โฌœ Offene Aufgabe +- ๐Ÿ”„ In Arbeit +- โœ… Erledigt + +> Tipp: Fertige Aufgaben regelmรครŸig aus der Tabelle entfernen oder archivieren. + +--- + +### ๐Ÿ’ก Best Practices +1. Aufgaben nach Kategorie sortieren โ†’ leichter รœberblick +2. Prioritรคt klar angeben: Hoch / Mittel / Niedrig +3. Verantwortlich eintragen, wenn mehrere Entwickler beteiligt sind +4. Status aktuell halten โ†’ kein veralteter TODO +5. Externe Tools optional, aber nicht zwingend notwendig diff --git a/__init__.py b/__init__.py index 3c64cf3..13afe8f 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1,2 @@ -from .src import * \ No newline at end of file +from .src import handler +from .src import DevTools \ No newline at end of file diff --git a/api.py b/api.py index f61f2d5..cef30dd 100644 --- a/api.py +++ b/api.py @@ -1,35 +1,41 @@ +# ________ ________ ___ +#|\ __ \|\ __ \|\ \ +#\ \ \|\ \ \ \|\ \ \ \ +# \ \ __ \ \ ____\ \ \ +# \ \ \ \ \ \ \___|\ \ \ +# \ \__\ \__\ \__\ \ \__\ +# \|__|\|__|\|__| \|__| + +# --- STANDARD LIBRARIES --- +import json +import logging import os +from typing import Optional, List, Dict, Any + +# --- THIRD PARTY LIBRARIES --- import httpx -import logging -import json -import sys -from fastapi import FastAPI, HTTPException, Query, Request +import uvicorn +import yaml +from dotenv import load_dotenv +from fastapi import Depends, FastAPI, HTTPException, Query, Request from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import RedirectResponse from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials -from fastapi import Depends from fastapi.staticfiles import StaticFiles from pydantic import BaseModel -from typing import Optional, List, Dict, Any -from dotenv import load_dotenv -import yaml - -security = HTTPBearer() -def get_token(credentials: HTTPAuthorizationCredentials = Depends(security)): - return credentials.credentials - -# Import deiner Datenbank-Klasse +# --- LOCAL IMPORTS --- try: from src.DevTools import TempVCDatabase from src.DevTools.backend.database.welcome_db import WelcomeDatabase from src.DevTools.backend.database.levelsystem_db import LevelDatabase except ImportError: - from DevTools import TempVCDatabase - # Fallback if not available + TempVCDatabase = None WelcomeDatabase = None LevelDatabase = None + logging.warning("Database modules not found - some features may be unavailable") -# --- LOGGING SETUP (KEIN SPAM) --- +# --- LOGGING SETUP --- logging.basicConfig(level=logging.WARNING) logger = logging.getLogger("ManagerX-API") logger.setLevel(logging.INFO) @@ -39,58 +45,45 @@ def get_token(credentials: HTTPAuthorizationCredentials = Depends(security)): # --- KONFIGURATION --- load_dotenv(os.path.join("config", ".env")) -# --- KONFIGURATION --- -load_dotenv(os.path.join("config", ".env")) - -# Lade Bot-Config fรผr interne Prรผfungen +# Bot-Config laden config_path = os.path.join("config", "config.yaml") +bot_config = {} try: - import yaml with open(config_path, 'r', encoding='utf-8') as f: bot_config = yaml.safe_load(f) logger.info("Bot-Config fรผr API-Prรผfungen geladen") -except ImportError: - logger.warning("PyYAML nicht installiert, Config-Prรผfungen deaktiviert") - bot_config = {} +except FileNotFoundError: + logger.warning("Config-Datei nicht gefunden") except Exception as e: logger.error(f"Fehler beim Laden der Config: {e}") - bot_config = {} +# --- FASTAPI APP --- app = FastAPI(title="ManagerX Ultimate API") app.add_middleware( CORSMiddleware, - allow_origins=["*"], + allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) -# --- STATISCHE DATEIEN SERVIEREN --- -app.mount("/site", StaticFiles(directory="site", html=True), name="site") +# --- STATISCHE DATEIEN --- +if os.path.exists("site"): + app.mount("/site", StaticFiles(directory="site", html=True), name="site") -# --- HILFSFUNKTIONEN --- -def is_feature_enabled(feature_path: str) -> bool: - """Prรผft, ob ein Feature in der Config aktiviert ist. z.B. 'features.cogs.server_management.tempvc'""" - keys = feature_path.split('.') - current = bot_config - try: - for key in keys: - current = current.get(key, {}) - return current if isinstance(current, bool) else True # Standard True - except: - return True - -# Datenbank Instanz (Pfad zur .db Datei) +# --- DATENBANKEN INITIALISIEREN --- DB_PATH = os.path.join("data", "tempvc.db") -db = TempVCDatabase(DB_PATH) - -# Welcome DB +db = TempVCDatabase(DB_PATH) if TempVCDatabase else None welcome_db = WelcomeDatabase() if WelcomeDatabase else None - -# Level DB level_db = LevelDatabase() if LevelDatabase else None +# --- SECURITY --- +security = HTTPBearer() + +def get_token(credentials: HTTPAuthorizationCredentials = Depends(security)): + return credentials.credentials + # --- DATEN-MODELLE --- class TempVCUpdate(BaseModel): token: str @@ -124,13 +117,27 @@ class LevelUpdate(BaseModel): prestige_enabled: bool = True prestige_min_level: int = 50 -# --- ADMIN-CHECK LOGIK --- +class RefreshTokenRequest(BaseModel): + refresh_token: str + +# --- HILFSFUNKTIONEN --- +def is_feature_enabled(feature_path: str) -> bool: + """Prรผft, ob ein Feature in der Config aktiviert ist.""" + keys = feature_path.split('.') + current = bot_config + try: + for key in keys: + current = current.get(key, {}) + return current if isinstance(current, bool) else True + except: + return True + async def check_admin_permissions(guild_id: int, token: str): - """Prรผft bei Discord, ob der User wirklich Admin auf dem Server ist.""" + """Prรผft bei Discord, ob der User Admin-Rechte hat.""" async with httpx.AsyncClient() as client: try: res = await client.get( - "https://discord.com/api/users/@me/guilds", + "https://discord.com/api/users/@me/guilds", headers={"Authorization": f"Bearer {token}"}, timeout=5.0 ) @@ -148,39 +155,41 @@ async def check_admin_permissions(guild_id: int, token: str): # Bitwise check fรผr ADMINISTRATOR (0x8) if not (int(guild.get('permissions', 0)) & 0x8) == 0x8: raise HTTPException(status_code=403, detail="Du hast keine Admin-Rechte") + return True + except HTTPException: + raise except Exception as e: - if isinstance(e, HTTPException): raise e logger.error(f"Fehler bei Discord-Validierung: {e}") raise HTTPException(status_code=500, detail="Discord API Kommunikationsfehler") -# --- ALLE ENDPUNKTE --- +# --- ENDPOINTS --- -# 0. ROOT REDIRECT @app.get("/") async def root(): - from fastapi.responses import RedirectResponse + """Redirect zur Landing Page""" return RedirectResponse(url="/site/index.html") -# 1. BOT STATS (Neue & Alte Route) @app.get("/api/managerx/stats") @app.get("/api/v2/stats") async def get_bot_stats(): + """Bot-Statistiken laden""" stats_file = "bot_stats.json" if os.path.exists(stats_file): try: with open(stats_file, "r", encoding="utf-8") as f: return json.load(f) - except: - pass + except Exception as e: + logger.error(f"Fehler beim Laden der Stats: {e}") + return { "stats": {"server_count": 50, "user_count": 15000}, "bot_info": {"latency": 35, "status": "Online"} } -# 2. OAUTH2 CALLBACK (LOGIN) @app.get("/api/auth/callback") async def auth_callback(code: str): + """OAuth2 Callback fรผr Discord-Login""" async with httpx.AsyncClient() as client: payload = { 'client_id': os.getenv("DISCORD_CLIENT_ID"), @@ -190,55 +199,70 @@ async def auth_callback(code: str): 'redirect_uri': os.getenv("DISCORD_REDIRECT_URI") } r = await client.post('https://discord.com/api/oauth2/token', data=payload) + if r.status_code != 200: logger.error(f"Login Fehler: {r.text}") raise HTTPException(status_code=400, detail="Discord Token Austausch fehlgeschlagen") tokens = r.json() - u = await client.get('https://discord.com/api/users/@me', headers={'Authorization': f"Bearer {tokens['access_token']}"}) - return {"access_token": tokens['access_token'], "refresh_token": tokens.get('refresh_token'), "user": u.json()} + u = await client.get( + 'https://discord.com/api/users/@me', + headers={'Authorization': f"Bearer {tokens['access_token']}"} + ) + + return { + "access_token": tokens['access_token'], + "refresh_token": tokens.get('refresh_token'), + "user": u.json() + } @app.post("/api/auth/refresh") -async def refresh_access_token(data: dict): - refresh_token = data.get('refresh_token') - if not refresh_token: - raise HTTPException(status_code=400, detail="Kein Refresh-Token") - +async def refresh_access_token(data: RefreshTokenRequest): + """Token erneuern""" async with httpx.AsyncClient() as client: payload = { 'client_id': os.getenv("DISCORD_CLIENT_ID"), 'client_secret': os.getenv("DISCORD_CLIENT_SECRET"), 'grant_type': 'refresh_token', - 'refresh_token': refresh_token + 'refresh_token': data.refresh_token } r = await client.post('https://discord.com/api/oauth2/token', data=payload) + if r.status_code != 200: raise HTTPException(status_code=400, detail="Token-Refresh fehlgeschlagen") tokens = r.json() - return {"access_token": tokens['access_token'], "refresh_token": tokens.get('refresh_token')} + return { + "access_token": tokens['access_token'], + "refresh_token": tokens.get('refresh_token') + } -# 3. GUILD LISTE (DASHBOARD) @app.get("/api/user/guilds") async def get_user_guilds(token: str = Depends(get_token)): + """Alle Server mit Admin-Rechten""" async with httpx.AsyncClient() as client: res = await client.get( - "https://discord.com/api/users/@me/guilds", + "https://discord.com/api/users/@me/guilds", headers={"Authorization": f"Bearer {token}"} ) - if res.status_code != 200: return [] + if res.status_code != 200: + return [] + # Filtert nur Server mit Admin-Rechten return [g for g in res.json() if (int(g.get('permissions', 0)) & 0x8) == 0x8] -# 3. GUILD CHANNELS (fรผr Dropdowns) @app.get("/api/guild/{guild_id}/channels") async def get_guild_channels(guild_id: int, token: str = Depends(get_token)): + """Kanรคle eines Servers laden""" await check_admin_permissions(guild_id, token) - # Hole Guild-Info von Discord API async with httpx.AsyncClient() as client: headers = {"Authorization": f"Bearer {token}"} - res = await client.get(f"https://discord.com/api/guilds/{guild_id}/channels", headers=headers) + res = await client.get( + f"https://discord.com/api/guilds/{guild_id}/channels", + headers=headers + ) + if res.status_code == 401: raise HTTPException(status_code=401, detail="Token abgelaufen") if res.status_code != 200: @@ -253,16 +277,19 @@ async def get_guild_channels(guild_id: int, token: str = Depends(get_token)): ] return {"channels": filtered} -# 4. TEMPVC LADEN (GET) @app.get("/api/guild/{guild_id}/tempvc") async def get_tempvc(guild_id: int, token: str = Depends(get_token)): + """TempVC Einstellungen laden""" await check_admin_permissions(guild_id, token) if not is_feature_enabled('features.cogs.server_management.tempvc'): - raise HTTPException(status_code=403, detail="TempVC Feature ist in der Bot-Config deaktiviert") + raise HTTPException(status_code=403, detail="TempVC Feature ist deaktiviert") + + if not db: + raise HTTPException(status_code=500, detail="TempVC Database nicht verfรผgbar") - settings = db.get_tempvc_settings(guild_id) # Erwartet Tuple/List aus DB - ui = db.get_ui_settings(guild_id) # Erwartet Tuple/List aus DB + settings = db.get_tempvc_settings(guild_id) + ui = db.get_ui_settings(guild_id) return { "creator_channel_id": str(settings[0]) if settings else "", @@ -272,23 +299,22 @@ async def get_tempvc(guild_id: int, token: str = Depends(get_token)): "ui_prefix": ui[1] if ui else "๐Ÿ”ง" } -# 5. TEMPVC SPEICHERN (POST) @app.post("/api/guild/{guild_id}/tempvc") async def save_tempvc(guild_id: int, data: TempVCUpdate): - # Admin-Validierung + """TempVC Einstellungen speichern""" await check_admin_permissions(guild_id, data.token) if not is_feature_enabled('features.cogs.server_management.tempvc'): - raise HTTPException(status_code=403, detail="TempVC Feature ist in der Bot-Config deaktiviert") + raise HTTPException(status_code=403, detail="TempVC Feature ist deaktiviert") + + if not db: + raise HTTPException(status_code=500, detail="TempVC Database nicht verfรผgbar") try: - # Konvertierung zu Integer fรผr SQLite c_id = int(data.creator_channel_id) cat_id = int(data.category_id) - logger.info(f"๐Ÿ’พ SPEICHERN: Guild {guild_id} | IDs: {c_id}, {cat_id}") - # Datenbankbefehle ausfรผhren db.set_tempvc_settings(guild_id, c_id, cat_id, data.auto_delete_time) db.set_ui_settings(guild_id, data.ui_enabled, data.ui_prefix) @@ -296,21 +322,22 @@ async def save_tempvc(guild_id: int, data: TempVCUpdate): except ValueError: raise HTTPException(status_code=400, detail="Kanal- und Kategorie-IDs mรผssen Zahlen sein") except Exception as e: - logger.error(f"Datenbank-Fehler beim Schreiben: {e}") + logger.error(f"Datenbank-Fehler: {e}") raise HTTPException(status_code=500, detail="Interner Datenbank-Fehler") -# 6. WELCOME LADEN (GET) @app.get("/api/guild/{guild_id}/welcome") async def get_welcome(guild_id: int, token: str = Depends(get_token)): + """Welcome Einstellungen laden""" await check_admin_permissions(guild_id, token) if not is_feature_enabled('features.cogs.server_management.welcome'): - raise HTTPException(status_code=403, detail="Welcome Feature ist in der Bot-Config deaktiviert") + raise HTTPException(status_code=403, detail="Welcome Feature ist deaktiviert") if not welcome_db: raise HTTPException(status_code=500, detail="Welcome Database nicht verfรผgbar") settings = welcome_db.get_welcome_settings(guild_id) + if not settings: return { "channel_id": "", @@ -340,25 +367,21 @@ async def get_welcome(guild_id: int, token: str = Depends(get_token)): "delete_after": settings.get('delete_after', 0) } -# 7. WELCOME SPEICHERN (POST) @app.post("/api/guild/{guild_id}/welcome") async def save_welcome(guild_id: int, data: WelcomeUpdate): - # Admin-Validierung + """Welcome Einstellungen speichern""" await check_admin_permissions(guild_id, data.token) if not is_feature_enabled('features.cogs.server_management.welcome'): - raise HTTPException(status_code=403, detail="Welcome Feature ist in der Bot-Config deaktiviert") + raise HTTPException(status_code=403, detail="Welcome Feature ist deaktiviert") if not welcome_db: raise HTTPException(status_code=500, detail="Welcome Database nicht verfรผgbar") try: - # Konvertierung ch_id = int(data.channel_id) if data.channel_id else None - logger.info(f"๐Ÿ’พ SPEICHERN WELCOME: Guild {guild_id} | Channel: {ch_id}") - # Datenbank speichern success = welcome_db.update_welcome_settings( guild_id, channel_id=ch_id, @@ -380,19 +403,23 @@ async def save_welcome(guild_id: int, data: WelcomeUpdate): raise HTTPException(status_code=500, detail="Fehler beim Speichern") except ValueError: raise HTTPException(status_code=400, detail="Ungรผltige Channel-ID") + except Exception as e: + logger.error(f"Fehler beim Speichern: {e}") + raise HTTPException(status_code=500, detail="Interner Fehler") -# 8. LEVELSYSTEM LADEN (GET) @app.get("/api/guild/{guild_id}/levelsystem") async def get_levelsystem(guild_id: int, token: str = Query(...)): + """Levelsystem Einstellungen laden""" await check_admin_permissions(guild_id, token) if not is_feature_enabled('features.cogs.server_management.levelsystem'): - raise HTTPException(status_code=403, detail="Levelsystem Feature ist in der Bot-Config deaktiviert") + raise HTTPException(status_code=403, detail="Levelsystem Feature ist deaktiviert") if not level_db: raise HTTPException(status_code=500, detail="Levelsystem Database nicht verfรผgbar") settings = level_db.get_guild_config(guild_id) + if not settings: return { "levelsystem_enabled": True, @@ -414,25 +441,21 @@ async def get_levelsystem(guild_id: int, token: str = Query(...)): "prestige_min_level": settings.get('prestige_min_level', 50) } -# 9. LEVELSYSTEM SPEICHERN (POST) @app.post("/api/guild/{guild_id}/levelsystem") async def save_levelsystem(guild_id: int, data: LevelUpdate): - # Admin-Validierung + """Levelsystem Einstellungen speichern""" await check_admin_permissions(guild_id, data.token) if not is_feature_enabled('features.cogs.server_management.levelsystem'): - raise HTTPException(status_code=403, detail="Levelsystem Feature ist in der Bot-Config deaktiviert") + raise HTTPException(status_code=403, detail="Levelsystem Feature ist deaktiviert") if not level_db: raise HTTPException(status_code=500, detail="Levelsystem Database nicht verfรผgbar") try: - # Konvertierung ch_id = int(data.level_up_channel) if data.level_up_channel else None - logger.info(f"๐Ÿ’พ SPEICHERN LEVELSYSTEM: Guild {guild_id} | Channel: {ch_id}") - # Datenbank speichern config = { 'levelsystem_enabled': data.levelsystem_enabled, 'min_xp': data.min_xp, @@ -442,14 +465,14 @@ async def save_levelsystem(guild_id: int, data: LevelUpdate): 'prestige_enabled': data.prestige_enabled, 'prestige_min_level': data.prestige_min_level } - level_db.update_guild_config(guild_id, config) return {"status": "success", "message": "Levelsystem-Einstellungen gespeichert"} except ValueError: raise HTTPException(status_code=400, detail="Ungรผltige Channel-ID") + except Exception as e: + logger.error(f"Fehler beim Speichern: {e}") + raise HTTPException(status_code=500, detail="Interner Fehler") if __name__ == "__main__": - import uvicorn - # log_level="warning" hรคlt die Konsole sauber uvicorn.run(app, host="127.0.0.1", port=3002, log_level="warning") \ No newline at end of file diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 359b611..573cc6d 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -365,4 +365,35 @@ h2::before { font-weight: 600; } +/* --- 21. BUTTON OVERRIDES (From Blue to ManagerX Red) --- */ + +/* Haupt-Buttons (Primary) */ +.btn-primary { + background-color: var(--mx-red-primary) !important; + border-color: var(--mx-red-primary) !important; + color: #ffffff !important; + font-weight: 600; + transition: all 0.2s ease-in-out; +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active { + background-color: var(--mx-red-dark) !important; + border-color: var(--mx-red-dark) !important; + box-shadow: 0 0 0 0.25rem var(--mx-red-glow) !important; +} + +/* Outline-Buttons (z.B. in der Suche oder API-Links) */ +.btn-outline-primary { + color: var(--mx-red-primary) !important; + border-color: var(--mx-red-primary) !important; +} + +.btn-outline-primary:hover { + background-color: var(--mx-red-primary) !important; + border-color: var(--mx-red-primary) !important; + color: #ffffff !important; +} + /* --- END OF MANAGERX ULTIMATE RED THEME --- */ \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 5be075d..33c561f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,7 +7,7 @@ import sys sys.path.insert(0, os.path.abspath('../src')) -sys.setrecursionlimit(1500) +sys.setrecursionlimit(2500) # -- Project information ----------------------------------------------------- project = 'ManagerX' @@ -67,5 +67,5 @@ "icon": "fa-brands fa-square-github", "type": "fontawesome", } - ] + ], } \ No newline at end of file diff --git a/docs/dev_guide/architecture/cog_system.rst b/docs/dev_guide/architecture/cog_system.rst index 5b8f837..99b80ab 100644 --- a/docs/dev_guide/architecture/cog_system.rst +++ b/docs/dev_guide/architecture/cog_system.rst @@ -13,7 +13,7 @@ To create a new cog, developers typically define a class that extends the Cog ba Overall, the cog system is a powerful architectural feature of ManagerX that enhances the bot's flexibility and maintainability, making it easier for developers to manage and expand its capabilities. Py-cord Emample (without Ezcord) -~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: python @@ -34,7 +34,7 @@ Py-cord Emample (without Ezcord) This example demonstrates how to define a simple cog with a command. The `setup` function is used to add the cog to the bot when it is loaded. Ezcord Example (With Py-cord) -~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ With Ezcord, you can simplify cog creation even further: diff --git a/docs/dev_guide/architecture/command_handler.rst b/docs/dev_guide/architecture/command_handler.rst index c635b0c..76c9d5d 100644 --- a/docs/dev_guide/architecture/command_handler.rst +++ b/docs/dev_guide/architecture/command_handler.rst @@ -31,7 +31,7 @@ Py-cord Slash Command Structure for ManagerX ManagerX uses a modular Cog system with Slash Commands (`@slash_command`) for clean, maintainable command handling. Every command is a slash command with automatic parameter parsing, validation, and permission checks. 1. Example Cog with Slash Commands ------------------------------ +------------------------------------ .. code-block:: python @@ -58,7 +58,7 @@ ManagerX uses a modular Cog system with Slash Commands (`@slash_command`) for cl This example demonstrates how to define a cog with multiple Slash Commands. Each command is decorated with `@slash_command`, specifying its name and description. The commands accept parameters, which are automatically parsed and validated by Py-cord. 2. Features Demonstrated ----------------------- +----------------------------- - **Slash Command Registration:** `@discord.slash_command` or `@slash_command` automatically registers commands with Discord. - **Parameter Parsing:** Parameters like `user: discord.Member` are automatically parsed and validated. - **Validation:** Py-cord ensures parameters are of the correct type (e.g., `discord.Member`). diff --git a/docs/dev_guide/contributing/coding_standards.rst b/docs/dev_guide/contributing/coding_standards.rst new file mode 100644 index 0000000..342c716 --- /dev/null +++ b/docs/dev_guide/contributing/coding_standards.rst @@ -0,0 +1,16 @@ +Coding Standards +================ + +To maintain high code quality, please follow these guidelines: + +Python Style +------------ +* **PEP8**: Follow the PEP8 style guide strictly. +* **Naming**: Use meaningful variable and function names. +* **Docstrings**: Add docstrings for all public functions and classes. + +Design Principles +----------------- +* Write **modular** and reusable code. +* Ensure **backward compatibility** wherever possible. +* Keep functions small and focused on a single task. \ No newline at end of file diff --git a/docs/dev_guide/contributing/contributing.rst b/docs/dev_guide/contributing/contributing.rst new file mode 100644 index 0000000..8bd0457 --- /dev/null +++ b/docs/dev_guide/contributing/contributing.rst @@ -0,0 +1,17 @@ +Contributing to ManagerX +======================== + +Welcome to the ManagerX development community! ๐Ÿš€ +Your contributions help make ManagerX better for everyone. Whether you're fixing bugs, adding features, or improving documentation, we value your help. + +.. note:: + This project is permanently under development. We encourage developers to explore these resources and contribute to the growth and improvement of ManagerX! + + +Additional Information +---------------------- + +* :doc:`code_of_conduct` +* `Issue Tracker (GitHub) `_ + +Thank you for contributing! \ No newline at end of file diff --git a/docs/dev_guide/contributing/documentation.rst b/docs/dev_guide/contributing/documentation.rst new file mode 100644 index 0000000..50797e5 --- /dev/null +++ b/docs/dev_guide/contributing/documentation.rst @@ -0,0 +1,13 @@ +Documentation Guide +=================== + +Good documentation is just as important as good code. + +Guidelines +---------- +* **Update Docs**: If your changes affect functionality, update the relevant files. +* **Examples**: Add examples for new commands or features. +* **Format**: Use the same **reStructuredText** format as used here. + +.. hint:: + Always proofread your documentation for clarity and grammar before submitting. \ No newline at end of file diff --git a/docs/dev_guide/contributing/index.rst b/docs/dev_guide/contributing/index.rst deleted file mode 100644 index 922f427..0000000 --- a/docs/dev_guide/contributing/index.rst +++ /dev/null @@ -1,106 +0,0 @@ -Contributing to ManagerX -======================== - -Welcome to the ManagerX development community! This section provides guidelines and best practices for contributing to the ManagerX project. Whether you're fixing bugs, adding new features, or improving documentation, your contributions are valuable and appreciated. - -How to Contribute ------------------ - -1. Fork the Repository - Start by forking the ManagerX repository on GitHub to create your own copy of the project. - -2. Clone Your Fork - Clone your forked repository to your local machine using the following command:: - - git clone https://github.com/Oppro-net-Development/ManagerX.git - -3. Create a New Branch - Before making any changes, create a new branch for your work. This helps keep your changes organized and separate from the main codebase:: - - git checkout -b feature/your-feature-name - -4. Make Your Changes - Implement your changes in the codebase. Ensure that your code follows the project's coding standards and best practices. - -5. Test Your Changes - Thoroughly test your changes to ensure they work as expected and do not introduce any new issues. - -6. Commit Your Changes - Once you're satisfied with your changes, commit them to your branch with a descriptive commit message:: - - git add . - git commit -m "Add feature: your feature description" - -7. Push Your Changes - Push your branch to your forked repository on GitHub:: - - git push origin feature/your-feature-name - -8. Create a Pull Request - Navigate to the original ManagerX repository on GitHub and create a pull request from your forked repository. Provide a clear description of your changes and any relevant context. - -9. Address Feedback - Be prepared to address any feedback or requests for changes from the project maintainers. Collaboration is key to maintaining a high-quality codebase. - -10. Celebrate Your Contribution - Once your pull request is merged, celebrate your contribution to the ManagerX project! - -Issue Reporting ---------------- - -If you encounter any bugs or issues while using ManagerX, please report them on the GitHub repository: - -- Go to the `Issues `_ tab. -- Check if the issue has already been reported. -- If not, create a new issue with a **descriptive title** and detailed description. -- Include steps to reproduce the issue, expected behavior, and actual behavior. -- Attach any relevant logs or screenshots if applicable. - -Coding Standards ----------------- - -To maintain code quality, please follow these guidelines: - -- Follow PEP8 style guide for Python code. -- Use meaningful variable and function names. -- Write modular and reusable code. -- Add docstrings for all public functions and classes. -- Ensure backward compatibility wherever possible. - -Testing -------- - -- Write unit tests for new features and bug fixes. -- Ensure all existing tests pass before submitting a pull request. -- Use pytest or the built-in unittest framework. -- Document how to run tests in your pull request description. - -Documentation -------------- - -Good documentation is crucial for maintaining ManagerX: - -- Update existing documentation if your changes affect it. -- Add examples for new commands or features. -- Use the same reStructuredText format as in the `Developer Guide `_. -- Proofread for clarity and grammar. - -Resources ---------- - -- `ManagerX GitHub Repository `_ -- `Developer Guide `_ -- `Issue Tracker `_ -- `Code of Conduct `_ - -Community Guidelines -------------------- - -We value a positive and inclusive community. Please adhere to the following guidelines when contributing to ManagerX: - -- Be respectful and considerate in all interactions. -- Follow the project's code of conduct. -- Provide constructive feedback and be open to receiving it. -- Collaborate and communicate effectively with other contributors. - -Thank you for contributing to ManagerX! Your efforts help make this project better for everyone. diff --git a/docs/dev_guide/contributing/testing.rst b/docs/dev_guide/contributing/testing.rst new file mode 100644 index 0000000..5e45588 --- /dev/null +++ b/docs/dev_guide/contributing/testing.rst @@ -0,0 +1,24 @@ +Quality Assurance & Testing +=========================== + +In ManagerX, we focus on manual verification and functional integrity rather than using external testing libraries. + +How to Verify Your Changes +-------------------------- + +Before submitting a Pull Request, please ensure the following: + +1. **Manual Functional Test**: + Run the application and manually trigger the feature you changed. Verify that it behaves exactly as described in your PR. + +2. **No Regression**: + Check that your changes do not break existing core functionalities of ManagerX. + +3. **Log Check**: + Monitor the console output or log files while running your changes to ensure no new warnings or errors are being triggered. + +4. **Environment Check**: + Ensure your code runs in the standard development environment without requiring additional, unlisted dependencies. + +.. warning:: + Code that causes the application to crash or introduces obvious logic errors will be sent back for revision. \ No newline at end of file diff --git a/docs/dev_guide/contributing/workflow.rst b/docs/dev_guide/contributing/workflow.rst new file mode 100644 index 0000000..4ce24db --- /dev/null +++ b/docs/dev_guide/contributing/workflow.rst @@ -0,0 +1,41 @@ +Development Workflow +==================== + +Follow these 10 steps to contribute your changes to ManagerX. + +How to Contribute +----------------- + +1. **Fork the Repository**: Create your copy on GitHub. +2. **Clone Your Fork**: + .. code-block:: bash + + git clone https://github.com/Oppro-net-Development/ManagerX.git + +3. **Create a New Branch**: + .. code-block:: bash + + git checkout -b feature/your-feature-name + +4. **Make Your Changes**: Follow our coding standards. +5. **Test Your Changes**: Ensure everything works. +6. **Commit Your Changes**: + .. code-block:: bash + + git add . + git commit -m "Add feature: your description" + +7. **Push Your Changes**: + .. code-block:: bash + + git push origin feature/your-feature-name + +8. **Create a Pull Request**: Navigate to the original ManagerX repo. +9. **Address Feedback**: Collaborate with maintainers. +10. **Celebrate!** ๐ŸŽ‰ + +Issue Reporting +--------------- + +If you encounter any bugs, please report them on the `GitHub Issues `_ tab. +Include steps to reproduce, expected behavior, and logs. \ No newline at end of file diff --git a/docs/dev_guide/index.rst b/docs/dev_guide/index.rst index aecea91..5989969 100644 --- a/docs/dev_guide/index.rst +++ b/docs/dev_guide/index.rst @@ -1,13 +1,50 @@ Developer Guide ========================= -Welcome to the ManagerX Developer Guide! This section provides in-depth information for developers looking to contribute to or extend ManagerX, including architecture overviews, API references, and development best practices. + +Welcome to the ManagerX Developer Guide! This section provides in-depth information for developers looking to contribute to or extend ManagerX. + +.. note:: + This project is permanently under development. We recommend checking this guide frequently for updates. .. toctree:: - :maxdepth: 3 - :caption: Developer Guide: + :maxdepth: 2 + :caption: Getting Started: - Architecture - Contributing - Database + Installation + Development Setup + Quickstart Guide + +.. toctree:: + :maxdepth: 2 + :caption: Architecture: + + Architecture Overview API Reference +.. toctree:: + :maxdepth: 2 + :titlesonly: + :caption: Contribution: + + Contribution + Workflow + Coding Standards + Testing Procedures + Documentation Guidelines + +.. toctree:: + :maxdepth: 2 + :caption: Advanced Topics: + + Performance Optimization + Security Best Practices + +.. toctree:: + :maxdepth: 1 + :caption: Community & Support: + + FAQ + Glossary + Support Channels + +We encourage all developers to actively participate in the ManagerX community. Your contributions help make ManagerX better for everyone! \ No newline at end of file diff --git a/docs/dev_guide/installation/index.rst b/docs/dev_guide/installation/index.rst new file mode 100644 index 0000000..8f0b1de --- /dev/null +++ b/docs/dev_guide/installation/index.rst @@ -0,0 +1,11 @@ +installation of ManagerX +=============================== + +This guide explains how to install ManagerX on your system. + +.. toctree:: + :maxdepth: 2 + :caption: Installation Methods: + + Install from Source Code + Dependencies & Requirements \ No newline at end of file diff --git a/docs/dev_guide/installation/install_from_source.rst b/docs/dev_guide/installation/install_from_source.rst new file mode 100644 index 0000000..c50f23e --- /dev/null +++ b/docs/dev_guide/installation/install_from_source.rst @@ -0,0 +1,105 @@ +============================= +Install from Source Code +============================= + +This guide explains how to install **ManagerX** directly from its source code. This method is ideal for developers looking to contribute or those who require the latest features from the repository. + +.. note:: + If you encounter any issues during installation, please check our Troubleshooting section or open an issue on GitHub. + +Prerequisites +------------- + +Before proceeding, ensure you have the following installed on your system: + +* **Python 3.10** or higher +* **Git** +* A valid **Discord Bot Token** from the `Discord Developer Portal `_ + +Cloning the Repository +---------------------- + +First, clone the ManagerX repository from GitHub and navigate into the project directory: + +.. code-block:: bash + + git clone https://github.com/Oppro-net-Development/ManagerX.git + cd ManagerX + +Setting Up a Virtual Environment +-------------------------------- + +It is highly recommended to use a virtual environment to isolate dependencies and avoid conflicts with your system's Python packages. + +**On Linux/macOS:** + +.. code-block:: bash + + python3 -m venv venv + source venv/bin/activate + +**On Windows:** + +.. code-block:: bash + + python -m venv venv + .\venv\Scripts\activate + +Installing Dependencies +----------------------- + +ManagerX uses modular requirement files depending on your use case. Choose **one** of the following options: + +**1. Standard Installation** +Basic requirements for running the application: + +.. code-block:: bash + + pip install -r requirements/req.txt + +**2. Bot Only** +Minimal requirements to run only the Discord bot component: + +.. code-block:: bash + + pip install -r requirements/bot_req.txt + +**3. Development Environment** +Includes testing frameworks and code formatters (e.g., black, pytest): + +.. code-block:: bash + + pip install -r requirements/dev_req.txt + +**4. Documentation Tools** +Includes tools like Sphinx for building the documentation: + +.. code-block:: bash + + pip install -r requirements/docs_req.txt + +Configuration +------------- + +Before running the bot, you need to set up your environment variables. + +1. Create a ``.env`` file in the root directory. +2. Add your bot token as follows: + +.. code-block:: text + + TOKEN=your_discord_bot_token_here + +Running ManagerX +---------------- + +Once the installation and configuration are complete, start the application: + +.. code-block:: bash + + python main.py + +You should see an output indicating that **ManagerX** is successfully connected to Discord. + +.. tip:: + Ensure that **Privileged Gateway Intents** (Member, Presence, Message Content) are enabled in the Discord Developer Portal under the "Bot" tab, or the bot may not function correctly. \ No newline at end of file diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst index ee7d819..b27cbc7 100644 --- a/docs/plugins/index.rst +++ b/docs/plugins/index.rst @@ -1,21 +1,47 @@ Available Plugins for ManagerX -================================ +============================== No Plugins Available ๐Ÿ˜ฅ ------------------------- +----------------------- -At the moment, there are no plugins available for ManagerX. Please check back later for updates! -We are actively working on developing plugins to enhance the functionality of ManagerX. Stay tuned for future releases! +At the moment, there are **no plugins available** for ManagerX. +We are actively working on developing a variety of plugins to expand the functionality of ManagerX. +Stay tuned for future releases! -Code your Own Plugins +Code Your Own Plugins +--------------------- + +If you're interested in creating your own plugins for ManagerX, the **Developer Guide** provides detailed instructions, examples, and best practices. +Read the `Own Plugins Guide `_ to get started on building custom plugins tailored to your needs. + +Submitting Your Plugin ---------------------- -If you're interested in creating your own plugins for ManagerX, please refer to our Developer Guide for detailed instructions and best practices. -Read the `own Plugins Guide `_ to get started on building custom plugins tailored to your needs! +Once your plugin is ready and tested, you can submit it to the ManagerX team for review: + +1. **Ensure your plugin meets all requirements** + - Follows the **ManagerX Plugin Guidelines** (safety, structure, versioning, documentation). + - Verified to be **free of malicious code**. + +2. **Prepare a repository** + - Include your plugin code in a clean GitHub repository. + - Provide a `README.md` and any required metadata (e.g., `pyproject.toml` for PyPI plugins). + +3. **Submit for review via Discord** + - Join the **OPPRO.NET Development** Discord server. + - Go to the `#plugins` channel. + - Submit your plugin repository **with the tag `ManagerX`**. + - The ManagerX team will review your submission for **quality, security, and compliance**. + +4. **Approval & Listing** + - Approved plugins will be listed in the **Official Plugins** section of the docs. + - Plugins that are safe but not officially endorsed may appear in the **Other Plugins** section. .. toctree:: :maxdepth: 2 :caption: Plugin Documentation: :hidden: - Own Plugins Guide \ No newline at end of file + Own Plugins Guide + Official Plugins + Other Plugins diff --git a/docs/plugins/official_plugins/managerx_handler.rst b/docs/plugins/official_plugins/managerx_handler.rst new file mode 100644 index 0000000..a6cb9c0 --- /dev/null +++ b/docs/plugins/official_plugins/managerx_handler.rst @@ -0,0 +1,50 @@ +========================== +ManagerX-Handler (Official) +========================== + +**The Definitive Integration Layer for the ManagerX Ecosystem** + +Official Core Distribution +-------------------------- + +The **ManagerX-Handler** is the officially maintained plugin developed and issued by the **OPPRO.NET Development Team (ManagerX)**. It serves as the authoritative bridge between the ManagerX management system and your local platform. + +As an official distribution, this handler is engineered to the exact specifications of the ManagerX core, ensuring 100% compatibility, high-level security, and high-performance resource monitoring. + +Key Features +------------ + +* **Native Integration**: Direct, low-latency communication with the ManagerX API. +* **Official Maintenance**: Guaranteed compatibility with all future ManagerX updates. +* **Resource Monitoring**: Optimized for real-time tracking and seamless data synchronization. +* **Enterprise Standards**: Standardized deployment suitable for both production and development environments. + +Installation +------------ + +The ManagerX-Handler is distributed via PyPi for secure and version-controlled deployment. + +.. code-block:: bash + + pip install managerx-handler + +*Note: To ensure system stability, always verify you are installing the official package from the OPPRO.NET PyPi repository.* + +Usage & Implementation +---------------------- + +Once installed, the ManagerX-Handler integrates as a core component of your environment. It automatically establishes the necessary communication hooks for platform interoperability. + +For detailed API references and advanced implementation guides, please refer to the official documentation provided by the **OPPRO.NET Development Team**. + +Support & Contact +----------------- + +As this is an official product, we provide dedicated support for our ecosystem. + +* **Lead Developers**: OPPRO.NET Development Team +* **Official Support**: development@oppro-network.de +* **Official Website**: https://oppro.net + +Copyright (c) 2026 OPPRO.NET Network | All Rights Reserved. +*This software is an official release. Unauthorized redistribution or modification is strictly prohibited.* \ No newline at end of file diff --git a/docs/plugins/own_plugins/create_local_plugin.rst b/docs/plugins/own_plugins/create_local_plugin.rst index 3567cc8..2da8bae 100644 --- a/docs/plugins/own_plugins/create_local_plugin.rst +++ b/docs/plugins/own_plugins/create_local_plugin.rst @@ -1,5 +1,5 @@ Local Plugins (Main GitHub Repository) -===================================== +================================================ In addition to PyPI-based plugins, ManagerX also supports **local plugins** that live directly inside the **main GitHub repository**. @@ -12,7 +12,7 @@ These plugins are intended for: Local plugins are **not enabled or shipped by default**. Design Principle ----------------- +-------------------------------- Local plugins follow the same core philosophy as external plugins: @@ -23,7 +23,7 @@ Local plugins follow the same core philosophy as external plugins: This keeps the ManagerX core clean while still allowing flexibility and experimentation. Repository Structure --------------------- +------------------------------------ Local plugins are stored in a dedicated folder inside the main GitHub repository. @@ -47,7 +47,7 @@ Example structure: Local plugins **must not** modify core files directly. Enabling Local Plugins ----------------------- +-------------------------------------- Local plugins are **disabled by default**. @@ -59,7 +59,7 @@ To enable a local plugin: Only explicitly enabled plugins are loaded. Differences to PyPI Plugins ---------------------------- +------------------------------------------- +-------------------+------------------------+-------------------------+ | Feature | Local Plugins | PyPI Plugins | @@ -76,7 +76,7 @@ Differences to PyPI Plugins +-------------------+------------------------+-------------------------+ Promotion to PyPI ------------------ +--------------------------------- A local plugin can later be **promoted to a PyPI plugin** if it: - proves stable @@ -90,7 +90,7 @@ In this case, it must follow the PyPI naming scheme: managerx-[plugin-name] Conclusion ----------- +-------------------------- Local plugins provide a **safe space for innovation** without increasing the default footprint of ManagerX. @@ -100,12 +100,4 @@ They allow contributors to: - collaborate inside the main repository All without forcing functionality onto every ManagerX user. -Happy coding! ๐Ÿš€ - -.. toctree:: - :maxdepth: 2 - :caption: Next Steps - - Create a PyPi Plugin - - Plugin Guidelines \ No newline at end of file +Happy coding! ๐Ÿš€ \ No newline at end of file diff --git a/docs/plugins/own_plugins/create_pypi_plugin.rst b/docs/plugins/own_plugins/create_pypi_plugin.rst index 93c4ad5..a968f8d 100644 --- a/docs/plugins/own_plugins/create_pypi_plugin.rst +++ b/docs/plugins/own_plugins/create_pypi_plugin.rst @@ -1,10 +1,10 @@ Create your own PyPI Plugin for ManagerX -======================================= +====================================================== ManagerX provides a flexible **plugin system** that allows developers to extend its functionality without modifying the core project. Plugins are developed as **separate Python packages** and distributed via **PyPI**. Plugin Philosophy ------------------ +-------------------------- Plugins are **not included by default** in ManagerX. @@ -16,7 +16,7 @@ This is an intentional design decision to keep ManagerX: Every plugin is installed **explicitly by the user** and lives outside the core project. Plugin Naming Convention ------------------------- +--------------------------- All ManagerX plugins **must** follow this naming scheme: @@ -35,7 +35,7 @@ This naming convention ensures: - automatic recognition by ManagerX Plugin Examples on GitHub -------------------------- +---------------------------------- The official ManagerX GitHub repository contains an **examples folder** to help developers get started. @@ -57,7 +57,7 @@ Structure: - examples are **reference implementations**, not production code How Plugins Work ----------------- +------------------- A ManagerX plugin is a **standalone Python package** that: @@ -68,7 +68,7 @@ A ManagerX plugin is a **standalone Python package** that: Once installed, ManagerX scans for compatible plugins and enables them at runtime. Installing a Plugin -------------------- +---------------------------- Plugins are installed like any other PyPI package: @@ -79,7 +79,7 @@ Plugins are installed like any other PyPI package: After installation, restart ManagerX to activate the plugin. Creating Your Own Plugin ------------------------- +------------------------------ 1. Create a new Python project 2. Name it using the required prefix: ``managerx-`` @@ -93,17 +93,10 @@ By following standard Python packaging rules, plugins remain: - easy to remove Conclusion ----------- +---------------- The ManagerX plugin system is designed for **modularity and freedom**. You decide which features you need, and plugins provide them โ€” without bloating the core. Build small, focused plugins and share them with the community ๐Ÿš€ Happy coding! - -.. toctree:: - :maxdepth: 2 - :caption: Next Steps - - Local Cog Development - Plugin Guidelines \ No newline at end of file diff --git a/docs/plugins/own_plugins/index.rst b/docs/plugins/own_plugins/index.rst index 34ceadf..1a64e56 100644 --- a/docs/plugins/own_plugins/index.rst +++ b/docs/plugins/own_plugins/index.rst @@ -14,21 +14,21 @@ Before you begin, make sure you have: - Familiarity with the ManagerX bot architecture 1. Set Up Your Development Environment -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Install all dependencies required by ManagerX. - Clone the ManagerX repository from GitHub to get the latest codebase. - For PyPi plugins, ensure you have `setuptools` and `wheel` installed to package your plugin. 2. Understand the Plugin Structure -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - **Local Cogs**: look inside the `cogs` or `plugins` directory. Each plugin is typically a single Python file or module. - **PyPi Plugins**: structure your project like a standard Python package with a `setup.py` or `pyproject.toml` file. - Review existing plugins to understand naming conventions, commands, and event listeners. 3. Create Your Plugin -~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~ **Local Cog Example:** @@ -54,7 +54,7 @@ Before you begin, make sure you have: - Make sure your Cog is loaded automatically when installed 4. Register Your Plugin -~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - **Local Cogs**: add the Cog in your botโ€™s `setup` function or main script. - **PyPi Plugins**: once installed via `pip`, ensure ManagerX can discover and load your plugin dynamically. @@ -72,6 +72,6 @@ Best Practices :maxdepth: 2 :caption: Next Steps - Create a PyPi Plugin - Local Cog Development + Create a PyPi Plugin + Local Cog Development Plugin Guidelines \ No newline at end of file diff --git a/docs/plugins/own_plugins/plugin_guidelines.rst b/docs/plugins/own_plugins/plugin_guidelines.rst index 79e4c1b..49e36ae 100644 --- a/docs/plugins/own_plugins/plugin_guidelines.rst +++ b/docs/plugins/own_plugins/plugin_guidelines.rst @@ -1,5 +1,5 @@ Plugin Policy -============= +============================================ This document defines the official rules and requirements for all ManagerX plugins, including **Local Plugins** and **PyPI Plugins**. @@ -12,20 +12,20 @@ The goal of this policy is to keep ManagerX: Plugins are never part of the core by default. ---- +------------------------------------------------------------------------------------------------------------------- General Principles ------------------- +---------------------------------- - All plugins are **optional**. - All plugins are **disabled by default**. - The ManagerX core must never depend on plugins. - Plugins must not modify or patch core files. ---- +--------------------------------------------------------------------------------------------------- Plugin Types ------------- +---------------------------- ManagerX supports two types of plugins: @@ -53,20 +53,20 @@ ManagerX supports two types of plugins: - Fully independent and always stored in their own GitHub repository ---- +----------------------------------------------------------------------------------- License -------- +----------------------- - ManagerX itself is licensed under **GPL-3.0**. - Local Plugins included in the repository **must also be GPL-3.0 compatible**. - PyPI Plugins can use any license **compatible with GPL-3.0**. - Plugins without a clear license will **not be accepted**. ---- +----------------------------------------------------------------------------------- Source Code Separation Requirement ----------------------------------- +-------------------------------------------------- All plugins, whether Local or PyPI, must have a **dedicated GitHub repository**. @@ -74,10 +74,10 @@ All plugins, whether Local or PyPI, must have a **dedicated GitHub repository**. - The **canonical source** is always the plugin's own repo. - One plugin = one repository. ---- +------------------------------------------------------------------- Ownership & Responsibility --------------------------- +------------------------------------------ - Each plugin must have a clearly defined owner or maintainer. - The owner is responsible for: @@ -86,10 +86,10 @@ Ownership & Responsibility - legal matters - ManagerX does **not** provide support for third-party plugins. ---- +----------------------------------------------------------------------------------- Security Requirements ---------------------- +------------------------------------- Plugins must not: - contain malicious code @@ -97,10 +97,10 @@ Plugins must not: - perform hidden network requests - auto-update without user consent ---- +------------------------------------------------------------------- Versioning Rules ----------------- +-------------------------------- - Every plugin must define a version. - Breaking changes require a major version bump. @@ -109,7 +109,7 @@ Versioning Rules --- Documentation Requirement -------------------------- +----------------------------------------- Each plugin must include a `README.md` that explains: - what the plugin does @@ -119,10 +119,10 @@ Each plugin must include a `README.md` that explains: Plugins without documentation are not accepted. ---- +------------------------------------------------------------------- Compatibility Rules -------------------- +----------------------------------- - Plugins must declare supported ManagerX versions. - Plugins must use only public plugin APIs. @@ -131,7 +131,7 @@ Compatibility Rules --- Enable / Disable & Removal --------------------------- +------------------------------------------ - Plugins must be safely disableable. - Plugins must not block ManagerX startup. @@ -140,7 +140,7 @@ Enable / Disable & Removal --- Official Plugin Status ----------------------- +-------------------------------------- If a plugin fulfills **all requirements** in this policy, it **may** be: @@ -161,7 +161,7 @@ Promotion is evaluated on: --- Final Checklist ---------------- +------------------------------- Before a plugin can be accepted or promoted: @@ -176,15 +176,7 @@ Before a plugin can be accepted or promoted: --- Conclusion ----------- +-------------------------- Local and PyPI plugins provide **modularity and freedom**. -The core remains clean and minimal, while plugins can evolve independently. - -.. toctree:: - :maxdepth: 2 - :caption: Next Steps - - Local Cog Development - - Create a PyPi Plugin \ No newline at end of file +The core remains clean and minimal, while plugins can evolve independently. \ No newline at end of file diff --git a/main.py b/main.py index 780d550..cc5e344 100644 --- a/main.py +++ b/main.py @@ -27,7 +27,7 @@ from ezcord import CogLog import yaml from discord.ext import tasks -from log import logger, LogLevel, LogFormat, Category +from logger import logger, LogLevel, LogFormat, Category BASEDIR = Path(__file__).resolve().parent @@ -36,11 +36,9 @@ # โ— LOKALE BIBLIOTHEKEN try: - from handler import VersionChecker from DevTools import SettingsDB class BotConfig: - VERSION = "2.0.0-dev" TOKEN = os.getenv("TOKEN") except ImportError as e: @@ -206,7 +204,6 @@ async def update_dashboard_data(): stats = { "bot_info": { "name": str(bot.user.name), - "version": BotConfig.VERSION, "status": "online", "latency": round(bot.latency * 1000, 1) }, @@ -243,9 +240,25 @@ async def on_ready(): # ============================================================================= if __name__ == '__main__': - print(f"\n{Fore.CYAN}{'=' * 60}") + # Definieren des Logos als Liste von Strings, um Formatierungsprobleme zu umgehe + logo_lines = [ + r" _____ ______ ________ ________ ________ ________ _______ ________ ___ ___ ", + r"|\ _ \ _ \|\ __ \|\ ___ \|\ __ \|\ ____\|\ ___ \ |\ __ \ |\ \ / /|", + r"\ \ \\\__\ \ \ \ \|\ \ \ \\ \ \ \ \|\ \ \ \___|\ \ __/|\ \ \|\ \ \ \ \/ / /", + r" \ \ \\|__| \ \ \ __ \ \ \\ \ \ \ __ \ \ \ __\ \ _|/_\ \ _ _\ \ \ / / ", + r" \ \ \ \ \ \ \ \ \ \ \ \\ \ \ \ \ \ \ \ \|\ \ \ \_|\ \ \ \\ \| / \/ ", + r" \ \__\ \ \__\ \__\ \__\ \__\\ \__\ \__\ \__\ \_______\ \_______\ \__\\ _\ / /\ \ ", + r" \|__| \|__|\|__|\|__|\|__| \|__|\|__|\|__|\|_______|\|_______|\|__|\|__|/__/ /\ __\ ", + r" |__|/ \|__| " + ] + + # Ausgabe + print(Fore.CYAN) + for line in logo_lines: + print(line) + print(f"{'=' * 91}") print(f" ManagerX Discord Bot v{BotConfig.VERSION}") - print(f"{'=' * 60}{Style.RESET_ALL}\n") + print(f"{'=' * 91}{Style.RESET_ALL}\n") try: db = SettingsDB() @@ -255,7 +268,6 @@ async def on_ready(): logger.critical(Category.DATABASE, f"Datenbankfehler: {e}") # --- GEFIXTER LOAD-PROZESS --- - # EzCord's ignored_cogs filtert gegen den Dateinamen (z.B. "autocomplete") ignored = get_ignored_list(cogs_config) bot.load_cogs( @@ -267,6 +279,7 @@ async def on_ready(): if not BotConfig.TOKEN: logger.critical(Category.DEBUG, "Kein TOKEN gefunden!") + import sys sys.exit(1) bot.run(BotConfig.TOKEN) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 1797abc..d3e6b88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "ManagerX" -version = "2.0.0" +version = "2026.0.1" description = "A powerful Discord bot for server management and fun." readme = "README.md" requires-python = ">=3.8" @@ -44,7 +44,9 @@ dependencies = [ "Jinja2==3.1.6", "MarkupSafe==3.0.3", "starlette==0.50.0", - "timedelta==2020.12.3" + "timedelta==2020.12.3", + "ManagerX-Handler==1.0.4", + "ManagerX-DevTools==1.0.0" ] [project.urls] @@ -133,5 +135,5 @@ package-dir = {"src" = "src"} [tool.setuptools.packages.find] where = ["src"] -include = ["managerx*", "plugins*", "handlers*", "DevTools*", "cogs*"] +include = ["managerx*", "plugins*", "DevTools*", "cogs*"] exclude = ["tests*"] \ No newline at end of file diff --git a/requirements/bot_req.txt b/requirements/bot_req.txt index f40847b..c57a8c7 100644 --- a/requirements/bot_req.txt +++ b/requirements/bot_req.txt @@ -12,3 +12,5 @@ yarl==1.22.0 frozenlist==1.8.0 h11==0.16.0 multidict==6.7.0 +ManagerX-Handler==1.0.1 +ManagerX-DevTools==1.0.0 \ No newline at end of file diff --git a/requirements/dev_req.txt b/requirements/dev_req.txt index 66a6f2f..069cae8 100644 --- a/requirements/dev_req.txt +++ b/requirements/dev_req.txt @@ -17,3 +17,5 @@ FastAPI uvicorn SimpleColoredLogs timedelta==2020.12.3 +ManagerX-Handler==1.0.1 +ManagerX-DevTools==1.0.0 \ No newline at end of file diff --git a/requirements/req.txt b/requirements/req.txt index 174b1e7..ef43f5d 100644 --- a/requirements/req.txt +++ b/requirements/req.txt @@ -12,7 +12,10 @@ yarl==1.22.0 frozenlist==1.8.0 h11==0.16.0 multidict==6.7.0 - +FastAPI==0.128.0 +uvicorn==0.22.0 +ManagerX-Handler==1.0.1 +ManagerX-DevTools==1.0.0 # Dev python-dotenv==1.2.1 diff --git a/src/DevTools/__init__.py b/src/DevTools/__init__.py deleted file mode 100644 index 289902d..0000000 --- a/src/DevTools/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -from .backend import * -from .ui import * \ No newline at end of file diff --git a/src/DevTools/backend/__init__.py b/src/DevTools/backend/__init__.py deleted file mode 100644 index 0c0e07d..0000000 --- a/src/DevTools/backend/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .database import * - -from .config import * - -from .logging import * \ No newline at end of file diff --git a/src/DevTools/backend/config/__init__.py b/src/DevTools/backend/config/__init__.py deleted file mode 100644 index 4fdeb61..0000000 --- a/src/DevTools/backend/config/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -from .links import * -from .permission import * \ No newline at end of file diff --git a/src/DevTools/backend/config/links.py b/src/DevTools/backend/config/links.py deleted file mode 100644 index 543921b..0000000 --- a/src/DevTools/backend/config/links.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -SUPPORT_SERVER = "https://discord.gg/VWR75Tc8DR" -BOT_INVITE = "https://discord.com/oauth2/authorize?client_id=1368201272624287754&permissions=8&integration_type=0&scope=bot" - diff --git a/src/DevTools/backend/config/permission.py b/src/DevTools/backend/config/permission.py deleted file mode 100644 index 2917cd7..0000000 --- a/src/DevTools/backend/config/permission.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -KICK = "kick_members" -BAN = "ban_members" -ADMIN = "administrator" -MANAGE_CHANNELS = "manage_channels" -MANAGE_GUILD = "manage_guild" -ADD_REACT = "add_reactions" -VIEW_AUDIT = "view_audit_log" -PRIORITY_SPEAKER = "priority_speaker" -STREAM = "stream" -VIEW_CHANNEL = "view_channel" -SEND_MSG = "send_messages" -SEND_TTS = "send_tts_messages" -MANAGE_MSG = "manage_messages" -EMBED_LINKS = "embed_links" -ATTACH_FILES = "attach_files" -READ_HISTORY = "read_message_history" -MENTION_ALL = "mention_everyone" -USE_EXT_EMOJIS = "use_external_emojis" -VIEW_INSIGHTS = "view_guild_insights" -CONNECT = "connect" -SPEAK = "speak" -MUTE = "mute_members" -DEAFEN = "deafen_members" -MOVE = "move_members" -USE_VAD = "use_voice_activation" -CHANGE_NICK = "change_nickname" -MANAGE_NICK = "manage_nicknames" -MANAGE_ROLES = "manage_roles" -MANAGE_WEBHOOKS = "manage_webhooks" -MANAGE_EMOJIS = "manage_emojis_and_stickers" -USE_APP_COMMANDS = "use_application_commands" -REQUEST_TO_SPEAK = "request_to_speak" -MANAGE_THREADS = "manage_threads" -USE_PUBLIC_THREADS = "use_public_threads" -USE_PRIVATE_THREADS = "use_private_threads" -USE_EXT_STICKERS = "use_external_stickers" -SEND_MSG_THREADS = "send_messages_in_threads" -START_EMBED_ACT = "start_embedded_activities" -MODERATE = "moderate_members" \ No newline at end of file diff --git a/src/DevTools/backend/database/Stats_db.py b/src/DevTools/backend/database/Stats_db.py deleted file mode 100644 index 748539e..0000000 --- a/src/DevTools/backend/database/Stats_db.py +++ /dev/null @@ -1,476 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import sqlite3 -import asyncio -import json -from datetime import datetime, timedelta -from typing import Optional, List, Tuple, Dict -import logging - -logger = logging.getLogger(__name__) - - -class StatsDB: - """Enhanced database handler for Discord bot statistics with global level system.""" - - def __init__(self, db_file="data/stats.db"): - self.db_file = db_file - self.conn = sqlite3.connect(db_file, check_same_thread=False) - self.cursor = self.conn.cursor() - self.lock = asyncio.Lock() - self._create_tables() - - def _create_tables(self): - """Create all necessary tables for enhanced stats tracking.""" - tables = [ - '''CREATE TABLE IF NOT EXISTS messages ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL, - guild_id INTEGER NOT NULL, - channel_id INTEGER NOT NULL, - message_id INTEGER NOT NULL, - timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, - word_count INTEGER DEFAULT 0, - has_attachment BOOLEAN DEFAULT FALSE, - message_type TEXT DEFAULT 'text' - )''', - - '''CREATE TABLE IF NOT EXISTS voice_sessions ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL, - guild_id INTEGER NOT NULL, - channel_id INTEGER NOT NULL, - start_time DATETIME DEFAULT CURRENT_TIMESTAMP, - end_time DATETIME, - duration_minutes REAL DEFAULT 0 - )''', - - '''CREATE TABLE IF NOT EXISTS global_user_levels ( - user_id INTEGER PRIMARY KEY, - global_level INTEGER DEFAULT 1, - global_xp INTEGER DEFAULT 0, - total_messages INTEGER DEFAULT 0, - total_voice_minutes INTEGER DEFAULT 0, - total_servers INTEGER DEFAULT 0, - first_seen DATETIME DEFAULT CURRENT_TIMESTAMP, - last_activity DATETIME DEFAULT CURRENT_TIMESTAMP, - achievements TEXT DEFAULT '[]', - daily_streak INTEGER DEFAULT 0, - best_streak INTEGER DEFAULT 0, - last_daily_activity DATE - )''', - - '''CREATE TABLE IF NOT EXISTS daily_stats ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL, - guild_id INTEGER NOT NULL, - date DATE NOT NULL, - messages_count INTEGER DEFAULT 0, - voice_minutes REAL DEFAULT 0, - active_hours INTEGER DEFAULT 0, - UNIQUE(user_id, guild_id, date) - )''', - - '''CREATE TABLE IF NOT EXISTS channel_stats ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - channel_id INTEGER NOT NULL, - guild_id INTEGER NOT NULL, - date DATE NOT NULL, - total_messages INTEGER DEFAULT 0, - unique_users INTEGER DEFAULT 0, - avg_words_per_message REAL DEFAULT 0, - UNIQUE(channel_id, date) - )''', - - '''CREATE TABLE IF NOT EXISTS user_achievements ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL, - achievement_name TEXT NOT NULL, - unlocked_at DATETIME DEFAULT CURRENT_TIMESTAMP, - description TEXT, - icon TEXT DEFAULT '๐Ÿ†' - )''', - - '''CREATE TABLE IF NOT EXISTS active_voice_sessions ( - user_id INTEGER PRIMARY KEY, - guild_id INTEGER NOT NULL, - channel_id INTEGER NOT NULL, - start_time DATETIME DEFAULT CURRENT_TIMESTAMP - )''' - ] - - for table_sql in tables: - self.cursor.execute(table_sql) - - # Create indexes for better performance - indexes = [ - 'CREATE INDEX IF NOT EXISTS idx_messages_user_timestamp ON messages(user_id, timestamp)', - 'CREATE INDEX IF NOT EXISTS idx_messages_channel_timestamp ON messages(channel_id, timestamp)', - 'CREATE INDEX IF NOT EXISTS idx_voice_user_timestamp ON voice_sessions(user_id, start_time)', - 'CREATE INDEX IF NOT EXISTS idx_daily_stats_user_date ON daily_stats(user_id, date)', - 'CREATE INDEX IF NOT EXISTS idx_global_levels_xp ON global_user_levels(global_xp DESC)' - ] - - for index_sql in indexes: - self.cursor.execute(index_sql) - - self.conn.commit() - logger.info("Enhanced Stats database initialized") - - async def log_message(self, user_id: int, guild_id: int, channel_id: int, message_id: int, - word_count: int = 0, has_attachment: bool = False, message_type: str = 'text'): - """Log a message and update global XP.""" - async with self.lock: - try: - # Insert message - self.cursor.execute(''' - INSERT INTO messages (user_id, guild_id, channel_id, message_id, word_count, has_attachment, message_type) - VALUES (?, ?, ?, ?, ?, ?, ?) - ''', (user_id, guild_id, channel_id, message_id, word_count, has_attachment, message_type)) - - # Update daily stats - today = datetime.now().date() - self.cursor.execute(''' - INSERT OR IGNORE INTO daily_stats (user_id, guild_id, date, messages_count) - VALUES (?, ?, ?, 1) - ''', (user_id, guild_id, today)) - - self.cursor.execute(''' - UPDATE daily_stats SET messages_count = messages_count + 1 - WHERE user_id = ? AND guild_id = ? AND date = ? - ''', (user_id, guild_id, today)) - - # Update global level system - await self._update_global_xp(user_id, guild_id, 'message', word_count) - - self.conn.commit() - - except Exception as e: - logger.error(f"Error logging message: {e}") - self.conn.rollback() - - async def start_voice_session(self, user_id: int, guild_id: int, channel_id: int): - """Start a voice session.""" - async with self.lock: - try: - # End any existing session first - await self._end_existing_voice_session(user_id) - - # Start new session - self.cursor.execute(''' - INSERT INTO active_voice_sessions (user_id, guild_id, channel_id) - VALUES (?, ?, ?) - ''', (user_id, guild_id, channel_id)) - - self.conn.commit() - - except Exception as e: - logger.error(f"Error starting voice session: {e}") - self.conn.rollback() - - async def end_voice_session(self, user_id: int, channel_id: int): - """End a voice session and calculate duration.""" - async with self.lock: - try: - # Get active session - self.cursor.execute(''' - SELECT guild_id, channel_id, start_time FROM active_voice_sessions - WHERE user_id = ? - ''', (user_id,)) - - session = self.cursor.fetchone() - if not session: - return - - guild_id, session_channel_id, start_time = session - start_datetime = datetime.fromisoformat(start_time) - duration_minutes = (datetime.now() - start_datetime).total_seconds() / 60 - - # Only log if session was longer than 30 seconds - if duration_minutes > 0.5: - # Insert completed session - self.cursor.execute(''' - INSERT INTO voice_sessions (user_id, guild_id, channel_id, start_time, end_time, duration_minutes) - VALUES (?, ?, ?, ?, ?, ?) - ''', (user_id, guild_id, session_channel_id, start_time, datetime.now(), duration_minutes)) - - # Update daily stats - today = datetime.now().date() - self.cursor.execute(''' - INSERT OR IGNORE INTO daily_stats (user_id, guild_id, date, voice_minutes) - VALUES (?, ?, ?, ?) - ''', (user_id, guild_id, today, duration_minutes)) - - self.cursor.execute(''' - UPDATE daily_stats SET voice_minutes = voice_minutes + ? - WHERE user_id = ? AND guild_id = ? AND date = ? - ''', (duration_minutes, user_id, guild_id, today)) - - # Update global XP - await self._update_global_xp(user_id, guild_id, 'voice', duration_minutes) - - # Remove active session - self.cursor.execute('DELETE FROM active_voice_sessions WHERE user_id = ?', (user_id,)) - self.conn.commit() - - except Exception as e: - logger.error(f"Error ending voice session: {e}") - self.conn.rollback() - - async def _end_existing_voice_session(self, user_id: int): - """Helper to end any existing voice session.""" - self.cursor.execute('SELECT channel_id FROM active_voice_sessions WHERE user_id = ?', (user_id,)) - existing = self.cursor.fetchone() - if existing: - await self.end_voice_session(user_id, existing[0]) - - async def _update_global_xp(self, user_id: int, guild_id: int, activity_type: str, value: float = 0): - """Update global XP and level system.""" - try: - # Calculate XP based on activity - xp_gain = 0 - if activity_type == 'message': - base_xp = 1 - word_bonus = min(value * 0.1, 5) # Max 5 bonus XP for long messages - xp_gain = base_xp + word_bonus - elif activity_type == 'voice': - xp_gain = value * 0.5 # 0.5 XP per minute - - # Get current user data - self.cursor.execute(''' - SELECT global_level, global_xp, total_messages, total_voice_minutes, total_servers, last_daily_activity, daily_streak - FROM global_user_levels WHERE user_id = ? - ''', (user_id,)) - - user_data = self.cursor.fetchone() - today = datetime.now().date() - - if user_data: - current_level, current_xp, total_msg, total_voice, total_servers, last_daily, daily_streak = user_data - - # Check for daily streak - if last_daily: - last_date = datetime.strptime(last_daily, '%Y-%m-%d').date() - if today == last_date + timedelta(days=1): - daily_streak += 1 - elif today != last_date: - daily_streak = 1 - else: - daily_streak = 1 - - # Update stats - new_xp = current_xp + xp_gain - new_level = self._calculate_level(new_xp) - - if activity_type == 'message': - total_msg += 1 - elif activity_type == 'voice': - total_voice += value - - # Count unique servers (simplified - you might want to track this differently) - self.cursor.execute('SELECT COUNT(DISTINCT guild_id) FROM messages WHERE user_id = ?', (user_id,)) - server_count = self.cursor.fetchone()[0] or 1 - - self.cursor.execute(''' - UPDATE global_user_levels - SET global_level = ?, global_xp = ?, total_messages = ?, total_voice_minutes = ?, - total_servers = ?, last_activity = ?, last_daily_activity = ?, daily_streak = ?, - best_streak = MAX(best_streak, ?) - WHERE user_id = ? - ''', (new_level, new_xp, total_msg, total_voice, server_count, datetime.now(), - today, daily_streak, daily_streak, user_id)) - - # Check for level up achievements - if new_level > current_level: - await self._check_level_achievements(user_id, new_level) - - else: - # Create new user - initial_level = self._calculate_level(xp_gain) - self.cursor.execute(''' - INSERT INTO global_user_levels - (user_id, global_level, global_xp, total_messages, total_voice_minutes, total_servers, - last_daily_activity, daily_streak, best_streak) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) - ''', (user_id, initial_level, xp_gain, 1 if activity_type == 'message' else 0, - value if activity_type == 'voice' else 0, 1, today, 1, 1)) - - except Exception as e: - logger.error(f"Error updating global XP: {e}") - - def _calculate_level(self, xp: float) -> int: - """Calculate level based on XP using a logarithmic scale.""" - if xp < 0: - return 1 - # Level formula: level = floor(sqrt(xp/100)) + 1 - import math - return int(math.sqrt(xp / 100)) + 1 - - def _xp_for_level(self, level: int) -> int: - """Calculate XP required for a specific level.""" - return (level - 1) ** 2 * 100 - - async def get_user_stats(self, user_id: int, hours: int = 24, guild_id: Optional[int] = None) -> Tuple[int, float]: - """Get user statistics for a time period.""" - async with self.lock: - try: - cutoff_time = datetime.now() - timedelta(hours=hours) - - # Message count - if guild_id: - self.cursor.execute(''' - SELECT COUNT(*) FROM messages - WHERE user_id = ? AND guild_id = ? AND timestamp > ? - ''', (user_id, guild_id, cutoff_time)) - else: - self.cursor.execute(''' - SELECT COUNT(*) FROM messages - WHERE user_id = ? AND timestamp > ? - ''', (user_id, cutoff_time)) - - message_count = self.cursor.fetchone()[0] or 0 - - # Voice time - if guild_id: - self.cursor.execute(''' - SELECT COALESCE(SUM(duration_minutes), 0) FROM voice_sessions - WHERE user_id = ? AND guild_id = ? AND start_time > ? - ''', (user_id, guild_id, cutoff_time)) - else: - self.cursor.execute(''' - SELECT COALESCE(SUM(duration_minutes), 0) FROM voice_sessions - WHERE user_id = ? AND start_time > ? - ''', (user_id, cutoff_time)) - - voice_minutes = self.cursor.fetchone()[0] or 0 - - return message_count, voice_minutes - - except Exception as e: - logger.error(f"Error getting user stats: {e}") - return 0, 0 - - async def get_global_user_info(self, user_id: int) -> Optional[Dict]: - """Get global user information including level and achievements.""" - async with self.lock: - try: - self.cursor.execute(''' - SELECT global_level, global_xp, total_messages, total_voice_minutes, total_servers, - daily_streak, best_streak, first_seen, achievements - FROM global_user_levels WHERE user_id = ? - ''', (user_id,)) - - result = self.cursor.fetchone() - if not result: - return None - - level, xp, total_msg, total_voice, servers, streak, best_streak, first_seen, achievements = result - - # Calculate XP for next level - next_level_xp = self._xp_for_level(level + 1) - current_level_xp = self._xp_for_level(level) - xp_progress = xp - current_level_xp - xp_needed = next_level_xp - current_level_xp - - return { - 'level': level, - 'xp': xp, - 'xp_progress': xp_progress, - 'xp_needed': xp_needed, - 'total_messages': total_msg, - 'total_voice_minutes': total_voice, - 'total_servers': servers, - 'daily_streak': streak, - 'best_streak': best_streak, - 'first_seen': first_seen, - 'achievements': json.loads(achievements) if achievements else [] - } - - except Exception as e: - logger.error(f"Error getting global user info: {e}") - return None - - async def get_leaderboard(self, limit: int = 10, guild_id: Optional[int] = None) -> List[Tuple]: - """Get global or guild-specific leaderboard.""" - async with self.lock: - try: - if guild_id: - # Guild-specific leaderboard based on recent activity - self.cursor.execute(''' - SELECT user_id, COUNT(*) as messages, - COALESCE(SUM(word_count), 0) as total_words - FROM messages - WHERE guild_id = ? AND timestamp > datetime('now', '-30 days') - GROUP BY user_id - ORDER BY messages DESC - LIMIT ? - ''', (guild_id, limit)) - else: - # Global leaderboard - self.cursor.execute(''' - SELECT user_id, global_level, global_xp, total_messages, total_voice_minutes - FROM global_user_levels - ORDER BY global_xp DESC - LIMIT ? - ''', (limit,)) - - return self.cursor.fetchall() - - except Exception as e: - logger.error(f"Error getting leaderboard: {e}") - return [] - - async def _check_level_achievements(self, user_id: int, new_level: int): - """Check and award level-based achievements.""" - achievements = [] - - level_milestones = { - 5: ("Newcomer", "Reached level 5!", "๐ŸŒŸ"), - 10: ("Regular", "Reached level 10!", "โญ"), - 25: ("Veteran", "Reached level 25!", "๐Ÿ…"), - 50: ("Expert", "Reached level 50!", "๐Ÿ†"), - 100: ("Legend", "Reached level 100!", "๐Ÿ‘‘") - } - - for milestone, (name, desc, icon) in level_milestones.items(): - if new_level >= milestone: - # Check if already has this achievement - self.cursor.execute(''' - SELECT id FROM user_achievements - WHERE user_id = ? AND achievement_name = ? - ''', (user_id, name)) - - if not self.cursor.fetchone(): - self.cursor.execute(''' - INSERT INTO user_achievements (user_id, achievement_name, description, icon) - VALUES (?, ?, ?, ?) - ''', (user_id, name, desc, icon)) - achievements.append((name, desc, icon)) - - return achievements - - async def cleanup_old_data(self, days: int = 90): - """Clean up old data to keep database size manageable.""" - async with self.lock: - try: - cutoff_date = datetime.now() - timedelta(days=days) - - # Clean old messages (keep recent ones for stats) - self.cursor.execute('DELETE FROM messages WHERE timestamp < ?', (cutoff_date,)) - - # Clean old daily stats - self.cursor.execute('DELETE FROM daily_stats WHERE date < ?', (cutoff_date.date(),)) - - # Clean old voice sessions - self.cursor.execute('DELETE FROM voice_sessions WHERE start_time < ?', (cutoff_date,)) - - self.conn.commit() - logger.info(f"Cleaned up data older than {days} days") - - except Exception as e: - logger.error(f"Error cleaning up old data: {e}") - - def close(self): - """Close database connection.""" - if self.conn: - self.conn.close() - logger.info("Enhanced Stats database connection closed") \ No newline at end of file diff --git a/src/DevTools/backend/database/__init__.py b/src/DevTools/backend/database/__init__.py deleted file mode 100644 index 0bd4d49..0000000 --- a/src/DevTools/backend/database/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -from .vc_db import * -from .warn_db import * -from .spam_db import * -from .notes_db import * -from .Stats_db import * -from .globalchat_db import db as GlobalChatDatabase -from .levelsystem_db import * -from .logging_db import * -from .autodelete_db import * -from .welcome_db import * -from .lang_db import * -from .autorole_db import AutoRoleDatabase \ No newline at end of file diff --git a/src/DevTools/backend/database/autodelete_db.py b/src/DevTools/backend/database/autodelete_db.py deleted file mode 100644 index 9f4f73d..0000000 --- a/src/DevTools/backend/database/autodelete_db.py +++ /dev/null @@ -1,843 +0,0 @@ -import sqlite3 -import json -from datetime import datetime - - -class AutoDeleteDB: - """ - Database manager for AutoDelete functionality in Discord channels. - - Manages AutoDelete configurations, whitelists, schedules, and statistics - for automatic message deletion in Discord channels. - - Parameters - ---------- - db_file : str, optional - Path to the SQLite database file (default: "data/autodelete.db") - - Attributes - ---------- - db_file : str - Path to the database file - conn : sqlite3.Connection - Active database connection - cursor : sqlite3.Cursor - Database cursor for operations - - Examples - -------- - >>> db = AutoDeleteDB("my_database.db") - >>> db.add_autodelete(channel_id=123456, duration=3600) - >>> db.close() - - Or using context manager: - >>> with AutoDeleteDB() as db: - ... db.add_autodelete(channel_id=123456, duration=3600) - """ - - def __init__(self, db_file="data/autodelete.db"): - self.db_file = db_file - self.conn = sqlite3.connect(db_file) - self.cursor = self.conn.cursor() - self._create_tables() - - def _create_tables(self): - """ - Create all required database tables. - - Creates the following tables if they don't exist: - - autodelete: Main configuration - - autodelete_whitelist: Whitelist for roles/users - - autodelete_schedules: Time schedules - - autodelete_stats: Statistics - - Notes - ----- - This method is automatically called during initialization. - """ - self.cursor.execute(''' - CREATE TABLE IF NOT EXISTS autodelete ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - channel_id INTEGER NOT NULL UNIQUE, - duration INTEGER NOT NULL, - exclude_pinned BOOLEAN DEFAULT 1, - exclude_bots BOOLEAN DEFAULT 0, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) - ''') - - self.cursor.execute(''' - CREATE TABLE IF NOT EXISTS autodelete_whitelist ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - channel_id INTEGER NOT NULL, - target_id INTEGER NOT NULL, - target_type TEXT NOT NULL CHECK (target_type IN ('role', 'user')), - added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (channel_id) REFERENCES autodelete (channel_id) ON DELETE CASCADE, - UNIQUE (channel_id, target_id, target_type) - ) - ''') - - self.cursor.execute(''' - CREATE TABLE IF NOT EXISTS autodelete_schedules ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - channel_id INTEGER NOT NULL, - start_time TEXT NOT NULL, - end_time TEXT NOT NULL, - days TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (channel_id) REFERENCES autodelete (channel_id) ON DELETE CASCADE - ) - ''') - - self.cursor.execute(''' - CREATE TABLE IF NOT EXISTS autodelete_stats ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - channel_id INTEGER NOT NULL UNIQUE, - deleted_count INTEGER DEFAULT 0, - error_count INTEGER DEFAULT 0, - last_deletion TIMESTAMP, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (channel_id) REFERENCES autodelete (channel_id) ON DELETE CASCADE - ) - ''') - - self.conn.commit() - self._migrate_old_data() - - def _migrate_old_data(self): - """ - Migrate old data to new structure. - - Adds missing columns to existing autodelete table if they don't exist. - This ensures backward compatibility with older database versions. - - Notes - ----- - Errors during migration are printed to console but don't halt execution. - """ - try: - columns = [description[1] for description in - self.cursor.execute("PRAGMA table_info(autodelete)").fetchall()] - - if 'exclude_pinned' not in columns: - self.cursor.execute('ALTER TABLE autodelete ADD COLUMN exclude_pinned BOOLEAN DEFAULT 1') - if 'exclude_bots' not in columns: - self.cursor.execute('ALTER TABLE autodelete ADD COLUMN exclude_bots BOOLEAN DEFAULT 0') - if 'created_at' not in columns: - self.cursor.execute('ALTER TABLE autodelete ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP') - if 'updated_at' not in columns: - self.cursor.execute('ALTER TABLE autodelete ADD COLUMN updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP') - - self.conn.commit() - except sqlite3.Error as e: - print(f"Migration error: {e}") - - # === MAIN FUNCTIONS === - - def add_autodelete(self, channel_id, duration, exclude_pinned=True, exclude_bots=False): - """ - Add or update AutoDelete configuration for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - duration : int - Time in seconds before messages are deleted - exclude_pinned : bool, optional - Whether to exclude pinned messages from deletion (default: True) - exclude_bots : bool, optional - Whether to exclude bot messages from deletion (default: False) - - Notes - ----- - If a configuration for the channel already exists, it will be updated. - Automatically creates a statistics entry if one doesn't exist. - - Examples - -------- - >>> db.add_autodelete(channel_id=123456, duration=3600) - >>> db.add_autodelete(channel_id=789012, duration=7200, exclude_bots=True) - """ - self.cursor.execute(''' - INSERT OR REPLACE INTO autodelete - (channel_id, duration, exclude_pinned, exclude_bots, updated_at) - VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) - ''', (channel_id, duration, exclude_pinned, exclude_bots)) - - self.cursor.execute(''' - INSERT OR IGNORE INTO autodelete_stats (channel_id) - VALUES (?) - ''', (channel_id,)) - - self.conn.commit() - - def get_autodelete(self, channel_id): - """ - Get AutoDelete duration for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - - Returns - ------- - int or None - Duration in seconds, or None if no configuration exists - - Notes - ----- - This method is for backward compatibility. Use `get_autodelete_full()` - for complete configuration details. - - Examples - -------- - >>> duration = db.get_autodelete(123456) - >>> if duration: - ... print(f"Messages deleted after {duration} seconds") - """ - self.cursor.execute("SELECT duration FROM autodelete WHERE channel_id=?", (channel_id,)) - result = self.cursor.fetchone() - return result[0] if result else None - - def get_autodelete_full(self, channel_id): - """ - Get complete AutoDelete configuration for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - - Returns - ------- - tuple or None - Tuple of (duration, exclude_pinned, exclude_bots) or None if not found - - Examples - -------- - >>> config = db.get_autodelete_full(123456) - >>> if config: - ... duration, exclude_pinned, exclude_bots = config - ... print(f"Duration: {duration}s, Exclude pinned: {exclude_pinned}") - """ - self.cursor.execute(''' - SELECT duration, exclude_pinned, exclude_bots - FROM autodelete WHERE channel_id=? - ''', (channel_id,)) - return self.cursor.fetchone() - - def remove_autodelete(self, channel_id): - """ - Remove AutoDelete configuration and all associated data. - - Parameters - ---------- - channel_id : int - Discord channel ID - - Notes - ----- - This cascades to delete all associated whitelist entries, schedules, - and statistics for the channel due to foreign key constraints. - - Examples - -------- - >>> db.remove_autodelete(123456) - """ - self.cursor.execute("DELETE FROM autodelete WHERE channel_id=?", (channel_id,)) - self.conn.commit() - - def get_all(self): - """ - Get all AutoDelete configurations. - - Returns - ------- - list of tuple - List of tuples containing (channel_id, duration, exclude_pinned, exclude_bots) - sorted by channel_id - - Examples - -------- - >>> configs = db.get_all() - >>> for channel_id, duration, exclude_pinned, exclude_bots in configs: - ... print(f"Channel {channel_id}: {duration}s") - """ - self.cursor.execute(''' - SELECT channel_id, duration, exclude_pinned, exclude_bots - FROM autodelete ORDER BY channel_id - ''') - return self.cursor.fetchall() - - # === WHITELIST FUNCTIONS === - - def add_to_whitelist(self, channel_id, target_id, target_type): - """ - Add an entry to the whitelist. - - Parameters - ---------- - channel_id : int - Discord channel ID - target_id : int - Discord role ID or user ID - target_type : {'role', 'user'} - Type of the whitelist target - - Raises - ------ - ValueError - If target_type is not 'role' or 'user' - - Notes - ----- - Whitelisted roles/users will not have their messages auto-deleted. - Duplicate entries are silently ignored. - - Examples - -------- - >>> db.add_to_whitelist(channel_id=123456, target_id=789012, target_type='role') - >>> db.add_to_whitelist(channel_id=123456, target_id=345678, target_type='user') - """ - if target_type not in ['role', 'user']: - raise ValueError("target_type must be 'role' or 'user'") - - self.cursor.execute(''' - INSERT OR IGNORE INTO autodelete_whitelist - (channel_id, target_id, target_type) - VALUES (?, ?, ?) - ''', (channel_id, target_id, target_type)) - self.conn.commit() - - def remove_from_whitelist(self, channel_id, target_id, target_type): - """ - Remove an entry from the whitelist. - - Parameters - ---------- - channel_id : int - Discord channel ID - target_id : int - Discord role ID or user ID - target_type : {'role', 'user'} - Type of the whitelist target - - Examples - -------- - >>> db.remove_from_whitelist(channel_id=123456, target_id=789012, target_type='role') - """ - self.cursor.execute(''' - DELETE FROM autodelete_whitelist - WHERE channel_id=? AND target_id=? AND target_type=? - ''', (channel_id, target_id, target_type)) - self.conn.commit() - - def get_whitelist(self, channel_id): - """ - Get whitelist for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - - Returns - ------- - dict - Dictionary with 'roles' and 'users' keys, each containing a list of IDs - - Examples - -------- - >>> whitelist = db.get_whitelist(123456) - >>> print(f"Whitelisted roles: {whitelist['roles']}") - >>> print(f"Whitelisted users: {whitelist['users']}") - """ - self.cursor.execute(''' - SELECT target_id, target_type FROM autodelete_whitelist - WHERE channel_id=? - ''', (channel_id,)) - - results = self.cursor.fetchall() - whitelist = {'roles': [], 'users': []} - - for target_id, target_type in results: - if target_type == 'role': - whitelist['roles'].append(target_id) - elif target_type == 'user': - whitelist['users'].append(target_id) - - return whitelist - - def clear_whitelist(self, channel_id): - """ - Clear complete whitelist for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - - Examples - -------- - >>> db.clear_whitelist(123456) - """ - self.cursor.execute("DELETE FROM autodelete_whitelist WHERE channel_id=?", (channel_id,)) - self.conn.commit() - - # === SCHEDULE FUNCTIONS === - - def add_schedule(self, channel_id, start_time, end_time, days): - """ - Add a time schedule for AutoDelete. - - Parameters - ---------- - channel_id : int - Discord channel ID - start_time : str - Start time in HH:MM format - end_time : str - End time in HH:MM format - days : str - Days when schedule is active (e.g., "Mon,Tue,Wed") - - Notes - ----- - Schedules allow AutoDelete to only run during specific time windows. - - Examples - -------- - >>> db.add_schedule(channel_id=123456, start_time="09:00", - ... end_time="17:00", days="Mon,Tue,Wed,Thu,Fri") - """ - self.cursor.execute(''' - INSERT INTO autodelete_schedules - (channel_id, start_time, end_time, days) - VALUES (?, ?, ?, ?) - ''', (channel_id, start_time, end_time, days)) - self.conn.commit() - - def remove_schedule(self, channel_id, start_time=None): - """ - Remove schedule(s) for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - start_time : str, optional - Specific start time to remove. If None, removes all schedules - - Examples - -------- - >>> db.remove_schedule(channel_id=123456, start_time="09:00") - >>> db.remove_schedule(channel_id=123456) # Remove all schedules - """ - if start_time: - self.cursor.execute(''' - DELETE FROM autodelete_schedules - WHERE channel_id=? AND start_time=? - ''', (channel_id, start_time)) - else: - self.cursor.execute(''' - DELETE FROM autodelete_schedules WHERE channel_id=? - ''', (channel_id,)) - self.conn.commit() - - def get_schedules(self, channel_id): - """ - Get all schedules for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - - Returns - ------- - list of tuple - List of tuples containing (start_time, end_time, days) sorted by start_time - - Examples - -------- - >>> schedules = db.get_schedules(123456) - >>> for start, end, days in schedules: - ... print(f"{start}-{end} on {days}") - """ - self.cursor.execute(''' - SELECT start_time, end_time, days - FROM autodelete_schedules - WHERE channel_id=? - ORDER BY start_time - ''', (channel_id,)) - return self.cursor.fetchall() - - # === STATISTICS FUNCTIONS === - - def update_stats(self, channel_id, deleted_count=0, error_count=0): - """ - Update statistics for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - deleted_count : int, optional - Number of messages deleted (default: 0) - error_count : int, optional - Number of errors encountered (default: 0) - - Notes - ----- - Counts are cumulative. The last_deletion timestamp is only updated - if deleted_count > 0. - - Examples - -------- - >>> db.update_stats(channel_id=123456, deleted_count=10) - >>> db.update_stats(channel_id=123456, error_count=1) - """ - timestamp = datetime.utcnow().timestamp() if deleted_count > 0 else None - - self.cursor.execute(''' - INSERT OR REPLACE INTO autodelete_stats - (channel_id, deleted_count, error_count, last_deletion, updated_at) - VALUES ( - ?, - COALESCE((SELECT deleted_count FROM autodelete_stats WHERE channel_id=?), 0) + ?, - COALESCE((SELECT error_count FROM autodelete_stats WHERE channel_id=?), 0) + ?, - COALESCE(?, (SELECT last_deletion FROM autodelete_stats WHERE channel_id=?)), - CURRENT_TIMESTAMP - ) - ''', (channel_id, channel_id, deleted_count, channel_id, error_count, timestamp, channel_id)) - self.conn.commit() - - def get_stats(self, channel_id): - """ - Get statistics for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - - Returns - ------- - dict or None - Dictionary containing statistics or None if not found. - Keys: 'deleted_count', 'error_count', 'last_deletion', - 'created_at', 'updated_at' - - Examples - -------- - >>> stats = db.get_stats(123456) - >>> if stats: - ... print(f"Deleted: {stats['deleted_count']} messages") - ... print(f"Errors: {stats['error_count']}") - """ - self.cursor.execute(''' - SELECT deleted_count, error_count, last_deletion, created_at, updated_at - FROM autodelete_stats WHERE channel_id=? - ''', (channel_id,)) - - result = self.cursor.fetchone() - if result: - return { - 'deleted_count': result[0], - 'error_count': result[1], - 'last_deletion': result[2], - 'created_at': result[3], - 'updated_at': result[4] - } - return None - - def reset_stats(self, channel_id): - """ - Reset statistics for a channel. - - Parameters - ---------- - channel_id : int - Discord channel ID - - Notes - ----- - Sets deleted_count and error_count to 0, clears last_deletion timestamp. - - Examples - -------- - >>> db.reset_stats(123456) - """ - self.cursor.execute(''' - UPDATE autodelete_stats - SET deleted_count=0, error_count=0, last_deletion=NULL, updated_at=CURRENT_TIMESTAMP - WHERE channel_id=? - ''', (channel_id,)) - self.conn.commit() - - def get_global_stats(self): - """ - Get global statistics across all channels. - - Returns - ------- - dict or None - Dictionary containing global statistics or None if no data exists. - Keys: 'active_channels', 'total_deleted', 'total_errors', 'latest_deletion' - - Examples - -------- - >>> stats = db.get_global_stats() - >>> if stats: - ... print(f"Active channels: {stats['active_channels']}") - ... print(f"Total deleted: {stats['total_deleted']}") - """ - self.cursor.execute(''' - SELECT - COUNT(*) as active_channels, - SUM(deleted_count) as total_deleted, - SUM(error_count) as total_errors, - MAX(last_deletion) as latest_deletion - FROM autodelete_stats s - JOIN autodelete a ON s.channel_id = a.channel_id - ''') - - result = self.cursor.fetchone() - if result: - return { - 'active_channels': result[0], - 'total_deleted': result[1] or 0, - 'total_errors': result[2] or 0, - 'latest_deletion': result[3] - } - return None - - # === EXPORT/IMPORT FUNCTIONS === - - def export_all_settings(self): - """ - Export all AutoDelete settings. - - Returns - ------- - dict - Dictionary containing all configurations, whitelists, schedules, and stats - - Notes - ----- - The returned dictionary can be serialized to JSON and later imported - using `import_settings()`. - - Examples - -------- - >>> data = db.export_all_settings() - >>> import json - >>> with open('backup.json', 'w') as f: - ... json.dump(data, f, indent=2) - """ - data = { - 'exported_at': datetime.utcnow().isoformat(), - 'channels': [] - } - - self.cursor.execute(''' - SELECT channel_id, duration, exclude_pinned, exclude_bots, created_at, updated_at - FROM autodelete ORDER BY channel_id - ''') - - for row in self.cursor.fetchall(): - channel_id = row[0] - channel_data = { - 'channel_id': channel_id, - 'duration': row[1], - 'exclude_pinned': bool(row[2]), - 'exclude_bots': bool(row[3]), - 'created_at': row[4], - 'updated_at': row[5], - 'whitelist': self.get_whitelist(channel_id), - 'schedules': self.get_schedules(channel_id), - 'stats': self.get_stats(channel_id) - } - data['channels'].append(channel_data) - - return data - - def import_settings(self, data, overwrite=False): - """ - Import AutoDelete settings. - - Parameters - ---------- - data : dict - Dictionary containing exported settings (from `export_all_settings()`) - overwrite : bool, optional - Whether to overwrite existing configurations (default: False) - - Returns - ------- - dict - Dictionary with 'imported' and 'skipped' counts - - Notes - ----- - If overwrite is False, existing channel configurations are skipped. - If overwrite is True, existing configurations are replaced. - - Examples - -------- - >>> import json - >>> with open('backup.json', 'r') as f: - ... data = json.load(f) - >>> result = db.import_settings(data, overwrite=True) - >>> print(f"Imported: {result['imported']}, Skipped: {result['skipped']}") - """ - imported_count = 0 - skipped_count = 0 - - for channel_data in data.get('channels', []): - channel_id = channel_data['channel_id'] - - if not overwrite and self.get_autodelete(channel_id): - skipped_count += 1 - continue - - self.add_autodelete( - channel_id, - channel_data['duration'], - channel_data.get('exclude_pinned', True), - channel_data.get('exclude_bots', False) - ) - - if overwrite: - self.clear_whitelist(channel_id) - - whitelist = channel_data.get('whitelist', {}) - for role_id in whitelist.get('roles', []): - self.add_to_whitelist(channel_id, role_id, 'role') - for user_id in whitelist.get('users', []): - self.add_to_whitelist(channel_id, user_id, 'user') - - if overwrite: - self.remove_schedule(channel_id) - - for start_time, end_time, days in channel_data.get('schedules', []): - self.add_schedule(channel_id, start_time, end_time, days) - - imported_count += 1 - - return {'imported': imported_count, 'skipped': skipped_count} - - # === MAINTENANCE FUNCTIONS === - - def cleanup_orphaned_data(self): - """ - Remove orphaned data from auxiliary tables. - - Returns - ------- - int - Number of orphaned records removed - - Notes - ----- - Removes whitelist entries, schedules, and statistics that reference - non-existent AutoDelete configurations. - - Examples - -------- - >>> removed = db.cleanup_orphaned_data() - >>> print(f"Removed {removed} orphaned records") - """ - self.cursor.execute(''' - DELETE FROM autodelete_whitelist - WHERE channel_id NOT IN (SELECT channel_id FROM autodelete) - ''') - - self.cursor.execute(''' - DELETE FROM autodelete_schedules - WHERE channel_id NOT IN (SELECT channel_id FROM autodelete) - ''') - - self.cursor.execute(''' - DELETE FROM autodelete_stats - WHERE channel_id NOT IN (SELECT channel_id FROM autodelete) - ''') - - self.conn.commit() - return self.cursor.rowcount - - def vacuum_database(self): - """ - Optimize the database. - - Notes - ----- - Rebuilds the database file, repacking it into a minimal amount of disk space. - This can improve performance but may take time on large databases. - - Examples - -------- - >>> db.vacuum_database() - """ - self.cursor.execute("VACUUM") - self.conn.commit() - - def get_database_info(self): - """ - Get database information and statistics. - - Returns - ------- - dict - Dictionary containing record counts for each table and file size information - - Examples - -------- - >>> info = db.get_database_info() - >>> print(f"Database size: {info['file_size_mb']} MB") - >>> print(f"AutoDelete configs: {info['autodelete_count']}") - """ - info = {} - - tables = ['autodelete', 'autodelete_whitelist', 'autodelete_schedules', 'autodelete_stats'] - for table in tables: - self.cursor.execute(f"SELECT COUNT(*) FROM {table}") - info[f"{table}_count"] = self.cursor.fetchone()[0] - - import os - if os.path.exists(self.db_file): - info['file_size_bytes'] = os.path.getsize(self.db_file) - info['file_size_mb'] = round(info['file_size_bytes'] / 1024 / 1024, 2) - - return info - - def close(self): - """ - Close the database connection. - - Notes - ----- - Should be called when done using the database to free resources. - Not needed when using the context manager syntax. - - Examples - -------- - >>> db = AutoDeleteDB() - >>> # ... use database ... - >>> db.close() - """ - if self.conn: - self.conn.close() - - def __enter__(self): - """Context manager entry.""" - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - """Context manager exit.""" - self.close() \ No newline at end of file diff --git a/src/DevTools/backend/database/autorole_db.py b/src/DevTools/backend/database/autorole_db.py deleted file mode 100644 index 23f4f3c..0000000 --- a/src/DevTools/backend/database/autorole_db.py +++ /dev/null @@ -1,102 +0,0 @@ -import aiosqlite -import random -import string -import os - -class AutoRoleDatabase: - def __init__(self, db_path="data/autorole.db"): - self.db_path = db_path - # Erstellt den Ordner 'data', falls er fehlt - directory = os.path.dirname(self.db_path) - if directory and not os.path.exists(directory): - os.makedirs(directory, exist_ok=True) - - async def init_db(self): - """Erstellt die Tabelle, falls sie noch nicht existiert""" - async with aiosqlite.connect(self.db_path) as db: - await db.execute(""" - CREATE TABLE IF NOT EXISTS autoroles ( - autorole_id TEXT PRIMARY KEY, - guild_id INTEGER NOT NULL, - role_id INTEGER NOT NULL, - enabled INTEGER DEFAULT 1, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) - """) - await db.commit() - - def generate_autorole_id(self, guild_id: int, role_id: int): - guild_part = str(guild_id)[-2:].zfill(2) - role_part = str(role_id)[-2:].zfill(2) - random_part = ''.join(random.choices(string.digits, k=3)) - return f"{guild_part}-{role_part}-{random_part}" - - async def add_autorole(self, guild_id: int, role_id: int): - # WICHTIG: Erst sicherstellen, dass die Tabelle da ist! - await self.init_db() - - autorole_id = self.generate_autorole_id(guild_id, role_id) - - async with aiosqlite.connect(self.db_path) as db: - # Check ob ID existiert - while True: - async with db.execute( - "SELECT autorole_id FROM autoroles WHERE autorole_id = ?", - (autorole_id,) - ) as cursor: - if not await cursor.fetchone(): - break - autorole_id = self.generate_autorole_id(guild_id, role_id) - - await db.execute(""" - INSERT INTO autoroles (autorole_id, guild_id, role_id, enabled) - VALUES (?, ?, ?, 1) - """, (autorole_id, guild_id, role_id)) - await db.commit() - - return autorole_id - - async def get_all_autoroles(self, guild_id: int): - await self.init_db() - async with aiosqlite.connect(self.db_path) as db: - async with db.execute( - "SELECT autorole_id, role_id, enabled FROM autoroles WHERE guild_id = ?", - (guild_id,) - ) as cursor: - rows = await cursor.fetchall() - return [{"autorole_id": r[0], "role_id": r[1], "enabled": bool(r[2])} for r in rows] - - async def get_autorole(self, autorole_id: str): - await self.init_db() - async with aiosqlite.connect(self.db_path) as db: - async with db.execute( - "SELECT autorole_id, guild_id, role_id, enabled FROM autoroles WHERE autorole_id = ?", - (autorole_id,) - ) as cursor: - row = await cursor.fetchone() - return {"autorole_id": row[0], "guild_id": row[1], "role_id": row[2], "enabled": bool(row[3])} if row else None - - async def get_enabled_autoroles(self, guild_id: int): - await self.init_db() - async with aiosqlite.connect(self.db_path) as db: - async with db.execute( - "SELECT role_id FROM autoroles WHERE guild_id = ? AND enabled = 1", - (guild_id,) - ) as cursor: - rows = await cursor.fetchall() - return [r[0] for r in rows] - - async def remove_autorole(self, autorole_id: str): - await self.init_db() - async with aiosqlite.connect(self.db_path) as db: - await db.execute("DELETE FROM autoroles WHERE autorole_id = ?", (autorole_id,)) - await db.commit() - - async def toggle_autorole(self, autorole_id: str, enabled: bool): - await self.init_db() - async with aiosqlite.connect(self.db_path) as db: - await db.execute( - "UPDATE autoroles SET enabled = ? WHERE autorole_id = ?", - (1 if enabled else 0, autorole_id) - ) - await db.commit() \ No newline at end of file diff --git a/src/DevTools/backend/database/globalchat_db.py b/src/DevTools/backend/database/globalchat_db.py deleted file mode 100644 index 0fb592b..0000000 --- a/src/DevTools/backend/database/globalchat_db.py +++ /dev/null @@ -1,955 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import sqlite3 -import os -import logging -from typing import Optional, List, Dict, Tuple -from datetime import datetime, timedelta -import time - -# Logger -logger = logging.getLogger(__name__) - -DB_PATH = "data/globalchat.db" - - -class GlobalChatDatabase: - """ - Database manager for Discord GlobalChat system. - - Manages channel configurations, message logging, blacklists, guild settings, - and statistics for a cross-server global chat system. - - Attributes - ---------- - DB_PATH : str - Path to the SQLite database file - - Notes - ----- - Automatically creates necessary tables and performs migrations on initialization. - Uses context managers for database connections to ensure proper resource management. - - Examples - -------- - >>> db = GlobalChatDatabase() - >>> db.set_globalchat_channel(guild_id=123456, channel_id=789012) - >>> channels = db.get_all_channels() - """ - - def __init__(self): - self._ensure_db_dir() - self.create_tables() - self.migrate_database() - - def _ensure_db_dir(self): - """ - Ensure that the data directory exists. - - Notes - ----- - Creates parent directories if they don't exist. Does not raise an error - if the directory already exists. - """ - os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) - - def _get_connection(self): - """ - Get a database connection. - - Returns - ------- - sqlite3.Connection - Database connection with Row factory enabled - - Notes - ----- - The connection uses sqlite3.Row as row_factory, allowing dictionary-style - access to columns. - - Examples - -------- - >>> with self._get_connection() as conn: - ... cursor = conn.cursor() - ... cursor.execute("SELECT * FROM globalchat_channels") - """ - conn = sqlite3.connect(DB_PATH) - conn.row_factory = sqlite3.Row - return conn - - def _column_exists(self, table_name: str, column_name: str) -> bool: - """ - Check if a column exists in a table. - - Parameters - ---------- - table_name : str - Name of the database table - column_name : str - Name of the column to check - - Returns - ------- - bool - True if column exists, False otherwise - - Notes - ----- - Returns False if any database error occurs during the check. - - Examples - -------- - >>> if db._column_exists('globalchat_channels', 'guild_name'): - ... print("Column exists") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - c.execute(f"PRAGMA table_info({table_name})") - columns = [row[1] for row in c.fetchall()] - return column_name in columns - except sqlite3.Error: - return False - - def migrate_database(self): - """ - Perform database migrations. - - Adds missing columns to existing tables to ensure schema compatibility - with newer versions. Migrations are idempotent and safe to run multiple times. - - Raises - ------ - sqlite3.Error - If migration fails - - Notes - ----- - Automatically called during initialization. Logs each migration step. - Critical migration: Adds 'content' column to message_log table. - - Examples - -------- - >>> db = GlobalChatDatabase() # Migrations run automatically - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - - # Migration for globalchat_channels - if not self._column_exists('globalchat_channels', 'guild_name'): - logger.info("Adding column 'guild_name' to globalchat_channels") - c.execute("ALTER TABLE globalchat_channels ADD COLUMN guild_name TEXT") - - if not self._column_exists('globalchat_channels', 'channel_name'): - logger.info("Adding column 'channel_name' to globalchat_channels") - c.execute("ALTER TABLE globalchat_channels ADD COLUMN channel_name TEXT") - - if not self._column_exists('globalchat_channels', 'created_at'): - logger.info("Adding column 'created_at' to globalchat_channels") - c.execute("ALTER TABLE globalchat_channels ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP") - - if not self._column_exists('globalchat_channels', 'last_activity'): - logger.info("Adding column 'last_activity' to globalchat_channels") - c.execute("ALTER TABLE globalchat_channels ADD COLUMN last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP") - - if not self._column_exists('globalchat_channels', 'message_count'): - logger.info("Adding column 'message_count' to globalchat_channels") - c.execute("ALTER TABLE globalchat_channels ADD COLUMN message_count INTEGER DEFAULT 0") - - if not self._column_exists('globalchat_channels', 'is_active'): - logger.info("Adding column 'is_active' to globalchat_channels") - c.execute("ALTER TABLE globalchat_channels ADD COLUMN is_active BOOLEAN DEFAULT 1") - - # CRITICAL MIGRATION: message_log content column - if not self._column_exists('message_log', 'content'): - logger.info("โœจ Adding column 'content' to message_log") - c.execute("ALTER TABLE message_log ADD COLUMN content TEXT") - - conn.commit() - logger.info("โœ… Database migration completed") - - except sqlite3.Error as e: - logger.error(f"โŒ Migration error: {e}") - raise - - def create_tables(self): - """ - Create all required database tables. - - Creates the following tables if they don't exist: - - globalchat_channels: Channel configurations - - message_log: Message history for moderation - - globalchat_blacklist: Banned users and guilds - - guild_settings: Per-guild configuration - - daily_stats: Daily statistics - - Raises - ------ - sqlite3.Error - If table creation fails - - Notes - ----- - Safe to call multiple times. Uses IF NOT EXISTS to avoid errors. - - Examples - -------- - >>> db = GlobalChatDatabase() # Tables created automatically - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - - # GlobalChat Channels - c.execute(""" - CREATE TABLE IF NOT EXISTS globalchat_channels ( - guild_id INTEGER PRIMARY KEY, - channel_id INTEGER NOT NULL - ) - """) - - # Message Log - CORRECTED with content column - c.execute(""" - CREATE TABLE IF NOT EXISTS message_log ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL, - guild_id INTEGER NOT NULL, - channel_id INTEGER NOT NULL, - content TEXT, - attachment_urls TEXT, - timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) - """) - - # Blacklist System - c.execute(""" - CREATE TABLE IF NOT EXISTS globalchat_blacklist ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - entity_type TEXT NOT NULL CHECK (entity_type IN ('user', 'guild')), - entity_id INTEGER NOT NULL, - reason TEXT, - banned_by INTEGER, - banned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - expires_at TIMESTAMP, - is_permanent BOOLEAN DEFAULT 0, - UNIQUE(entity_type, entity_id) - ) - """) - - # Guild Settings - c.execute(""" - CREATE TABLE IF NOT EXISTS guild_settings ( - guild_id INTEGER PRIMARY KEY, - filter_enabled BOOLEAN DEFAULT 1, - nsfw_filter BOOLEAN DEFAULT 1, - embed_color TEXT DEFAULT '#5865F2', - custom_webhook_name TEXT, - max_message_length INTEGER DEFAULT 1900, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) - """) - - # Statistics - c.execute(""" - CREATE TABLE IF NOT EXISTS daily_stats ( - date DATE PRIMARY KEY, - total_messages INTEGER DEFAULT 0, - active_guilds INTEGER DEFAULT 0, - active_users INTEGER DEFAULT 0 - ) - """) - - conn.commit() - logger.info("โœ… Base database tables created") - except sqlite3.Error as e: - logger.error(f"โŒ Error creating tables: {e}") - raise - - def set_globalchat_channel(self, guild_id: int, channel_id: int, guild_name: str = None, channel_name: str = None) -> bool: - """ - Set a GlobalChat channel for a guild. - - Parameters - ---------- - guild_id : int - Discord guild ID - channel_id : int - Discord channel ID - guild_name : str, optional - Name of the guild (default: None) - channel_name : str, optional - Name of the channel (default: None) - - Returns - ------- - bool - True if successful, False otherwise - - Notes - ----- - Updates existing configuration if guild already has a channel set. - Automatically updates last_activity timestamp if the column exists. - - Examples - -------- - >>> db.set_globalchat_channel(guild_id=123456, channel_id=789012) - >>> db.set_globalchat_channel(guild_id=123456, channel_id=789012, - ... guild_name="My Server", channel_name="global-chat") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - - has_guild_name = self._column_exists('globalchat_channels', 'guild_name') - has_channel_name = self._column_exists('globalchat_channels', 'channel_name') - has_last_activity = self._column_exists('globalchat_channels', 'last_activity') - - if has_guild_name and has_channel_name and has_last_activity: - c.execute(""" - INSERT OR REPLACE INTO globalchat_channels - (guild_id, channel_id, guild_name, channel_name, last_activity) - VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) - """, (guild_id, channel_id, guild_name, channel_name)) - else: - c.execute(""" - INSERT OR REPLACE INTO globalchat_channels - (guild_id, channel_id) - VALUES (?, ?) - """, (guild_id, channel_id)) - - conn.commit() - logger.info(f"โœ… GlobalChat channel set: Guild {guild_id} -> Channel {channel_id}") - return True - except sqlite3.Error as e: - logger.error(f"โŒ Error setting GlobalChat channel: {e}") - return False - - def get_all_channels(self) -> List[int]: - """ - Get all active GlobalChat channel IDs. - - Returns - ------- - list of int - List of active channel IDs - - Notes - ----- - Only returns active channels if the is_active column exists. - Returns empty list if an error occurs. - - Examples - -------- - >>> channels = db.get_all_channels() - >>> print(f"Active channels: {len(channels)}") - >>> for channel_id in channels: - ... print(f"Channel: {channel_id}") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - - if self._column_exists('globalchat_channels', 'is_active'): - c.execute("SELECT channel_id FROM globalchat_channels WHERE is_active = 1") - else: - c.execute("SELECT channel_id FROM globalchat_channels") - - result = [row['channel_id'] for row in c.fetchall()] - logger.debug(f"๐Ÿ“Š All active channels retrieved: {len(result)} channels") - return result - except sqlite3.Error as e: - logger.error(f"โŒ Error retrieving all channels: {e}") - return [] - - def get_globalchat_channel(self, guild_id: int) -> Optional[int]: - """ - Get the channel ID for a guild. - - Parameters - ---------- - guild_id : int - Discord guild ID - - Returns - ------- - int or None - Channel ID if found, None otherwise - - Notes - ----- - Only returns channel if it's marked as active (when is_active column exists). - - Examples - -------- - >>> channel_id = db.get_globalchat_channel(123456) - >>> if channel_id: - ... print(f"Guild has channel: {channel_id}") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - - if self._column_exists('globalchat_channels', 'is_active'): - c.execute("SELECT channel_id FROM globalchat_channels WHERE guild_id = ? AND is_active = 1", (guild_id,)) - else: - c.execute("SELECT channel_id FROM globalchat_channels WHERE guild_id = ?", (guild_id,)) - - result = c.fetchone() - return result['channel_id'] if result else None - except sqlite3.Error as e: - logger.error(f"โŒ Error retrieving channel for guild {guild_id}: {e}") - return None - - def remove_globalchat_channel(self, guild_id: int) -> bool: - """ - Remove a GlobalChat channel configuration. - - Parameters - ---------- - guild_id : int - Discord guild ID - - Returns - ------- - bool - True if channel was removed, False if not found or error occurred - - Examples - -------- - >>> if db.remove_globalchat_channel(123456): - ... print("Channel removed successfully") - ... else: - ... print("No channel found or error occurred") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - c.execute("DELETE FROM globalchat_channels WHERE guild_id = ?", (guild_id,)) - changes = c.rowcount - conn.commit() - - if changes > 0: - logger.info(f"โœ… GlobalChat channel removed for guild {guild_id}") - return True - else: - logger.warning(f"โš ๏ธ No channel found for guild {guild_id}") - return False - except sqlite3.Error as e: - logger.error(f"โŒ Error removing GlobalChat channel: {e}") - return False - - def update_channel_activity(self, guild_id: int): - """ - Update last activity and increment message count. - - Parameters - ---------- - guild_id : int - Discord guild ID - - Notes - ----- - Only updates fields that exist in the schema. Safe to call even if - columns don't exist yet. - - Examples - -------- - >>> db.update_channel_activity(123456) - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - - has_last_activity = self._column_exists('globalchat_channels', 'last_activity') - has_message_count = self._column_exists('globalchat_channels', 'message_count') - - if has_last_activity and has_message_count: - c.execute(""" - UPDATE globalchat_channels - SET last_activity = CURRENT_TIMESTAMP, message_count = message_count + 1 - WHERE guild_id = ? - """, (guild_id,)) - elif has_message_count: - c.execute(""" - UPDATE globalchat_channels - SET message_count = message_count + 1 - WHERE guild_id = ? - """, (guild_id,)) - - conn.commit() - except sqlite3.Error as e: - logger.error(f"โŒ Error updating activity: {e}") - - def log_message(self, user_id: int, guild_id: int, channel_id: int, content: str, attachment_urls: str = None): - """ - Log a message for moderation purposes. - - Parameters - ---------- - user_id : int - Discord user ID who sent the message - guild_id : int - Discord guild ID where message was sent - channel_id : int - Discord channel ID where message was sent - content : str - Message content - attachment_urls : str, optional - URLs of message attachments (default: None) - - Notes - ----- - Logs are used for moderation and can be retrieved with get_user_message_history(). - - Examples - -------- - >>> db.log_message(user_id=123456, guild_id=789012, channel_id=345678, - ... content="Hello world!") - >>> db.log_message(user_id=123456, guild_id=789012, channel_id=345678, - ... content="Check this out", attachment_urls="https://example.com/image.png") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - c.execute(""" - INSERT INTO message_log - (user_id, guild_id, channel_id, content, attachment_urls) - VALUES (?, ?, ?, ?, ?) - """, (user_id, guild_id, channel_id, content, attachment_urls)) - conn.commit() - logger.debug(f"๐Ÿ“ Message logged: User {user_id} in Guild {guild_id}") - except sqlite3.Error as e: - logger.error(f"โŒ Error logging message: {e}") - - def get_user_message_history(self, user_id: int, limit: int = 10) -> List[Dict]: - """ - Get recent messages from a user. - - Parameters - ---------- - user_id : int - Discord user ID - limit : int, optional - Maximum number of messages to retrieve (default: 10) - - Returns - ------- - list of dict - List of message dictionaries, newest first. Each dictionary contains: - id, user_id, guild_id, channel_id, content, attachment_urls, timestamp - - Examples - -------- - >>> messages = db.get_user_message_history(123456, limit=5) - >>> for msg in messages: - ... print(f"{msg['timestamp']}: {msg['content']}") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - c.execute(""" - SELECT * FROM message_log - WHERE user_id = ? - ORDER BY timestamp DESC - LIMIT ? - """, (user_id, limit)) - return [dict(row) for row in c.fetchall()] - except sqlite3.Error as e: - logger.error(f"โŒ Error retrieving message history: {e}") - return [] - - def add_to_blacklist(self, entity_type: str, entity_id: int, reason: str, banned_by: int, duration_hours: int = None): - """ - Add a user or guild to the blacklist. - - Parameters - ---------- - entity_type : {'user', 'guild'} - Type of entity to ban - entity_id : int - Discord ID of the user or guild - reason : str - Reason for the ban - banned_by : int - Discord user ID of the moderator issuing the ban - duration_hours : int, optional - Duration in hours (default: None for permanent ban) - - Returns - ------- - bool - True if successful, False otherwise - - Notes - ----- - If duration_hours is None, the ban is permanent. Otherwise, it expires - after the specified duration. - - Examples - -------- - >>> db.add_to_blacklist(entity_type='user', entity_id=123456, - ... reason="Spam", banned_by=789012, duration_hours=24) - >>> db.add_to_blacklist(entity_type='guild', entity_id=345678, - ... reason="Abuse", banned_by=789012) # Permanent - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - expires_at = None - is_permanent = duration_hours is None - - if duration_hours: - expires_at = datetime.now() + timedelta(hours=duration_hours) - - c.execute(""" - INSERT OR REPLACE INTO globalchat_blacklist - (entity_type, entity_id, reason, banned_by, expires_at, is_permanent) - VALUES (?, ?, ?, ?, ?, ?) - """, (entity_type, entity_id, reason, banned_by, expires_at, is_permanent)) - conn.commit() - logger.info(f"๐Ÿ”จ Added to blacklist: {entity_type} {entity_id}") - return True - except sqlite3.Error as e: - logger.error(f"โŒ Error adding to blacklist: {e}") - return False - - def remove_from_blacklist(self, entity_type: str, entity_id: int) -> bool: - """ - Remove a user or guild from the blacklist. - - Parameters - ---------- - entity_type : {'user', 'guild'} - Type of entity to unban - entity_id : int - Discord ID of the user or guild - - Returns - ------- - bool - True if entity was removed, False if not found or error occurred - - Examples - -------- - >>> if db.remove_from_blacklist('user', 123456): - ... print("User unbanned successfully") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - c.execute("DELETE FROM globalchat_blacklist WHERE entity_type = ? AND entity_id = ?", (entity_type, entity_id)) - changes = c.rowcount - conn.commit() - - if changes > 0: - logger.info(f"โœ… Removed from blacklist: {entity_type} {entity_id}") - return True - return False - except sqlite3.Error as e: - logger.error(f"โŒ Error removing from blacklist: {e}") - return False - - def is_blacklisted(self, entity_type: str, entity_id: int) -> bool: - """ - Check if a user or guild is blacklisted. - - Parameters - ---------- - entity_type : {'user', 'guild'} - Type of entity to check - entity_id : int - Discord ID of the user or guild - - Returns - ------- - bool - True if blacklisted, False otherwise - - Notes - ----- - Automatically removes expired temporary bans when checking. - Permanent bans always return True. - - Examples - -------- - >>> if db.is_blacklisted('user', 123456): - ... print("User is banned") - ... else: - ... print("User is not banned") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - c.execute(""" - SELECT expires_at, is_permanent FROM globalchat_blacklist - WHERE entity_type = ? AND entity_id = ? - """, (entity_type, entity_id)) - result = c.fetchone() - - if not result: - return False - - if result['is_permanent']: - return True - - if result['expires_at']: - expires_at = datetime.fromisoformat(result['expires_at']) - if datetime.now() > expires_at: - self.remove_from_blacklist(entity_type, entity_id) - return False - return True - - return False - except sqlite3.Error as e: - logger.error(f"โŒ Error checking blacklist: {e}") - return False - - def get_blacklist(self, entity_type: str = None) -> List[Dict]: - """ - Get the complete blacklist or filtered by type. - - Parameters - ---------- - entity_type : {'user', 'guild'}, optional - Type of entities to retrieve (default: None for all) - - Returns - ------- - list of dict - List of blacklist entries. Each dictionary contains: - id, entity_type, entity_id, reason, banned_by, banned_at, - expires_at, is_permanent - - Examples - -------- - >>> all_bans = db.get_blacklist() - >>> user_bans = db.get_blacklist(entity_type='user') - >>> for ban in user_bans: - ... print(f"User {ban['entity_id']}: {ban['reason']}") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - if entity_type: - c.execute("SELECT * FROM globalchat_blacklist WHERE entity_type = ?", (entity_type,)) - else: - c.execute("SELECT * FROM globalchat_blacklist") - return [dict(row) for row in c.fetchall()] - except sqlite3.Error as e: - logger.error(f"โŒ Error retrieving blacklist: {e}") - return [] - - def get_guild_settings(self, guild_id: int) -> Dict: - """ - Get settings for a guild. - - Parameters - ---------- - guild_id : int - Discord guild ID - - Returns - ------- - dict - Dictionary containing guild settings. If no custom settings exist, - returns default settings. Keys: guild_id, filter_enabled, nsfw_filter, - embed_color, custom_webhook_name, max_message_length - - Examples - -------- - >>> settings = db.get_guild_settings(123456) - >>> print(f"Filter enabled: {settings['filter_enabled']}") - >>> print(f"Embed color: {settings['embed_color']}") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - c.execute("SELECT * FROM guild_settings WHERE guild_id = ?", (guild_id,)) - result = c.fetchone() - - if result: - return dict(result) - else: - return { - 'guild_id': guild_id, - 'filter_enabled': True, - 'nsfw_filter': True, - 'embed_color': '#5865F2', - 'custom_webhook_name': None, - 'max_message_length': 1900 - } - except sqlite3.Error as e: - logger.error(f"โŒ Error retrieving guild settings: {e}") - return {} - - def update_guild_setting(self, guild_id: int, setting_name: str, value) -> bool: - """ - Update a guild setting. - - Parameters - ---------- - guild_id : int - Discord guild ID - setting_name : str - Name of the setting to update (must match column name) - value : Any - New value for the setting - - Returns - ------- - bool - True if successful, False otherwise - - Notes - ----- - Creates guild_settings entry if it doesn't exist. - Valid setting names: filter_enabled, nsfw_filter, embed_color, - custom_webhook_name, max_message_length - - Examples - -------- - >>> db.update_guild_setting(123456, 'filter_enabled', False) - >>> db.update_guild_setting(123456, 'embed_color', '#FF5733') - >>> db.update_guild_setting(123456, 'max_message_length', 2000) - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - c.execute("SELECT guild_id FROM guild_settings WHERE guild_id = ?", (guild_id,)) - if not c.fetchone(): - c.execute("INSERT INTO guild_settings (guild_id) VALUES (?)", (guild_id,)) - - c.execute(f"UPDATE guild_settings SET {setting_name} = ? WHERE guild_id = ?", (value, guild_id)) - conn.commit() - logger.debug(f"โš™๏ธ Setting updated: {setting_name} = {value} for Guild {guild_id}") - return True - except sqlite3.Error as e: - logger.error(f"โŒ Error updating guild settings: {e}") - return False - - def get_global_stats(self) -> Dict: - """ - Get global statistics. - - Returns - ------- - dict - Dictionary containing global statistics. Keys: active_guilds, - total_messages, today_messages, banned_users, banned_guilds - - Notes - ----- - Returns empty dict if an error occurs. - - Examples - -------- - >>> stats = db.get_global_stats() - >>> print(f"Active guilds: {stats['active_guilds']}") - >>> print(f"Total messages: {stats['total_messages']}") - >>> print(f"Banned users: {stats['banned_users']}") - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - - if self._column_exists('globalchat_channels', 'is_active'): - c.execute("SELECT COUNT(*) as count FROM globalchat_channels WHERE is_active = 1") - else: - c.execute("SELECT COUNT(*) as count FROM globalchat_channels") - active_guilds = c.fetchone()['count'] - - c.execute("SELECT total_messages FROM daily_stats WHERE date = DATE('now')") - today_messages = c.fetchone() - today_messages = today_messages['total_messages'] if today_messages else 0 - - if self._column_exists('globalchat_channels', 'message_count'): - c.execute("SELECT SUM(message_count) as total FROM globalchat_channels") - total_messages = c.fetchone()['total'] or 0 - else: - total_messages = 0 - - c.execute("SELECT COUNT(*) as count FROM globalchat_blacklist WHERE entity_type = 'user'") - banned_users = c.fetchone()['count'] - - c.execute("SELECT COUNT(*) as count FROM globalchat_blacklist WHERE entity_type = 'guild'") - banned_guilds = c.fetchone()['count'] - - return { - 'active_guilds': active_guilds, - 'total_messages': total_messages, - 'today_messages': today_messages, - 'banned_users': banned_users, - 'banned_guilds': banned_guilds - } - except sqlite3.Error as e: - logger.error(f"โŒ Error retrieving statistics: {e}") - return {} - - def update_daily_stats(self): - """ - Update daily statistics. - - Notes - ----- - Increments the message count for today and updates active guild count. - Creates a new daily_stats entry if one doesn't exist for today. - - Examples - -------- - >>> db.update_daily_stats() # Call after each message - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - c.execute(""" - INSERT OR REPLACE INTO daily_stats - (date, total_messages, active_guilds) - SELECT - DATE('now'), - COALESCE((SELECT total_messages FROM daily_stats WHERE date = DATE('now')), 0) + 1, - (SELECT COUNT(*) FROM globalchat_channels WHERE 1=1) - """) - conn.commit() - except sqlite3.Error as e: - logger.error(f"โŒ Error updating daily stats: {e}") - - def cleanup_old_data(self, days: int = 30): - """ - Clean up old data from the database. - - Parameters - ---------- - days : int, optional - Number of days to keep message logs (default: 30) - - Notes - ----- - Performs the following cleanup: - - Removes message logs older than specified days - - Removes expired temporary bans - - Removes daily statistics older than 90 days - - Examples - -------- - >>> db.cleanup_old_data(days=30) # Keep last 30 days - >>> db.cleanup_old_data(days=7) # Keep only last week - """ - try: - with self._get_connection() as conn: - c = conn.cursor() - - c.execute("DELETE FROM message_log WHERE timestamp < datetime('now', '-{} days')".format(days)) - deleted_messages = c.rowcount - - c.execute("DELETE FROM globalchat_blacklist WHERE expires_at < datetime('now') AND is_permanent = 0") - deleted_bans = c.rowcount - - c.execute("DELETE FROM daily_stats WHERE date < date('now', '-90 days')") - deleted_stats = c.rowcount - - conn.commit() - logger.info(f"๐Ÿงน Cleanup: {deleted_messages} messages, {deleted_bans} bans, {deleted_stats} stats deleted") - except sqlite3.Error as e: - logger.error(f"โŒ Error during cleanup: {e}") - -db = GlobalChatDatabase() \ No newline at end of file diff --git a/src/DevTools/backend/database/lang_db.py b/src/DevTools/backend/database/lang_db.py deleted file mode 100644 index c1716eb..0000000 --- a/src/DevTools/backend/database/lang_db.py +++ /dev/null @@ -1,46 +0,0 @@ -# src/database/settings_db.py - -import sqlite3 -import os -from datetime import datetime - -class SettingsDB: - """ - Datenbank-Klasse zur Verwaltung von Benutzer- und Servereinstellungen. - """ - def __init__(self, db_path="data/settings.db"): - self.db_path = db_path - os.makedirs(os.path.dirname(self.db_path), exist_ok=True) - self.conn = sqlite3.connect(self.db_path) - self.cursor = self.conn.cursor() - self.create_tables() - print(f"[{datetime.now().strftime('%H:%M:%S')}] [DATABASE] Settings Database initialized โœ“") - - def create_tables(self): - """Erstellt die Benutzereinstellungen-Tabelle, falls sie nicht existiert.""" - self.cursor.execute(""" - CREATE TABLE IF NOT EXISTS user_settings ( - user_id INTEGER PRIMARY KEY, - language TEXT NOT NULL DEFAULT 'en' - ) - """) - self.conn.commit() - - def set_user_language(self, user_id: int, lang_code: str): - """Speichert den Sprachcode fรผr einen Benutzer.""" - self.cursor.execute(""" - INSERT OR REPLACE INTO user_settings (user_id, language) - VALUES (?, ?) - """, (user_id, lang_code)) - self.conn.commit() - - def get_user_language(self, user_id: int) -> str: - """Ruft den Sprachcode fรผr einen Benutzer ab. Standard: 'en'.""" - self.cursor.execute("SELECT language FROM user_settings WHERE user_id = ?", (user_id,)) - result = self.cursor.fetchone() - - # 'en' als gewรผnschter Standard, falls kein Eintrag gefunden wird - return result[0] if result else 'en' - - def close(self): - self.conn.close() \ No newline at end of file diff --git a/src/DevTools/backend/database/levelsystem_db.py b/src/DevTools/backend/database/levelsystem_db.py deleted file mode 100644 index d50a505..0000000 --- a/src/DevTools/backend/database/levelsystem_db.py +++ /dev/null @@ -1,758 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import sqlite3 -import asyncio -from typing import Optional, List, Tuple, Dict, Any -import os -import logging -import time -from collections import defaultdict -import csv -import io - - -class LevelSystemLogger: - def __init__(self): - self.logger = logging.getLogger('levelsystem') - if not self.logger.handlers: - handler = logging.FileHandler('data/levelsystem.log') - formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') - handler.setFormatter(formatter) - self.logger.addHandler(handler) - self.logger.setLevel(logging.INFO) - - def log_level_up(self, user_id: int, guild_id: int, old_level: int, new_level: int): - self.logger.info(f"User {user_id} in guild {guild_id} leveled up: {old_level} -> {new_level}") - - def log_xp_gain(self, user_id: int, guild_id: int, xp_gained: int, total_xp: int): - self.logger.debug(f"User {user_id} in guild {guild_id} gained {xp_gained} XP (total: {total_xp})") - - def log_prestige(self, user_id: int, guild_id: int, old_level: int): - self.logger.info(f"User {user_id} in guild {guild_id} prestiged from level {old_level}") - - -class AntiSpamDetector: - def __init__(self): - self.user_patterns = defaultdict(list) - self.user_messages = defaultdict(list) - - def is_xp_farming(self, user_id: int, message_content: str, timestamp: float) -> bool: - patterns = self.user_patterns[user_id] - - # Cleanup old patterns (รคlter als 10 Minuten) - patterns = [(content, ts) for content, ts in patterns if timestamp - ts < 600] - self.user_patterns[user_id] = patterns - - # Gleiche Nachricht in den letzten 5 Nachrichten - recent_messages = [content for content, ts in patterns[-5:]] - if recent_messages.count(message_content) >= 3: - return True - - # Nachricht zu kurz - if len(message_content.strip()) < 3: - return True - - patterns.append((message_content, timestamp)) - return False - - def is_spam(self, user_id: int, current_time: float, max_messages: int = 5, time_window: int = 60) -> bool: - messages = self.user_messages[user_id] - messages = [t for t in messages if current_time - t < time_window] - self.user_messages[user_id] = messages - - if len(messages) >= max_messages: - return True - - messages.append(current_time) - return False - - -class LevelDatabase: - def __init__(self, db_path: str = "data/levelsystem.db"): - self.db_path = db_path - self.logger = LevelSystemLogger() - self.anti_spam = AntiSpamDetector() - - # Cache fรผr bessere Performance - self.level_roles_cache = {} - self.enabled_guilds_cache = set() - self.guild_configs_cache = {} - - self.init_db() - self.load_caches() - - def init_db(self): - """Initialisiert die Datenbank und erstellt Tabellen""" - os.makedirs(os.path.dirname(self.db_path), exist_ok=True) - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - # User Levels Tabelle - cursor.execute(''' - CREATE TABLE IF NOT EXISTS user_levels ( - user_id INTEGER, - guild_id INTEGER, - xp INTEGER DEFAULT 0, - level INTEGER DEFAULT 0, - messages INTEGER DEFAULT 0, - last_message REAL DEFAULT 0, - prestige_level INTEGER DEFAULT 0, - total_xp_earned INTEGER DEFAULT 0, - PRIMARY KEY (user_id, guild_id) - ) - ''') - - # Level Roles Tabelle - cursor.execute(''' - CREATE TABLE IF NOT EXISTS level_roles ( - guild_id INTEGER, - level INTEGER, - role_id INTEGER, - is_temporary BOOLEAN DEFAULT FALSE, - duration_hours INTEGER DEFAULT 0, - PRIMARY KEY (guild_id, level, role_id) - ) - ''') - - # Guild Settings Tabelle - cursor.execute(''' - CREATE TABLE IF NOT EXISTS guild_settings ( - guild_id INTEGER PRIMARY KEY, - levelsystem_enabled BOOLEAN DEFAULT TRUE, - min_xp INTEGER DEFAULT 10, - max_xp INTEGER DEFAULT 20, - xp_cooldown INTEGER DEFAULT 30, - level_up_channel INTEGER DEFAULT NULL, - webhook_url TEXT DEFAULT NULL, - prestige_enabled BOOLEAN DEFAULT TRUE, - prestige_min_level INTEGER DEFAULT 50 - ) - ''') - - # Channel Settings Tabelle - cursor.execute(''' - CREATE TABLE IF NOT EXISTS channel_settings ( - guild_id INTEGER, - channel_id INTEGER, - xp_multiplier REAL DEFAULT 1.0, - is_blacklisted BOOLEAN DEFAULT FALSE, - PRIMARY KEY (guild_id, channel_id) - ) - ''') - - # XP Boosts Tabelle - cursor.execute(''' - CREATE TABLE IF NOT EXISTS xp_boosts ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - guild_id INTEGER, - user_id INTEGER, - multiplier REAL, - start_time REAL, - end_time REAL, - is_global BOOLEAN DEFAULT FALSE - ) - ''') - - # Achievements Tabelle - cursor.execute(''' - CREATE TABLE IF NOT EXISTS achievements ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - guild_id INTEGER, - user_id INTEGER, - achievement_type TEXT, - achievement_value INTEGER, - earned_at REAL DEFAULT (datetime('now')), - UNIQUE(guild_id, user_id, achievement_type, achievement_value) - ) - ''') - - # Temporary Roles Tabelle - cursor.execute(''' - CREATE TABLE IF NOT EXISTS temporary_roles ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - guild_id INTEGER, - user_id INTEGER, - role_id INTEGER, - granted_at REAL, - expires_at REAL - ) - ''') - - # Performance-Indizes - cursor.execute('CREATE INDEX IF NOT EXISTS idx_user_guild ON user_levels(user_id, guild_id)') - cursor.execute('CREATE INDEX IF NOT EXISTS idx_guild_xp ON user_levels(guild_id, xp DESC)') - cursor.execute('CREATE INDEX IF NOT EXISTS idx_level_roles ON level_roles(guild_id, level)') - cursor.execute('CREATE INDEX IF NOT EXISTS idx_channel_settings ON channel_settings(guild_id, channel_id)') - cursor.execute('CREATE INDEX IF NOT EXISTS idx_xp_boosts ON xp_boosts(guild_id, start_time, end_time)') - - conn.commit() - conn.close() - - def load_caches(self): - """Lรคdt hรคufig verwendete Daten in den Cache""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - # Level-Rollen Cache laden - cursor.execute('SELECT guild_id, level, role_id FROM level_roles') - for guild_id, level, role_id in cursor.fetchall(): - if guild_id not in self.level_roles_cache: - self.level_roles_cache[guild_id] = {} - self.level_roles_cache[guild_id][level] = role_id - - # Aktivierte Server laden - cursor.execute('SELECT guild_id FROM guild_settings WHERE levelsystem_enabled = TRUE') - self.enabled_guilds_cache = {row[0] for row in cursor.fetchall()} - - # Guild-Konfigurationen laden - cursor.execute('SELECT * FROM guild_settings') - for row in cursor.fetchall(): - guild_id = row[0] - self.guild_configs_cache[guild_id] = { - 'enabled': row[1], - 'min_xp': row[2], - 'max_xp': row[3], - 'cooldown': row[4], - 'level_up_channel': row[5], - 'webhook_url': row[6], - 'prestige_enabled': row[7] if len(row) > 7 else True, - 'prestige_min_level': row[8] if len(row) > 8 else 50 - } - - conn.close() - - def add_xp(self, user_id: int, guild_id: int, xp_amount: int, message_content: str = "") -> Tuple[bool, int]: - """Fรผgt XP zu einem User hinzu mit Anti-Spam Schutz""" - current_time = time.time() - - # Anti-Spam Check - if self.anti_spam.is_spam(user_id, current_time): - return False, 0 - - if message_content and self.anti_spam.is_xp_farming(user_id, message_content, current_time): - return False, 0 - - # XP-Boost anwenden - xp_amount = int(xp_amount * self.get_active_xp_multiplier(guild_id, user_id)) - - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - SELECT xp, level, messages, total_xp_earned FROM user_levels - WHERE user_id = ? AND guild_id = ? - ''', (user_id, guild_id)) - - result = cursor.fetchone() - - if result: - current_xp, current_level, messages, total_earned = result - new_xp = current_xp + xp_amount - new_level = self.calculate_level(new_xp) - new_total_earned = total_earned + xp_amount - - cursor.execute(''' - UPDATE user_levels - SET xp = ?, level = ?, messages = messages + 1, last_message = ?, total_xp_earned = ? - WHERE user_id = ? AND guild_id = ? - ''', (new_xp, new_level, current_time, new_total_earned, user_id, guild_id)) - - level_up = new_level > current_level - if level_up: - self.logger.log_level_up(user_id, guild_id, current_level, new_level) - else: - new_xp = xp_amount - new_level = self.calculate_level(new_xp) - - cursor.execute(''' - INSERT INTO user_levels (user_id, guild_id, xp, level, messages, last_message, total_xp_earned) - VALUES (?, ?, ?, ?, 1, ?, ?) - ''', (user_id, guild_id, new_xp, new_level, current_time, xp_amount)) - - level_up = new_level > 0 - - conn.commit() - conn.close() - - self.logger.log_xp_gain(user_id, guild_id, xp_amount, new_xp) - - # Achievements prรผfen - if level_up: - self.check_achievements(user_id, guild_id, new_level) - - return level_up, new_level - - def batch_add_xp(self, updates: List[Tuple[int, int, int]]): - """Fรผgt XP fรผr mehrere User in einem Batch hinzu""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - current_time = time.time() - - for user_id, guild_id, xp_amount in updates: - cursor.execute(''' - INSERT OR REPLACE INTO user_levels - (user_id, guild_id, xp, level, messages, last_message, total_xp_earned) - VALUES ( - ?, ?, - COALESCE((SELECT xp FROM user_levels WHERE user_id = ? AND guild_id = ?), 0) + ?, - ?, -- Level wird spรคter berechnet - COALESCE((SELECT messages FROM user_levels WHERE user_id = ? AND guild_id = ?), 0) + 1, - ?, - COALESCE((SELECT total_xp_earned FROM user_levels WHERE user_id = ? AND guild_id = ?), 0) + ? - ) - ''', (user_id, guild_id, user_id, guild_id, xp_amount, - self.calculate_level(xp_amount), user_id, guild_id, current_time, - user_id, guild_id, xp_amount)) - - conn.commit() - conn.close() - - def get_user_stats(self, user_id: int, guild_id: int) -> Optional[Tuple[int, int, int, int, int]]: - """Holt erweiterte User-Statistiken""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - SELECT xp, level, messages, prestige_level, total_xp_earned - FROM user_levels - WHERE user_id = ? AND guild_id = ? - ''', (user_id, guild_id)) - - result = cursor.fetchone() - conn.close() - - if result: - xp, level, messages, prestige, total_earned = result - xp_needed = self.xp_for_level(level + 1) - xp - return xp, level, messages, xp_needed, prestige, total_earned - return None - - def get_leaderboard(self, guild_id: int, limit: int = 10) -> List[Tuple[int, int, int, int, int]]: - """Holt die erweiterte Leaderboard fรผr einen Server""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - SELECT user_id, xp, level, messages, prestige_level - FROM user_levels - WHERE guild_id = ? - ORDER BY prestige_level DESC, level DESC, xp DESC - LIMIT ? - ''', (guild_id, limit)) - - result = cursor.fetchall() - conn.close() - return result - - def get_detailed_analytics(self, guild_id: int) -> Dict[str, Any]: - """Holt detaillierte Server-Analytics""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - current_time = time.time() - today_start = current_time - (current_time % 86400) # Tagesbeginn - week_start = current_time - (7 * 86400) # Eine Woche zurรผck - - analytics = {} - - # Grundlegende Statistiken - cursor.execute(''' - SELECT - COUNT(*) as total_users, - AVG(level) as avg_level, - MAX(level) as max_level, - SUM(xp) as total_xp, - SUM(messages) as total_messages - FROM user_levels WHERE guild_id = ? - ''', (guild_id,)) - - result = cursor.fetchone() - if result: - analytics.update({ - 'total_users': result[0], - 'avg_level': result[1] or 0, - 'max_level': result[2] or 0, - 'total_xp': result[3] or 0, - 'total_messages': result[4] or 0 - }) - - # Aktivitรคt heute (basierend auf last_message) - cursor.execute(''' - SELECT COUNT(*) FROM user_levels - WHERE guild_id = ? AND last_message > ? - ''', (guild_id, today_start)) - - analytics['active_today'] = cursor.fetchone()[0] - - # XP-Verteilung - cursor.execute(''' - SELECT - COUNT(CASE WHEN level BETWEEN 1 AND 10 THEN 1 END) as novice, - COUNT(CASE WHEN level BETWEEN 11 AND 25 THEN 1 END) as intermediate, - COUNT(CASE WHEN level BETWEEN 26 AND 50 THEN 1 END) as advanced, - COUNT(CASE WHEN level > 50 THEN 1 END) as expert - FROM user_levels WHERE guild_id = ? - ''', (guild_id,)) - - level_distribution = cursor.fetchone() - analytics['level_distribution'] = { - 'novice': level_distribution[0], - 'intermediate': level_distribution[1], - 'advanced': level_distribution[2], - 'expert': level_distribution[3] - } - - conn.close() - return analytics - - def set_guild_config(self, guild_id: int, **config): - """Setzt Guild-spezifische Konfiguration""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - # Aktuelle Konfiguration holen - cursor.execute('SELECT * FROM guild_settings WHERE guild_id = ?', (guild_id,)) - current = cursor.fetchone() - - if current: - # Update bestehende Konfiguration - set_clauses = [] - values = [] - for key, value in config.items(): - set_clauses.append(f"{key} = ?") - values.append(value) - values.append(guild_id) - - query = f"UPDATE guild_settings SET {', '.join(set_clauses)} WHERE guild_id = ?" - cursor.execute(query, values) - else: - # Neue Konfiguration erstellen - keys = list(config.keys()) + ['guild_id'] - values = list(config.values()) + [guild_id] - placeholders = ', '.join(['?'] * len(keys)) - - query = f"INSERT INTO guild_settings ({', '.join(keys)}) VALUES ({placeholders})" - cursor.execute(query, values) - - conn.commit() - conn.close() - - # Cache aktualisieren - if guild_id not in self.guild_configs_cache: - self.guild_configs_cache[guild_id] = {} - self.guild_configs_cache[guild_id].update(config) - - def get_guild_config(self, guild_id: int) -> Dict[str, Any]: - """Holt Guild-Konfiguration""" - if guild_id in self.guild_configs_cache: - return self.guild_configs_cache[guild_id] - - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute('SELECT * FROM guild_settings WHERE guild_id = ?', (guild_id,)) - result = cursor.fetchone() - conn.close() - - if result: - config = { - 'enabled': result[1], - 'min_xp': result[2], - 'max_xp': result[3], - 'cooldown': result[4], - 'level_up_channel': result[5], - 'webhook_url': result[6], - 'prestige_enabled': result[7] if len(result) > 7 else True, - 'prestige_min_level': result[8] if len(result) > 8 else 50 - } - else: - config = { - 'enabled': True, - 'min_xp': 10, - 'max_xp': 20, - 'cooldown': 30, - 'level_up_channel': None, - 'webhook_url': None, - 'prestige_enabled': True, - 'prestige_min_level': 50 - } - - self.guild_configs_cache[guild_id] = config - return config - - def set_channel_multiplier(self, guild_id: int, channel_id: int, multiplier: float): - """Setzt XP-Multiplikator fรผr einen Kanal""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - INSERT OR REPLACE INTO channel_settings (guild_id, channel_id, xp_multiplier) - VALUES (?, ?, ?) - ''', (guild_id, channel_id, multiplier)) - - conn.commit() - conn.close() - - def add_blacklisted_channel(self, guild_id: int, channel_id: int): - """Fรผgt einen Kanal zur Blacklist hinzu""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - INSERT OR REPLACE INTO channel_settings (guild_id, channel_id, is_blacklisted) - VALUES (?, ?, TRUE) - ''', (guild_id, channel_id)) - - conn.commit() - conn.close() - - def is_channel_blacklisted(self, guild_id: int, channel_id: int) -> bool: - """Prรผft ob ein Kanal auf der Blacklist steht""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - SELECT is_blacklisted FROM channel_settings - WHERE guild_id = ? AND channel_id = ? - ''', (guild_id, channel_id)) - - result = cursor.fetchone() - conn.close() - return result[0] if result else False - - def get_channel_multiplier(self, guild_id: int, channel_id: int) -> float: - """Holt den XP-Multiplikator fรผr einen Kanal""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - SELECT xp_multiplier FROM channel_settings - WHERE guild_id = ? AND channel_id = ? - ''', (guild_id, channel_id)) - - result = cursor.fetchone() - conn.close() - return result[0] if result else 1.0 - - def add_xp_boost(self, guild_id: int, user_id: Optional[int], multiplier: float, duration_hours: int): - """Fรผgt einen XP-Boost hinzu""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - current_time = time.time() - end_time = current_time + (duration_hours * 3600) - is_global = user_id is None - - cursor.execute(''' - INSERT INTO xp_boosts (guild_id, user_id, multiplier, start_time, end_time, is_global) - VALUES (?, ?, ?, ?, ?, ?) - ''', (guild_id, user_id, multiplier, current_time, end_time, is_global)) - - conn.commit() - conn.close() - - def get_active_xp_multiplier(self, guild_id: int, user_id: int) -> float: - """Holt den aktuell aktiven XP-Multiplikator fรผr einen User""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - current_time = time.time() - - cursor.execute(''' - SELECT multiplier FROM xp_boosts - WHERE guild_id = ? AND (user_id = ? OR is_global = TRUE) - AND start_time <= ? AND end_time > ? - ORDER BY multiplier DESC LIMIT 1 - ''', (guild_id, user_id, current_time, current_time)) - - result = cursor.fetchone() - conn.close() - return result[0] if result else 1.0 - - def prestige_user(self, user_id: int, guild_id: int) -> bool: - """Fรผhrt ein Prestige fรผr einen User durch""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - SELECT level, prestige_level FROM user_levels - WHERE user_id = ? AND guild_id = ? - ''', (user_id, guild_id)) - - result = cursor.fetchone() - if not result or result[0] < self.get_guild_config(guild_id)['prestige_min_level']: - conn.close() - return False - - old_level, current_prestige = result - - cursor.execute(''' - UPDATE user_levels - SET level = 0, xp = 0, prestige_level = prestige_level + 1 - WHERE user_id = ? AND guild_id = ? - ''', (user_id, guild_id)) - - conn.commit() - conn.close() - - self.logger.log_prestige(user_id, guild_id, old_level) - return True - - def check_achievements(self, user_id: int, guild_id: int, level: int): - """Prรผft und verleiht Achievements""" - achievements_to_grant = [] - - # Level-basierte Achievements - milestone_levels = [10, 25, 50, 75, 100] - for milestone in milestone_levels: - if level >= milestone: - achievements_to_grant.append(('level_milestone', milestone)) - - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - for achievement_type, value in achievements_to_grant: - cursor.execute(''' - INSERT OR IGNORE INTO achievements (guild_id, user_id, achievement_type, achievement_value) - VALUES (?, ?, ?, ?) - ''', (guild_id, user_id, achievement_type, value)) - - conn.commit() - conn.close() - - def export_guild_data(self, guild_id: int) -> List[Tuple]: - """Exportiert alle Guild-Daten""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - SELECT user_id, xp, level, messages, prestige_level, total_xp_earned - FROM user_levels WHERE guild_id = ? - ORDER BY prestige_level DESC, level DESC, xp DESC - ''', (guild_id,)) - - result = cursor.fetchall() - conn.close() - return result - - def get_user_rank(self, user_id: int, guild_id: int) -> int: - """Holt den Rang eines Users auf dem Server""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - SELECT COUNT(*) + 1 as rank - FROM user_levels u1 - WHERE u1.guild_id = ? AND ( - u1.prestige_level > (SELECT prestige_level FROM user_levels WHERE user_id = ? AND guild_id = ?) OR - (u1.prestige_level = (SELECT prestige_level FROM user_levels WHERE user_id = ? AND guild_id = ?) AND - u1.level > (SELECT level FROM user_levels WHERE user_id = ? AND guild_id = ?)) OR - (u1.prestige_level = (SELECT prestige_level FROM user_levels WHERE user_id = ? AND guild_id = ?) AND - u1.level = (SELECT level FROM user_levels WHERE user_id = ? AND guild_id = ?) AND - u1.xp > (SELECT xp FROM user_levels WHERE user_id = ? AND guild_id = ?)) - ) - ''', (guild_id, user_id, guild_id, user_id, guild_id, user_id, guild_id, - user_id, guild_id, user_id, guild_id, user_id, guild_id)) - - result = cursor.fetchone() - conn.close() - return result[0] if result else 0 - - def add_level_role(self, guild_id: int, level: int, role_id: int, is_temporary: bool = False, duration_hours: int = 0): - """Fรผgt eine Level-Rolle hinzu""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - INSERT OR REPLACE INTO level_roles (guild_id, level, role_id, is_temporary, duration_hours) - VALUES (?, ?, ?, ?, ?) - ''', (guild_id, level, role_id, is_temporary, duration_hours)) - - conn.commit() - conn.close() - - # Cache aktualisieren - if guild_id not in self.level_roles_cache: - self.level_roles_cache[guild_id] = {} - self.level_roles_cache[guild_id][level] = role_id - - def remove_level_role(self, guild_id: int, level: int): - """Entfernt eine Level-Rolle""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - DELETE FROM level_roles - WHERE guild_id = ? AND level = ? - ''', (guild_id, level)) - - conn.commit() - conn.close() - - # Cache aktualisieren - if guild_id in self.level_roles_cache and level in self.level_roles_cache[guild_id]: - del self.level_roles_cache[guild_id][level] - - def get_level_roles(self, guild_id: int) -> List[Tuple[int, int, bool, int]]: - """Holt alle Level-Rollen fรผr einen Server""" - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute(''' - SELECT level, role_id, is_temporary, duration_hours FROM level_roles - WHERE guild_id = ? - ORDER BY level ASC - ''', (guild_id,)) - - result = cursor.fetchall() - conn.close() - return result - - def get_role_for_level(self, guild_id: int, level: int) -> Optional[int]: - """Holt die Rolle fรผr ein bestimmtes Level aus Cache""" - if guild_id in self.level_roles_cache: - # Finde die hรถchste Rolle <= level - applicable_roles = {l: r for l, r in self.level_roles_cache[guild_id].items() if l <= level} - if applicable_roles: - highest_level = max(applicable_roles.keys()) - return applicable_roles[highest_level] - return None - - def set_levelsystem_enabled(self, guild_id: int, enabled: bool): - """Aktiviert/Deaktiviert das Levelsystem fรผr einen Server""" - self.set_guild_config(guild_id, levelsystem_enabled=enabled) - - # Cache aktualisieren - if enabled: - self.enabled_guilds_cache.add(guild_id) - else: - self.enabled_guilds_cache.discard(guild_id) - - def is_levelsystem_enabled(self, guild_id: int) -> bool: - """Prรผft ob das Levelsystem fรผr einen Server aktiviert ist (aus Cache)""" - if guild_id in self.enabled_guilds_cache: - return True - - # Fallback zur Datenbank wenn nicht im Cache - config = self.get_guild_config(guild_id) - enabled = config.get('enabled', True) - - if enabled: - self.enabled_guilds_cache.add(guild_id) - - return enabled - - @staticmethod - def calculate_level(xp: int) -> int: - """Berechnet das Level basierend auf XP""" - level = 0 - while xp >= LevelDatabase.xp_for_level(level + 1): - level += 1 - return level - - @staticmethod - def xp_for_level(level: int) -> int: - """Berechnet die benรถtigten XP fรผr ein Level""" - if level == 0: - return 0 - return int(100 * (level ** 1.5)) diff --git a/src/DevTools/backend/database/logging_db.py b/src/DevTools/backend/database/logging_db.py deleted file mode 100644 index 6abe517..0000000 --- a/src/DevTools/backend/database/logging_db.py +++ /dev/null @@ -1,413 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# File: logging_database.py - -import sqlite3 -import asyncio -import os -from typing import Optional, Dict, List -import threading -import logging - -# Setup logging -logger = logging.getLogger(__name__) - -class LoggingDatabase: - """ - Improved database class for Discord logging system - Handles all database operations for log channel configurations - """ - - def __init__(self, db_path: str = "data/log_channels.db"): - self.db_path = db_path - self._lock = threading.Lock() - self._ensure_directory() - self.init_db() - - def _ensure_directory(self): - """Stellt sicher, dass das data/ Verzeichnis existiert""" - directory = os.path.dirname(self.db_path) - if directory and not os.path.exists(directory): - os.makedirs(directory) - - def init_db(self): - """Erstellt die Tabelle fรผr Log-Channels mit verbesserter Struktur""" - try: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - - # Neue Tabelle mit separaten Eintrรคgen fรผr verschiedene Log-Typen - cursor.execute(''' - CREATE TABLE IF NOT EXISTS log_channels ( - guild_id INTEGER NOT NULL, - log_type TEXT NOT NULL, - channel_id INTEGER NOT NULL, - enabled BOOLEAN DEFAULT 1, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (guild_id, log_type) - ) - ''') - - # Index fรผr bessere Performance - cursor.execute(''' - CREATE INDEX IF NOT EXISTS idx_guild_enabled - ON log_channels (guild_id, enabled) - ''') - - cursor.execute(''' - CREATE INDEX IF NOT EXISTS idx_channel_id - ON log_channels (channel_id) - ''') - - # Migration von alter Struktur falls nรถtig - cursor.execute("PRAGMA table_info(log_channels)") - columns = [column[1] for column in cursor.fetchall()] - - if 'log_type' not in columns: - logger.info("Migrating old database structure...") - # Backup der alten Daten - cursor.execute(''' - CREATE TABLE IF NOT EXISTS log_channels_backup AS - SELECT * FROM log_channels - ''') - - # Neue Struktur erstellen - cursor.execute('DROP TABLE log_channels') - cursor.execute(''' - CREATE TABLE log_channels ( - guild_id INTEGER NOT NULL, - log_type TEXT NOT NULL DEFAULT 'general', - channel_id INTEGER NOT NULL, - enabled BOOLEAN DEFAULT 1, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (guild_id, log_type) - ) - ''') - - # Alte Daten migrieren - cursor.execute(''' - INSERT INTO log_channels (guild_id, log_type, channel_id, enabled) - SELECT guild_id, 'general', channel_id, enabled - FROM log_channels_backup - ''') - - cursor.execute('DROP TABLE log_channels_backup') - logger.info("Database migration completed successfully") - - conn.commit() - logger.info("Database initialized successfully") - - except Exception as e: - logger.error(f"Database initialization error: {e}") - raise - - async def set_log_channel(self, guild_id: int, channel_id: int, log_type: str = 'general'): - """Setzt den Log-Channel fรผr einen bestimmten Log-Typ""" - def _insert(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - cursor.execute(''' - INSERT OR REPLACE INTO log_channels - (guild_id, log_type, channel_id, enabled, updated_at) - VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) - ''', (guild_id, log_type, channel_id, True)) - conn.commit() - logger.debug(f"Set log channel: Guild {guild_id}, Type {log_type}, Channel {channel_id}") - except Exception as e: - logger.error(f"Error setting log channel: {e}") - raise - - await asyncio.get_event_loop().run_in_executor(None, _insert) - - async def get_log_channel(self, guild_id: int, log_type: str = 'general') -> Optional[int]: - """Holt die Channel-ID fรผr einen Server und Log-Typ""" - def _select(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - cursor.execute(''' - SELECT channel_id FROM log_channels - WHERE guild_id = ? AND log_type = ? AND enabled = 1 - ''', (guild_id, log_type)) - row = cursor.fetchone() - result = row[0] if row else None - logger.debug(f"Get log channel: Guild {guild_id}, Type {log_type} -> {result}") - return result - except Exception as e: - logger.error(f"Error getting log channel: {e}") - return None - - return await asyncio.get_event_loop().run_in_executor(None, _select) - - async def get_all_log_channels(self, guild_id: int) -> Dict[str, int]: - """Holt alle konfigurierten Log-Channels fรผr einen Server""" - def _select_all(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - cursor.execute(''' - SELECT log_type, channel_id FROM log_channels - WHERE guild_id = ? AND enabled = 1 - ORDER BY log_type - ''', (guild_id,)) - result = dict(cursor.fetchall()) - logger.debug(f"Get all log channels for guild {guild_id}: {len(result)} types") - return result - except Exception as e: - logger.error(f"Error getting all log channels: {e}") - return {} - - return await asyncio.get_event_loop().run_in_executor(None, _select_all) - - async def remove_log_channel(self, guild_id: int, log_type: str = None): - """Entfernt Log-Channel(s) fรผr einen Server""" - def _delete(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - if log_type: - cursor.execute(''' - DELETE FROM log_channels - WHERE guild_id = ? AND log_type = ? - ''', (guild_id, log_type)) - logger.debug(f"Removed log channel: Guild {guild_id}, Type {log_type}") - else: - cursor.execute(''' - DELETE FROM log_channels WHERE guild_id = ? - ''', (guild_id,)) - logger.debug(f"Removed all log channels for guild {guild_id}") - - deleted_count = cursor.rowcount - conn.commit() - return deleted_count - except Exception as e: - logger.error(f"Error removing log channel: {e}") - return 0 - - return await asyncio.get_event_loop().run_in_executor(None, _delete) - - async def remove_all_log_channels(self, guild_id: int): - """Entfernt alle Log-Channels fรผr einen Server""" - return await self.remove_log_channel(guild_id) - - async def disable_logging(self, guild_id: int, log_type: str = None): - """Deaktiviert das Logging fรผr einen Server (alle Typen oder spezifischen Typ)""" - def _update(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - if log_type: - cursor.execute(''' - UPDATE log_channels SET enabled = 0 - WHERE guild_id = ? AND log_type = ? - ''', (guild_id, log_type)) - else: - cursor.execute(''' - UPDATE log_channels SET enabled = 0 WHERE guild_id = ? - ''', (guild_id,)) - updated_count = cursor.rowcount - conn.commit() - logger.debug(f"Disabled logging: Guild {guild_id}, Type {log_type}, Count {updated_count}") - return updated_count - except Exception as e: - logger.error(f"Error disabling logging: {e}") - return 0 - - return await asyncio.get_event_loop().run_in_executor(None, _update) - - async def enable_logging(self, guild_id: int, log_type: str = None): - """Aktiviert das Logging fรผr einen Server (alle Typen oder spezifischen Typ)""" - def _update(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - if log_type: - cursor.execute(''' - UPDATE log_channels SET enabled = 1 - WHERE guild_id = ? AND log_type = ? - ''', (guild_id, log_type)) - else: - cursor.execute(''' - UPDATE log_channels SET enabled = 1 WHERE guild_id = ? - ''', (guild_id,)) - updated_count = cursor.rowcount - conn.commit() - logger.debug(f"Enabled logging: Guild {guild_id}, Type {log_type}, Count {updated_count}") - return updated_count - except Exception as e: - logger.error(f"Error enabling logging: {e}") - return 0 - - return await asyncio.get_event_loop().run_in_executor(None, _update) - - async def channel_exists(self, guild_id: int, log_type: str) -> bool: - """Prรผft ob ein Log-Channel fรผr den Typ existiert""" - def _exists(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - cursor.execute(''' - SELECT 1 FROM log_channels - WHERE guild_id = ? AND log_type = ? - ''', (guild_id, log_type)) - return cursor.fetchone() is not None - except Exception as e: - logger.error(f"Error checking channel existence: {e}") - return False - - return await asyncio.get_event_loop().run_in_executor(None, _exists) - - async def get_guilds_with_logging(self) -> List[int]: - """Holt alle Guild-IDs die Logging aktiviert haben""" - def _select_guilds(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - cursor.execute(''' - SELECT DISTINCT guild_id FROM log_channels WHERE enabled = 1 - ''') - result = [row[0] for row in cursor.fetchall()] - logger.debug(f"Found {len(result)} guilds with logging enabled") - return result - except Exception as e: - logger.error(f"Error getting guilds with logging: {e}") - return [] - - return await asyncio.get_event_loop().run_in_executor(None, _select_guilds) - - async def get_channels_by_guild(self, guild_id: int) -> List[Dict]: - """Holt detaillierte Channel-Info fรผr eine Guild""" - def _select_detailed(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - cursor.execute(''' - SELECT log_type, channel_id, enabled, created_at, updated_at - FROM log_channels - WHERE guild_id = ? - ORDER BY log_type - ''', (guild_id,)) - - columns = ['log_type', 'channel_id', 'enabled', 'created_at', 'updated_at'] - return [dict(zip(columns, row)) for row in cursor.fetchall()] - except Exception as e: - logger.error(f"Error getting detailed channels: {e}") - return [] - - return await asyncio.get_event_loop().run_in_executor(None, _select_detailed) - - async def cleanup_invalid_channels(self, valid_channel_ids: set): - """Entfernt ungรผltige Channel-IDs aus der Datenbank""" - def _cleanup(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - - if valid_channel_ids: - placeholders = ','.join('?' * len(valid_channel_ids)) - cursor.execute(f''' - DELETE FROM log_channels - WHERE channel_id NOT IN ({placeholders}) - ''', list(valid_channel_ids)) - else: - # Wenn keine gรผltigen Channels vorhanden, alle lรถschen - cursor.execute('DELETE FROM log_channels') - - deleted = cursor.rowcount - conn.commit() - - if deleted > 0: - logger.info(f"Cleaned up {deleted} invalid channel entries") - - return deleted - except Exception as e: - logger.error(f"Error cleaning up channels: {e}") - return 0 - - return await asyncio.get_event_loop().run_in_executor(None, _cleanup) - - async def get_statistics(self) -> Dict: - """Holt Datenbankstatistiken""" - def _get_stats(): - try: - with self._lock: - with sqlite3.connect(self.db_path) as conn: - cursor = conn.cursor() - - stats = {} - - # Total entries - cursor.execute('SELECT COUNT(*) FROM log_channels') - stats['total_entries'] = cursor.fetchone()[0] - - # Enabled entries - cursor.execute('SELECT COUNT(*) FROM log_channels WHERE enabled = 1') - stats['enabled_entries'] = cursor.fetchone()[0] - - # Unique guilds - cursor.execute('SELECT COUNT(DISTINCT guild_id) FROM log_channels') - stats['unique_guilds'] = cursor.fetchone()[0] - - # Unique channels - cursor.execute('SELECT COUNT(DISTINCT channel_id) FROM log_channels') - stats['unique_channels'] = cursor.fetchone()[0] - - # Log types distribution - cursor.execute(''' - SELECT log_type, COUNT(*) FROM log_channels - WHERE enabled = 1 - GROUP BY log_type - ''') - stats['log_types'] = dict(cursor.fetchall()) - - return stats - except Exception as e: - logger.error(f"Error getting statistics: {e}") - return {} - - return await asyncio.get_event_loop().run_in_executor(None, _get_stats) - - async def backup_database(self, backup_path: str = None) -> bool: - """Erstellt ein Backup der Datenbank""" - if not backup_path: - backup_path = f"{self.db_path}.backup" - - def _backup(): - try: - with self._lock: - # Quelle รถffnen - with sqlite3.connect(self.db_path) as source: - # Ziel erstellen - with sqlite3.connect(backup_path) as target: - source.backup(target) - - logger.info(f"Database backup created: {backup_path}") - return True - except Exception as e: - logger.error(f"Error creating backup: {e}") - return False - - return await asyncio.get_event_loop().run_in_executor(None, _backup) - - def close(self): - """Cleanup-Methode fรผr ordnungsgemรครŸe SchlieรŸung""" - logger.debug("Database connection closed") - pass - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() \ No newline at end of file diff --git a/src/DevTools/backend/database/notes_db.py b/src/DevTools/backend/database/notes_db.py deleted file mode 100644 index 16736e4..0000000 --- a/src/DevTools/backend/database/notes_db.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import sqlite3 -import os - -from colorama import Fore, Style - -class NotesDatabase: - def __init__(self, base_path): - db_path = os.path.join(base_path, "data", "notes.db") - os.makedirs(os.path.dirname(db_path), exist_ok=True) - - self.conn = sqlite3.connect(db_path) - self.cursor = self.conn.cursor() - self.cursor.execute(""" - CREATE TABLE IF NOT EXISTS notes ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - guild_id INTEGER, - user_id INTEGER, - author_id INTEGER, - author_name TEXT, - note TEXT, - timestamp TEXT - ) - """) - self.conn.commit() - - def add_note(self, guild_id, user_id, author_id, author_name, note, timestamp): - self.cursor.execute( - "INSERT INTO notes (guild_id, user_id, author_id, author_name, note, timestamp) VALUES (?, ?, ?, ?, ?, ?)", - (guild_id, user_id, author_id, author_name, note, timestamp) - ) - self.conn.commit() - - def get_notes(self, guild_id, user_id): - self.cursor.execute( - "SELECT id, note, timestamp, author_name FROM notes WHERE guild_id = ? AND user_id = ?", - (guild_id, user_id) - ) - rows = self.cursor.fetchall() - return [ - {"id": row[0], "content": row[1], "timestamp": row[2], "author_name": row[3]} - for row in rows - ] - - def delete_note(self, note_id): - self.cursor.execute("DELETE FROM notes WHERE id = ?", (note_id,)) - self.conn.commit() - return self.cursor.rowcount > 0 - - def get_note_by_id(self, note_id): - self.cursor.execute("SELECT * FROM notes WHERE id = ?", (note_id,)) - return self.cursor.fetchone() - - def close(self): - self.conn.close() diff --git a/src/DevTools/backend/database/spam_db.py b/src/DevTools/backend/database/spam_db.py deleted file mode 100644 index bcc4623..0000000 --- a/src/DevTools/backend/database/spam_db.py +++ /dev/null @@ -1,494 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import sqlite3 -import os -import logging -from datetime import datetime, timedelta -from typing import Optional, Dict, List, Tuple -from contextlib import contextmanager - -from colorama import Fore, Style - - -class SpamDBError(Exception): - """Custom exception for SpamDB errors""" - pass - - -class SpamDB: - def __init__(self, db_path='data/spam.db'): - """Initialize spam database with enhanced error handling and logging.""" - self.db_path = db_path - self.logger = logging.getLogger(__name__) - - try: - # Ensure data directory exists - os.makedirs(os.path.dirname(self.db_path), exist_ok=True) - self.conn = sqlite3.connect(self.db_path, check_same_thread=False) - self.conn.row_factory = sqlite3.Row # Enable dict-like access - self.create_tables() - self._migrate_database() # Add migration step - self._init_database() - except Exception as e: - self.logger.error(f"Failed to initialize database: {e}") - raise SpamDBError(f"Database initialization failed: {e}") - - @contextmanager - def get_cursor(self): - """Context manager for database operations with proper error handling.""" - cursor = self.conn.cursor() - try: - yield cursor - except sqlite3.Error as e: - self.conn.rollback() - self.logger.error(f"Database error: {e}") - raise SpamDBError(f"Database operation failed: {e}") - finally: - cursor.close() - - def _get_table_columns(self, table_name: str) -> List[str]: - """Get list of columns for a table.""" - with self.get_cursor() as cursor: - cursor.execute(f"PRAGMA table_info({table_name})") - return [row[1] for row in cursor.fetchall()] - - def _migrate_database(self): - """Handle database migrations for schema changes.""" - try: - tables = [table[0] for table in self._get_tables()] - - # Migrate spam_settings table - if 'spam_settings' in tables: - spam_settings_columns = self._get_table_columns('spam_settings') - if 'created_at' not in spam_settings_columns: - with self.get_cursor() as cursor: - cursor.execute( - 'ALTER TABLE spam_settings ADD COLUMN created_at DATETIME DEFAULT CURRENT_TIMESTAMP') - - if 'updated_at' not in spam_settings_columns: - with self.get_cursor() as cursor: - cursor.execute( - 'ALTER TABLE spam_settings ADD COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP') - - # Migrate spam_logs table - if 'spam_logs' in tables: - spam_logs_columns = self._get_table_columns('spam_logs') - if 'message_count' not in spam_logs_columns: - with self.get_cursor() as cursor: - cursor.execute('ALTER TABLE spam_logs ADD COLUMN message_count INTEGER DEFAULT 1') - - # Migrate spam_whitelist table - if 'spam_whitelist' in tables: - whitelist_columns = self._get_table_columns('spam_whitelist') - if 'added_by' not in whitelist_columns: - with self.get_cursor() as cursor: - cursor.execute('ALTER TABLE spam_whitelist ADD COLUMN added_by INTEGER') - - if 'added_at' not in whitelist_columns: - with self.get_cursor() as cursor: - cursor.execute( - 'ALTER TABLE spam_whitelist ADD COLUMN added_at DATETIME DEFAULT CURRENT_TIMESTAMP') - - if 'reason' not in whitelist_columns: - with self.get_cursor() as cursor: - cursor.execute('ALTER TABLE spam_whitelist ADD COLUMN reason TEXT') - - self.conn.commit() - self.logger.info("Database migration completed successfully") - - except Exception as e: - self.logger.error(f"Database migration failed: {e}") - # Don't raise here - let the application continue with basic functionality - - def _get_tables(self) -> List[Tuple]: - """Get list of all tables in the database.""" - with self.get_cursor() as cursor: - cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") - return cursor.fetchall() - - def create_tables(self): - """Create all necessary tables with improved schema.""" - with self.get_cursor() as cursor: - # Spam settings table with better constraints - cursor.execute(''' - CREATE TABLE IF NOT EXISTS spam_settings ( - guild_id INTEGER PRIMARY KEY, - max_messages INTEGER DEFAULT 5 CHECK (max_messages > 0), - time_frame INTEGER DEFAULT 10 CHECK (time_frame > 0), - log_channel_id INTEGER - ) - ''') - - # Spam logs with better indexing - cursor.execute(''' - CREATE TABLE IF NOT EXISTS spam_logs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - guild_id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - message TEXT NOT NULL, - message_count INTEGER DEFAULT 1, - timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (guild_id) REFERENCES spam_settings(guild_id) - ) - ''') - - # Whitelist with better constraints - cursor.execute(''' - CREATE TABLE IF NOT EXISTS spam_whitelist ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - guild_id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - UNIQUE(guild_id, user_id) - ) - ''') - - # Create indexes for better performance - cursor.execute(''' - CREATE INDEX IF NOT EXISTS idx_spam_logs_guild_timestamp - ON spam_logs(guild_id, timestamp) - ''') - - cursor.execute(''' - CREATE INDEX IF NOT EXISTS idx_spam_logs_user_timestamp - ON spam_logs(user_id, timestamp) - ''') - - cursor.execute(''' - CREATE INDEX IF NOT EXISTS idx_whitelist_guild_user - ON spam_whitelist(guild_id, user_id) - ''') - - self.conn.commit() - - def _init_database(self): - """Initialize database with any required default data.""" - # Add any initialization logic here if needed - pass - - def set_spam_settings(self, guild_id: int, max_messages: int = 5, - time_frame: int = 10, log_channel_id: Optional[int] = None) -> bool: - """Set spam detection settings for a guild with validation.""" - if max_messages <= 0 or time_frame <= 0: - raise SpamDBError("max_messages and time_frame must be positive integers") - - with self.get_cursor() as cursor: - # Check if updated_at column exists - columns = self._get_table_columns('spam_settings') - - if 'updated_at' in columns: - cursor.execute(''' - INSERT OR REPLACE INTO spam_settings - (guild_id, max_messages, time_frame, log_channel_id, updated_at) - VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) - ''', (guild_id, max_messages, time_frame, log_channel_id)) - else: - # Fallback for tables without updated_at column - cursor.execute(''' - INSERT OR REPLACE INTO spam_settings - (guild_id, max_messages, time_frame, log_channel_id) - VALUES (?, ?, ?, ?) - ''', (guild_id, max_messages, time_frame, log_channel_id)) - - self.conn.commit() - return True - - def set_log_channel(self, guild_id: int, channel_id: int) -> bool: - """Set the log channel for a guild.""" - with self.get_cursor() as cursor: - # Get current settings or use defaults - cursor.execute('SELECT max_messages, time_frame FROM spam_settings WHERE guild_id = ?', - (guild_id,)) - result = cursor.fetchone() - - if result: - max_messages, time_frame = result['max_messages'], result['time_frame'] - else: - max_messages, time_frame = 5, 10 # Default values - - # Check if updated_at column exists - columns = self._get_table_columns('spam_settings') - - if 'updated_at' in columns: - cursor.execute(''' - INSERT OR REPLACE INTO spam_settings - (guild_id, max_messages, time_frame, log_channel_id, updated_at) - VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) - ''', (guild_id, max_messages, time_frame, channel_id)) - else: - cursor.execute(''' - INSERT OR REPLACE INTO spam_settings - (guild_id, max_messages, time_frame, log_channel_id) - VALUES (?, ?, ?, ?) - ''', (guild_id, max_messages, time_frame, channel_id)) - - self.conn.commit() - return True - - def get_spam_settings(self, guild_id: int) -> Optional[Dict]: - """Get spam settings for a guild.""" - with self.get_cursor() as cursor: - columns = self._get_table_columns('spam_settings') - - # Build query based on available columns - select_columns = ['max_messages', 'time_frame', 'log_channel_id'] - if 'created_at' in columns: - select_columns.append('created_at') - if 'updated_at' in columns: - select_columns.append('updated_at') - - query = f"SELECT {', '.join(select_columns)} FROM spam_settings WHERE guild_id = ?" - cursor.execute(query, (guild_id,)) - result = cursor.fetchone() - - if result: - settings = { - 'max_messages': result['max_messages'], - 'time_frame': result['time_frame'], - 'log_channel_id': result['log_channel_id'] - } - - if 'created_at' in columns: - settings['created_at'] = result.get('created_at') - if 'updated_at' in columns: - settings['updated_at'] = result.get('updated_at') - - return settings - return None - - def get_log_channel(self, guild_id: int) -> Optional[int]: - """Get the log channel ID for a guild.""" - with self.get_cursor() as cursor: - cursor.execute(''' - SELECT log_channel_id FROM spam_settings WHERE guild_id = ? - ''', (guild_id,)) - result = cursor.fetchone() - return result['log_channel_id'] if result and result['log_channel_id'] else None - - def log_spam(self, guild_id: int, user_id: int, message: str, message_count: int = 1) -> bool: - """Log a spam incident with message count.""" - with self.get_cursor() as cursor: - columns = self._get_table_columns('spam_logs') - - if 'message_count' in columns: - cursor.execute(''' - INSERT INTO spam_logs (guild_id, user_id, message, message_count) - VALUES (?, ?, ?, ?) - ''', (guild_id, user_id, message[:1000], message_count)) - else: - # Fallback for tables without message_count column - cursor.execute(''' - INSERT INTO spam_logs (guild_id, user_id, message) - VALUES (?, ?, ?) - ''', (guild_id, user_id, message[:1000])) - - self.conn.commit() - return True - - def get_spam_logs(self, guild_id: int, limit: int = 10) -> List[Dict]: - """Get recent spam logs for a guild.""" - with self.get_cursor() as cursor: - cursor.execute(''' - SELECT user_id, message, message_count, timestamp - FROM spam_logs WHERE guild_id = ? - ORDER BY timestamp DESC LIMIT ? - ''', (guild_id, limit)) - - return [ - { - 'user_id': row['user_id'], - 'message': row['message'], - 'message_count': row['message_count'], - 'timestamp': row['timestamp'] - } - for row in cursor.fetchall() - ] - - def get_user_spam_history(self, guild_id: int, user_id: int, - hours: int = 24, limit: int = 50) -> List[Dict]: - """Get spam history for a specific user within a time frame.""" - cutoff_time = datetime.now() - timedelta(hours=hours) - - with self.get_cursor() as cursor: - cursor.execute(''' - SELECT message, message_count, timestamp - FROM spam_logs - WHERE guild_id = ? AND user_id = ? AND timestamp > ? - ORDER BY timestamp DESC LIMIT ? - ''', (guild_id, user_id, cutoff_time, limit)) - - return [ - { - 'message': row['message'], - 'message_count': row['message_count'], - 'timestamp': row['timestamp'] - } - for row in cursor.fetchall() - ] - - def clear_spam_logs(self, guild_id: int, older_than_days: Optional[int] = None) -> int: - """Clear spam logs for a guild, optionally only older entries.""" - with self.get_cursor() as cursor: - if older_than_days: - cutoff_date = datetime.now() - timedelta(days=older_than_days) - cursor.execute(''' - DELETE FROM spam_logs - WHERE guild_id = ? AND timestamp < ? - ''', (guild_id, cutoff_date)) - else: - cursor.execute('DELETE FROM spam_logs WHERE guild_id = ?', (guild_id,)) - - deleted_count = cursor.rowcount - self.conn.commit() - return deleted_count - - def add_to_whitelist(self, guild_id: int, user_id: int, - added_by: Optional[int] = None, reason: Optional[str] = None) -> bool: - """Add user to spam whitelist with additional metadata.""" - with self.get_cursor() as cursor: - columns = self._get_table_columns('spam_whitelist') - - # Build query based on available columns - if 'added_by' in columns and 'reason' in columns: - cursor.execute(''' - INSERT OR IGNORE INTO spam_whitelist (guild_id, user_id, added_by, reason) - VALUES (?, ?, ?, ?) - ''', (guild_id, user_id, added_by, reason)) - else: - cursor.execute(''' - INSERT OR IGNORE INTO spam_whitelist (guild_id, user_id) - VALUES (?, ?) - ''', (guild_id, user_id)) - - success = cursor.rowcount > 0 - self.conn.commit() - return success - - def remove_from_whitelist(self, guild_id: int, user_id: int) -> bool: - """Remove user from spam whitelist.""" - with self.get_cursor() as cursor: - cursor.execute(''' - DELETE FROM spam_whitelist WHERE guild_id = ? AND user_id = ? - ''', (guild_id, user_id)) - success = cursor.rowcount > 0 - self.conn.commit() - return success - - def is_whitelisted(self, guild_id: int, user_id: int) -> bool: - """Check if user is whitelisted.""" - with self.get_cursor() as cursor: - cursor.execute(''' - SELECT 1 FROM spam_whitelist WHERE guild_id = ? AND user_id = ? - ''', (guild_id, user_id)) - return cursor.fetchone() is not None - - def get_whitelist(self, guild_id: int) -> List[Dict]: - """Get all whitelisted users for a guild with metadata.""" - with self.get_cursor() as cursor: - columns = self._get_table_columns('spam_whitelist') - - # Build query based on available columns - select_columns = ['user_id'] - if 'added_by' in columns: - select_columns.append('added_by') - if 'added_at' in columns: - select_columns.append('added_at') - if 'reason' in columns: - select_columns.append('reason') - - query = f"SELECT {', '.join(select_columns)} FROM spam_whitelist WHERE guild_id = ? ORDER BY user_id" - cursor.execute(query, (guild_id,)) - - result = [] - for row in cursor.fetchall(): - entry = {'user_id': row['user_id']} - if 'added_by' in columns: - entry['added_by'] = row.get('added_by') - if 'added_at' in columns: - entry['added_at'] = row.get('added_at') - if 'reason' in columns: - entry['reason'] = row.get('reason') - result.append(entry) - - return result - - def get_guild_stats(self, guild_id: int) -> Dict: - """Get comprehensive statistics for a guild.""" - with self.get_cursor() as cursor: - # Get spam logs count - cursor.execute('SELECT COUNT(*) as total FROM spam_logs WHERE guild_id = ?', (guild_id,)) - total_logs = cursor.fetchone()['total'] - - # Get recent spam (last 24 hours) - yesterday = datetime.now() - timedelta(hours=24) - cursor.execute(''' - SELECT COUNT(*) as recent FROM spam_logs - WHERE guild_id = ? AND timestamp > ? - ''', (guild_id, yesterday)) - recent_logs = cursor.fetchone()['recent'] - - # Get whitelist count - cursor.execute('SELECT COUNT(*) as count FROM spam_whitelist WHERE guild_id = ?', (guild_id,)) - whitelist_count = cursor.fetchone()['count'] - - # Get top spammers (last 7 days) - week_ago = datetime.now() - timedelta(days=7) - cursor.execute(''' - SELECT user_id, COUNT(*) as spam_count, SUM(message_count) as total_messages - FROM spam_logs - WHERE guild_id = ? AND timestamp > ? - GROUP BY user_id - ORDER BY spam_count DESC - LIMIT 5 - ''', (guild_id, week_ago)) - top_spammers = cursor.fetchall() - - return { - 'total_spam_logs': total_logs, - 'recent_spam_logs': recent_logs, - 'whitelist_count': whitelist_count, - 'top_spammers': [ - { - 'user_id': row['user_id'], - 'spam_incidents': row['spam_count'], - 'total_messages': row['total_messages'] - } - for row in top_spammers - ] - } - - def cleanup_old_logs(self, days_to_keep: int = 30) -> int: - """Clean up old spam logs across all guilds.""" - cutoff_date = datetime.now() - timedelta(days=days_to_keep) - - with self.get_cursor() as cursor: - cursor.execute('DELETE FROM spam_logs WHERE timestamp < ?', (cutoff_date,)) - deleted_count = cursor.rowcount - self.conn.commit() - - if deleted_count > 0: - self.logger.info(f"Cleaned up {deleted_count} old spam logs") - - return deleted_count - - def backup_database(self, backup_path: str) -> bool: - """Create a backup of the database.""" - try: - backup_conn = sqlite3.connect(backup_path) - self.conn.backup(backup_conn) - backup_conn.close() - return True - except Exception as e: - self.logger.error(f"Backup failed: {e}") - return False - - def __enter__(self): - """Context manager entry.""" - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - """Context manager exit with proper cleanup.""" - self.close() - - def close(self): - """Close database connection.""" - if hasattr(self, 'conn') and self.conn: - self.conn.close() \ No newline at end of file diff --git a/src/DevTools/backend/database/vc_db.py b/src/DevTools/backend/database/vc_db.py deleted file mode 100644 index 2319667..0000000 --- a/src/DevTools/backend/database/vc_db.py +++ /dev/null @@ -1,176 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import sqlite3 -import os -from typing import Optional, Tuple -from colorama import Fore, Style - -class TempVCDatabase: - def __init__(self, db_path: str = "data/tempvc.db"): - self.db_path = db_path - os.makedirs(os.path.dirname(self.db_path), exist_ok=True) - self.init_db() - - def init_db(self): - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute(''' - CREATE TABLE IF NOT EXISTS tempvc_settings ( - guild_id INTEGER PRIMARY KEY, - creator_channel_id INTEGER NOT NULL, - category_id INTEGER NOT NULL, - auto_delete_time INTEGER DEFAULT 0 - ) - ''') - cursor.execute(''' - CREATE TABLE IF NOT EXISTS temp_channels ( - channel_id INTEGER PRIMARY KEY, - guild_id INTEGER NOT NULL, - owner_id INTEGER NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ) - ''') - # New table for UI settings - cursor.execute(''' - CREATE TABLE IF NOT EXISTS ui_settings ( - guild_id INTEGER PRIMARY KEY, - ui_enabled BOOLEAN DEFAULT 0, - ui_prefix TEXT DEFAULT '๐Ÿ”ง' - ) - ''') - conn.commit() - conn.close() - - def set_tempvc_settings(self, guild_id: int, creator_channel_id: int, category_id: int, auto_delete_time: int = 0): - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute(''' - INSERT OR REPLACE INTO tempvc_settings - (guild_id, creator_channel_id, category_id, auto_delete_time) - VALUES (?, ?, ?, ?) - ''', (guild_id, creator_channel_id, category_id, auto_delete_time)) - conn.commit() - conn.close() - - def get_tempvc_settings(self, guild_id: int) -> Optional[Tuple[int, int, int]]: - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute(''' - SELECT creator_channel_id, category_id, auto_delete_time - FROM tempvc_settings - WHERE guild_id = ? - ''', (guild_id,)) - result = cursor.fetchone() - conn.close() - return result - - def remove_tempvc_settings(self, guild_id: int): - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute('DELETE FROM tempvc_settings WHERE guild_id = ?', (guild_id,)) - cursor.execute('DELETE FROM temp_channels WHERE guild_id = ?', (guild_id,)) - cursor.execute('DELETE FROM ui_settings WHERE guild_id = ?', (guild_id,)) # Also remove UI settings - conn.commit() - conn.close() - - def add_temp_channel(self, channel_id: int, guild_id: int, owner_id: int): - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute(''' - INSERT INTO temp_channels (channel_id, guild_id, owner_id) - VALUES (?, ?, ?) - ''', (channel_id, guild_id, owner_id)) - conn.commit() - conn.close() - - def remove_temp_channel(self, channel_id: int): - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute('DELETE FROM temp_channels WHERE channel_id = ?', (channel_id,)) - conn.commit() - conn.close() - - def is_temp_channel(self, channel_id: int) -> bool: - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute('SELECT 1 FROM temp_channels WHERE channel_id = ?', (channel_id,)) - result = cursor.fetchone() - conn.close() - return result is not None - - def get_temp_channel_owner(self, channel_id: int) -> Optional[int]: - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute('SELECT owner_id FROM temp_channels WHERE channel_id = ?', (channel_id,)) - result = cursor.fetchone() - conn.close() - return result[0] if result else None - - def get_all_temp_channels(self, guild_id: int) -> list: - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute(''' - SELECT channel_id, owner_id, created_at - FROM temp_channels - WHERE guild_id = ? - ''', (guild_id,)) - result = cursor.fetchall() - conn.close() - return result - - def update_channel_activity(self, channel_id: int): - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute(''' - UPDATE temp_channels - SET last_activity = CURRENT_TIMESTAMP - WHERE channel_id = ? - ''', (channel_id,)) - conn.commit() - conn.close() - - def get_channels_to_delete(self, guild_id: int, minutes_inactive: int) -> list: - if minutes_inactive <= 0: - return [] - - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute(''' - SELECT channel_id FROM temp_channels - WHERE guild_id = ? - AND datetime(last_activity, ? || ' minutes') < datetime('now') - ''', (guild_id, str(minutes_inactive))) # Fixed SQL injection - result = [row[0] for row in cursor.fetchall()] - conn.close() - return result - - # New UI Settings methods - def set_ui_settings(self, guild_id: int, ui_enabled: bool, ui_prefix: str = "๐Ÿ”ง"): - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute(''' - INSERT OR REPLACE INTO ui_settings - (guild_id, ui_enabled, ui_prefix) - VALUES (?, ?, ?) - ''', (guild_id, ui_enabled, ui_prefix)) - conn.commit() - conn.close() - - def get_ui_settings(self, guild_id: int) -> Optional[Tuple[bool, str]]: - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute(''' - SELECT ui_enabled, ui_prefix - FROM ui_settings - WHERE guild_id = ? - ''', (guild_id,)) - result = cursor.fetchone() - conn.close() - return result - - def remove_ui_settings(self, guild_id: int): - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - cursor.execute('DELETE FROM ui_settings WHERE guild_id = ?', (guild_id,)) - conn.commit() - conn.close() \ No newline at end of file diff --git a/src/DevTools/backend/database/warn_db.py b/src/DevTools/backend/database/warn_db.py deleted file mode 100644 index 13ad680..0000000 --- a/src/DevTools/backend/database/warn_db.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import os -import sqlite3 -from contextlib import contextmanager - -from colorama import Fore, Style -class WarnDatabase: - def __init__(self, base_path): - self.db_path = os.path.join(base_path, "Datenbanken", "warns.db") - os.makedirs(os.path.dirname(self.db_path), exist_ok=True) - - # Initialize the database - self._init_database() - def _init_database(self): - """Initialize the database with required tables""" - with self._get_connection() as conn: - cursor = conn.cursor() - cursor.execute(""" - CREATE TABLE IF NOT EXISTS warns ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - guild_id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - moderator_id INTEGER NOT NULL, - reason TEXT NOT NULL, - timestamp TEXT NOT NULL - ) - """) - conn.commit() - - @contextmanager - def _get_connection(self): - """Context manager for database connections""" - conn = sqlite3.connect(self.db_path) - try: - yield conn - finally: - conn.close() - - def add_warning(self, guild_id, user_id, moderator_id, reason, timestamp): - """Add a warning to the database""" - try: - with self._get_connection() as conn: - cursor = conn.cursor() - cursor.execute( - "INSERT INTO warns (guild_id, user_id, moderator_id, reason, timestamp) VALUES (?, ?, ?, ?, ?)", - (guild_id, user_id, moderator_id, reason, timestamp) - ) - conn.commit() - warning_id = cursor.lastrowid - print(f"Warning added successfully with ID: {warning_id}") - return warning_id - except Exception as e: - print(f"Error adding warning: {e}") - raise - - def get_warnings(self, guild_id, user_id): - """Get all warnings for a specific user in a guild""" - try: - with self._get_connection() as conn: - cursor = conn.cursor() - cursor.execute( - "SELECT id, reason, timestamp FROM warns WHERE guild_id = ? AND user_id = ? ORDER BY id DESC", - (guild_id, user_id) - ) - return cursor.fetchall() - except Exception as e: - print(f"Error getting warnings: {e}") - return [] - - def get_warning_by_id(self, warn_id): - """Get a specific warning by ID""" - try: - with self._get_connection() as conn: - cursor = conn.cursor() - cursor.execute("SELECT * FROM warns WHERE id = ?", (warn_id,)) - return cursor.fetchone() - except Exception as e: - print(f"Error getting warning by ID: {e}") - return None - - def delete_warning(self, warn_id): - """Delete a warning by ID""" - try: - with self._get_connection() as conn: - cursor = conn.cursor() - cursor.execute("DELETE FROM warns WHERE id = ?", (warn_id,)) - conn.commit() - if cursor.rowcount > 0: - print(f"Warning {warn_id} deleted successfully") - return True - else: - print(f"Warning {warn_id} not found") - return False - except Exception as e: - print(f"Error deleting warning: {e}") - return False - - def get_warning_count(self, guild_id, user_id): - """Get the total number of warnings for a user""" - try: - with self._get_connection() as conn: - cursor = conn.cursor() - cursor.execute( - "SELECT COUNT(*) FROM warns WHERE guild_id = ? AND user_id = ?", - (guild_id, user_id) - ) - return cursor.fetchone()[0] - except Exception as e: - print(f"Error getting warning count: {e}") - return 0 - - def get_total_warnings(self): - """Get total number of warnings in database (for debugging)""" - try: - with self._get_connection() as conn: - cursor = conn.cursor() - cursor.execute("SELECT COUNT(*) FROM warns") - return cursor.fetchone()[0] - except Exception as e: - print(f"Error getting total warnings: {e}") - return 0 \ No newline at end of file diff --git a/src/DevTools/backend/database/welcome_db.py b/src/DevTools/backend/database/welcome_db.py deleted file mode 100644 index 5336ad6..0000000 --- a/src/DevTools/backend/database/welcome_db.py +++ /dev/null @@ -1,552 +0,0 @@ -""" -Welcome Database Handler -========================= - -Datenbank-Handler fรผr das Welcome System mit vollstรคndiger -Rรผckwรคrtskompatibilitรคt und automatischer Migration. - -Copyright (c) 2025 OPPRO.NET Network -""" - -import sqlite3 -import aiosqlite -import asyncio -import logging -from typing import Optional, Dict, Any -from datetime import datetime - -# Logger Setup -logger = logging.getLogger(__name__) - - -class WelcomeDatabase: - """ - Datenbank-Handler fรผr Welcome System Einstellungen. - - Bietet synchrone und asynchrone Methoden mit automatischer - Fallback-Logik fรผr Rรผckwรคrtskompatibilitรคt. Unterstรผtzt - automatische Datenbankmigrationen. - - Parameters - ---------- - db_path : str, optional - Pfad zur SQLite-Datenbank, by default "data/welcome.db" - - Attributes - ---------- - db_path : str - Pfad zur SQLite-Datenbank - migration_done : bool - Status der Datenbankmigrierung - - Examples - -------- - >>> db = WelcomeDatabase() - >>> await db.update_welcome_settings(123456, channel_id=789012) - True - """ - - def __init__(self, db_path: str = "data/welcome.db"): - """ - Initialisiert den Datenbank-Handler. - - Parameters - ---------- - db_path : str, optional - Pfad zur SQLite-Datenbank, by default "data/welcome.db" - - Notes - ----- - Erstellt automatisch die Basis-Tabellen wenn sie nicht existieren. - """ - self.db_path = db_path - self.migration_done = False - self.init_database() - - def init_database(self): - """ - Initialisiert die Datenbank synchron fรผr Rรผckwรคrtskompatibilitรคt. - - Notes - ----- - Erstellt die Basis-Tabelle `welcome_settings` mit allen - ursprรผnglichen Feldern. Neue Felder werden spรคter durch - `migrate_database()` hinzugefรผgt. - - Diese Methode ist synchron um Kompatibilitรคt mit รคlteren - Versionen zu gewรคhrleisten. - """ - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - # Basis-Tabelle erstellen (alte Version) - cursor.execute(''' - CREATE TABLE IF NOT EXISTS welcome_settings ( - guild_id INTEGER PRIMARY KEY, - channel_id INTEGER, - welcome_message TEXT, - enabled INTEGER DEFAULT 1, - embed_enabled INTEGER DEFAULT 0, - embed_color TEXT DEFAULT '#00ff00', - embed_title TEXT, - embed_description TEXT, - embed_thumbnail INTEGER DEFAULT 0, - embed_footer TEXT, - ping_user INTEGER DEFAULT 0, - delete_after INTEGER DEFAULT 0, - created_at TEXT DEFAULT (datetime('now')), - updated_at TEXT DEFAULT (datetime('now')) - ) - ''') - - conn.commit() - conn.close() - - async def migrate_database(self): - """ - Migriert die Datenbank zu neuen Features (async). - - Notes - ----- - Fรผgt folgende neue Spalten hinzu: - - auto_role_id: Automatische Rollenvergabe - - join_dm_enabled: Private Willkommensnachrichten - - join_dm_message: DM Nachrichtentext - - template_name: Verwendete Vorlage - - welcome_stats_enabled: Statistik-Tracking - - rate_limit_enabled: Rate-Limiting aktiv - - rate_limit_seconds: Rate-Limit Zeitfenster - - Erstellt auรŸerdem die `welcome_stats` Tabelle fรผr Statistiken. - - Die Migrierung wird nur einmal pro Instanz ausgefรผhrt. - """ - if self.migration_done: - return - - try: - async with aiosqlite.connect(self.db_path) as conn: - # Prรผfe welche Spalten bereits existieren - cursor = await conn.execute("PRAGMA table_info(welcome_settings)") - columns = await cursor.fetchall() - existing_columns = [col[1] for col in columns] - - # Neue Spalten hinzufรผgen falls nicht vorhanden - new_columns = { - 'auto_role_id': 'INTEGER', - 'join_dm_enabled': 'INTEGER DEFAULT 0', - 'join_dm_message': 'TEXT', - 'template_name': 'TEXT', - 'welcome_stats_enabled': 'INTEGER DEFAULT 0', - 'rate_limit_enabled': 'INTEGER DEFAULT 1', - 'rate_limit_seconds': 'INTEGER DEFAULT 60' - } - - for column_name, column_def in new_columns.items(): - if column_name not in existing_columns: - try: - await conn.execute(f'ALTER TABLE welcome_settings ADD COLUMN {column_name} {column_def}') - logger.info(f"Spalte {column_name} hinzugefรผgt") - except sqlite3.OperationalError: - # Spalte existiert bereits - pass - - # Neue Tabelle fรผr Statistiken - await conn.execute(''' - CREATE TABLE IF NOT EXISTS welcome_stats ( - guild_id INTEGER, - date TEXT, - joins INTEGER DEFAULT 0, - leaves INTEGER DEFAULT 0, - PRIMARY KEY (guild_id, date) - ) - ''') - - await conn.commit() - self.migration_done = True - logger.info("Datenbankmigrierung abgeschlossen") - - except Exception as e: - logger.error(f"Fehler bei Datenbankmigrierung: {e}") - - async def set_welcome_channel(self, guild_id: int, channel_id: int) -> bool: - """ - Setzt den Welcome Channel (Rรผckwรคrtskompatible Methode). - - Parameters - ---------- - guild_id : int - Discord Server ID - channel_id : int - Discord Channel ID - - Returns - ------- - bool - True bei Erfolg, False bei Fehler - - Notes - ----- - Diese Methode ist deprecated, verwende stattdessen - `update_welcome_settings(guild_id, channel_id=channel_id)`. - """ - return await self.update_welcome_settings(guild_id, channel_id=channel_id) - - async def set_welcome_message(self, guild_id: int, message: str) -> bool: - """ - Setzt die Welcome Message (Rรผckwรคrtskompatible Methode). - - Parameters - ---------- - guild_id : int - Discord Server ID - message : str - Welcome Message Text - - Returns - ------- - bool - True bei Erfolg, False bei Fehler - - Notes - ----- - Diese Methode ist deprecated, verwende stattdessen - `update_welcome_settings(guild_id, welcome_message=message)`. - """ - return await self.update_welcome_settings(guild_id, welcome_message=message) - - async def update_welcome_settings(self, guild_id: int, **kwargs) -> bool: - """ - Aktualisiert Welcome Einstellungen mit Fallback auf sync. - - Parameters - ---------- - guild_id : int - Discord Server ID - **kwargs : dict - Felder zum Aktualisieren (siehe Notes) - - Returns - ------- - bool - True bei Erfolg, False bei Fehler - - Notes - ----- - Gรผltige Felder in kwargs: - - channel_id : int - - welcome_message : str - - enabled : bool/int - - embed_enabled : bool/int - - embed_color : str (Hex-Format) - - embed_title : str - - embed_description : str - - embed_thumbnail : bool/int - - embed_footer : str - - ping_user : bool/int - - delete_after : int (Sekunden) - - auto_role_id : int - - join_dm_enabled : bool/int - - join_dm_message : str - - template_name : str - - welcome_stats_enabled : bool/int - - rate_limit_enabled : bool/int - - rate_limit_seconds : int - - Erstellt automatisch einen neuen Eintrag wenn keiner existiert. - Bei async-Fehlern wird automatisch auf sync Fallback gewechselt. - - Examples - -------- - >>> await db.update_welcome_settings( - ... 123456, - ... channel_id=789012, - ... welcome_message="Willkommen %mention%!", - ... embed_enabled=True - ... ) - True - """ - try: - await self.migrate_database() - - async with aiosqlite.connect(self.db_path) as conn: - # Prรผfen ob Eintrag existiert - cursor = await conn.execute('SELECT guild_id FROM welcome_settings WHERE guild_id = ?', (guild_id,)) - exists = await cursor.fetchone() - - if not exists: - # Neuen Eintrag erstellen - await conn.execute(''' - INSERT INTO welcome_settings (guild_id) VALUES (?) - ''', (guild_id,)) - - # Dynamisch die Felder aktualisieren - valid_fields = [ - 'channel_id', 'welcome_message', 'enabled', 'embed_enabled', - 'embed_color', 'embed_title', 'embed_description', 'embed_thumbnail', - 'embed_footer', 'ping_user', 'delete_after', 'auto_role_id', - 'join_dm_enabled', 'join_dm_message', 'template_name', - 'welcome_stats_enabled', 'rate_limit_enabled', 'rate_limit_seconds' - ] - - update_fields = [] - values = [] - - for key, value in kwargs.items(): - if key in valid_fields: - update_fields.append(f"{key} = ?") - values.append(value) - - if update_fields: - update_fields.append("updated_at = datetime('now')") - query = f"UPDATE welcome_settings SET {', '.join(update_fields)} WHERE guild_id = ?" - values.append(guild_id) - await conn.execute(query, values) - - await conn.commit() - return True - - except Exception as e: - logger.error(f"Async Update fehlgeschlagen, verwende Sync Fallback: {e}") - # Fallback auf synchrone Version - return self._sync_update_welcome_settings(guild_id, **kwargs) - - def _sync_update_welcome_settings(self, guild_id: int, **kwargs) -> bool: - """ - Sync Fallback fรผr alte Versionen. - - Parameters - ---------- - guild_id : int - Discord Server ID - **kwargs : dict - Felder zum Aktualisieren - - Returns - ------- - bool - True bei Erfolg, False bei Fehler - - Notes - ----- - Unterstรผtzt nur Basis-Felder fรผr Rรผckwรคrtskompatibilitรคt. - Neue Felder werden ignoriert. - """ - try: - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute('SELECT guild_id FROM welcome_settings WHERE guild_id = ?', (guild_id,)) - exists = cursor.fetchone() - - if not exists: - cursor.execute('INSERT INTO welcome_settings (guild_id) VALUES (?)', (guild_id,)) - - # Nur bekannte Felder fรผr Rรผckwรคrtskompatibilitรคt - valid_fields = [ - 'channel_id', 'welcome_message', 'enabled', 'embed_enabled', - 'embed_color', 'embed_title', 'embed_description', 'embed_thumbnail', - 'embed_footer', 'ping_user', 'delete_after' - ] - - update_fields = [] - values = [] - - for key, value in kwargs.items(): - if key in valid_fields: - update_fields.append(f"{key} = ?") - values.append(value) - - if update_fields: - update_fields.append("updated_at = datetime('now')") - query = f"UPDATE welcome_settings SET {', '.join(update_fields)} WHERE guild_id = ?" - values.append(guild_id) - cursor.execute(query, values) - - conn.commit() - conn.close() - return True - - except Exception as e: - logger.error(f"Sync Update Fehler: {e}") - return False - - async def get_welcome_settings(self, guild_id: int) -> Optional[Dict[str, Any]]: - """ - Holt Welcome Einstellungen mit sync Fallback. - - Parameters - ---------- - guild_id : int - Discord Server ID - - Returns - ------- - dict or None - Dictionary mit allen Einstellungen oder None wenn nicht vorhanden - - Notes - ----- - Gibt ein Dictionary zurรผck mit allen Feldern als Keys. - Bei async-Fehlern wird automatisch auf sync Fallback gewechselt. - - Examples - -------- - >>> settings = await db.get_welcome_settings(123456) - >>> if settings: - ... print(settings['channel_id']) - ... print(settings['welcome_message']) - """ - try: - await self.migrate_database() - - async with aiosqlite.connect(self.db_path) as conn: - cursor = await conn.execute('SELECT * FROM welcome_settings WHERE guild_id = ?', (guild_id,)) - result = await cursor.fetchone() - - if result: - columns = [description[0] for description in cursor.description] - return dict(zip(columns, result)) - return None - - except Exception as e: - logger.error(f"Async Get fehlgeschlagen, verwende Sync Fallback: {e}") - return self._sync_get_welcome_settings(guild_id) - - def _sync_get_welcome_settings(self, guild_id: int) -> Optional[Dict[str, Any]]: - """ - Sync Fallback fรผr Einstellungen holen. - - Parameters - ---------- - guild_id : int - Discord Server ID - - Returns - ------- - dict or None - Dictionary mit Einstellungen oder None - """ - try: - conn = sqlite3.connect(self.db_path) - cursor = conn.cursor() - - cursor.execute('SELECT * FROM welcome_settings WHERE guild_id = ?', (guild_id,)) - result = cursor.fetchone() - - if result: - columns = [description[0] for description in cursor.description] - return dict(zip(columns, result)) - - conn.close() - return None - - except Exception as e: - logger.error(f"Sync Get Fehler: {e}") - return None - - async def delete_welcome_settings(self, guild_id: int) -> bool: - """ - Lรถscht alle Welcome Einstellungen fรผr einen Server. - - Parameters - ---------- - guild_id : int - Discord Server ID - - Returns - ------- - bool - True bei Erfolg, False bei Fehler - - Notes - ----- - Lรถscht nur die Einstellungen, nicht die Statistiken. - Diese Aktion kann nicht rรผckgรคngig gemacht werden. - """ - try: - async with aiosqlite.connect(self.db_path) as conn: - await conn.execute('DELETE FROM welcome_settings WHERE guild_id = ?', (guild_id,)) - await conn.commit() - return True - except Exception as e: - logger.error(f"Fehler beim Lรถschen: {e}") - return False - - async def toggle_welcome(self, guild_id: int) -> Optional[bool]: - """ - Schaltet das Welcome System ein/aus. - - Parameters - ---------- - guild_id : int - Discord Server ID - - Returns - ------- - bool or None - Neuer Status (True=aktiviert, False=deaktiviert) - oder None wenn keine Einstellungen vorhanden - - Examples - -------- - >>> new_state = await db.toggle_welcome(123456) - >>> if new_state is not None: - ... print(f"Welcome System ist jetzt {'aktiviert' if new_state else 'deaktiviert'}") - """ - try: - settings = await self.get_welcome_settings(guild_id) - if not settings: - return None - - new_state = not settings.get('enabled', True) - await self.update_welcome_settings(guild_id, enabled=new_state) - return new_state - except Exception as e: - logger.error(f"Toggle Fehler: {e}") - return None - - async def update_welcome_stats(self, guild_id: int, joins: int = 0, leaves: int = 0): - """ - Aktualisiert Welcome Statistiken fรผr den aktuellen Tag. - - Parameters - ---------- - guild_id : int - Discord Server ID - joins : int, optional - Anzahl neuer Beitritte hinzuzufรผgen, by default 0 - leaves : int, optional - Anzahl Austritte hinzuzufรผgen, by default 0 - - Notes - ----- - Verwendet das aktuelle Datum als Schlรผssel. - Summiert die Werte wenn bereits Eintrรคge fรผr heute existieren. - Erstellt automatisch einen neuen Eintrag wenn keiner vorhanden ist. - - Die Statistiken werden in der `welcome_stats` Tabelle gespeichert - mit einer Zeile pro Server pro Tag. - - Examples - -------- - >>> # Einen neuen Join tracken - >>> await db.update_welcome_stats(123456, joins=1) - >>> - >>> # Einen Leave tracken - >>> await db.update_welcome_stats(123456, leaves=1) - """ - try: - await self.migrate_database() - date = datetime.now().strftime('%Y-%m-%d') - - async with aiosqlite.connect(self.db_path) as conn: - await conn.execute(''' - INSERT OR REPLACE INTO welcome_stats (guild_id, date, joins, leaves) - VALUES (?, ?, - COALESCE((SELECT joins FROM welcome_stats WHERE guild_id = ? AND date = ?), 0) + ?, - COALESCE((SELECT leaves FROM welcome_stats WHERE guild_id = ? AND date = ?), 0) + ?) - ''', (guild_id, date, guild_id, date, joins, guild_id, date, leaves)) - await conn.commit() - except Exception as e: - logger.error(f"Stats Update Fehler: {e}") \ No newline at end of file diff --git a/src/DevTools/backend/logging.py b/src/DevTools/backend/logging.py deleted file mode 100644 index 4491903..0000000 --- a/src/DevTools/backend/logging.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -""" -DevTools Backend Initialization -Initialisiert alle Datenbank-Module mit Logging -""" - -import colorama -from colorama import Fore, Style -from datetime import datetime -from typing import Callable, List -import logging - -colorama.init(autoreset=True) - -# Logger fรผr Backend -logger = logging.getLogger(__name__) - - -class DatabaseInitializer: - """Verwaltet Datenbank-Initialisierungen""" - - def __init__(self): - self.databases = [] - self.failed = [] - - @staticmethod - def timestamp() -> str: - """Gibt formatierten Timestamp zurรผck""" - return datetime.now().strftime(f"[{Fore.CYAN}%H:%M:%S{Style.RESET_ALL}]") - - @staticmethod - def log_success(db_name: str): - """Loggt erfolgreiche Initialisierung""" - print( - f"{DatabaseInitializer.timestamp()} " - f"[{Style.BRIGHT}{Fore.MAGENTA}DATABASE{Style.RESET_ALL}] " - f"{db_name} initialized โœ“" - ) - - @staticmethod - def log_error(db_name: str, error: Exception): - """Loggt Fehler bei Initialisierung""" - print( - f"{DatabaseInitializer.timestamp()} " - f"[{Fore.RED}DATABASE{Style.RESET_ALL}] " - f"{db_name} initialization failed: {error}" - ) - logger.error(f"Database init failed: {db_name}", exc_info=True) - - def register(self, name: str, init_func: Callable): - """Registriert eine Datenbank fรผr Initialisierung""" - self.databases.append((name, init_func)) - - def init_all(self) -> bool: - """ - Initialisiert alle registrierten Datenbanken - Returns: True wenn alle erfolgreich, sonst False - """ - print(f"\n{Fore.MAGENTA}{'โ”€' * 50}{Style.RESET_ALL}") - print(f"{Fore.MAGENTA} Initializing Databases...{Style.RESET_ALL}") - print(f"{Fore.MAGENTA}{'โ”€' * 50}{Style.RESET_ALL}\n") - - success_count = 0 - - for db_name, init_func in self.databases: - try: - init_func() - self.log_success(db_name) - success_count += 1 - except Exception as e: - self.log_error(db_name, e) - self.failed.append((db_name, str(e))) - - # Summary - print(f"\n{Fore.MAGENTA}{'โ”€' * 50}{Style.RESET_ALL}") - if self.failed: - print( - f"{Fore.YELLOW} โš  {success_count}/{len(self.databases)} databases initialized{Style.RESET_ALL}" - ) - for db_name, error in self.failed: - print(f"{Fore.RED} โœ— {db_name}: {error}{Style.RESET_ALL}") - else: - print( - f"{Fore.GREEN} โœ“ All {success_count} databases initialized successfully{Style.RESET_ALL}" - ) - print(f"{Fore.MAGENTA}{'โ”€' * 50}{Style.RESET_ALL}\n") - - return len(self.failed) == 0 - - -# ============================================================================= -# DATABASE INITIALIZATION FUNCTIONS -# ============================================================================= - -def init_spam_db(): - """Initialisiert Spam-Datenbank""" - try: - import DevTools.backend.database.spam_db - except Exception as e: - logger.debug(f"Spam DB import: {e}") - pass - - -def init_warn_db(): - """Initialisiert Warn-Datenbank""" - try: - import DevTools.backend.database.warn_db - except Exception as e: - logger.debug(f"Warn DB import: {e}") - pass - - -def init_notes_db(): - """Initialisiert Notes-Datenbank""" - try: - import DevTools.backend.database.notes_db - except Exception as e: - logger.debug(f"Notes DB import: {e}") - pass - - -def init_tempvc_db(): - """Initialisiert TempVC-Datenbank""" - try: - import DevTools.backend.database.vc_db - except Exception as e: - logger.debug(f"TempVC DB import: {e}") - pass - - -def init_stats_db(): - """Initialisiert Stats-Datenbank""" - try: - import DevTools.backend.database.Stats_db - except Exception as e: - logger.debug(f"Stats DB import: {e}") - pass - - -def init_levelsystem_db(): - """Initialisiert Levelsystem-Datenbank""" - try: - import DevTools.backend.database.levelsystem_db - except Exception as e: - logger.debug(f"Levelsystem DB import: {e}") - pass - - -def init_globalchat_db(): - """Initialisiert GlobalChat-Datenbank""" - try: - from .database.globalchat_db import GlobalChatDatabase - # Erstelle Instanz - db = GlobalChatDatabase() - except Exception as e: - logger.debug(f"GlobalChat DB import: {e}") - raise - pass - - -def init_logging_db(): - """Initialisiert Logging-Datenbank""" - try: - import DevTools.backend.database.logging_db - except Exception as e: - logger.debug(f"Logging DB import: {e}") - pass - - -def init_autodelete_db(): - """Initialisiert AutoDelete-Datenbank""" - try: - from .database.autodelete_db import db - except ImportError: - pass # Optional - - -def init_welcome_db(): - """Initialisiert Welcome-Datenbank""" - try: - from .database.welcome_db import db - except ImportError: - pass # Optional - - -# ============================================================================= -# MAIN INITIALIZATION -# ============================================================================= - -# Globaler Initializer -_initializer = DatabaseInitializer() - -# Alle Datenbanken registrieren -_initializer.register("Spam Database", init_spam_db) -_initializer.register("Warn Database", init_warn_db) -_initializer.register("Notes Database", init_notes_db) -_initializer.register("TempVC Database", init_tempvc_db) -_initializer.register("Stats Database", init_stats_db) -_initializer.register("Levelsystem Database", init_levelsystem_db) -_initializer.register("GlobalChat Database", init_globalchat_db) -_initializer.register("Logging Database", init_logging_db) -_initializer.register("AutoDelete Database", init_autodelete_db) -_initializer.register("Welcome Database", init_welcome_db) - - -def init_all() -> bool: - """ - Initialisiert alle Datenbank-Module - - Returns: - bool: True wenn alle erfolgreich initialisiert wurden - """ - return _initializer.init_all() - - -def get_failed_databases() -> List[tuple]: - """ - Gibt Liste der fehlgeschlagenen Datenbanken zurรผck - - Returns: - List[tuple]: Liste von (db_name, error_message) Tupeln - """ - return _initializer.failed - - -# Backwards Compatibility - Einzelne Funktionen exportieren -__all__ = [ - 'init_all', - 'init_spam_db', - 'init_warn_db', - 'init_notes_db', - 'init_tempvc_db', - 'init_stats_db', - 'init_levelsystem_db', - 'init_globalchat_db', - 'init_logging_db', - 'init_autodelete_db', - 'init_welcome_db', - 'get_failed_databases', -] \ No newline at end of file diff --git a/src/DevTools/backend/utils/__init__.py b/src/DevTools/backend/utils/__init__.py deleted file mode 100644 index d085c3a..0000000 --- a/src/DevTools/backend/utils/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .config import * \ No newline at end of file diff --git a/src/DevTools/ui/__init__.py b/src/DevTools/ui/__init__.py deleted file mode 100644 index 30f00a0..0000000 --- a/src/DevTools/ui/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -from .emojis import * diff --git a/src/DevTools/ui/emojis.py b/src/DevTools/ui/emojis.py deleted file mode 100644 index ed01688..0000000 --- a/src/DevTools/ui/emojis.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network - -# Allgemein -emoji_link = "<:link:1411749901099859998>" -emoji_slowmode = "<:slowmode:1411749933228359830>" -emoji_locked = "<:locked:1423971266737471488>" -emoji_delete = "<:delete:1411749869625802852>" -emoji_public = "<:public:1411749759319802018>" -emoji_gift = "<:gift:1411749736632946799>" -emoji_mediaadd = "<:mediaadd:1411749700620521482>" -emoji_member = "<:member:1423975509062193192>" - -# Channels & Rollen -emoji_rules = "<:rules:1411749662225989775>" -emoji_voice = "<:voicechannel:1411749608480047245>" -emoji_verified = "<:verifiedwhite:1411749568718045284>" -emoji_event = "<:event:1411749503727566858>" -emoji_pinned = "<:pinned:1411749445716152410>" -emoji_studenthub = "<:studenthub:1411749419291775117>" - -# Suche & Management -emoji_search = "<:search:1411749392943284374>" -emoji_manager = "<:manager:1411749363730092057>" -emoji_location = "<:location:1411749336492019915>" -emoji_entertainment = "<:entertainment:1411749311011881032>" -emoji_staff = "<:staff:1411749285627822203>" -emoji_moderator = "<:moderator:1411749252736094208>" -emoji_warn = "<:warn:1423974196664602704>" - -# Medien & Technik -emoji_media = "<:media:1411749223329955860>" -emoji_scienceandtech = "<:scienceandtech:1411749167038206012>" -emoji_gif = "<:gif:1411749131034300548>" -emoji_summary = "<:summary:1411749103754281081>" -emoji_upload = "<:upload:1411749080169840760>" - -# Hinzufรผgen & Verwaltung -emoji_add = "<:add:1411749054282596564>" -emoji_channelandroles = "<:channelsandroles:1411749031293747252>" -emoji_channel = "<:channel:1411749007318974484>" -emoji_developer = "<:developer:1411748983897985075>" -emoji_announcement = "<:announcement:1411748950783955025>" -emoji_statistics = "<:statistics:1411748924359971007>" - -# Guides & Owner -emoji_serverguide = "<:serverguide:1411748884463489166>" -emoji_owner = "<:owner:1411748853585023189>" -emoji_annoattention = "<:announcementattention:1411748828738097373>" - -# Status & Sperren -emoji_forbidden = "<:forbidden:1383743601791471697>" -emoji_no = "<:no:1380796085802500148>" -emoji_yes = "<:yes:1380796058963153017>" diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index b5d7926..0000000 --- a/src/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .handler import * -from .DevTools import * \ No newline at end of file diff --git a/src/cogs/Servermanament/tempvc.py b/src/cogs/Servermanament/tempvc.py index 9c17455..87fb7ec 100644 --- a/src/cogs/Servermanament/tempvc.py +++ b/src/cogs/Servermanament/tempvc.py @@ -3,7 +3,6 @@ import discord from discord import slash_command, option, SlashCommandGroup from discord.ext import commands -from DevTools import emoji_yes, emoji_no from discord.ui import Container import ezcord diff --git a/src/cogs/Servermanament/welcome.py b/src/cogs/Servermanament/welcome.py index a7c8688..cc9fb69 100644 --- a/src/cogs/Servermanament/welcome.py +++ b/src/cogs/Servermanament/welcome.py @@ -18,7 +18,6 @@ from datetime import datetime import ezcord from discord.ui import Container -from DevTools import emoji_yes, emoji_no, emoji_add # Logger Setup diff --git a/src/cogs/moderation/antispam.py b/src/cogs/moderation/antispam.py index 955ab1a..6664a44 100644 --- a/src/cogs/moderation/antispam.py +++ b/src/cogs/moderation/antispam.py @@ -8,22 +8,7 @@ from datetime import timedelta -from DevTools.ui import ( - emoji_yes, - emoji_no, - emoji_forbidden, - emoji_warn, - emoji_delete, - emoji_member, - emoji_channel, - emoji_moderator, - emoji_add, - emoji_statistics, - emoji_annoattention, - emoji_owner, -) - -from DevTools import SpamDB +from DevTools import AntiSpamDatabase as SpamDB class AntiSpam(ezcord.Cog): diff --git a/src/cogs/moderation/moderation.py b/src/cogs/moderation/moderation.py index 6730808..4956073 100644 --- a/src/cogs/moderation/moderation.py +++ b/src/cogs/moderation/moderation.py @@ -2,8 +2,6 @@ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ # >> Imports # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -from DevTools.ui import emoji_yes, emoji_no, emoji_member, emoji_warn, emoji_summary, emoji_staff, emoji_slowmode - import asyncio import re from datetime import datetime, timezone diff --git a/src/cogs/moderation/notes.py b/src/cogs/moderation/notes.py index fcf7d6c..7475c7d 100644 --- a/src/cogs/moderation/notes.py +++ b/src/cogs/moderation/notes.py @@ -7,7 +7,6 @@ import datetime import ezcord from DevTools import NotesDatabase -from DevTools import emoji_no, emoji_yes # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ # >> Cog # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ diff --git a/src/cogs/moderation/warningsystem.py b/src/cogs/moderation/warningsystem.py index 70235be..c56dd7f 100644 --- a/src/cogs/moderation/warningsystem.py +++ b/src/cogs/moderation/warningsystem.py @@ -2,9 +2,6 @@ # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ # >> Imports # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -from DevTools import ( - emoji_no, emoji_yes, emoji_warn, emoji_member, emoji_staff, emoji_slowmode, emoji_summary -) from DevTools import WarnDatabase import discord from discord import slash_command, Option diff --git a/src/cogs/setlang.py b/src/cogs/setlang.py index d838330..37bf622 100644 --- a/src/cogs/setlang.py +++ b/src/cogs/setlang.py @@ -4,7 +4,9 @@ from handler import TranslationHandler -class SetLangCog(ezcord.Cog, group="informationen"): + +class SetLangCog(ezcord.Cog): + """Cog for setting user language preferences.""" AVAILABLE_LANGUAGES = { "de": "Deutsch ๐Ÿ‡ฉ๐Ÿ‡ช", @@ -13,11 +15,11 @@ class SetLangCog(ezcord.Cog, group="informationen"): @commands.slash_command( name="set-lang", - description="Stelle deine bevorzugte Sprache fรผr Bot-Nachrichten ein." + description="Set your preferred language for bot messages." ) @discord.option( "language", - description="Wรคhle eine Sprache", + description="Choose a language", choices=[ discord.OptionChoice(name=name, value=code) for code, name in AVAILABLE_LANGUAGES.items() @@ -25,14 +27,21 @@ class SetLangCog(ezcord.Cog, group="informationen"): required=True ) async def set_language(self, ctx: discord.ApplicationContext, language: str): - # Sprache speichern + """ + Set the user's preferred language. + + Args: + ctx: Discord application context + language: Selected language code + """ + # Save language preference self.bot.settings_db.set_user_language(ctx.author.id, language) - # Name fรผr Anzeige + # Get display name for the selected language lang_name = self.AVAILABLE_LANGUAGES.get(language, language) - # Nachricht laden รผber TranslationHandler - response_text = TranslationHandler.get( + # Load response message using TranslationHandler + response_text = await TranslationHandler.get_async( language, "cog_setlang.message.language_set", default="Language has been set to {language}.", @@ -43,4 +52,5 @@ async def set_language(self, ctx: discord.ApplicationContext, language: str): def setup(bot): - bot.add_cog(SetLangCog(bot)) + """Setup function to add the cog to the bot.""" + bot.add_cog(SetLangCog(bot)) \ No newline at end of file diff --git a/src/handler/__init__.py b/src/handler/__init__.py deleted file mode 100644 index d21a21c..0000000 --- a/src/handler/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .translation_handler import TranslationHandler -from .update_checker import VersionChecker \ No newline at end of file diff --git a/src/handler/translation_handler.py b/src/handler/translation_handler.py deleted file mode 100644 index 751a79e..0000000 --- a/src/handler/translation_handler.py +++ /dev/null @@ -1,89 +0,0 @@ -# src/handler/translation_handler.py - -import yaml -from pathlib import Path - -class TranslationHandler: - """ - Zentrale Klasse zum Laden und Abrufen von รœbersetzungen. - Unterstรผtzt: - - Caching - - Fallback-Sprachen - - get_for_user - - Pfad als Liste oder String - """ - - TRANSLATION_PATH = Path("translation") / "messages" - FALLBACK_LANGS = ("en", "de") - DEFAULT_LANGUAGE = "en" - _cache: dict[str, dict] = {} - - @classmethod - def load_messages(cls, lang_code: str) -> dict: - """ - Lรคdt Sprachdateien mit Cache und Fallback. - """ - if lang_code in cls._cache: - return cls._cache[lang_code] - - for code in (lang_code, *cls.FALLBACK_LANGS): - file_path = cls.TRANSLATION_PATH / f"{code}.yaml" - - if file_path.exists(): - with open(file_path, "r", encoding="utf-8") as f: - data = yaml.safe_load(f) or {} - cls._cache[lang_code] = data - return data - - print(f"[TranslationHandler] WARNUNG: Keine Sprachdatei gefunden ({lang_code})") - cls._cache[lang_code] = {} - return {} - - @classmethod - def get(cls, lang_code: str, path, default: str = "", **placeholders) -> str: - """ - Holt eine รœbersetzung รผber einen Pfad (Liste oder Punkt-String) - und ersetzt Platzhalter. - """ - if isinstance(path, str): - path = path.split(".") - - messages = cls.load_messages(lang_code) - value = messages - - for key in path: - if not isinstance(value, dict): - return default - value = value.get(key) - - if not isinstance(value, str): - return default - - try: - return value.format(**placeholders) - except KeyError: - return value - - @classmethod - async def get_for_user(cls, bot, user_id: int, path, default: str = "", **placeholders) -> str: - """ - Holt die รœbersetzung automatisch fรผr einen User. - Benรถtigt `bot.settings_db.get_user_language(user_id)`. - """ - lang = cls.DEFAULT_LANGUAGE - try: - lang = bot.settings_db.get_user_language(user_id) or cls.DEFAULT_LANGUAGE - except Exception: - pass - - return cls.get(lang, path, default, **placeholders) - - @classmethod - def clear_cache(cls): - """Lรถscht den Cache (nรผtzlich fรผr Hot-Reload im DEV).""" - cls._cache.clear() - - -# Optionaler Alias -MessagesHandler = TranslationHandler -LangHandler = TranslationHandler \ No newline at end of file diff --git a/src/handler/update_checker.py b/src/handler/update_checker.py deleted file mode 100644 index b1fa1e1..0000000 --- a/src/handler/update_checker.py +++ /dev/null @@ -1,218 +0,0 @@ - # Copyright (c) 2025 OPPRO.NET Network -""" -Update Checker Module for ManagerX -=================================== - -Handles version checking and update notifications for the bot. -Compares current version against remote version to detect available updates. - -Version Format: MAJOR.MINOR.PATCH[-TYPE] - - TYPE: dev, beta, alpha, or stable (default) - - Example: 1.7.2-alpha, 2.0.0, 1.5.1-beta -""" - -import re -import asyncio -import aiohttp -from typing import Optional, Tuple -from colorama import Fore, Style - -try: - from log import logger, C -except ImportError: - # Fallback if logger is not available - import logging - logger = logging.getLogger(__name__) - - -# ============================================================================= -# Configuration -# ============================================================================= - -class UpdateCheckerConfig: - """ - Configuration for the Update Checker. - - Contains all URLs and settings needed for version checking. - """ - # GitHub repository - GITHUB_REPO = "https://github.com/Oppro-net-Development/ManagerX" - - # Raw GitHub URL for version file - # Points to the version.txt file on the main branch - VERSION_URL = "https://raw.githubusercontent.com/Oppro-net-Development/ManagerX/main/config/version.txt" - - # Timeout for version check requests (in seconds) - TIMEOUT = 10 - - -# ============================================================================= -# Version Checker Class -# ============================================================================= - -class VersionChecker: - """ - Handles version parsing and update checking for ManagerX. - - Supports semantic versioning with optional pre-release type identifiers. - Automatically detects when updates are available and logs appropriate messages. - - Attributes - ---------- - GITHUB_REPO : str - Repository URL for update notifications - VERSION_URL : str - URL to the version file on GitHub - TIMEOUT : int - Timeout for requests in seconds - - Examples - -------- - >>> current = "1.7.2-alpha" - >>> latest = await VersionChecker.check_update(current, UpdateCheckerConfig.VERSION_URL) - >>> print(f"Latest version: {latest}") - """ - - GITHUB_REPO = UpdateCheckerConfig.GITHUB_REPO - VERSION_URL = UpdateCheckerConfig.VERSION_URL - TIMEOUT = UpdateCheckerConfig.TIMEOUT - - @staticmethod - def parse_version(version_str: str) -> Tuple[int, int, int, str]: - """ - Parse version string into components. - - Parses semantic versioning with optional pre-release type. - Format: MAJOR.MINOR.PATCH[-TYPE] - - Parameters - ---------- - version_str : str - Version string to parse (e.g., "1.7.2-alpha") - - Returns - ------- - tuple - Tuple of (major, minor, patch, type) - - major : int - - minor : int - - patch : int - - type : str - 'dev', 'beta', 'alpha', or 'stable' (default) - - Examples - -------- - >>> VersionChecker.parse_version("1.7.2-alpha") - (1, 7, 2, 'alpha') - - >>> VersionChecker.parse_version("2.0.0") - (2, 0, 0, 'stable') - """ - match = re.match(r"(\d+)\.(\d+)\.(\d+)(?:[-_]?(dev|beta|alpha))?", version_str) - if match: - major, minor, patch, vtype = match.groups() - return int(major), int(minor), int(patch), vtype or "stable" - return 0, 0, 0, "unknown" - - @staticmethod - async def check_update(current_version: str, version_url: str) -> Optional[str]: - """ - Check for available updates by comparing current and latest versions. - - Fetches the latest version from a remote URL and compares it with - the current version. Logs appropriate messages based on comparison: - - - Up to date: Success message - - Dev build: Info message - - Pre-release: Warning message - - Update available: Yellow alert with download link - - Error: Error message with details - - Parameters - ---------- - current_version : str - Current bot version (e.g., "1.7.2-alpha") - version_url : str - URL pointing to the latest version number - Should return plain text with only the version number - - Returns - ------- - Optional[str] - Latest version string if successfully retrieved, None if error occurred - - Raises - ------ - None - All exceptions are caught and logged - - Examples - -------- - >>> url = "https://raw.githubusercontent.com/.../version.txt" - >>> latest = await VersionChecker.check_update("1.7.2", url) - >>> if latest and latest > "1.7.2": - ... print("Update available!") - - Notes - ----- - Network timeouts are set to 10 seconds. Failed connections are - logged but do not prevent bot startup. - """ - try: - async with aiohttp.ClientSession() as session: - async with session.get(version_url, timeout=aiohttp.ClientTimeout(total=VersionChecker.TIMEOUT)) as resp: - if resp.status != 200: - logger.error(C.DEV.VER, f"Version check failed (HTTP {resp.status})") - return None - - latest_version = (await resp.text()).strip() - if not latest_version: - logger.error(C.DEV.UPDATE, "Empty response from version server") - return None - - # Parse versions for comparison - current = VersionChecker.parse_version(current_version) - latest = VersionChecker.parse_version(latest_version) - - # Compare major, minor, patch (ignore pre-release type) - current_core = current[:3] - latest_core = latest[:3] - - # Version is up to date - if current_core == latest_core and current[3] == latest[3]: - logger.success(C.DEV.VER, f"Running latest version: {current_version}") - - # Dev build newer than public release - elif current_core > latest_core: - logger.info( - C.DEV.VER, - f"Dev build detected ({current_version}) - newer than public release ({latest_version})" - ) - - # Pre-release version - elif current_core == latest_core and current[3] in ("dev", "beta", "alpha"): - logger.warn( - C.DEV.VER, - f"Pre-release version ({current_version}) - latest stable: {latest_version}" - ) - - # Update available - else: - print( - f"[{Fore.YELLOW}UPDATE AVAILABLE{Style.RESET_ALL}] " - f"Current: {current_version} โ†’ Latest: {latest_version}\n" - f" Download: {Fore.CYAN}{VersionChecker.GITHUB_REPO}{Style.RESET_ALL}" - ) - - return latest_version - - except aiohttp.ClientConnectorError: - logger.error(C.DEV.UPDATE, "Could not connect to GitHub (network issue)") - except asyncio.TimeoutError: - logger.error(C.DEV.UPDATE, "Connection to version server timed out") - except Exception as e: - logger.error(C.DEV.UPDATE, f"Unexpected error: {e}") - - return None - - -__all__ = ["VersionChecker", "UpdateCheckerConfig"] From a366f244a02ffc9745d8385d65a3ca1a2ee8a15e Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Sat, 17 Jan 2026 16:30:40 +0100 Subject: [PATCH 4/8] UPDATED DATASTRUCKUR --- .readthedocs.yaml | 26 - LICENSE | 5 +- README.md | 12 + TODO.md | 60 - __init__.py | 2 - api.py | 478 ------ assets/img/ManagerX_banner.png | Bin 287258 -> 0 bytes config/example.env | 6 - config/version.txt | 1 - docs/Makefile | 4 +- docs/_static/custom.css | 399 ----- docs/_static/managerx.png | Bin 1549077 -> 0 bytes .../endpoints/authentication.rst | 87 - .../api_reference/endpoints/guilds.rst | 155 -- .../api_reference/endpoints/stats.rst | 74 - .../api_reference/examples/api_js.rst | 94 - docs/dev_guide/api_reference/index.rst | 48 - docs/dev_guide/architecture/cog_system.rst | 183 -- .../architecture/command_handler.rst | 69 - .../architecture/database_handler.rst | 43 - docs/dev_guide/architecture/error_handler.rst | 48 - docs/dev_guide/architecture/event_loop.rst | 42 - docs/dev_guide/architecture/index.rst | 17 - .../dev_guide/architecture/logging_system.rst | 44 - .../contributing/coding_standards.rst | 16 - docs/dev_guide/contributing/contributing.rst | 17 - docs/dev_guide/contributing/documentation.rst | 13 - docs/dev_guide/contributing/testing.rst | 24 - docs/dev_guide/contributing/workflow.rst | 41 - docs/dev_guide/database/index.rst | 514 ------ docs/dev_guide/index.rst | 50 - docs/dev_guide/installation/index.rst | 11 - .../installation/install_from_source.rst | 105 -- docs/dev_guide/self_hosting/index.rst | 29 - docs/make.bat | 4 +- docs/plugins/index.rst | 47 - .../official_plugins/managerx_handler.rst | 50 - .../own_plugins/create_local_plugin.rst | 103 -- .../own_plugins/create_pypi_plugin.rst | 102 -- docs/plugins/own_plugins/index.rst | 77 - .../plugins/own_plugins/plugin_guidelines.rst | 182 -- docs/releases/alpha/1.7.2a.rst | 20 - docs/releases/beta/1.7.2b.rst | 18 - docs/releases/index.rst | 48 - docs/releases/version/1.1glo.rst | 34 - docs/releases/version/1.3log.rst | 30 - docs/releases/version/1.4log.rst | 30 - docs/releases/version/1.5.0.rst | 42 - docs/releases/version/1.6.0.rst | 31 - docs/releases/version/1.6.1.rst | 32 - docs/releases/version/1.6.2.rst | 26 - docs/releases/version/1.6.3.rst | 30 - docs/releases/version/1.6.4.rst | 23 - docs/releases/version/1.6.5.rst | 32 - docs/releases/version/1.6.6.rst | 16 - docs/releases/version/1.7.0.rst | 50 - docs/releases/version/1.7.1.rst | 65 - docs/req.txt | 5 - docs/source/_static/custom.css | 1058 ++++++++++++ docs/{ => source}/conf.py | 8 +- .../dev_guide/getting_start/installation.rst | 65 + docs/source/dev_guide/index.rst | 20 + docs/{ => source}/index.rst | 7 +- docs/user_guide/commands/index.rst | 10 - docs/user_guide/commands/moderation.rst | 0 docs/user_guide/index.rst | 10 - examples/plugins/README.md | 32 - examples/plugins/example__init__.py | 18 - examples/plugins/example_plugin.py | 55 - examples/plugins/example_pyproject.toml | 29 - examples/plugins/functions.py | 28 - examples/plugins/utils.py | 17 - main.py | 340 +--- pyproject.toml | 6 +- renovate.json | 37 - requirements/bot_req.txt | 16 - requirements/dev_req.txt | 21 - requirements/docs_req.txt | 7 - requirements/req.txt | 47 - site/callback.html | 41 - site/css/styles.css | 481 ------ site/dashboard.html | 60 - site/guild.html | 102 -- site/index.html | 75 - site/js/api.js | 494 ------ site/js/particles.js | 66 - site/modules/index.html | 11 - site/modules/levelsystem.html | 83 - site/modules/tempvc.html | 125 -- site/modules/welcome.html | 97 -- site/privacy.html | 104 -- site/tos.html | 88 - src/bot/__init__.py | 1 + src/bot/core/__init__.py | 26 + src/bot/core/bot_setup.py | 76 + src/bot/core/cog_manager.py | 116 ++ src/bot/core/config.py | 74 + src/bot/core/dashboard.py | 101 ++ src/bot/core/database.py | 75 + src/bot/core/utils.py | 73 + src/cogs/Servermanament/autodelete.py | 309 ---- src/cogs/Servermanament/autorole.py | 273 --- src/cogs/Servermanament/globalchat.py | 1517 ----------------- src/cogs/Servermanament/levelsystem.py | 974 ----------- src/cogs/Servermanament/logging.py | 1465 ---------------- src/cogs/Servermanament/stats.py | 598 ------- src/cogs/Servermanament/tempvc.py | 612 ------- src/cogs/Servermanament/welcome.py | 1467 ---------------- src/cogs/fun/__init__.py | 0 src/cogs/fun/gewinnt.py | 214 --- src/cogs/fun/tictactoe.py | 197 --- src/cogs/fun/weather.py | 109 -- src/cogs/fun/wikipedia/__init__.py | 68 - src/cogs/fun/wikipedia/autocomplete.py | 63 - src/cogs/fun/wikipedia/cache.py | 66 - src/cogs/fun/wikipedia/cog.py | 461 ----- src/cogs/fun/wikipedia/components.py | 306 ---- src/cogs/fun/wikipedia/config.py | 44 - src/cogs/fun/wikipedia/containers.py | 228 --- src/cogs/fun/wikipedia/utils.py | 114 -- src/cogs/informationen/botstatus.py | 42 - src/cogs/informationen/serverinfo.py | 535 ------ src/cogs/informationen/usermanagemt.py | 403 ----- src/cogs/moderation/antispam.py | 439 ----- src/cogs/moderation/moderation.py | 549 ------ src/cogs/moderation/notes.py | 69 - src/cogs/moderation/warningsystem.py | 557 ------ src/cogs/setlang.py | 56 - src/managerx/cli.py | 45 - translation/ez_de.json | 32 - translation/ez_en.json | 31 - translation/messages/de.yaml | 116 -- translation/messages/en.yaml | 114 -- 133 files changed, 1808 insertions(+), 18279 deletions(-) delete mode 100644 .readthedocs.yaml delete mode 100644 TODO.md delete mode 100644 __init__.py delete mode 100644 api.py delete mode 100644 assets/img/ManagerX_banner.png delete mode 100644 config/example.env delete mode 100644 config/version.txt delete mode 100644 docs/_static/custom.css delete mode 100644 docs/_static/managerx.png delete mode 100644 docs/dev_guide/api_reference/endpoints/authentication.rst delete mode 100644 docs/dev_guide/api_reference/endpoints/guilds.rst delete mode 100644 docs/dev_guide/api_reference/endpoints/stats.rst delete mode 100644 docs/dev_guide/api_reference/examples/api_js.rst delete mode 100644 docs/dev_guide/api_reference/index.rst delete mode 100644 docs/dev_guide/architecture/cog_system.rst delete mode 100644 docs/dev_guide/architecture/command_handler.rst delete mode 100644 docs/dev_guide/architecture/database_handler.rst delete mode 100644 docs/dev_guide/architecture/error_handler.rst delete mode 100644 docs/dev_guide/architecture/event_loop.rst delete mode 100644 docs/dev_guide/architecture/index.rst delete mode 100644 docs/dev_guide/architecture/logging_system.rst delete mode 100644 docs/dev_guide/contributing/coding_standards.rst delete mode 100644 docs/dev_guide/contributing/contributing.rst delete mode 100644 docs/dev_guide/contributing/documentation.rst delete mode 100644 docs/dev_guide/contributing/testing.rst delete mode 100644 docs/dev_guide/contributing/workflow.rst delete mode 100644 docs/dev_guide/database/index.rst delete mode 100644 docs/dev_guide/index.rst delete mode 100644 docs/dev_guide/installation/index.rst delete mode 100644 docs/dev_guide/installation/install_from_source.rst delete mode 100644 docs/dev_guide/self_hosting/index.rst delete mode 100644 docs/plugins/index.rst delete mode 100644 docs/plugins/official_plugins/managerx_handler.rst delete mode 100644 docs/plugins/own_plugins/create_local_plugin.rst delete mode 100644 docs/plugins/own_plugins/create_pypi_plugin.rst delete mode 100644 docs/plugins/own_plugins/index.rst delete mode 100644 docs/plugins/own_plugins/plugin_guidelines.rst delete mode 100644 docs/releases/alpha/1.7.2a.rst delete mode 100644 docs/releases/beta/1.7.2b.rst delete mode 100644 docs/releases/index.rst delete mode 100644 docs/releases/version/1.1glo.rst delete mode 100644 docs/releases/version/1.3log.rst delete mode 100644 docs/releases/version/1.4log.rst delete mode 100644 docs/releases/version/1.5.0.rst delete mode 100644 docs/releases/version/1.6.0.rst delete mode 100644 docs/releases/version/1.6.1.rst delete mode 100644 docs/releases/version/1.6.2.rst delete mode 100644 docs/releases/version/1.6.3.rst delete mode 100644 docs/releases/version/1.6.4.rst delete mode 100644 docs/releases/version/1.6.5.rst delete mode 100644 docs/releases/version/1.6.6.rst delete mode 100644 docs/releases/version/1.7.0.rst delete mode 100644 docs/releases/version/1.7.1.rst delete mode 100644 docs/req.txt create mode 100644 docs/source/_static/custom.css rename docs/{ => source}/conf.py (89%) create mode 100644 docs/source/dev_guide/getting_start/installation.rst create mode 100644 docs/source/dev_guide/index.rst rename docs/{ => source}/index.rst (95%) delete mode 100644 docs/user_guide/commands/index.rst delete mode 100644 docs/user_guide/commands/moderation.rst delete mode 100644 docs/user_guide/index.rst delete mode 100644 examples/plugins/README.md delete mode 100644 examples/plugins/example__init__.py delete mode 100644 examples/plugins/example_plugin.py delete mode 100644 examples/plugins/example_pyproject.toml delete mode 100644 examples/plugins/functions.py delete mode 100644 examples/plugins/utils.py delete mode 100644 renovate.json delete mode 100644 requirements/bot_req.txt delete mode 100644 requirements/dev_req.txt delete mode 100644 requirements/docs_req.txt delete mode 100644 requirements/req.txt delete mode 100644 site/callback.html delete mode 100644 site/css/styles.css delete mode 100644 site/dashboard.html delete mode 100644 site/guild.html delete mode 100644 site/index.html delete mode 100644 site/js/api.js delete mode 100644 site/js/particles.js delete mode 100644 site/modules/index.html delete mode 100644 site/modules/levelsystem.html delete mode 100644 site/modules/tempvc.html delete mode 100644 site/modules/welcome.html delete mode 100644 site/privacy.html delete mode 100644 site/tos.html create mode 100644 src/bot/__init__.py create mode 100644 src/bot/core/__init__.py create mode 100644 src/bot/core/bot_setup.py create mode 100644 src/bot/core/cog_manager.py create mode 100644 src/bot/core/config.py create mode 100644 src/bot/core/dashboard.py create mode 100644 src/bot/core/database.py create mode 100644 src/bot/core/utils.py delete mode 100644 src/cogs/Servermanament/autodelete.py delete mode 100644 src/cogs/Servermanament/autorole.py delete mode 100644 src/cogs/Servermanament/globalchat.py delete mode 100644 src/cogs/Servermanament/levelsystem.py delete mode 100644 src/cogs/Servermanament/logging.py delete mode 100644 src/cogs/Servermanament/stats.py delete mode 100644 src/cogs/Servermanament/tempvc.py delete mode 100644 src/cogs/Servermanament/welcome.py delete mode 100644 src/cogs/fun/__init__.py delete mode 100644 src/cogs/fun/gewinnt.py delete mode 100644 src/cogs/fun/tictactoe.py delete mode 100644 src/cogs/fun/weather.py delete mode 100644 src/cogs/fun/wikipedia/__init__.py delete mode 100644 src/cogs/fun/wikipedia/autocomplete.py delete mode 100644 src/cogs/fun/wikipedia/cache.py delete mode 100644 src/cogs/fun/wikipedia/cog.py delete mode 100644 src/cogs/fun/wikipedia/components.py delete mode 100644 src/cogs/fun/wikipedia/config.py delete mode 100644 src/cogs/fun/wikipedia/containers.py delete mode 100644 src/cogs/fun/wikipedia/utils.py delete mode 100644 src/cogs/informationen/botstatus.py delete mode 100644 src/cogs/informationen/serverinfo.py delete mode 100644 src/cogs/informationen/usermanagemt.py delete mode 100644 src/cogs/moderation/antispam.py delete mode 100644 src/cogs/moderation/moderation.py delete mode 100644 src/cogs/moderation/notes.py delete mode 100644 src/cogs/moderation/warningsystem.py delete mode 100644 src/cogs/setlang.py delete mode 100644 src/managerx/cli.py delete mode 100644 translation/ez_de.json delete mode 100644 translation/ez_en.json delete mode 100644 translation/messages/de.yaml delete mode 100644 translation/messages/en.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml deleted file mode 100644 index e144f6b..0000000 --- a/.readthedocs.yaml +++ /dev/null @@ -1,26 +0,0 @@ - -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required -version: 2 - -# Set the OS, Python version, and other tools you might need -build: - os: ubuntu-24.04 - tools: - python: "3.12" - -# Build documentation in the "docs/" directory with Sphinx -sphinx: - configuration: docs/conf.py - -# Optionally, but recommended, -# declare the Python requirements required to build your documentation -# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -# python: -# install: -# - requirements: docs/requirements.txt -python: - install: - - requirements: requirements/docs_req.txt diff --git a/LICENSE b/LICENSE index b5874a1..5b5f70b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ -Copyright ยฉ 2024 OPPRO.NET Development -Copyright ยฉ 2025-present OPPRO.NET Network + Copyright ยฉ 2024 OPPRO.NET Development + Copyright ยฉ 2025-2026 OPPRO.NET Network + Copyright ยฉ 2026 ManagerX Development GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 diff --git a/README.md b/README.md index e952827..f90eb50 100644 --- a/README.md +++ b/README.md @@ -915,6 +915,18 @@ Wir verwenden standardisierte Commit-Prefixes fรผr bessere Nachvollziehbarkeit:
+### ๐Ÿ“Œ Versionierungs-Schema + +Um maximale Transparenz und Aktualitรคt zu gewรคhrleisten, nutzen wir eine duale Strategie: + +* **GitHub (Source Code):** Nutzt das **Semantic Versioning** (Beispiel: `2.0.0`). Dies markiert groรŸe Meilensteine und strukturelle ร„nderungen im Code. +* **PyPI (Distribution):** Nutzt **CalVer (Calendar Versioning)** (Beispiel: `2.2026.1.9.1`). Dies ermรถglicht es Entwicklern, sofort zu erkennen, wie aktuell das installierte Paket ist. + +| Plattform | Schema | Beispiel | +| :--- | :--- | :--- | +| **GitHub** | MAJOR.MINOR.PATCH | `2.0.0` | +| **PyPI** | MAJOR.JJJJ.MM.TT | `2.2026.01.09.1` | + ### ๐Ÿ”ง Development Workflow ```bash diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 36dce02..0000000 --- a/TODO.md +++ /dev/null @@ -1,60 +0,0 @@ -# ๐Ÿ“ ManagerX Developer Todo-Guide - -> รœbersicht รผber offene Aufgaben, Bugs, Refactors und Dokumentation. -> Dieses Dokument dient der internen Organisation und Contributor-Info. - ---- - -## ๐Ÿ“‚ Kategorien - -### 1๏ธโƒฃ Features -Neue Funktionen, die implementiert werden sollen. - -| Status | Aufgabe | Beschreibung | Prioritรคt | Verantwortlich | -|--------|--------|--------------|-----------|----------------| -| โฌœ | | | | | - ---- - -### 2๏ธโƒฃ Bugs / Fixes -Probleme, die behoben werden mรผssen. - -| Status | Aufgabe | Beschreibung | Prioritรคt | Verantwortlich | -|--------|--------|--------------|-----------|----------------| -| โฌœ | Wikipedia Link Button | Link Button fixen | Hoch | - | - ---- - -### 3๏ธโƒฃ Refactors / Code-Optimierung -Code-Struktur verbessern, Lesbarkeit erhรถhen. - -| Status | Aufgabe | Beschreibung | Prioritรคt | Verantwortlich | -|--------|--------|--------------|-----------|----------------| -| โฌœ | | | | | - ---- - -### 4๏ธโƒฃ Documentation -Alles, was mit Docs zu tun hat. - -| Status | Aufgabe | Beschreibung | Prioritรคt | Verantwortlich | -|--------|--------|--------------|-----------|----------------| -| โฌœ | | | | | - ---- - -### โœ… Status-Markierungen -- โฌœ Offene Aufgabe -- ๐Ÿ”„ In Arbeit -- โœ… Erledigt - -> Tipp: Fertige Aufgaben regelmรครŸig aus der Tabelle entfernen oder archivieren. - ---- - -### ๐Ÿ’ก Best Practices -1. Aufgaben nach Kategorie sortieren โ†’ leichter รœberblick -2. Prioritรคt klar angeben: Hoch / Mittel / Niedrig -3. Verantwortlich eintragen, wenn mehrere Entwickler beteiligt sind -4. Status aktuell halten โ†’ kein veralteter TODO -5. Externe Tools optional, aber nicht zwingend notwendig diff --git a/__init__.py b/__init__.py deleted file mode 100644 index 13afe8f..0000000 --- a/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .src import handler -from .src import DevTools \ No newline at end of file diff --git a/api.py b/api.py deleted file mode 100644 index cef30dd..0000000 --- a/api.py +++ /dev/null @@ -1,478 +0,0 @@ -# ________ ________ ___ -#|\ __ \|\ __ \|\ \ -#\ \ \|\ \ \ \|\ \ \ \ -# \ \ __ \ \ ____\ \ \ -# \ \ \ \ \ \ \___|\ \ \ -# \ \__\ \__\ \__\ \ \__\ -# \|__|\|__|\|__| \|__| - -# --- STANDARD LIBRARIES --- -import json -import logging -import os -from typing import Optional, List, Dict, Any - -# --- THIRD PARTY LIBRARIES --- -import httpx -import uvicorn -import yaml -from dotenv import load_dotenv -from fastapi import Depends, FastAPI, HTTPException, Query, Request -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import RedirectResponse -from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials -from fastapi.staticfiles import StaticFiles -from pydantic import BaseModel - -# --- LOCAL IMPORTS --- -try: - from src.DevTools import TempVCDatabase - from src.DevTools.backend.database.welcome_db import WelcomeDatabase - from src.DevTools.backend.database.levelsystem_db import LevelDatabase -except ImportError: - TempVCDatabase = None - WelcomeDatabase = None - LevelDatabase = None - logging.warning("Database modules not found - some features may be unavailable") - -# --- LOGGING SETUP --- -logging.basicConfig(level=logging.WARNING) -logger = logging.getLogger("ManagerX-API") -logger.setLevel(logging.INFO) -logging.getLogger("httpx").setLevel(logging.WARNING) -logging.getLogger("uvicorn.access").setLevel(logging.WARNING) - -# --- KONFIGURATION --- -load_dotenv(os.path.join("config", ".env")) - -# Bot-Config laden -config_path = os.path.join("config", "config.yaml") -bot_config = {} -try: - with open(config_path, 'r', encoding='utf-8') as f: - bot_config = yaml.safe_load(f) - logger.info("Bot-Config fรผr API-Prรผfungen geladen") -except FileNotFoundError: - logger.warning("Config-Datei nicht gefunden") -except Exception as e: - logger.error(f"Fehler beim Laden der Config: {e}") - -# --- FASTAPI APP --- -app = FastAPI(title="ManagerX Ultimate API") - -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -# --- STATISCHE DATEIEN --- -if os.path.exists("site"): - app.mount("/site", StaticFiles(directory="site", html=True), name="site") - -# --- DATENBANKEN INITIALISIEREN --- -DB_PATH = os.path.join("data", "tempvc.db") -db = TempVCDatabase(DB_PATH) if TempVCDatabase else None -welcome_db = WelcomeDatabase() if WelcomeDatabase else None -level_db = LevelDatabase() if LevelDatabase else None - -# --- SECURITY --- -security = HTTPBearer() - -def get_token(credentials: HTTPAuthorizationCredentials = Depends(security)): - return credentials.credentials - -# --- DATEN-MODELLE --- -class TempVCUpdate(BaseModel): - token: str - creator_channel_id: str - category_id: str - auto_delete_time: int - ui_enabled: bool - ui_prefix: str - -class WelcomeUpdate(BaseModel): - token: str - channel_id: str - welcome_message: str = "" - enabled: bool = True - embed_enabled: bool = False - embed_color: str = "#00ff00" - embed_title: str = "" - embed_description: str = "" - embed_thumbnail: bool = False - embed_footer: str = "" - ping_user: bool = False - delete_after: int = 0 - -class LevelUpdate(BaseModel): - token: str - levelsystem_enabled: bool = True - min_xp: int = 10 - max_xp: int = 20 - xp_cooldown: int = 30 - level_up_channel: str = "" - prestige_enabled: bool = True - prestige_min_level: int = 50 - -class RefreshTokenRequest(BaseModel): - refresh_token: str - -# --- HILFSFUNKTIONEN --- -def is_feature_enabled(feature_path: str) -> bool: - """Prรผft, ob ein Feature in der Config aktiviert ist.""" - keys = feature_path.split('.') - current = bot_config - try: - for key in keys: - current = current.get(key, {}) - return current if isinstance(current, bool) else True - except: - return True - -async def check_admin_permissions(guild_id: int, token: str): - """Prรผft bei Discord, ob der User Admin-Rechte hat.""" - async with httpx.AsyncClient() as client: - try: - res = await client.get( - "https://discord.com/api/users/@me/guilds", - headers={"Authorization": f"Bearer {token}"}, - timeout=5.0 - ) - if res.status_code == 401: - raise HTTPException(status_code=401, detail="Token abgelaufen") - if res.status_code != 200: - raise HTTPException(status_code=401, detail="Sitzung abgelaufen oder Token ungรผltig") - - guilds = res.json() - guild = next((g for g in guilds if int(g['id']) == guild_id), None) - - if not guild: - raise HTTPException(status_code=404, detail="Server nicht gefunden") - - # Bitwise check fรผr ADMINISTRATOR (0x8) - if not (int(guild.get('permissions', 0)) & 0x8) == 0x8: - raise HTTPException(status_code=403, detail="Du hast keine Admin-Rechte") - - return True - except HTTPException: - raise - except Exception as e: - logger.error(f"Fehler bei Discord-Validierung: {e}") - raise HTTPException(status_code=500, detail="Discord API Kommunikationsfehler") - -# --- ENDPOINTS --- - -@app.get("/") -async def root(): - """Redirect zur Landing Page""" - return RedirectResponse(url="/site/index.html") - -@app.get("/api/managerx/stats") -@app.get("/api/v2/stats") -async def get_bot_stats(): - """Bot-Statistiken laden""" - stats_file = "bot_stats.json" - if os.path.exists(stats_file): - try: - with open(stats_file, "r", encoding="utf-8") as f: - return json.load(f) - except Exception as e: - logger.error(f"Fehler beim Laden der Stats: {e}") - - return { - "stats": {"server_count": 50, "user_count": 15000}, - "bot_info": {"latency": 35, "status": "Online"} - } - -@app.get("/api/auth/callback") -async def auth_callback(code: str): - """OAuth2 Callback fรผr Discord-Login""" - async with httpx.AsyncClient() as client: - payload = { - 'client_id': os.getenv("DISCORD_CLIENT_ID"), - 'client_secret': os.getenv("DISCORD_CLIENT_SECRET"), - 'grant_type': 'authorization_code', - 'code': code, - 'redirect_uri': os.getenv("DISCORD_REDIRECT_URI") - } - r = await client.post('https://discord.com/api/oauth2/token', data=payload) - - if r.status_code != 200: - logger.error(f"Login Fehler: {r.text}") - raise HTTPException(status_code=400, detail="Discord Token Austausch fehlgeschlagen") - - tokens = r.json() - u = await client.get( - 'https://discord.com/api/users/@me', - headers={'Authorization': f"Bearer {tokens['access_token']}"} - ) - - return { - "access_token": tokens['access_token'], - "refresh_token": tokens.get('refresh_token'), - "user": u.json() - } - -@app.post("/api/auth/refresh") -async def refresh_access_token(data: RefreshTokenRequest): - """Token erneuern""" - async with httpx.AsyncClient() as client: - payload = { - 'client_id': os.getenv("DISCORD_CLIENT_ID"), - 'client_secret': os.getenv("DISCORD_CLIENT_SECRET"), - 'grant_type': 'refresh_token', - 'refresh_token': data.refresh_token - } - r = await client.post('https://discord.com/api/oauth2/token', data=payload) - - if r.status_code != 200: - raise HTTPException(status_code=400, detail="Token-Refresh fehlgeschlagen") - - tokens = r.json() - return { - "access_token": tokens['access_token'], - "refresh_token": tokens.get('refresh_token') - } - -@app.get("/api/user/guilds") -async def get_user_guilds(token: str = Depends(get_token)): - """Alle Server mit Admin-Rechten""" - async with httpx.AsyncClient() as client: - res = await client.get( - "https://discord.com/api/users/@me/guilds", - headers={"Authorization": f"Bearer {token}"} - ) - if res.status_code != 200: - return [] - - # Filtert nur Server mit Admin-Rechten - return [g for g in res.json() if (int(g.get('permissions', 0)) & 0x8) == 0x8] - -@app.get("/api/guild/{guild_id}/channels") -async def get_guild_channels(guild_id: int, token: str = Depends(get_token)): - """Kanรคle eines Servers laden""" - await check_admin_permissions(guild_id, token) - - async with httpx.AsyncClient() as client: - headers = {"Authorization": f"Bearer {token}"} - res = await client.get( - f"https://discord.com/api/guilds/{guild_id}/channels", - headers=headers - ) - - if res.status_code == 401: - raise HTTPException(status_code=401, detail="Token abgelaufen") - if res.status_code != 200: - logger.error(f"Discord API Fehler: {res.status_code} - {res.text}") - raise HTTPException(status_code=500, detail=f"Discord API Fehler: {res.status_code}") - - channels = res.json() - # Filtere Text-, Voice-Kanรคle und Kategorien - filtered = [ - {"id": str(ch["id"]), "name": ch["name"], "type": ch["type"]} - for ch in channels if ch["type"] in [0, 2, 4] # 0=Text, 2=Voice, 4=Category - ] - return {"channels": filtered} - -@app.get("/api/guild/{guild_id}/tempvc") -async def get_tempvc(guild_id: int, token: str = Depends(get_token)): - """TempVC Einstellungen laden""" - await check_admin_permissions(guild_id, token) - - if not is_feature_enabled('features.cogs.server_management.tempvc'): - raise HTTPException(status_code=403, detail="TempVC Feature ist deaktiviert") - - if not db: - raise HTTPException(status_code=500, detail="TempVC Database nicht verfรผgbar") - - settings = db.get_tempvc_settings(guild_id) - ui = db.get_ui_settings(guild_id) - - return { - "creator_channel_id": str(settings[0]) if settings else "", - "category_id": str(settings[1]) if settings else "", - "auto_delete_time": settings[2] if settings and len(settings) > 2 else 0, - "ui_enabled": bool(ui[0]) if ui else False, - "ui_prefix": ui[1] if ui else "๐Ÿ”ง" - } - -@app.post("/api/guild/{guild_id}/tempvc") -async def save_tempvc(guild_id: int, data: TempVCUpdate): - """TempVC Einstellungen speichern""" - await check_admin_permissions(guild_id, data.token) - - if not is_feature_enabled('features.cogs.server_management.tempvc'): - raise HTTPException(status_code=403, detail="TempVC Feature ist deaktiviert") - - if not db: - raise HTTPException(status_code=500, detail="TempVC Database nicht verfรผgbar") - - try: - c_id = int(data.creator_channel_id) - cat_id = int(data.category_id) - logger.info(f"๐Ÿ’พ SPEICHERN: Guild {guild_id} | IDs: {c_id}, {cat_id}") - - db.set_tempvc_settings(guild_id, c_id, cat_id, data.auto_delete_time) - db.set_ui_settings(guild_id, data.ui_enabled, data.ui_prefix) - - return {"status": "success", "message": "Daten wurden permanent gespeichert"} - except ValueError: - raise HTTPException(status_code=400, detail="Kanal- und Kategorie-IDs mรผssen Zahlen sein") - except Exception as e: - logger.error(f"Datenbank-Fehler: {e}") - raise HTTPException(status_code=500, detail="Interner Datenbank-Fehler") - -@app.get("/api/guild/{guild_id}/welcome") -async def get_welcome(guild_id: int, token: str = Depends(get_token)): - """Welcome Einstellungen laden""" - await check_admin_permissions(guild_id, token) - - if not is_feature_enabled('features.cogs.server_management.welcome'): - raise HTTPException(status_code=403, detail="Welcome Feature ist deaktiviert") - - if not welcome_db: - raise HTTPException(status_code=500, detail="Welcome Database nicht verfรผgbar") - - settings = welcome_db.get_welcome_settings(guild_id) - - if not settings: - return { - "channel_id": "", - "welcome_message": "Willkommen {user} auf {server}!", - "enabled": True, - "embed_enabled": False, - "embed_color": "#00ff00", - "embed_title": "Willkommen!", - "embed_description": "", - "embed_thumbnail": False, - "embed_footer": "", - "ping_user": False, - "delete_after": 0 - } - - return { - "channel_id": str(settings.get('channel_id', '')), - "welcome_message": settings.get('welcome_message', ''), - "enabled": bool(settings.get('enabled', True)), - "embed_enabled": bool(settings.get('embed_enabled', False)), - "embed_color": settings.get('embed_color', '#00ff00'), - "embed_title": settings.get('embed_title', ''), - "embed_description": settings.get('embed_description', ''), - "embed_thumbnail": bool(settings.get('embed_thumbnail', False)), - "embed_footer": settings.get('embed_footer', ''), - "ping_user": bool(settings.get('ping_user', False)), - "delete_after": settings.get('delete_after', 0) - } - -@app.post("/api/guild/{guild_id}/welcome") -async def save_welcome(guild_id: int, data: WelcomeUpdate): - """Welcome Einstellungen speichern""" - await check_admin_permissions(guild_id, data.token) - - if not is_feature_enabled('features.cogs.server_management.welcome'): - raise HTTPException(status_code=403, detail="Welcome Feature ist deaktiviert") - - if not welcome_db: - raise HTTPException(status_code=500, detail="Welcome Database nicht verfรผgbar") - - try: - ch_id = int(data.channel_id) if data.channel_id else None - logger.info(f"๐Ÿ’พ SPEICHERN WELCOME: Guild {guild_id} | Channel: {ch_id}") - - success = welcome_db.update_welcome_settings( - guild_id, - channel_id=ch_id, - welcome_message=data.welcome_message, - enabled=data.enabled, - embed_enabled=data.embed_enabled, - embed_color=data.embed_color, - embed_title=data.embed_title, - embed_description=data.embed_description, - embed_thumbnail=data.embed_thumbnail, - embed_footer=data.embed_footer, - ping_user=data.ping_user, - delete_after=data.delete_after - ) - - if success: - return {"status": "success", "message": "Welcome-Einstellungen gespeichert"} - else: - raise HTTPException(status_code=500, detail="Fehler beim Speichern") - except ValueError: - raise HTTPException(status_code=400, detail="Ungรผltige Channel-ID") - except Exception as e: - logger.error(f"Fehler beim Speichern: {e}") - raise HTTPException(status_code=500, detail="Interner Fehler") - -@app.get("/api/guild/{guild_id}/levelsystem") -async def get_levelsystem(guild_id: int, token: str = Query(...)): - """Levelsystem Einstellungen laden""" - await check_admin_permissions(guild_id, token) - - if not is_feature_enabled('features.cogs.server_management.levelsystem'): - raise HTTPException(status_code=403, detail="Levelsystem Feature ist deaktiviert") - - if not level_db: - raise HTTPException(status_code=500, detail="Levelsystem Database nicht verfรผgbar") - - settings = level_db.get_guild_config(guild_id) - - if not settings: - return { - "levelsystem_enabled": True, - "min_xp": 10, - "max_xp": 20, - "xp_cooldown": 30, - "level_up_channel": "", - "prestige_enabled": True, - "prestige_min_level": 50 - } - - return { - "levelsystem_enabled": settings.get('levelsystem_enabled', True), - "min_xp": settings.get('min_xp', 10), - "max_xp": settings.get('max_xp', 20), - "xp_cooldown": settings.get('xp_cooldown', 30), - "level_up_channel": str(settings.get('level_up_channel', '')), - "prestige_enabled": settings.get('prestige_enabled', True), - "prestige_min_level": settings.get('prestige_min_level', 50) - } - -@app.post("/api/guild/{guild_id}/levelsystem") -async def save_levelsystem(guild_id: int, data: LevelUpdate): - """Levelsystem Einstellungen speichern""" - await check_admin_permissions(guild_id, data.token) - - if not is_feature_enabled('features.cogs.server_management.levelsystem'): - raise HTTPException(status_code=403, detail="Levelsystem Feature ist deaktiviert") - - if not level_db: - raise HTTPException(status_code=500, detail="Levelsystem Database nicht verfรผgbar") - - try: - ch_id = int(data.level_up_channel) if data.level_up_channel else None - logger.info(f"๐Ÿ’พ SPEICHERN LEVELSYSTEM: Guild {guild_id} | Channel: {ch_id}") - - config = { - 'levelsystem_enabled': data.levelsystem_enabled, - 'min_xp': data.min_xp, - 'max_xp': data.max_xp, - 'xp_cooldown': data.xp_cooldown, - 'level_up_channel': ch_id, - 'prestige_enabled': data.prestige_enabled, - 'prestige_min_level': data.prestige_min_level - } - level_db.update_guild_config(guild_id, config) - - return {"status": "success", "message": "Levelsystem-Einstellungen gespeichert"} - except ValueError: - raise HTTPException(status_code=400, detail="Ungรผltige Channel-ID") - except Exception as e: - logger.error(f"Fehler beim Speichern: {e}") - raise HTTPException(status_code=500, detail="Interner Fehler") - -if __name__ == "__main__": - uvicorn.run(app, host="127.0.0.1", port=3002, log_level="warning") \ No newline at end of file diff --git a/assets/img/ManagerX_banner.png b/assets/img/ManagerX_banner.png deleted file mode 100644 index ed15b3e1ca801ef1aa8ad6e012b5703659f89ed3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 287258 zcmV(>K-j;DP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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

UL7@WUY0XKbctOZ!5{{4+QFU=`ibjm! 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Φ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 %h>n5`ZcbCN~W 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%0DB!twK38cSe#xrpO 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 a { - color: var(--mx-red-primary) !important; - font-weight: 600; - background: linear-gradient(90deg, var(--mx-red-glow) 0%, transparent 100%); - border-radius: 0 20px 20px 0; -} - -.bd-sidebar-primary .caption-text { - color: var(--mx-red-dark); - font-weight: 800; - font-size: 0.7rem; - text-transform: uppercase; -} - -/* --- 5. CODE BLOCKS & KBD --- */ -div.highlight { - border: 1px solid rgba(225, 29, 72, 0.1) !important; - border-radius: 14px !important; - box-shadow: inset 0 2px 4px rgba(0,0,0,0.02); - padding: 5px; -} - -/* Wenn du in RST :kbd:`STRG` nutzt */ -kbd { - background: #f8fafc; - border: 1px solid #cbd5e1; - border-radius: 5px; - box-shadow: 0 2px 0 #cbd5e1; - color: var(--mx-red-dark); - font-family: var(--pst-font-family-monospace); - padding: 2px 6px; -} - -/* --- 6. RST TABLES --- */ -table.docutils { - width: 100%; - border-collapse: separate !important; - border-spacing: 0; - border-radius: 12px; - overflow: hidden; - border: 1px solid rgba(0,0,0,0.05) !important; - margin: 2rem 0; -} - -table.docutils thead th { - background: var(--mx-red-primary) !important; - color: white !important; - padding: 12px !important; - border: none !important; -} - -table.docutils tbody td { - padding: 12px !important; - border-bottom: 1px solid rgba(0,0,0,0.05) !important; -} - -/* --- 7. CUSTOM RST CLASSES (Fรผr deine Container) --- */ -/* Nutzung in RST via .. container:: mx-hero */ -.mx-hero { - text-align: center; - padding: 4rem 2rem; - background: radial-gradient(circle at center, var(--mx-red-glow) 0%, transparent 70%); - border-radius: 30px; - margin-bottom: 3rem; -} - -/* --- 8. SMOOTH ANCHORING & SECTIONS --- */ -/* Verhindert, dass รœberschriften beim Springen hinter dem Header verschwinden */ -:target { - scroll-margin-top: 100px; - animation: highlight-pulse 2s ease-out; -} - -@keyframes highlight-pulse { - 0% { background-color: var(--mx-red-glow); } - 100% { background-color: transparent; } -} - -/* --- 9. PYGMENTS SYNTAX HIGHLIGHTING TUNING --- */ -/* Wir fรคrben die Syntax-Elemente dezent passend zum Bot-Thema */ -.highlight .k { color: var(--mx-red-primary); font-weight: bold; } /* Keywords */ -.highlight .nc { color: var(--mx-red-dark); font-weight: bold; } /* Class names */ -.highlight .s2 { color: #2d5a27; } /* Strings (grรผnlich fรผr Kontrast) */ -.highlight .c1 { color: #94a3b8; font-style: italic; } /* Comments */ - -/* --- 10. MODERNE NAVIGATION BUTTONS --- */ -/* Die "Previous" und "Next" Buttons am Ende jeder Seite */ -.prev-next-area a { - border-radius: 12px !important; - border: 1px solid rgba(0,0,0,0.05) !important; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; -} - -.prev-next-area a:hover { - border-color: var(--mx-red-primary) !important; - box-shadow: 0 10px 20px var(--mx-red-glow) !important; - transform: translateY(-2px); -} - -.prev-next-area .prev-next-info .prev-next-title { - color: var(--mx-red-primary) !important; -} - -/* --- 11. API REFERENCE (Autodoc) STYLING --- */ -/* Wenn du Python-Klassen oder Funktionen dokumentierst */ -dl.py.function, dl.py.class, dl.py.method { - background: var(--mx-red-light); - border-radius: 10px; - padding: 1rem; - margin-bottom: 2rem; - border: 1px solid rgba(225, 29, 72, 0.05); -} - -[data-theme="dark"] dl.py.function, -[data-theme="dark"] dl.py.class { - background: rgba(225, 29, 72, 0.05); -} - -dt.sig { - font-family: var(--pst-font-family-monospace); - font-size: 1.1rem; - color: var(--mx-red-primary); -} - -/* --- 12. SIDEBAR-TOGGLE FรœR MOBILE --- */ -/* Den mobilen Button anpassen */ -.bd-header .navbar-toggler { - border-color: var(--mx-red-primary); - color: var(--mx-red-primary); -} - -/* --- 13. LAYOUT HELPERS --- */ -.mx-grid-2 { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 20px; - margin: 20px 0; -} - -@media (max-width: 768px) { - .mx-grid-2 { grid-template-columns: 1fr; } -} - -.mx-box { - padding: 1.5rem; - border-radius: 12px; - background: #f8fafc; - border-bottom: 4px solid var(--mx-red-primary); -} - -[data-theme="dark"] .mx-box { - background: #1e293b; -} - -/* --- 14. SEARCH EXPERIENCE (Modal & Input) --- */ -/* Das Suchfeld oben rechts im ManagerX Look */ -.bd-search .form-control { - border-radius: 50px !important; - border: 1px solid rgba(225, 29, 72, 0.2) !important; - transition: all 0.3s ease; -} - -.bd-search .form-control:focus { - border-color: var(--mx-red-primary) !important; - box-shadow: 0 0 0 4px var(--mx-red-glow) !important; - outline: none; -} - -/* Such-Shortcut KBD im Input */ -.search-button__kbd-shortcut { - background: var(--mx-red-light) !important; - color: var(--mx-red-primary) !important; - border: none !important; -} - -/* --- 15. INTERACTIVE LINKS & INLINE ELEMENTS --- */ -/* Hover-Effekt fรผr normale Textlinks */ -article a.reference.internal, -article a.reference.external { - position: relative; - text-decoration: none !important; - transition: color 0.3s ease; -} - -article a.reference:after { - content: ''; - position: absolute; - width: 100%; - transform: scaleX(0); - height: 1px; - bottom: -1px; - left: 0; - background-color: var(--mx-red-primary); - transform-origin: bottom right; - transition: transform 0.25s ease-out; -} - -article a.reference:hover:after { - transform: scaleX(1); - transform-origin: bottom left; -} - -/* --- 16. IMAGE & FIGURE STYLING --- */ -/* Bilder erhalten einen dezenten Shadow und abgerundete Ecken */ -figure.align-default { - margin: 2rem 0; - padding: 10px; - background: white; - border-radius: 16px; - box-shadow: 0 10px 30px rgba(0,0,0,0.05); - text-align: center; -} - -[data-theme="dark"] figure.align-default { - background: #1e293b; -} - -figure.align-default img { - border-radius: 10px; -} - -figcaption { - margin-top: 10px; - font-size: 0.85rem; - color: #64748b; - font-style: italic; -} - -/* --- 17. IMPROVED TYPOGRAPHY (Vertical Rhythm) --- */ -h1, h2, h3, h4 { - color: #0f172a; - margin-top: 2.5rem !important; - margin-bottom: 1.25rem !important; -} - -[data-theme="dark"] h1, -[data-theme="dark"] h2, -[data-theme="dark"] h3 { - color: #f1f5f9; -} - -/* Marker vor รœberschriften (Dezenter ManagerX-Dot) */ -h2::before { - content: "โ—ข"; - font-size: 0.6em; - margin-right: 10px; - color: var(--mx-red-primary); - vertical-align: middle; -} - -/* --- 18. VERSION SWITCHER & DROPDOWNS --- */ -.bd-version-switcher__button { - border-radius: 8px !important; - border: 1px solid var(--mx-red-glow) !important; -} - -.bd-version-switcher__button:hover { - background-color: var(--mx-red-light) !important; - color: var(--mx-red-primary) !important; -} - -/* --- 19. FOOTER CLEANUP --- */ -.bd-footer { - padding: 3rem 0; - font-size: 0.9rem; - border-top: 1px solid rgba(0,0,0,0.05); -} - -.footer-items__end { - color: #94a3b8; -} - -.footer-items__end strong { - color: var(--mx-red-primary); -} - -/* --- 20. CUSTOM NOTIFICATIONS (Banner) --- */ -/* Falls du oben eine Ankรผndigung einblendest (.. announcement::) */ -.bd-header-announcement { - background: linear-gradient(90deg, var(--mx-red-dark), var(--mx-red-primary)) !important; - color: white !important; - font-weight: 600; -} - -/* --- 21. BUTTON OVERRIDES (From Blue to ManagerX Red) --- */ - -/* Haupt-Buttons (Primary) */ -.btn-primary { - background-color: var(--mx-red-primary) !important; - border-color: var(--mx-red-primary) !important; - color: #ffffff !important; - font-weight: 600; - transition: all 0.2s ease-in-out; -} - -.btn-primary:hover, -.btn-primary:focus, -.btn-primary:active { - background-color: var(--mx-red-dark) !important; - border-color: var(--mx-red-dark) !important; - box-shadow: 0 0 0 0.25rem var(--mx-red-glow) !important; -} - -/* Outline-Buttons (z.B. in der Suche oder API-Links) */ -.btn-outline-primary { - color: var(--mx-red-primary) !important; - border-color: var(--mx-red-primary) !important; -} - -.btn-outline-primary:hover { - background-color: var(--mx-red-primary) !important; - border-color: var(--mx-red-primary) !important; - color: #ffffff !important; -} - -/* --- END OF MANAGERX ULTIMATE RED THEME --- */ \ No newline at end of file diff --git a/docs/_static/managerx.png b/docs/_static/managerx.png deleted file mode 100644 index 950a8962cebc119c1b02a241cacc8118dbc33641..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1549077 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 se?>eZ_zdPk=Jfmi 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

yZjrg92rH9b!URryTCu@hw84THe0lFpcsy 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
      S7)inKxljxw_;;?fSGRws&Jy#R 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

      -Z{?K|W#pe!{FePY_cOhbqi}df6Jxslv zn@{)g9Ri}=`PkP``A^Emx(VEkstaeHB;`59Mz`Y)y&7XJZ@rMBx_SH&N-Ia3|je2M4DveqqWoZbN#v**sH zVWkEg51u8XGWjU8xadnd`DK)W=y_zznrs%tb#w*>@&#hZWc9Ad9pnq@m-?3`-mU|E z{idPYOAd=>-%Ll>lPGD=JEEC%Y!$G*x8oq?k2r^F_lguFk9|Tim{l^|Wg`{YKbLQ^ zG>;P$+HjUO8U=3xGu#L7gkNJd2~gE7b7nhp69UWgS(mxK#THMx2DtxV&=g)c>G1o}Oif zj8H1rMY5=ePf>xPF267p-qHWLeL#K0J_7*8slbT90S)t`< z{nGWYuV$ctex`xnhln-s(-2GA9l~}1fE@b0Fum8+;6HaDd|O8d1W=%(^4O*R>cCZgU`>Gxc+rS8}zX(W}F4Iot{JiPpZyyc)A-W zy!+w4^$sa_XSvX|fLHm+0G@aA;v%^`h20m9brj8MWARx+oq=v>;~bA(kLI!5;taf3 z^JRBpG0e0|v|jmn8VrA4JtWHLx9(%lJ+w;Hz7^w_78B#yY)3x^j* zRYNOXgag8#*&)-aYpY++SUnmE{X2T-?RJCX`!Xb zgS9H-IG|0k_5D(eU0$czqxci$w{L>31Tbr#2&C)1)ab2LV@Gr24Ua)H{GEIAmkPRE zjoFm`F7{z~+MyP?idS{UeqWx?@A?8=8%g+Ee+$Ue<(n^bktxH}91GifMXL*LqvTce zrEN;DRFPB)wY_tB+Njb^rfnzbKR`pbF-W>_9QAD|%*A_I%Q-kk(ATpo;d>$H8F}e4 zVaJq&7pH;hnIe5x^V~rvXSbA1UEPMlP@lRRIzTy$XkaK{YOa3PxP9sDY%~xg zUT%ZK6u?5FF&+2E^ZijL)UW;;;;Q9UVNQBFx0JJPZ$_z}x{dO72EA^(;ouRRRiLxB zw7g6@Jlomor&<$Sf(_-8qbA!0t-Oi_1Xc-7y{2E{BhB;YaJB~WzoT8R4!}xI7JqK0 zECK==ftEB8m^@Z)V*WvXOC>b?>hdKEZM0C?pANn< zk3t@V?0z>4cF1p;JhTAy*`0=)T`$Fkrur-v(wpD<7NK+kJ+%T zhSfIDw^2-goT78aF4FMUtee-XR@bfNfBW>$^#eS;_)c!mtYaWs>$nFKI@*EA!fxv)b;O1#d<$9oBMW10hSF3gDl#W47Kehc(Q! zAGNxrS72YQz|u;WNz(GX;$;Of9nm_Li-h(N{twIvxE(e9D-#cxcURtsi_Yd59~M8! zEm51A>i5y*@GwJl&E0X)?&F47{-u}uX2@yK>voU2ejT3`>V6|bzAZFOrLi}%B836Hy}Sw@Vd5p_OZA?1VG(bM||42=;lm{S=KHsdK!{7vOJ0D9yz+7b<<&ocWNOkgtPgb66ZYq25Awvb7Vn!fNSL|*zB z&o|oAoaBgmo0`+w1!)S)-pl&c`3$%d+ze5ZvT#G+XQWj3YFfnmkA&PQ@5ka!}M z{sqBisnd1PnX`{o$MJ&GS8~et*oI>+bjX) zv=x?VCMRP+Uz}cMBRl)z^Oy?=ZEcV9r?0_+AhIInI&^P0%0D+jyuWcw2Q9y_)uXA$ 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%0A5drlEy+y*AdD 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

      K))@iZQ@-RR+VHFS}cFs&ByT(|JoT%2trw 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%0DioU-6$pGsH<^Bn(9&ss%g&LuUMK_n1>yU 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
      Tc&yxHl4W1M+$-TQJF>9!>mh4->s?=2Oy< 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�eY2 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�a>6}CaAyNUTq$PT!;sHn*qRiOI1 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%0AOYJ~y;3M{#G}f>-DKaWHdzN)DHQ=SNNxre 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 _!eDTeP9i@8z{Hl^!lz3gURBz8m#0bI>Z*OmI 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

      tFT*a$}5{Qy0ST<1k)?Tib#H|4QtuDa3% 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%0DXFU=DBzCZQH!Fqjt|6-#8h*cSZ7(SFh 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%0DQfn2ku0#( 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�WkfSJ$LFL6wj7Ai%cIwjPg%+97=J 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

      NT$broKR#HYMlv(A;l{O=5i>RJPSEEc1Sgw? zoK-Nod!Fn~4|K_#-D0=Jr~2N?@A?da<~h0DKoTs$&>sHWYra@5w7V5xf{`UfSl3&% z+Iv-ttwd3DGoz1Zc?>+m^q>EJT9}3n+cmC(>CJ#IPAF(k9)M2Ix@&(1*?`%|`Hc48BfgO%ZkGvy4M}OJ zO9eAKmE&wCx*8ssu7Z{I|=S`UcUMdmp*09Pm zDx&zhwatear0-BCyJNean(DT4NW(V9D?4{W2m*0S5)ov~uL z5XMlORNHo`@>F+y_D6c>N@mQglV`0B+8{xP4R`X6PAC@VrJ&Z$-|Z2;-1*(SK&xm# z0byTTCm)*^R3q=@i!^96Z`E4c=;&kwWuVTLhlRV)`pX$qRk@k^{vHu~#afF%X3j~` zpah<}D8+Ua!tM7Y!1eLIQbXN0=ard`Pv*b9mcd{ev4!`Qsgg3czx;*IS}nL)b&bpm zZRAV3=)cN#RF;^!An^AA1`&Wcf6iGJqjRiI0H;7$zczdkU`cy8HB$N3<||!^PnygP~53*&vnXWN#8{+rR&P0|vJp z`#I0dYY^rwlq?pqxVU{)_n1%{>~5JYLl)0{mIsK2k62b+&34%o4hRchfR$=e=T1B4 zl4OZtszg{f(Mj=njxQeq{%Z#8rrOLMHK(n-kB6TuZ^asvdE~iJx*J^tv+pD2@_W+fBbtBAXY0Yki(OP#b0aJq+xL>1Nvb9LQYNr|hO_fY$ZmLVT`_NQ9%&I$2 z*|IEDr-gM7zbxmTwR}$_HoG-$=4vykx{0vh_Rhv2XGy@!Bzfg^F71K-Smza84Op26 zz}5x$UEk_d&qUpqlz0z-H!sNLVT)Cg%4|Rq27(rf#QFWTSej&V|Bo=qMuK47BJai9 zn-Cy+LNV`-smI5)|eF1vzbbRF#3WO=}tRT#F@RxJx7N0g0-biFj4R z#vXIkwtP+XSrocvD^WFIqCvL8%mn03w`t-It(0|>L`2M?$7nJ-BD=OP8kc*uI7olO z>81W_I3d-}q2&jqi!u?^Tx=MjyfwAz$-Z|-gfNfKA#ezi8=yw9zzB9#MC{4TOEC0& zu2kIyr*GD;E-vObDI<6xW7`UKpUPlVmbvXS-_tA2?W@3=J6&126&-y+n1wVox>!n zgjxGE)m5MU=_*ZsU{3wUp|{r9d)y>-rA272nd($WgoNb=M0Wut*+m6Z8Ow@MliY z{C!xvFZalbGAF(&bfrea+;|% zoU;p^du?{ECWuI2u5#$PPK!8svh+e}+m_E|i@wa^`{PD$i@kQL?#+5K@2wde(S*u- zB|YcdN?)7qG{j(!-3JI2@G;Ol_uifjDzm57mUG6Z@$*^X6K3|T%+Acr?$NtgQw&L= z1z8GGn*08)y_Sc&7#F8-@367;Tlvu_?%qk z^eB~yl{)8Pm((@cMzvYcBJMq=Y4n;(m%aJ#K z&#xOl>kBfoWCkLc>b7mMmrYzx@6OA>a0iit%u;uzfn5b*#}4;*7NsNs!9;^+cbofO zBU)0oIy3LN7lOg7QvZW-uAa?PHz?h%lW7sgK6#z&RNhkKvz8eI&|HPnIWJg&BDygO z=jYttd*hwVOycwn;XyjLrhm3p_+Gv(B3ilj24|Fp8GvY;V}(twyjzJXqb;}F7tYU$ z2+~w4i+Ij8A-MWx$^5fCKFho->)!A%veY(jWwr=&EnBg6W}oNj?z+{9Mwxr8O^U)= zJ8yNTID&yINNNv_WNj1?n%Ie|Gih8FkmlBu-7Q#StSqE~?C$I%R#j$pb~;0-|d^3lw z*rZZfg=TkEUNc`|?H2Kw0CcM=%b*?Z=AyDo1)GX4Y`LxQ$*K3v-{-gPbF;ci69fPU z#p?8M`eqBpkmN762ui5a-dwa}CR`;mGpBpVFcyYZXASS)NtWt%W*wQ-B(3_wtV-EA zJt-6BXR5*5O9t*RnrCKJ4k|uVSr=#xi$Ka-_Z9_-;Y*!9^*-sM2X|p1kBuHoCgnyB zISQFs>gloOsEuf<%4thC<{EGQc4UnPnw0LGK8zXm`i|b`tszy7cxZA6Rb_&OyLnYr z%IKNh#rq^*ri%zo0T6tkI{hUSL&QxTG=U2z)xtcT?53i)M5SV5T~=nPxW5dAfQn7hy5K%=XwcJ?FPj zqN;0}x}rsFiZy?xK%pzgb=dPNJLgI?r>`|yh5>oMIcRlFegtU-vv?Pcg0*M@WcKlTY3kzvoW(_$`17ifDEIWR{?-W{Q2{lFa=HB zFalzAW!|6x)JZ-2c6**BX_ zb*+dtztgS+x_UmaW9(>&&b_yQ>fs2}%q%Ft9kUOdor}>RklW}H%VTzZ8hSDcppn$L zX1WBfSdewL6O9JTsDA&nU1&N`nR!~(6D90+BbvYGp<|%f-Kb8?&Ie-9opkT&Q|kJw z;s)N=k|x7}3B_~|)HgLz62?#nHndxkY@!ITm*U*^lqmbPBk{=e?IDm2$;uNe-lwT1`S!t+~jr|>Q{X{1##+&>ZL$*Quj z*6nkBg}J$}uYW&#<@-s52rD%KaxD*!R0%M8-P6Ka+sp_*Pg?}s-1yy}&u8_(pwv|z z<|Y`RzsBFXQ^G;BPu*BCqZ+YyEc5v6wQV`0x+XkEBJ+|ATLZ?@Raeosh&~;*tGe0u zIVX=9cdX%78+~mr_0RJJ;l{b}Z1>pF>XWxie3x7sqAmOGPg=X1x}WE#GrOt<9|vu9 z7jhuj1v4K|`&)jsSsJ%F)t&D-tXvy6o?DJ>u@1M29 z>D6lV9Pcg0pwcj`*y_Hw2=-K!jWEy<=C*v9cdP30wPp`od3*YfXp<%lUxO*Zpq%`m zvUAQHfXm!xuF4t5%H6VSXv>q$jR-drT!fQYY;@j=717Ms<#a(*HX^8Z);)WeJBtWl zwv%9G7dcEGm%(J{?xXu0noD$0Zfw$rNM>rgr-k~P2I=bN+oF^SGhmiaKEQ0!{M~qU z(gPZC0cK8*9zGA*n7SK5-g_A=h~^XPuI%a#iy1?^MeAlJvTwDU3vW1;F!u=e_1QMg z&LI<;y{Dq?x_8q1BRm4FF@zqr;O%a1phwKG3C)P8ygd>B&xgdlDF7Cqh(G`Q5nerB zL;xH#@ON#GrPro`7S;}r@Cj3x`&x?*%t)(%;cfKf(>u#1N9=BHQ)U=m_uKgdq>dFv zw=f$1e@y+|k|arvbb+Y?Fwg4wNa4@BkbM6)qLAF_3^zcP7l``Ez1fwK-s!5y40kg? z^_*EMD)Bw6dt_?6yK?v3`^kvRT*2{d|9g*|nT%whdjw_VB8&3WIR_Er-tEAvcPn6s zFNVnKElqyA7ZDUIBP(}W(w3H~uX#>ZRz#XHdV4f$C<7&EgyI)P00axhbdN3=;Q&I@ zn|$4-$Jx^bDbIL_9V?ViJK!2L5WKBD34G zXVpBJQCV2Ea_odl(pRk#br3nD0J4fJeF8o1xw0*1Rxnmc1_Zv}4z|RIRyD|m|eQ%}Z< zwAWreaYr8HX9Pe@BjR^c>AjF?g{@?xf>M@kS?sEH5Bk|smTf@gPOj5e}Ct_>%Jys z$;WB>$$Ea0(9iSi;rh;W-#QPz^^T?HqKKK-XnPnc9+3-#3Xd#bpUmF^i?l0Dw_N!om#6X)DJRaser zpm@&NNail3Gt&?TgLxv~``-86vEfghU^-AyOfWYdwazSVE}y}k`Hn?5Z4fzD(l)Y~ ztclc<i40#qSy$(c8D0gI?Z%rk&{4W&=P%W`si-sFQ=ab6dTKtik>6Aoj0Mw?=*Y z({WhH<9N<SAaH2!^ZR2>+*TV^||PUU-F0Q5}X(R3@Z3&1>C$oM%0qvuxex_2=Q zWz`vIBov~udmQ-5Cz#eOWHKTnBWp=&Lt!-UZ*Ns;1JI__>U%eHdCpFz_y2htPK0r% zXH(v=p+I?F$dL!&nBNn~$$fvK^;Ciwjk7k{MhCo&W1;dy66P*aB6cJeQPK{Q(YK|q z+$zk9z?P!|l_}s`Tyt0OtEvfVJ2RN~zBUjn9tI=hsqg;belFl8V`j$8c;#mI1r_Go z_tV`N2S$>I2%BMeh7L9W?%kV+-udrpsDZa%fj{T@&wu_fkX0@9y;V3&AVn&})HZaq&HmEu?B84G2mV@=wPaOv5 zzW40_cBMQc1m|7?_K^5_e(E`yq0t`7zT9hL?wxjDSLFXD1zFS@6UUow3V1Xc-FK#^ zA|g0;MA(yAncqRCR?8IrR_h}IQco5vg_);Ts%m)N9$!)^NYm3YdgVV`im^4~h8zHx zyGiMua}uH5uRs&u>grNqe4_Yee9zBPYa9BQmozK4(>@j+2an&5CX5 zR2>Z%3GD5Tlm#MpJu9%_y$bo9%x`oAC%<1%FyvtpLCxIx+}~^8+_h1rL+VcOInQbb z28zs}yWjWyC~zV)6A`%$hKhAi{5^3m7V29%I)(mALSGQs2H^3$J?RQ!hNqV;g6TrR;xShW(fH4+5^4B=4 zz72DFNZsPU4xAw?DNjW7|7S%sXOQnBUv7zQMnq8K|8Z-*0AcV1Su< z>MTMfBH!64@0x=#mfWzCJG^qczpEArfy^?n>B`F0)Yx#pFW_8s0i!KO%63v~1KaC0 z050%>hUE?;&;A6z;NA%4o|>6$^cJ|e|I36UiWwQDcA_#9^jel@PaydnUP*VKIT5y~ zxtVF&#JY-UW@SV;qHp(1FaoML>vjr%Z^#(WA`}F3Pdu~;5yO{|t#_J?f6gE7P$Gih zQ$PQlpYt3|kM=Tb%kMj%-%s}{fGzuZVq4_Ncw3_OG?PUJ)vfW4hP2qitIV)FfalNu zGAwmOMAn+bPZs5#3Fe8&=eaw_t(12WqGbH}`B?$@*w3Fou1Iq3)x~yt_KcWJ1YuR2 z)hobARzzIQH?9Ko?aCNf>SQGnYG<4}_J9DRSSRaGJtvlKx}`H*8v&{QUm+ z^LcH(_qKbVzx7jpe*W=T(5bpJ9zEyh=hVok04tzP|7V`!p#Zzb=T!atjFs{9=c5t4 zl$^*NS#PERI8RlTX6jV3KA+F;@8{?F;UR&loI6q{sPX&x*G8U*g=YjKD0d)&>ix}` znb%*qP4F;k4>xWyB2%|_KX8)CGv1Z6LEd)jW<+IXP-z3L|E+aXFbJvv_`Ub`j9Q2t zaL;Pmo<9+>V%!ymN96KG^AsZ*iaaz<#bFgWGYCHW?ok}(^qBAr9&)K_VcUqX%uJl~ zk$hFmQ_q#odDambk(uniTuQz0-gj2YFcbJ@xDz>ndh+KvX+k>Bu^AQk+9VA)p2SzA z!h0vP4xi~)E%L8L88CYrN9PngbMM?q=YwfgoS$c??t8HW-&k#sHEKjs z;7I)5(UhllSNWemKM|3Uh@c3plodU5`#ax^I+aHOM0$_f(_f3^N_NR253)6;E16I2 zYQArGUkh*yY-uQg0>YSa#_7I{tfw-cz7wqf{PRx`_w7a-y0 zRPt|^@pgCjzTkJ`v9+KccWZn{9m&t_&*ue}>xK4}bo*+Q5Q+2rseIr#k+3m-04^2? zj)2v10`&LJNQB^-+FT6^N5nL5Gs@-cNT+)1Ii@-9eB8 z?3W3v{4DJFQs#`BusEZ>cf(pe3ZCcZ&lj6R0_+(RQgEaEJAP&u)ZZGx$kRPD1S`*T zp6Tx-U^dyrFQK227DiyQ=YCTony`zIFqm$9F)~JBk$ULv>4u%bv+L1(j09p&y4Wfg zb2)DGUvgqZ{6yxd4AEaZ41-K*5UEixpL1Nfw-Ri8$(%c_B}kHqb50hE*n)VPV!e;Gx5)$Sir( zA`pMq8H|t}Usf2#6IscSzeA$=uvjEN-YpJTjH{Zl09N-r*LrGWnyU3^lQo{5g zeOrx-5P`7zo#cZ4ai^yh8C6Ltm+UE2A~J0Ns8ckmOhS?|z@~MvPZ$U5lw!*mh&*Q<*m2`+NI3L`!p{YF7|2Bc3c)ep}-HdnXwUfXZClu%Q8}&hs1-@26*3Ra;3} zbtSZe1AGmpJMeU6MHQvM79;4z)aJ3g5*2*IP~#m#sI?CHsgr!IKn=iC1*O(-9LE(p1{eFV|JT0?>Q$k-`f!a zm?#=n^c~13R)A5#xEh;f@FZbeb-&M3(^rZof|>CY`qS^5RljNm{&{Neqd)(7bg_>2 zwoe5%qPQfF#-*ZIQJHb)1FYvT=EknlB6)SsNd!l}?>tZZ_w%VNWQ^n)h6jGt6$RjS zM^ReQmi6{?>Yso9`Th6JzTMb>1GSHOf7LLKWIE6D zeU++}Nk(dBRmk!^Po6y85R|d4sYp_up0OkIdic-J8R>KH&X_-Q6A?dIC~|YW^BvmG zkfalH-+TX@(*Qh`b?1^mhOQzLW}HVBOv6;6t=83OTb>J4xL$5V^SHMQJ(p22SeD`X9T;2+y=Q} z%n5(4llQ%O!%TxqdP&5d>m$;`w?AaiZu8IcG$vG{+{&n+NY1z+AOaiM^_Gm%Afb%?uq!i5D=!T=UT2fwiwi%^UoRh zu=+MFtA{vr_Z#FOi?~Ka`c81~1q&*Y?!F4AP(JDDMMh4@M8#uy`exJsbYv#Jf+7Yu zR<}JwWx%>k6Az|4Dl!U!hO3>n-S3i)@V!=4Xp9J9U>nlJc5f_b8=%2chu}0S;`hHF zGM;Cnz0ODg!F;l0?H?Pn#@@lR=c7gB?>SQ4A4XP0Tkq$M3aV`~I8qSAnSRH#m04>x z{E8)FB&H(1ENq8q3mJC?Six3ryCoxAiaef>bgH-Y^6dYZ8Ov&YQ8fTW(Hi)ZBNq!1&*NZ0BJ* zWep%R>|sO5h^NkA7>j8ZS3wJXH;smRU{}K5)sB;~$xZ~Qz`}fE)Y|)P8<_=@Xl}RE zYf%Vzai?3zc5EgO)Kvg=e)|4yYF*kiQAV&LF?#Kq#ULpom+wUKecykcpB)4IZ6KA# z`)Onn!R=PQpEn~j0**1NLI!i6=CObWXc3pVeQ8(yAa~^KlN?K-KuV@%#m>%04rXS0 zvCn&nBSw=CCJUTY_l=~SNb-zrZ>H`73c43J7}XSX1+%(d%kEM zPhT)x%=>xk6hWNO=LV{Uvuuv zO!w#C|Nc+Z($ki3Iaw!iN4E*<_FGG2m*(zLcNp>S`?>%AOQHUGV#@@X`IEwEH17uv ztO?bj#_!d=Gd;h*e}h1I7`&ew#mrz$o+r=I?YZ;s?<=rT|GuB@p1wfr9*+P=S!o~{ zhNXF)Cl4a44xjV9SEo+p8K|njg=>4dmsb4y`7eY&|2*xEi1YK4=Q-!R-F^Ex#o)Lv z)E>(M-_Pgvd%I1Uy#=do|K2MzPgcbL{LlY;JkL*&t|-=l1R%1$l3~xEpC@+w65bQM zIgyN~aFV9gV4gY&y))3L=TyD#ogQc^9}lOs>4=~6WOA9p`_2lrWJRU|+me|XEzZ}Db&=KM(DXcY0KnRv+NSq5XLav|$wdNMRdIe!C2|Mq zW45N}JSURxowgfexfbNI09@Voe*WM8umAUT2l3upr~di*VUiV=W!z~5Gb=L?uBi2o z1I{cg&i@O%k5f4HkokV@eS3g?`h2>tAY;Xk+=!uJPmpPVGn{(Pcbq1}`h7ode>MZt zeaC$&iMV|yC9;fP#>f1b>Y zQ;D>M*qDdU&&e#4+wgz>{N$+s_jZbOWZ4Jed>%$y$i$Nrv6uocqH0Gv$FqQKLv^9Y>z$Sz`5IY{+d- z)PvZ;fa%a|NfM^l#FF1%z;Q2Pcb4d-?{P4rB3Z`r(gPmt|7jzc8C9pAV^36QM(RM= zti2+BZ>;eh0B(*`kUgI<_%5LUu!ey|+?j4==5tO~*+a7`PsS__=Bv1uS{c66XpS3q6B(Iw~T0?|U`DTyxHZN0uQ5lM$TT3H6=Z+GQya>TY*%bMlFZZh1T{ zQ%Mrh{mL@weS^^pSqfS0tLgFf=r^B`u{rqr4IWF~*93_zB_Qx+0+HO{Q7d9UfISvk znz=I?FKR8e7*<$H#g?n!%n+b`;?Gsj!1W|BD4w&`NAt@+HEdz21G?VB2O{Ws&Dm=C zoss(c+Wb<5)fSDho~ZEjY8``j9Dz~qMr1>4kwwP+?9^HY_<#Gq{9hCFTqEvWBA&Gp zI?i*p+TJr#|9Sqox1(_1f&KjaDaLQV`yI+;kGVHy#%vl4mIuap&imU)67W@3jb7nz zH;4%<^4Z)O;b8ropa0MA{}h?QZq*3@kw2gJ_fHj*|NVW>$=`qPfBp~u!2JFE{ygQ` zWmt^or;dybZoc=oqRf(Uk~8=AWIdWjgyEB%f#f3x$3@C)Nn~^Al{x<|Kv$yIM2_YzgE^&lLYCtW&P#Hdf*d5 z9)>@kU$T-Bp_c#2pO4+R9_QaqQJuUqG|oAaKJSN)1$G7r5!Bmvq+&@o>N$iQ;$&73 z_)5i1Ig9U|AXw-2TTCXmxB7F=dtWmEbKpcJ$tX~Op=mb^Yj@vO)!ksoU$hArMgIHw zoOA4+zi%cR4pzhB88#AIDjGy;m$qv+!-MLQ>QWao%5gL&-~kORTTji zm+UD$nZH(k4S+k#RWau_4rV5que#!=l7X`4#c;eIPd1Fm&pFD_ zo$nlakQ;zBSrPpZD`rz5>w6+#9^qm5(?u`*xlhb$;cw(A*td zJg3H!DCw0LnP2W)EnwU|0<#Kzzj5fyh~$i0UzFadbJ>X<=gip2HK^gv&0KNpoab5X zd}SbbKR1J`myN%%Z2blFfv6MjyuJcvIK_D!lXCk5^Kwkmy?qng2 zI-e(-vlE8rYh>AHJU8VK`S1HL&dworTyJck|J&!|(pEPO zc4Dq7GMGqN9CwP1`BP1zYZTh{{vXZ?)BsPY(L!M=)(R{p`SXwDJDnMS3xb*Sg(|9V?+2P0AV2SWGIwM4 z=bv*|;TcP8&^PK2$BIa0h)7F|aCSq54ZcEDL}os>FF64M+5Mh#Hs8PbDKh_e?GI?6 zDsqR8{2Rqj#&Vv>()8{inIt)LxzrFF-{V12Yd&@Nn^9TO_eSP7%FB>uv(F?N3Ss|_ zHtTtS3E=I{s#(+xm{GeRV)ENpX7#+bGnUjKnll1~C|j@-DO}kRnVFEsU!E=DKuBZ6 zj6g+%#`y$cHL);fu!fcPcH6jm(n7Z@^M&?SbAPheKueX64XYhIS-o;`w;B#5H?Qa& zlo-(86ZLr#ihY@O-;At$>{%J}a$$@hU5tHq5P1GPv|7U`bywxAYay73J8#uP_#1-l zX2yw(z?kZB5b$D=+#g}3TVQhA-w2+F1rG2p26EFUhDOF6o`~QK>ZAova}`~v>(@pA zQ5E!U70Ar)*EZ}yoXVZ^_I;~Lnzcx5zQP}YtD|c z1{pLa;J3f%Ua%q-j>Oe2fCB-+meZAI-{~4N%|T>H_B!425WKouV^d?D*V~HUg+ygy zcMj%o&3zLre2?`TL0m;`9C9#UgbTmfOPKW>y>~=%vI-8!wf|kn?0d7Giu%t__0|8p z|N7I+G9of*j(zfJzXZ=y2s*rs5!fWxXRe9y-ZM8cnD2dWtAcb)e}@2DANf;fhQct; zdt06WPoBv9_wz5e?z#GG+KQlyG-5tok&8*``~Kw5e&wd`e}4Y_`+2K4Bg48Ab*d^D zBUhmBj1?Kctn1E97^4n)CWT?GcTV{{p`Tcv#mV`7C9&!-s!~@6=!-fc*wV}^r@;Rf4bWn?HlPhdY-JP zyze{inBqnXd=bMhFN8D|i?g|A8i zCuM+D=c(d0mB9DjlaX;?GcdzXzmWue@>!hO$)AkC$=f%OJw89VL41ZaLS{fqWJ7(a zi5|3i=cAqtAS3L`<3LZxiewpqTy>MWe}h?g{+vKg`r)4qnUjKY@AFqTQKK$zr-hOj zRi}EoSec>0V&TD|eF(!n`1$h_b*k@Qlj1gP77WlbnAtO1qxQ5JMjMfc_x}Dl{|6S@ z-&!(=v%Bw@Q|GpB|Bl^uGChS<&r65k%}Rc2&6*|qaE;&Oi3&n+h!Ft)3}1U9k`W@@ zJ*;!ir|*c{2xshzJOcRh=Zps4Au}YO;2_<%V`7Y8|33K-`%m|MP$RKUlgiKi%KREMYk_OtzXC$uqYr^EJXE z`J4>H&>e;C8Jr5yrdpM|YzB*J%-pETiLX6*W0V777WwUQ&{09I7~-#GGYd8;Nhc!D zKbr3Dj1oN-+k-X=o{S9Wx~S}-Q@e^l6k;ePVxwFs5?4L0pA)7q zUSyIy(MV!wOtNT!x$14$Zf}s?#3-tnPwY`7p~aFg0NmR& z1Vz>|>+*YDUxSdMD#oKB@p(UW$|S{Du;XYJTe;~yI>4+a`eKO6dxwDt{?r*Mm=iZ5 zKA+!=3V5&wQNtk5j5K4ag7KWC(wu)0ta0KxKNMQO0+f)$NGLN(dR%-d{#P zneTk;Kt}NB{oJ`#v9KfAj*SmGR<$EAu=7-ANX|Nd`+g#d_MJDr2U*lp-2mhu#$Vvl zXsvm&yGQd1JSUT()~kP?^XDKYIo(K{Ek#JMe|`?X(_g9kUz^r}bl9n{VI#2aGA}UjJ1CdYq&U?E~@{8H>0%8g6 z$kJ<9p)tGT!&kh_Ejq!KCrV(bVe@Q>9=?EwGBbB1w9E8mklvoR-{+jb%CEmJj6@)T z?`^=SfT1)kcW z`Ip7}&IxDWeQ%yK)1&*Je||om9*4UHxlcTqd2d&_XNoa`ga{^aXCktq2)FNfPG4q3T z&!6}9f&~(V=z(9U!g)?OPUVa;mI51|ZU|=U9#)h+u{peZKUoh2h@;Cm2uiB+1pN8D z8Jr%XvkDh)Uji)jeWS_?h*;kWFupLRC#oR4@1jLq^(RQlHZo4I96N{bw1RoNn@sR? zdxd$Q&qe&@rk*k-On?#3^_zjd9a(l;PDa3=&nK!1#|eApww8?;VA7i6i6?$P|31MP z&rA?ek2UwTJ%=Zs`1jx6li{|kh?L|&WI?ES@L)Vp82Y`JOeD=X`DZ+E1c0pheDX*= zs;H$mMfJUlZ_`ZTc^=;GwtVNDpFBr%?U}h6gPgvZ*(1pn+;OT#wQ>VlR?AtcOmR#0 zk1cQI%Nk9bLxz!8Bi&%Zd`==Vfk8*+{k&Tj7PNEAg|$0EYo-<>3b}Fp0`KGu`*@6Y$PULu&l|`Pl>zCPZYdsll1jN_dmfz3(9MR4|y+ zJ%671NNB~6t0MBzw810?Va!4H^h)#;8Kk2|nz`^&EIKO$UEM&|DN%C`Znzb}poRRZ z8D^(FGjVET!hyZ>k%Q^0P{P-k`>r_?a6}DoA}s8?)6sHx24KIFKS9E%C;eW<)x;vC z=#fYQyXm&3&O>P3oc)v?-9=W(fbZv75Y2YcPIzJy!vFsg)*tXMr0;t3t#YVlMKw_9_fnA!8p!}1eggUGj9);enl+{J+sCp%eIhA2WhWInWv5x5a(lV10u&7 zJAfi>bF|Ep@*u<${5Jpf#)_sWd@m*xP7Iso1U4O znh7$u&}@+zk;fYv0*@JIJ4(XGWv0I!wRs`+48t z1X!yeD|Yw0w4s(}2vp>t)jRhgf*y_Z^He5hG`cVhjbpZ}0p9X*VwQzyU(=Io8~ER)T2*nx;TPv-X` z31wF0b2iC5($$^rb%lAp8DB7l?y(S=Cz(Ib;c6a9X2|zsXva5rBt$-_KZa(scZ_*-NUE z=jZgS68hWp7l3X8!3w6gPvq&5H3+naB+qud8WuAn6!g#Y&ps_rL~JkQ-f#8s?f1P4 zyO#X+iy(+_^IVh{5gLz13AIA|-_73aia48xfz+ z=lAnp%jW668M|iL6Ga$^lQ0`MIQ{mlA}2Hc4ht(zoI^Porw(^GBN%>8Wt{!vTc)+` zWdITWdlXE5K|W1TlmSUSTl3~D%O-g3^PJ3_uZlkR2!r*Xco)&~%7;KAtm*j;gpFd( z24Jo6Fk+oQ#xh6-djvxn)S|986~AfjZ&ND(d2XG$p30}?2vo&#HbkCN+L8>0q0!vF z?|r>EW`@SQmCZ`XpgySDAfxGVAVco<0Grcej|t|ffOqIqK}PP{;x0MS*ffq2 zfwZvKyz_PS?0sgpCBD<*dQfa{OEM8G5{cJiY+nAbYQQ=_l@+NxKUoL#IZypOiwEC} z%DxygqMl5m&dJ1}g(QeTo^x++l>Pg)mLT#JxeXTp==+Wuj*RqZu`nAQj96N(1AOmC z8n65ZT0MCn3~Ih2BLQvERCffXJ0q%|6`L{&dyf`K&d7tFZ>2+hyXUr+XVvOOrf%!O zq&6%x(rC0CA<5kTAS@Fy(&-3qKU$jUVye5&8TWqS_wYIbHSgy$8}MDvphJUcL0%kt z1{je+@XRzLEW7Wtv>+G;=%)(u`)RAyrZJEa(qBm+ScQs1`lpW6a<6A$@mKglA`O0- z@x9;z4Waw?^sLv3nRW|0m6g2rYV!@oUIx((FdVbpLj(5hSF4wueX)a#OllZ}7H=K= zN?K0rA3DClq6)+oOk`*!v-iIDcQt$13s*&W17bqNqNpmlPm|3_Rm2jVonH+d0|Mi0 zu*(^hNkpzho6NS{t|&qr6jSEReeVj6c6M8qU$y!L;)&!J3m%bd_sU7;z8WR5#If7g zRxMzS2yVh)JC=)=UAon-`$&WtGuGR!d2%TecI?rD`>ShQQ}g!vJ#_We-ci3uW<+A_+m{)!AAV*sgGj8u z^KYpi+|0~iR9SbLU?PSv^mBf`oGr&Y^Y8nLh{Kt|G{S$L$J&fM&hzB56NJ{i{fP+2 z1o-Ei05XzBMLm&oJ2Q9g*)vIoeV8C;)Sm{HL=iG!)kyAxoP2ir?3i9xypbBlDb}^W+H@?EZY-w`IYe_g$D{RUxQ$ zYW&@RUj_*G-BjOUR#cwzK-SF0%5FQpniAJ@wv=?vA(ELd=SCMIR&KFb8qFTs-Wjze z&^mP%o?W%wnHPHvYCICSC{O3^cUSP!sycSBMoD+^7$MJldkb?S?(KSxgLiIEFVK3!!(N2z!;HvX z{ZE?`;yHhoV5NP`(}4HSrWw0wYfu>=)VEuas48QUks=W@uYwx_6=7M>^Yg?xmEnd* z8L*IKWW-YuB-JfeXfLV2Sovf)dfGjA-o150jHt>i=E>aDMl!?5tO!3(Z8$y{FpI+a z1Oxw^6TynT@9O;XJb#i#GRc#HzAwKakg;Cz_ z5i0ZN=TAhOie2oJO#ihz@2Y2%S=#+lY+HcD7k!sRMlHXG2qKoE{sjVz4LuPuJq(5d zCM$D)pZNtpA$A%fYx+Bb-NONs0ZGfZ)I0CLuQt2y;o_%B+wVKev0D{a&vmzficE%} z?ye$%ao>BFQ8C?uB8udlt2WMutts zKm(nMN-p6gPlBRYk%@3D6SL}MMb-0+=Z;W2sfNtef(26e&hmzWdOTzXy>}Lq)3K!O1h0nO_Z}=G#X{0F19)e&58Vt#fiOApoc6-VXELkLTqg#sfnA?G1Be zsZTMYYy^Xu0KB(RhIPlXL*4z3zKf?F{Vddhky%-*3x0l1YiC2EO+c$p1}h&T2I{M; zYhi4H_ifEc*rE2uULqqRE&I<&?=FATz1YBc=e~2Dh=}E*vO?o4efl$i=UQ_jO;|Yj zWJUuO`Q5`?%R#TFGAc=5GV7oa~R>osQY$S?sEIo$tdg$umTZ;2%oB- z=coQW9_~d-^R+N$WKVZX!2jpp|IhE+m1|7W=e@yiDX}n-`k%Sr0(;dpFht}U~$}@S2OzWe}C`2!9bp#o^izK?g*@rPV%WraIcW^0J%U$ zzr6FY{O5^GzJ1-ES&%+8FmZeL067a~0XRM<|NMEn=Y21O=VWk*ST#*Vj!m)W18t*z zm|^preDWvweaXoU#B+XN?%s9-5QXyi-YWqKhwp}_G~i56kG4z$;(4A8gi5~e`_B9J zo0aSE{W&@4k9hArl~FsOZ4~e4)g6xld;i&t z{|aFOaGX#^-y6&bPESieRWRI*Zrd3NBZ~L;zQ3RQPVfX#CnKuXI!~@{Sz*?(gMvIw zEst#MnaRkk+7mXbe*XMtXW{LAdM2@u4ez+)OVEot&%=b|6=K^n;p`E!bq871lS?|=XM`+3!5 z3fg(n=eDKDdQQ;k;l0;VTioJYmCU~m;L%r=g3)9hd55QrN)!>^FZ2e$cELoG!8kQL z0|T*WjQDn=5@arzn*j#W3VdsnQJIPC&&U(ZLcIOT;`VgZq+}_ijc+MF@L}^X~P7@zjHFUStPR;cq6i zKm8)Ie$IGq_c>>WY@d&Uz}>@w#gG*dl6!pL8<{h@uOg2A!XP0-4u$3a`R{KFGrJ%~ zM)W(e{SQ{ufwb@Y3{Lv*pDinb!IS)|jz^#VjA2;lzAX%cG`;8G6y)5M~vyJuN6IcHxrG}Qh%L$LY+V) z9a_Yar>A#H$~{nMK-819A;MSvuM-q>l(r$P33Qk%RlvZjR4G7HNV;X8BZLTSgAI@R}C5aA=C8q4Wfbu zXSYbZYIJ0UB~(b;`}9bV=T1ZgnA!_-kPb(1xwtr0cHld2C&-9;s&>!srB2y$W5Mvu zy#d5>WQ|yGZv@DwnArnl#k@X03}_Pp<6 zv6PvNm}@gLN^>m**%GV_X9gk$-QD+XBu*v@j3bX>P!-FY(zYl!ez1|ozk1U>x(gtK zCQkiCj{DE%mYiyB8VtiS_e1e?*q+1Ps@`GMnSVA*}3m{DxOmn z`2H4yS>L#ZiZLzq@c;3D`M=sq<~#j%|5Qe7RdnH|JfF9N%=D?B-+%v`&yTSdoR}+6v69#6+w(+CG~*mbkL33FN}K&)ay~bz0%$d` zH4gs#d2DF(x{EPtMtUYAS^4|>`{(DMrIVkmp|{ZS`F#G@KR<^5eQ##k_RRCoA0lSD z-|LgLF2P(e9+3>7M-1Xb^e)xscltR`$bZgx}*|-}k>2xqVRC0ToXKdl_Dt09GeC-HQlM z08p`9<$l*_1dx>)Md&IZLz% z#=S2x|M~OJeXo7@+dy*m5R!nA&+%2ytn~U6z2@{D?n{yAo>LY227QqXVZ|sjj#%Bj z{j62WV?9U#gxk)o1vSn(k4^Fmy@1RtW7OY>LVm}?8u-++@m{x?v0$P#)r4a(l{wJk zM1;rJ&B&)xqTDumZsrN?c89@e4UPW|sejI+{tyY`ohBU2h6#Lk=#c~hi{kS}a^2Dw z;e&3Sb4HR3%9e-EDcStr5${zVGQ!$E?4Rf7opx{Lc~L;${HaG**Fg@Y`FVcczMK4q zsipEwBZA;k_ruWstQ^ab-?&7}CKfAR6+~`F?cUE0OIi(a&`+G15mogEmW}Cqevb8} zEM&6IGrgzxiCEkrq^>+X<3;~6?nx4u;no0+}SVlrKr!p!vCiF@b zr_u4f2WZwoHN<9RBfziFu}AQ3O1EdT7is!yji8}Aq4pAN9ZJXErGq(rL68NB`|Lk; zKktlUUt=v2W=K8XUtk1yPJLQC9sbE^W2B7izR6O0@hpGW7SZ!&)c!N3)$wCC8%Zo$CkpK__A)6tDs$WO%JnjA5kqb z4Vj`)S)i9D0s|ZN(g+FY)R86wV}hLb&8)>05c|C>V+7V0l1EZPdU_$66@h}^S?UcC z>KUk*tT%(LJFgy&#BMnv(u=(&}s(Q+oCL0JrStN&%d9jMEuR}S%$ZDT~!ulX&JysyVP3h zsLcTQfBQfGpZ~H81AI=A=I{OdoO)+O_w|VycQGPDxNv~`0vL>f#o8|k-IGzj_mjD{ zitP7A92V6hi*YLXbp_eWD`^ji=R6}M)bQ;~@TqzwOV4>oPES=yvQ(!4^&MAGvg678 z?H5J@*AB2wz4untOrNJt{oLErZ}McaJ#%HQE`U94T4FIwEeWI|MU2#U{ydL#BaXfw zUS;sTZwAP`eSa#?dD@yg8S%~p6_Ibx$-}UQ^S*h`^gTa6mNr?IfzQ96++km0&u=@e z+#>xuZ)Sk$R{d1}>M4)oo%ebE81CB}sYbf;>`!nc-mfh47qW)_vdY zTb_(-FBTvpci?iW-o9ISYH)`u+*43;p9|gBB7tQLY&~-3F1c}q9N)m}qK<&>$w*T( z$|^~iS)cjZy%m7f@=s*Xt@8s}g44;6mB{vF(sXW^jJZE!SC$ifEj=%453_Ek?UK9a61Nz*`@J4IScv7O0f zSS@dH(P3G6>goHLwNz?kRMCLWqb@EEeAdBJCUf!RUR40U0=HgJeg{<0%p%ucbz0-{!Wf7Yi2Sc zGPGRk#noU#o}kQHixUvy_vI?XLx*UO0}+SPNRW_B#?_oU^R;3OS2gGHxA5Y# zNRX^ZJEYfN6eq;hi-hLJDM|DF%Z;;qJ0dhPc`^kQqTTi+>vj{UbEFZFnfLP+1C@j< zN-JCuVDboGv|nmd*4K~ zmBkIl{#0&9aaVTBhU}h<0GKD|HbKY#F6`4@^xodEa&ejGdG4n((b8s?o;)*fm@*Q& z!@n@=s%I-+4n1+!5zrbSa+M6Ap^Oxe{?-J7oB9hX{`>x0xe=9x|@3N10dw-Cu`QF6XJ$m8b8*G!X<7J73T%8&QyOBCdwZ zpBmknB?1RHBSckVW`rGe^2vH{SLW{Jb_CGs=XoM?x`|j$F#qrWr~i}9tdeFg)pd@0 zTxiJx2mV@194vV<;Kh)Ba`>OE&M#S(Yx`$Qj1A~Rpl>|chRl2&$K&z$3J!Gy-Y8N1dsx}SS=NP zevW%g1bLU8EDJu*^ZB2D^XHs%rYACIhQ>~hBdhx^tiwUh{C?iZ5P3GtmPg%v`{&Oe z@8Dm~NE;D&r=NT@qeLidz4L;sNX_)BMPlOt3Fz(j#0l_j*+GcyxsmtY%vjOk5-X+A z_cqCYKfi$f`Op8F9;xg6XqB;m)MlxN0TMkINJK)~P?@@s!7C?2j3?c`>Ma<3@v>V9 z1>WhswV!h^2DFay%GxgcT|wACf1b?W&u`|52uS^<`%pc=I^{*Crq>}7H)UC#w}%q=POCj&n>+}$Sx21_HUZvY&St9)IEYJ^q=!*EMLV_ zqOcP$+s51>RrNHbp30gl)+W3i+$T_HoVhnM#Qpu2IT44$t#gj}6xHV0)%f;jymCfn z`c9G~SmW547q~xuINRAm85*8Qrgm0O_ps|Lg z*i!<7kc;)v=gG&xxoypPjs~#fDYZ16l{?B^MUgDe2EWaWVhHTpb!dGPwO0cUogmVD zeNUX3$;>gWOE4=Vb7O5wTau8pgPCXbZ1zfC1NdgI&5-@A+>q`@6bbhrd@_22eVRH) z#(q}&8?%Lt@p9F->h=voe{JJ-W{#A3vt;ls+z&)Kt4LhUQ%`qSMB9+EQoWi3 z!h6HDzlb0db1)I1X^=q0Mp^?5^qp^hdgD(Lzl6;=|2+S{3X^0wqU0eMQp@K#@B4y? zI&<%K!d59)SY|_gDT-kU)Y>;VZ$}mOQ|)F%k^oy1u}2khA68l8u|#I&vA=Y_xk3fM z%j>_^1H)=YA-tDc;4cQq{`on#FJ{@Bj)jgH&hS^^6qp%&BR%6QVed6qgr^rSWYT-n zyS)m_@T|Kuz;8k|3li0ihXL4$?HyV~Xx%E(f`M20&CPNBty5E47{YfIwO(9@t(m{= z-93$)wrzUk)Tzh%vUfLRDwt&05q0~Lt0p4;-b`7&ogSk=6UpEvnrt_nSj4I}vUoOQ@g=|- zi^YSvP1loY==1s1sX#JPJ((CNk>6kEWfLR-Zg9{5q^Hosk39zJGb9!M4Wo+5V;GDzW4LF z|NWm|dpUZD%-gR)iJEyopWp5}r($8~>=}0hh{)gH-#w5Ry3>Z=_x9~~J}v9^d;k0C z-(*x)M8;EVJFW}_bZ5HHIZ^2d1TvzY10gaE=1F{yJJ`biRh7AtvR-}htteqP<3n_%ETT+H-kaC4@oYKMZXl7@_o@*cj;J^i0LrA$XS zOo9>TOux5V*P8a|?Q0`!jJIf>=KyBKbAFPU3_9;vt?66F7fiAJA=)DZh(vINZgsaL zz0zL6Q0bt?b7$O%tjgt}buWbi zwh~&WBkZJgJLqt{b0z$olRFY7wd~_HuZ{lu-`~%@Ags3W_S|mSn>C-c+5j1qtmjD* zpZl>vIIDIIjZn8%Dt_vmterGe)uOCp!;?e=lABo^+3~QuciJX5G+Fzen1*`p+@)s7 zMB7j^gAz6vc`~#1UNKgtIV;8!`uk}RB-T}ns(RmPcU68fNUiSA+@1}XVn_FEez&FM z{zyh{k+}n9_^W_hlq`H{LklKWc<`wGuP+8AI@NTaEu6a zkIkN@u@yuE+BoNE3B0n_5xdsB_xA+|YBZjGtkrqWpZM7iEuRD;gjp&cXgg0tFaq83~9nn?q)FL$vTESSA=@{m3oF63E#j)i?c7ya}Kt`k2nZlS#I@cGUJ=I_;&N= zYDOag-bFrba{X>@d$^>Wi1QS%@21?gPdF+vB3ThE+993uhurLw-BZbW&SKA&Td(Qo zdH&ab{<9UlAZmFp_a?$%B>wz78f2dD9M8P(<+dF?dmUJ6WW;T~n|KyIZZ}RA!u2E~ zVcxlZXYYsizMuO>CW9xBh5LToQp*9s6=}^}Aq09X+i!1$;fo9l;+z6k!?=|3J-+iB zaVYQ^mT5u=m@NAoN zg~v8_dIvg#>(o|{0RWX1WM&GqLo3FTwNeo~7{+i@T+Ah)t?gA?<1PZqg>M-KP9?y; zy<=~~>MMC>ul7+9nyz35J$?3qM^pyCns0mkYct)Sy*%uf4(6#tEM9XY?6Q~KA@H6+ zPvrw3gYD^QH#YY@J$*lbBLkTgV9fjb*`U;P-|iV;Q*H1>)N@A2%F44%hFtV072jYD zJ;OcgnB?9eHQ(ojlZC%27Xn!sYj*}|j||3lDq*gbml27u5obxF1`*;nwXsD8I*?zX z@3JN{o~juIGBT>-3nD@;97W#Y(N`R4tEXW^#Hk`Sb!-B$mzCs<-uv!Zj%JXO2GWQO zc)ABOrT}`pI)D$w?2+9=$D!|c5wJMh%NM<^TWR_p$%EC0_^a3ACf=E8 zT{!FomCA(U#FH6$)pwelJMX7||MrX6bEBAH$Pp1_o!T!?pnm&Pd64wLqw7W}s+LI^ zd64Tw;%KR^Hc)9+`dSuvW3WTqk`7!{_a+2Z-kEH839 z%YQPf*mGeP!{Q<;&pFZ{Fymkv3qw`q+KM(O{hTJWH_YDiH9 zsz<-?zn)%HH-zm4gp*@Ce(&es-+vi&pjVwI!k$lS+SvM#it(AZ`&vrrsW{K~{eFI) z#C9%8qFZYLGkP?es!cL8M;=WEpQlXq=$w>hd=V>sF@)*s1^HLqvG5)L%*=UeEMc$9 zNv~{1b)K*D;EBwG*n$u(>pD@HMf3WV2LkmMR1mxajiyJQh=3z9Msti4W%Zu_b}$K{ zHUIs5Zg>6sV6bkT_Q%qG1eLknhm5tqq{Gvf*6sdgAuJ)JuBt2;`*uSbL5zmE)3X>2 zGgs+y`#J*50KX}&s>p!m=lq=KXE1Ny&*yGMmJWQUl8XwfpP!$I=$SPh$e3}}%GJAv zUvPE1HM42ph>ARw*#0c=`LtIy8Cg~H_PrO_)TKhKd_JEZc`)j4TkiJ2L9!}WkGYq< z@4msK78z@L&%Y|ExG%8t~3{;Sfr3=o-B=Lw1=Xf^C%dVf)pkXjKpRY_}+J8ua!KJ;gDoHBfcZWaDs8j zh;I=-zj@`Xm@vq!m>ysdYpb$7K}IdWYIBOU+j2pfxpYoT+l2tyjG2J!J-eN4rs8iz z?2EX8=e=*8TK?Y`bdzzGhazV#%2cd{zOy2eyqd8+*4zR-1A7k?kThSghNZ+(+s$;H zhe;3!1B2vpPBIf2LmBWjq`h!j-*@93-F`1Y2x9D= zGFDcIwU{vn$#*tj=>-T@gzeTev}?&NSY`!)IMJh?5mZ%?`OnWm4(w@>5v+>HB$KwS zSx)j2L&uIx6YqT&dj@8(*1WScPa;;LgfAWjn=rPx$3e}=D{ zY~sv+k-o^-6k#N2SH?nsw~*aCY_z&tBe?f+tkq6UgUd&^mVRt4n{PZ!Xlu1(%7nXH zSF&vFn*l9Iqbn(bbt1D?s}hVB)GrxzG7#s)Qr8^N&ix7I4&_7(0gb0;Pl?~!5yDo_ z$U;cpeNg0y_x;@IU}hDAg6+tYn^TG?%ev|jw#d0jx@kHRx%oTTbq;y5$cjLE=HA=7 zf`AmKPSx&!9bWZusNsJAsMWHonmUte=M z=s1Ops$8TG2uE7su?+QO^5^Gy>X7-=PyQU3=Nx%2$khF!%>#rW-Fk9C4gX)J{$^W_ zRb1% z+Rtz;Q}EV1eK8I~p?hn~bGG{yz6!Tkd{9@7{rBfjBKKC_yt|2p(cN$N*kUUAJkMq{ ztL}cXhXj4^MUa7di;j(vK+a5RJ$CG#uUR|<>F4MDKmPasjL_rynIz+RZ2$fHLz-AG zC^GY(l|{8@3PgN9M`QsKCgL`NVYqs_?U_*4jPiKq-nvzr*XB9PAl{j1Ji-b9K4+t! zzkdDx#FHn4R3`obHhb0H-;RTh9`B4nn;w3zVcvHth|lNOHxEA0KS77aJik88@VMM0 z;v}W(R?tSA9M8$D+E)>$(Mg%sGKr zZ3jaaUfD=Z_icORp!l4RzBloKNe|?R0CX~UW!&YBvbdK;5P<%n(t2fc84N|Y>yEZX zQ}^%t1MaRkx@V@Qn(}jU0l+8YZYOGQM{H_*}lBJs2_0;YA_ukv(!Sg&4 zYoLttd0@L{Ns3>45~+XQ^fc~uwJps%OLT_4Y8|8bISbu6IuX$rh|fud1g!hH-V4u6 zldJ*pje&e~;*xU3?~++%Mw~cYt4YMv?0IhYxzk??g~(<7nEg*mS2XIqm22Gm#*Os7 ztGr#9$Ri_z0o|_dMxZ=fT?6EdVb`7a=k@o#2lT3)^Laix`nf;d-i~n_+r^5^6X~JH zacDR~3T?O801vryP|8*xzHLkWlHd9+SY?KQrz33D04jMxcq+da&47OA0c z`Osuw8=|D7f!~_yn%mu=VpF8r(7V3xKOz{=Ib7CIaG;-BvEZf@=A4YAA_?4|yD+7h zy^hRw*Y~0`4QfMSC!SD{c}^zcd%;_F;D#W_eyeSth)@8bh@L&$dF_C}Hc=?aUmywW z@0hcvMeWLRzkZRTHlaS>$<{{UG2_l}z!}wsMQmFK+{*^+B*sgww7*dn4&vH$`g?kr(4PlaUW=7 zamxmyg?K3PIbmUiTw3ti>zo|8}F_1%*-t%Yx?_K$A0q3hzxCj?yFr{vKUB4 zi<`0bc*^ab-b?C0;c7>{Uh3rb*#i-036@P?gy5@*pE7=w8}U9HveFy34JmTiXi8@P-Sz=Ud5@r^Wa&Y5?K;Q-r6(rWzcfBg%! zTUNH)0>FEh)VmI-wVL;IH4v6v$mcQs)KBUR=8o&Xe}DfAWBmE~IZ?6WfMp3!ZkR6LQyIlp0t1;u+immCT{nMLN7xFgCVg=g&fb$8Dqt0ym98K)au6jy<~b1nln@;cQ9nx_x)>~SiA!qUN^4kR2riZXo@;iX@lz< zL`qKgns^B91%{6T`M3W*On^!BxP7&755;}ocG&~9nZ{20WE9#;j>n`1*H$ciMVP{3 z3}fFnXgHJqun<*0SCmyS?RxLf?T8s?YDXJf*TwkP^O)F1_8$0G~?DhzgU0B4e|ZUi`!mJP*0}8eqD=(k1yL+)u-KjU8Pg3tx&CipMfP79eX3yyv4}9HSL&U9{c|Onc)(ba{s$p`EvG-0S z`kK*uYKB@m_$Om6!ZSZL&-noEo)l+vK4RqYh+*v7I`%ELbRdP6(X*l3FLBTy=hjRC z>dezyjBt@L-i$M#p{!wwKvZ2qFd{Wo%c0v7G{2My3@j=)jQ2&V_d9*^*Ni(l^h+s$ zjkagsiZ|%L-QBUuqG5X^S_xop9glR4V0fh>fpxBhgVM}!C~|5->xyhJ?2F+p`GUr( z^z>yX7*3rfcUuVQoSdqNGJYmjMZ4sUmJcReuj;2HDjZe=+r`xw*NquX7s!MOAEu3r{|q9X;Fj0j1(B`W(;j}0pY;uRMt#72uQhn8^EBSU-|y6sTqD_ zv{F8iHM1wq#Y9c8%j5O!D1+6@FL9u@s<#&muKkL4dE885VrfH)GqX9U5qBrGxSxMA z=NqLY+8taF^d-PC5@1icU&Ijs z;(0z>z_VM>EDH|rR)CNW0MFB1Xog%}9v8L|;}w%J7e3y}2vZ8j7~VlI0*W;57%NL4 z9P$dcX8z$GZ473rex}bSt0}t~e}C?I^mDIVPoAGYKYI9yr{3Fd8TI@3Z;Wogntj%@ zdLkvb!Jofxo_L-|%6nf$JSXbj8Rt1LFt+Ob+dAiY9_*mP8!w}wd^CvA%$EZ|8%!ow z*oft$D`vW;k-u2=^Xv2J#(giz^E}=5lrrABvHkPGw_NonB58+!uqKcb-3McMLWv!!-wt z5-B%``HKrAU23t!-dxye9im-XuKYLC~6G#t-q7s%M4C!bX&*~&vq&(KFP z#Gsk$Vwq+CVc?K5t9k>ng1_D-I~f^l*AbKF@)g%MffHGC?Xc&>xi#NWrbXVmZ-_{_ zcs_?@-`m~sk;|J#uW1Fp;M0BSabj=ue0S!WHf=d9E(s~ri2#oH)Ulw>=#Pe#O+4^>-WDc_pQ>_J&1Ki zkbugb?#QKpjD4oCw=!W*5Lh%#w`bnnV8uB#trP}TgD-s)k%?lV-0zr~>U~t&3lG@s z)V5nayHnC&?!DNDzQ;=y>#gHq0}eBOGKY4L;*95=k%9PfcS&~(9JA`x&S z4$CpVWFE!OG-MX^1TZ;y`<_Tji^cOSJ^HCb3O%96{gaB3ykP=9AJ!xZRXQpO%&6*77Xj4zL9P(nnc>$`hoZ2sxqYb&toC%m^)YF6f% z9)h|jlpm%TpQgYpq#lgSb)k>l>mahwP9IzhTUU-&c4L#`NEvOBwh$$vTl_W z`i}h=OKA198zpVS#!v($R~H83h>d;mEJ~UKmxX}I@pjNjGjqh+o2ip#pt=6ZjgQO+>J-ckK_mYIY0d8d8{r%3y^F%I{%zJk@o0mVdlYLwFcD z)r&)&8Az!E(%m41h=8lauo&abDCkMtYuE$Ees{Fr6mY^pVgR@mTHsG8zVel7(6ys_ zr3aZg7y^;Uz<5#;)rJCfYoVxqe<;NX;aAUsn{It0Se)51-|j^KFu!~PBp7+_y@N=d z>)W#{_O1E`$%UkRyL@af_d=oY^eFV?%DC2u5^t~9mI0L;U)wLFJhrBw!RijrNiR~O z=I35LX{-0#oH?QY{{6x9uk$EBI=P$QU(aX8No9EE-uM0U^WV%oCqMbg^I0?mlRC#p zXJS}C?X}16Y}NDmh!Ca~e4d1aX>f8OdeiyIUPw;gjWlf}5D{+cFrN=G|N7T& z&=%sH*A-GKhWz>Oe+fUC99Org&6BV}C?pK3Tkg;2G451jc4LDi+=YRK^DBRy^L);x zv?qcs5K#R0zyEowKq4{3j6B_S-@3dvdT~1b`T5&)SIsyXN3n6OG``K(P;R6M6!iXd za43E9oH+FM?fU+_({-NYZbZ3g0fnM&F~AH(V#d%DzuXd$Co!$9Y<1uJ-YO!`lYh(i z&V?%?_y0Ji9T19dcSe8;Mcangt@e2yNi|nel1Dhopt^npZ{>G>-kR44ikUg~y+cz( z^`L9PawiWxb>H!f=d7j;{MWA!rVTC;oYeCO&{PQ06e$6p=XmheO)``{e&5&QD$m3k z4+e~dyN&NALOFLkZL41wJzd40`T@GC-oBffc4M_Mw|en|_r7j#vul%^XpqvE_aPY7 zU3I1CVMJswLsLxx6_TiJDWtpR*7SAtb_E7Dah@Y;j2g}upWME{4%)2DjL2_Iko1ZU1{el{!mUdw^}yd|6UR*D zCa*Hj^Xoi2w)fT<;psiX+Ci;dNRb2^qgd!sXtu~mU~1Drc{Vc)n_f-wNI|%b{#Mi% z$hG+VRh~@uUL$O(rm#)xz8f`UB>!pk{QO+24TNw`VoQEzD7(we0cOzM;PPZKWeO3L zfSy~I<`I3H?%Ulx>YlcO?@zhQJw4;`qdcD@sEN9bu5aNobBTB9Q1JPrB7|=!K7zXi z0{p&zLjd_!b=`%WW+bT1ZUdmg9>CqTLl|tJY1gw!ks-YsfxNeSIDZoSi0GjF$G zMT+5R1|p)T>%Ox+eY>jOdi77120{(;Nz%}4l5jA_2-W~3_8yc$a7KV*edq!PUA7>} zv&}xsH0VZG)qTHTBYhzyihnwggKuFwuvG_dVBNg$?J6#(A!1hP>^-{dMs6FCWAax9 zJTqmu-X@wL#!8COU84K#Mq|2bV|+2w6a%@CpPH%Kcn!X>B^{DK5*QJtpA^b8?ysBU8@ z{>NysKACavt7>7z@ITgJ&|kc1*M!LB2a^}B8W`BR#ZDyWOu-yp?+_M0v$w(v3>pd;mo%wPa;#?eOG_mUqN4!02Kxoe1mgQ7% zH?!9@J%Ax^ZuOtFfcuL>L{MfKR-Wh zoD*($)%o|Qe%i#58bdO~sU1mw*|Q2M&urOO{98Yocz%6uU4`Zjze=C!namg$bh;Yb zN)Boe&-wHB4~+P}=_&G7pG;5vy%&m;v9|1UG=r})uRR_{h*ZE0cfTvAh1^$pc7Ip( zGwpx<`Ze~ti%tK$@BU>A#EecFK~MEa-0j{jjSV*Dn*`wIRJ}BV=XrkKp9OxWl8a#C zM(d+c^;6w_o{y);elnZvZU$q}_danT{plaHr8pl=v!??Aku)RT_a~JnPkZWC9(BWF z-O}y{Ya%oRi;NgfFI6xf^c|QXHWvgr-G(EBC#Pn?+P$Cr_-EZ&Se)XYd+GlDe5yTt zt#6OCdpjg(_xOq@b()PKgqqR{wPyFb*elepj5}EIyPJrau|S@jx%{SgVK0gq|KI=o zA@%Qn|BG!4KlNiX$W&hU4r|w&yYEy{j9k6_6Zz-oPasCJI~Z#U)W#D8LbnR0!cuNr zr@INKj$o68Nz+E2xIGcMU9b+rw6s_}X9RyC}4h}Hoopqi2xk)A30ES*?V^8ItG`}29oeHKBX z@e)^PDIsa|(Sgt_jJrMv8|q`DMJhVt~Sai8bou7%;XXMGbR(-d~#sOrXy;gFOuJs|py z!i*djzfn1V!#D8EoKJT3wlf>c@ZdS|{*(@Fa82eGG_MJr+v5xY+@zqS8CL(C^ANbTv7&|c(zDKn7B~RRCpboP#IR@2G+piS2K~io7**K( z3`C&p>4KxX&dJU21o<62!TXz)(EUwmli!^9MokvD-`jls>X0oLvO~u2w|k384m46|tyH z%i29`@?75&(Yv4ks~g)MR9628@#VQQ{EgkOgxkw7?U`RE+a8R_zM~Axw7pBG{6=rk z)3Uf;uu*U|Y%u+Ozr*>pwYRrc*V{EG-0g+U!gox6U(a6-Fvnk3)p^dHySXZQGb8^5 zx+uZ7`Y3Lfq@_fA89kBW+%|!#PBEY7)}5Y{8^6L#dk+#xj+E%0=^_|;Y`c4ilj;Al z=TL=8=dikw5%vmW=VV6Y`~F=#9mVf~Y*&Zj6=;L(uFQv+!ARNnM(&+IjO`i1j;g=U zuMgnq?H4<6Ml(IT`|9@cxWA~`|M&mv|8alrCPu33Yye`0Odic`fk?Ke+sV+Tr+WVW z{QUm?Yi0+n~Gcsd9}&0j`%b8_vbU?sVetO|N8v9Ye<*Bdd`R(PTl)?K2>w4pC`Nav1*5p zKGXG1OUzjJG*09+hF>)X4W{PaV3_cD~JAgNo^cSPj^OpL1giKkrvBl1>B-zWBlDW?5=p01iH>Z~a1 z*8M#3#CgY6FHFT*5Z2FI0LnfTQYb_&HDI5^PV)Kvt8Uj+P}S2_`5e<)BdJSqY8cj? ztAN0AClj8k9*)hE2QY*C0N+ykGC|(Aq&bo2IrDaP=jZ8Lt1j7Xa1W|qMq&zJp69-$ z3{>rtzo+v#=vkr4(pHv1n0l7R`z!OUf|(J6uIjD7Ei2-EuXgg+6O48nPQ`#pw*7Yf zQjVac997l0eJArdae!Kg7LxI;`f65i_9$jtUZ^mu zXSyRF>H826xTdO|CL-xxllEQ@~-FuYkwSbR%F25)z zlfUOCSNjGKyP5CPm{BFIB!_?7W z;a5LYWIWZ^iW`C~wN zg1LeLtLJ8f95?zCPu;J(^nEKb+I}L-MR=AzFw@wxID2N53$)7D;}M@wzZK6zulNAnGIg(&Yq$94OS(daZipwNySqy|)F`6gQ6hA@i;%Z;jiq{!n&6q4 z5c^xhg0%kx0mji9z`n5GSRf}k?TD@$5uwabci*m*?wA|7u}w@@M1meOh?t*Z4hIIv3W+;ybYnO;B$Ue-|1FH*ZrKQYyc6&2;5uHx$nF9(xpcBfT(R#$bh2j zMI=`PD^*>YJV7us>)x)G_?0Knlo&!y*YE`BWQ@N+pN)alQt9@(HKuT90?JU2Jtf6_ z^MhNq#?o~?^r%r>ZDk0-= zy2Oz9zO_XJk&Kvn4N*x?y$x09IDmHMG3I?Qwaa`DrfN=vgYJ#Afss=MBQwWU(=ruj z>Y4<(}p}`^Mr- zus99B?@wlES8vw$TIDYfpVYF>+CKRqr~6wG&;BVIfwbn}kUolc5maDgzWsA}x+eYs zlJ}h_Vm_Z*T?_U6I)8qCe*ga0`|~qKKGBBN9+yWkDBngLVmS7_HSp27w?(hMai!2b zO(7BhLh?KKu^E73)1H~EAE)74S&yG zum(f`Z#)N8)jcc<33>drDEM~0V^nvXk33>bnp2p!7UD%2mXGWhR{R-!eJLG!@rY zha$rR-MLtb_jj@>gf~gwRVQ@LXFUD(OzUKBJd`nGX?AOH@)7xV1zFwCBLjSLYD7e2 z*Mzcs-|3(Y9G&Sslc3&r%Ryq^emOWNcNE$lL5!H1B?W+({=Qtc9XR8M5fOD?AZv;s z9fX71qCtdQOFDMs*X_k{_cb3>>p7b%P-yqM5{az2+X4(F$(q6!c)Un@6XW_;LVw;j zG6cUSM_S~F8<5Kr5rJ|4Q@98|(`|mqkISwU_J56;I}?E4>Xh2LA| zcII|*LzoV+DMf}|o>BzIk@|L_fI(1Gua)9-Wb_#QHHT=a{ot$+ZfUNJ+wEYiAgqfu z6zWUJiJfimOPqphJG<-C!tIxce4+~>+0y*TXBIXP48)VU`<=~r?5Umd;%kj|VaFP# zL%H>(@hFIW!bcovh_`RfD?AI}>6yAWKJ*AeX6zlU(EtZqTxW!Mv5OIXNo~=X^CWt8 zU7oJ)i6i&Bdsi@O>gcH@4u?`Z6fUza^-oAEU>Hn3N0g}9zlwiE z1f<=(zUK+9j>_dPNGnY1%M(-MIwKBsd-~@M>HfSwe_s#pb>@?KF!T4le}DcCkz!TX z?f2*X&;Rk?-~alRLRcibzp|uI4p49P%*mwV*4yn~CaahcX3vzJdk3{0aRxE%1~L*; zZ`ZGXee}e83sRmFN1U&d#j^o!l`n+z`6#se9Wk!^X9k|GYdBN={?uI@^><&m=}895 z4L2ks^L+9g!Iq}GjTqebT@v}{_hZB1i+k@2ZM42g*84)rIMZGapV@8Gtm^mApE&vN z|Mh=S$b)Y8G_i{zVp9v`o#|CG!%Matm&|iwsy8ru&e0>=k@1{|G;U``PuEOOvHRZY zDh3w;zH_Eq7uGqshPM;S2qrP}>(_^jdAqv-dqxAoAsSpDVt#%Tyt{{}MTX+!U z=SdN_#>PzMTP)KF|-iQ<`J`-C!1F#7&zgD$--Ut(Z4 z0wdq)o>}n!dz)rFNyS=y#zQW1PF3#-uKlFCe%>E?sA)``r`mttKO9z-VJW7DfaN@? zpfY#I3fVx_o#{AvBFm_`Cr(Y>_s&e&NS%{hI^B4Y{C5gwS7&Ikc2)oA7+c$Ei8v+@ z`jz=G{`~#VRB^AppmQ}w2q_+ps{;+Z?@!}e0rI0{uet*A zi@*P~sz=PT$`mmI9MrwwG((Y)zx;6bxO=*)x~{RP^Dk3fsZGAqe(Sw|?i9d1bjV}u z1PV(t=tk!etYnZ6#%3oKN^YKl@sF?vWA~J(eHLuycI(^qo^wLX*%jc}aND;VoHlxZv2U+)lSI!%Mnu};%_e zlh*d!`r7N;hqTduyQ?%5Q`N* z=PVE=q@GcVC$QQNEi!lpLvh+OOL=EtEw=n-GFB?E$C9ag-xH#~sq_%@@I+9!Q<6cQ z{JN`PMTUqmlws=01hnKQO5Xho=W`xO3T1HI)0UB`vv<@5E_T-@m4myT&<^;`J;-`n zUxs!NLDszshJWAP|D?OBtI^LBCd-H?HgE@c02AXoZgK6Fy}FWtr-#d-8ym<+aSjz| z+}ks*W!fvTO`uJ7mEj>~5&J>yA=oqT)J*TB`1@R3f;L9hLY6@;URFv37~F%)jUVt^-) z6ow-_Q@08$e%bVX^`2h0@wu>2j|F5X&xz-Bp{g)L#Q^j-jaKvSOOfCzif1OE+BMvM znzrbmi08A;1dtlfV5%p0GN1E^+*VM}cxt0?j2Lw|u+Uf8gE(BIp5aygzVAEJM-dTb z*k3z%h*X*#c|Onc>-j`vW<(~)?(P923EJxJL9atk5t~chx&MB}Om7|0?yiA3oQMc4 z)ooqQyK5Gv_enQPZ=E)!N9Xzcs=hz-ZZTX$U=6{@(63*=JR;AN3F-5E_Qvz~?^~Sq z+;YvOlOE29`Rn-@HC>9#)N@V*Pb6g_IHFr*#tEY5#&lu&HWcwZ7_Lu7kq$s#U=#l# z<+c0Xze@)1Tcqmt?K|^w=$iBVa^SvKiqZ5`yLthQ8`B=RdaA(Su%~YQqyia-5gD}r z+{{At*fTl_6W7%%%VhG@*H+NV7~ntu{f`YU5z^iUD0}609x|VlVxN{6bk)!^lTXG; zCic}B+R(^7apHLd!(H8&{RBl%b@j_4)a@C#UDIEh(V|CZBF?{me@sX4-s--)G#pHI zqao$z^E|&l3~f^ap)vmcy(W@L_^tP+?zbhhDoJACJZFyuHVT!g-=7Z%_v{wJ19-aY zM1DRwz`fVwbHY?t4GPnqJ{iXHCFVI1`Lu^p7YHhz)g0sz<%|;%=XnqjPu}UO-s9y= zD?;qCBcI5F?F<#8%7gp!zWx5(*V8S$fB)RufPa22V21kkeP4KFMZ}SirhCpx}5oGayYk3c`^ir5H3p`Mt;(PJWrm_K8yB1*0;#oywlt2kLb1L9pEaP|(Q?v>(OHNTKt5v8UCv0S@lp_pRG!-N?Xo8(Zo{m&54p zUAlZP_%$9bZyShPGgWh&grE&0{dxcX{rTJD*aP&SFy5^N-Bmw7FXk&(s`+|&L3#kK zZ>33`&$+k8(+%`UhgbxOd%PJaV-~1SfKX3&&-=cEFr!7rvM3yJl*gFZC-=$rRJCm= zwPxAjOx=DxJ|SRkH`n{k?@0edB68nP+!yo0t-+yJBPesKyXLL36OdcC+biY-uw&;; zIhIl07!IE2oQYktVf&tiCjzh%s_`@w+DAmg>n3TN@Ol6MyxpFOVV;Q3;~BfQMMt!&V?_~>y>JT+iW!pLt3Vt;g`FS4hnArY;d>t8Q1NV}0Ido=sBS=Iw zv@lcJ((}nU=f8jdT4S$@Y)uHLuBzHbjonR-_EtICk`||L-Fv6K(NOLdX8$%Qk5(cv z-9cpLIfo$$#6KKOrI<1~PVuYc7%trJz55PY>=9?Q+ozdfE5`v)ib;3aU&yb$mT@X9r9w) z<{|&%gxk#lcrwMfKQ%S~eB})7UJ*9$I~fuZ4T9$h5VGvu1&&v@64B(iO-kk`Lq;Z? zxDBJ3kYmA{fM;&If1M|iM|v3d{o8dBJbUelQ@6%mk!ib5obx%iXC=LMuZR3dzdpaV z(r!<6@8u=W!M0kAP>dp&n~&n)lTqdS&f9l4^=(Vp-R+rsIegAX%G(ne#6+eCGi*;y z-R@`CD1DRX*XLIsNDr{=T2*gt%Xv$fROCCZ@XE90C(@rY(xpQf^7% zwnK0vb$H%){@y?D+vL|hvL%Gumpq}M;_v%<7eLi{KA{}wCI9-H~B@ zB2J#c{B$qCFY+@GHbA_$qwowQXFhvV8nz4yxocI%3RwT);LiK=<5}hlGPrulnXT(} zVaxV&YmE7vOr7UM1AQBzC!gKe*{qsDN&5Hm`((WJ`Ze%X)qI|Z8Fe>j8m9W*8k8Bh1^fux9dzSCM{$UWT+hJp9}D<~r3a5tH=wJyT9tBcbMdc$=0{8V+# znmoqcbBE)u(1~RfGrHcI`uu*-mFSP2+Kwx14EEgkUgc_6`BU!(8S}~b{C>{!aSLhFf`G_b;Rz%7oJE>-#me{NV8>!{0|`z+A!uo=*{Ra&nY0a*=4{+ zK*X22bhdIQ&djdw|K4}Dg*WLr&M;r2Y1MPMEt;>W zpu5qgGoZ+1j4Y_f%t$FRo^1$7_id1bPvok)OzCt=-|phfa5Yv*{V6kt-3B zu)~D#OjYAs1*#n+orv~Sw=%)l?tb+UT;DplW*1VicSVH~;HFWm>h{J@rwN=mTN1F> zXOh^9ZNKl&d#6Mk9e^4}M4aeVFh+8)RS>FY!FveIT;u1y-92P`ro8wgojmKUU)H`I z-LG53~c(bww)g$#Kk&5(~aQU*F7+~wewU&(hP99&dblc^%B!=e368py_Dde`uom2 z84>KM>KfogMvz2Gw=ZdJe;)|!kZW?OLIB8hlX8c9UesUr?SQaPl4SuWIzVE$NpL{3=6*^TtRiq;Gc9qv{L3k`b&j;Z9-pD6H?@!%Z z68`(=PxsbU&*xWQ$*E|sWPNjDzV~+5v^zr*Gos%YjpunzYTThS;sU0I1Ny!{9(P?y z0sQ;dzkdDtRQKOoqGsk!X~ynAoQQ4A@A(9<2n?&Q5W{)zMO)BMcLdTV{QLKlN=!(a zO%(Q9w>EJX%FpLR>Tg{zS+vlNcD?ug`{!qB{@%ZT{=C47Gw))jy6gS<5p~Y_`S~+; z*G{p}ZKa^NU4Q#d4J9c)zs~Q>=lPsG%1~sxrrN+0nJ0hlPfDN9^R=A@|NQ;$&-<4e zFJ0Wu=K+xl1@Gtff04I2!6wMq1*A~`Fuj@kQniN zq`cM7Ip^~k;?FyPH|FMl*m`8L=2pMeWip>*s(s@erR*SMr?U0) zmjHn3?^_=>6u*A`D}qf##KmytoH*x%VrFREE)t*5NB@9&QyC!(iomyz=4mo`?{rmY zp3liZ+11@!PTq$QwNE4y3T?0?9HhlqtT?c_ zCUx-V{_T4cXPJKB3cP|0Y7{t7R|QC5JJZb(yxWqwB{CzfZ(Z*?>h3KT+OX5=$Z6kO z5KcUi@%fzmb;x+jIwvBgs(L*VvE2cnDekp=Lo}fra2+kMYay}#m>CgLPcPd=iq>Ai z!N`yx{QTToZ^QedJo!nG&F&fWlVR#eCl6@|5z06uX=LP+N2v`Bu9?`x=Xtj4OlpZX ztHd#zqp=$U7~hE#2=}*E?)P3PmF(7_b0Y-tJ^#<#pF7%qI{6QR0&rtF@-u^8CT3qaYr@d^@ z%|`(SBkt6Ff9_N$_V&|_`_+Ai>F_px+Y<&92MZC;qu@Vl8D$=QKUrI(shzC5_o>Ah zbM{syV)8_AshQdm^VZ73-}*cinMa|$XhvjpiOlEO#>fUQ_lNJPeeRj;-T@>+6rI|u zOYfR=ZEhI%48)!bIQG*D3`uB+S$G32XsQiIC{oM#t?rWt|3HY$nYw_@eNy@D0^+1B z`I`h?w(=xn2Qh+#DX{-hbr!aZ%{Fqh#EA zv-zA<;4mpD_})Ihp3L+9{ZoJbEKt(+wK6}jr|O&tWZmldNqw-2TJy(Q1$&p zc1-*56P53I(}V$59BQ zMp4Lo#;&@dBPpLif8oVH?@LgMCr=A3luJ+iJAdD$Zbzt7qDd?rxb2uHVu0>zGAX9& zj)(#7t;Z3e!o33_JOvVi-@l&wx9*gl&r#S-Xv|028yaeITR82XpT8J5lU=TPG1QsR zhX$kGY8M%$eokT*Zx@(xyOw^Lr|Uiu1JZboZqq&O+wSM{AxNBo-us4i&KWv@*Aw8E z=gN2@dYO_&WR4BQ;@X-mk&9Y6&ZnesKU(j ziKk{}`taO-XY>EuURu!{4iOYQ#RX-+%roOOenQh%3Vw1h+#+6E)Od8F-)s6zK7pRo zGu4+|D5YWEYi@Ik8~X_Y_vghU4JS;jtaNH-)wAxwQSemVJm%w+JY0Ko&LNTAg{y zGj(ZEF7S{uB~U&H8-Qe&mb+~Ctz`gg(%yjS@x1 z{$`(ZW^;JEZ6EXD<^njL!PYMErH&X8_U!4Y-ZGRSgD3K8x;jF`!4R%3T!}%7#E7z{ z`{WKOi(@k5pxc9gqBB(~SWly>O9YKw9&upz#t&g2XoPJv7LW^qh?*g}L~nd|N|Mk& z=(SkxpGDG?Y>?B0E%SMQU(4pXULqw1eHsQ86 zDs;o2_|V1!LN&F>Ah^YtLAeJ&&jN9QDc@+3w8H(5$<58j#1g9e}lPk5Dx; zvsj_y?(orc{!kYQLt~Bh)fbQUPx&5oi0W&<4H;^`13r9P?dqHQHoXv zgSjyfh3p`Zin%xA=!u`de}@c458j`jp88+^`u9&)-}iHp`7dK4d0*F5gnr(io(;Yt z&Vh_%za6Pey@NP0FW$Ny{OR|1sCp4K_~b9M?`@1hxhhUh`}6ymp$F3)k$~U(PWSKU z+~!*^$m1ah`{%vSuTTB_6=D-90;i`j!3mvn;?JMI)KYx8T*z;hv3cM3U!PCU+%5#i zO>7Z-Z-n!6>pW*W^!o^v4v6!4l%Yn%srTpJ8u1Yth!cU>2jA_Rh>ValzAn7)tMhE{ zi1HN0IXV~p^Y;$soO3b=08e4&zEtEx47=xKp3v)iZy#rC1dpO_N6MtD+f6E%VGDk@ zkq5c@=e;y}&dL0H|Bt}$Fn*n9XnQn3;`8L~MnLg&-9eoU&@7IbKhT|Q$2=4 z91&wGk3jHN@$&#UpA#*e=(pMf0ZY=hMf`eB`2<<~d2M>0=NE&Cy6rrX&TZTeiQ9^- zdjroV1V7Jt>)u?MRDA|)BU52K&{Nk$@n?h64<&i_2>$JU^QP1;;C6$a?-C0^{Yjl_89e#4>Q;S{;r##p`TKbidAghYLjAtA^!?B4 zlgFOv0b^WfrxIi6(486L8TbCBb$1w}ZzBU(yFw^AJ#{ZKfX zJ-$5z$ic)qtw4z*7yu*Z@;QAmU0q`E`8@Yt!{Kdjv2JfgsRmSc6(fFyRt|;p{r6J> z(Kh;SieTWrLk=T_sOggj(%i19jDwYIEi6y`AM?mos=j7iL{|eOaPk-FHm=1NDiw-ef4h1^tZ;=827F<9^@VTiNo!9PGE+a5*CQXzsNl zL58LwJJ;A0$PHwDu>N|SZR^)nrH3G04*qxflF=1qI2sURh zoY?T&;qB(!g{u!+p59W*RwcQg4jrjnm}LqT6*JDr4QB_106e?4MUR711$D%)xkUz{ zsb<8?%hlU|Z7tCEOam(4_s!@0&+8V5NE+D7d&+y6!dC?2A@V%;mcwE!UaYDj*y94_ zA&yZtH)|(G1KqvF9FMDtiY+r@Gnn9Xe~*}EME5u8$wAZK=&Zk_11Q6T@i%g&(1L#? zHr*IpG86lBGJgL4oQ$p}#~5iNRlR|2^}Zcwu-ZX_tobHPz%9a{>g{hua01C#G_W$G zE?o1?eYNrBPVY1Q3x1rbc8jd3ZI)($j-Q`bX&U#dHQ+Z1*#NJ^DFZy4vv{oUTF)Tw?Ytr*gh zA~3yQ`0~)o+^AU>#_eSM{`aqb%fzg+MbU5N$?aZKy7%pw{D(~e_dZSs_H<;1RPQ)O z48VO`0Y#pC-uv#HC!PfCw|~4tJHd0Fr>5Tb{rA6q&!Fzh(Xis2RI1J7b^rH2f2epO zy%H?2&^zkNn z&inI55KvI%E&g%}6utzs#vZ;+*85i1=hx@$VYkO|a%_7c8*LN4fQ!@?-C9wyVb6)v zuBr-AaY)v^Rg+J4zeId~|8mdt0Ml?VXf?M6xR4HlI-nFiua%ft^nPRIQ)7Q;`_+af zEk?q9XFhStjT&XdlU-fagI@2V0j2)_=TGKY;#_x8bmRH#3V28JQ*BO5Q43!TN>P2g z{Oi|en$C#=;e=o%1PA?t{zz&`7y(gpEI@;>X5i?X}Sl>(Z)WB1j*cPX00w z*o~s?;b@b`-TN`zLW(JQo0IFjp~n+AhN-Eax#(Z#LverFHZrqrN9Hzwrnef%o?5h8 z5$Gl(A_!F9y^SpLdiQ1MLB`s--kzkt6Tt<{8^Nf1H-c~agg`Ai1Zz2sl)o2~@A<2W z8Ez{giEUGaDCy_#b$E9W3Ju2BUf5Oy#uS#XGBvSIw`o8dIRj@i7WTH1R@kSrTLRTx|V# z5c>YtUbq|JceqCk7Pdw!M4sp_x6#yxgwR6;)jgb^l-hvI*-fIy)(JFgI+W7|5jMZ0 zt8I_tUdwj2nz~C$v`q{nM3V>ipxLP{hm*so*90Q~b)+=&AZ2 zU-9fiKqiArB>Y}*nz7QfRH(ORLwYz}tErm4WDNR58tf`DAa~CRA$0G}ID6m*=A2&; z>%Hd8%!cBc;7U$r-dlMN;BIH~zAwnk1Xwcyswz(&<(&$sJ^fFD7SvH%>?&jbINw&b zA|li^`-oPgJ$0KI0gk;+p@sO4eS)+3za$z9@#y!Ca3oRfiQqu)n|bQ%OyI_DsG&$eTVFbsjdv|i15fHqyd{~`IWU;pd(@88?| z+5*U))U_QWcinaR#FHmao)e$n|B6i3pj-Js9L)NehiEs$0!BmS`*ZE>)pUEB7y{JUi^K8Db;eTWa8l5RtCI z{rmU+GvvsKJfC`Bl1wrAI}eGPZyBb#ry9ZARkz7Ac6-ph)6c}#2NK_&CA({7YC)KI ztIiTd;pCRq;&~ofKR-Y3{UIqty{)k_6=C~i9z`&wC-PB#`SpuR{yyw`zQ72~t=?et z)~N#oC39oo{obkB7o~PP5+L}T^V7X;Rev1gzFR4%foTeZM7wr*% zzGJg){rvsI*zS+ZeeXp<`~RBNuQDS5Z1`q8GY#~;Nij1iOdY>@vd>-?h&B~K+itQ;k7ya{QX1QVE#eVwBhcaax5OPhK9(l zo}P&4Zb3&{adAy=bg*ZtYNubM9_65JzmmeCcHcX9t{W%-5zmQSF)sYAPM+s<_sOt< z_8M_!|03rro7gz}#wWb^Tq7Bw=;=1TYYJHKGENBO2^u|JZxQo6k0fL6OmA&~XQx_Y zgz_+y2LRbLQo;R>6llu@(xY#s*yOm`TWMIm{JtX{3~5N)ofjg#hEp5B9ULR?#usLfGzG?|VJd7lBwlaW}fV z=2lm5H|ZNG1&52~6~bK<2XQ`mB6gS!^XJwq!3wkQhi|(K42BS~_iKl=2Z(ov(3qY3 z)_tq`dNv}uS$AwDJV+|psGphXMXK$9WUUk%nwL0kk6rV=_vi25?N$KH&y#WNUSfZH zBo9zChzWDLGqP*oh2hV4IQ8|D@AF^(e?N}qV5*lqwv1FX(O3~hh~NAFSjY%5qA;t< znr_;pv?NC|*8@F6Zk=cZrq0O(tk4pzr-y^7f*H@zj>$=L$n2S_x2tC?N9G|#$PIsi zqRc!ntE#5$Nk%N^^u8zKJO}dJ;S6I9wka`FBa7=&2PnmE4@}?*VGQDluv^Q^%%pPh zM?!E6&c2##EQrjrbOK)+=AGId!*)bICnBEj=!U?zOC+wdMc5l2tr?I+27)5n-6%vhoYoiT{CyxnGMguYJK){%)8BnLa+{+;pan{Vl zt-@31|ISIg@~pWmTdEX`@jC*cZ3p( zx9);wIjp|h_zx0P-8%WC`v>D)<;S*}L1?B;cHMvd{_X194YK;4IK5-tSbVWFa@+Fu z+?k_OQ;SDGCt$p;{+SG)^Xv8<`(%dr{=A=G|C)Y#ye@H==hyS+zkf3JR}W;QG<~aQ zp|)Mtj?!m(6^MZ^{qL)!Km@JQoS%*nnbVIE1J$cyl*Wf4es76 zq8&(`!1%pC!9(K3Xhsp!otYr-eV=#~_<1{GtAq#c=W{sxaV69<`*brgHK1Pqe9q_n z`Z20*EN=#H)JkK7xm5rzx;@qscw*;IKZ?yJ%g!f8qf2q=Oy*u|NiHBp7Z?j z^saO>p1<$k&+}O$I=JVlMbdqNaPge(f=TV{Yx{_SDa3V+up6a?k=lLj3 z-R2aZa5oUug`{hr@>WDD-upv)B)})~eMjPx`RC_H;`1DnT_v!(W(*)R`g>HspCMa~9ZbL7OLfKq>9<7 zUgemq*ns_YS{R#EM`13+TA91689~YDHPZ3jjS7plo_&K4l@l@;8;DUIP3jbq{#K=j zH-6mKEQ-2iocuWFpa+|RBhYMAb-ORKX#&{$<5Gc~ID{>iN~LO;HEj(Dg^q4Rw;AeX zA-!FU>U4LfojxwhY7fs*sCr=PqG;oMd#Euf(9Mu))J!xLOfJg3xktu?{e zZW3?g2xgt9XHW3jBQXCHk)35kLU*h;Ml(yc%mysX$nV~e?pQSu;ymlRtGj3HDyy!D zm~X0yM#;SL?K3oca!TeH5d+K|Je4c%d1+{nE%Q{NT;6O7B+R`}gQ8njIowRC!9@?^ z2$f~-pmZ9L1u2^sZ4X6?X2#A2fcMH_R28{=O$L)Q7@e}7+em55EUPhbEC^^6%q)8OI^5>K6B zFtkJwVKzTL&3PBCiZJ8KJOzB#$}Xc7%4isO6l_F)=B$Q0DrGi{9JK)@fV6?y9iz<_ zOJIa|mz(cOj)1vGe+^70KoHv9F*ZHcAXG?Jozo1$BVdhE_uOOY9;{)J+U#KG;^%H` zluoz_i0V|Is%Cf5?rX8kjXBD$+S56+^+A5S#*C?h!n#+g|2)4=W_H}Gw!-J3 z{Ng6utus%RgSKw>efo4u)sk!lXx@b|PPH6x3mWH^UP_g^G^{sX%$?yO0+_s1i#n~H z^>G(OwtyoDVs|6X-k)m;M7M<-Fi@CzEzm7<(}OBimmHekUbVEY3$SLH2_A!k^RTm1 zK*VCpEly=bbZh4!P3(vjjhg%7C^}-=U`lmck!uncYTLV~ss)FepL52bY^HTDCc*>P zPpP}RJHIIw#TtR18HHvbz=k1MTXdRV4KPsX>$)=Q>>ch+89X?{YaZ2_2%~gb!3iC; zJLzFyA5GqFxnaQ!zxnkxhrdNA5~gLVAv7VZb+1r2K$qNPsRnti8^Ju^RI&r8Yu%?B zlEUV{UJ)nDKy^Ron0Z35w*==6sOCxUF+%P(6a$wpb!WDjSJlTCfPEg?`uFF*p0meD z1-HyYGn!mPcY;oO5F%|>z4NZJ(+7?*-GIE;U8?Rf3w4i+I?P&1wh5*F=jXG}p`7lW zDwQMLSMFZxnrN)S-EAfg<0Sn=Sg)q`v#UE|CTG?#V;M}HRc-E2q21?UY*C%nl?T`L zG1xxe@KEX0Hk!Ftol0?Pqa5CRUhz|wzt48IlMU-^sqghksPd`Ig6{Tgg=63kW%*g3 z=gEmT&*6gIJ(s;cbn-vWd)SVhHog9 zk>Jk zfWnJ3o$3lEx~3r@v#$&N_8~dv6sMVco`eWvccKp&eHvz%S)509s?@Mw!OaJa8}2kz zF- zQ&3kR#&QK`_+?dHojCzH2011tP0e>!5Og8evJyy<0Tw`a6s)S_n$ZSEb`DMX7;CL( zZSxY=@>M#U^Iq_WZYNWHTfZa$ke zHv(W-?WRCSLqQW|>IT(GjQ^If%HeE@ZKn~1LLM!A{5RHFcE6iIeB z0mj=t=ti)?ncq}b<2BUjO%wc;@?str1-NRrlWa9d%{HlTsyV%0i)azvDs;h}rD6iK z08ZB&8Vm+2D9-bkn}OY>Im!AI)EF~l5iVPN7x#mmn69~bfH1sHLz!EPndvb43N^+K zK=EZTTY!A)UU~=23^R1^nek*6I9DX=%&^Fs-<4-;v0JRULQipr_VSh}2CS`7UCpsb z_T0n+1_#aABH!7*nGu4zss(wsE?*I0l{8Gsp0cW(JB6DGT7!-yD%<=;9EA^?O2c4{ z2))2zm^fFsl#Jr=S3%YJ?hIco(sW9cg<1Ej-7|MK&6G*lL`JpLerPj*r%6y04<~-y!}OYr|G^wS)Ix;ur)k; zj66(LcM--ol9oxmps^@vlal@9UsAEdh1wZ^4F zQb%Lq$m%<8s#)ctVM2yzb!k*E*!w9R8f%~V8oSd?RsB5Ugy`SrRP|-y;LhDuFkfbM z+E;W{k8?Qte811L-Epr~Dw3nMG`DWn7bV7Z(LBr&qS;z&9^t1p(ABlio(uRnJKP-} z|G3e<&*SD-tjx2YuXv2SBZ3j;iyZMyXA*sC?>~R&^6So%bK<8F=2flg&U$`--+jND zHmTa)=kz&UEk~XMB?+Rlk`m-5=E-nhYu)R<)>Rmj94eoz6l8AIRe9dveF2h%Uru$` zk+Mm%AvfH2p>~(sx+3BV^Eg$&n++YiVZ@t@oBM!Ohxt^F^6c!Rrkm&Kn2NJV!6;Bl zWhS~-MD1=BiRvOd799xp`OLHcdnt62sU2(EBmsq*{IpaNt0@L;YzaE57R|$H)SQ)# zSzC47j1F>O*k|DNeNrtjuIr;}H_pJv+&=fed+&+1Wu;kEZg;=0HI-I?oHDOrXVpo2 z=e7a&%+pma1zc2Tt2*Wk+I9I2q1iAuH+KuS@GJAo0^#k@H>Yl8hbmQ_=Xpq)52Q!4 zW(8lohtVcWVotcZO-38RFmlMs1S)k-xABa&}|M>8?3s<8O6pJWX3`wJ2t%*hjdb+;PxAM>?F4|=VbU4kt$$WD8GNZb?vrz8l%O?=kJ|oe# z+2U3X_#q~lFcWT@u&og@nez#?lVl*bAV-%f<8>WMY%tiOg_;Jx)?%1pTuE{{TSgkZ zBvC0A0zcDjFXFs6UG6Ls0T|IMikJx*6tLvBnM9wC*d-g*k zPN^(&%aj|h%hy`8@m|SbVu#y`D^H&1OIs3RF*~Jp$6C=!xXcVv<^kjp7DQ=GtEalU z09c_)RYGT}AS}OT>Ejb@t?E$(?CMfDMVfQ1#lWemU2eYKRS>41eZ`$fzGYG&< zs6wlh9btr-@gUV>c^jx_hlgLTDL1%P7D8S9YP=>x1y*D=uvc!h|zUpm_(DgE7d$3tES09yb-kS^A7W?DWqzC zp4n-p?vAzGr_W`R+<9Btd?!mv%q!A}Fbgj8=#;I9bk5|FNsK+t6OF(h2|@l8Ck)MnE@I^gyuHfk>}}_g@xY%^*-_QIdu$>iQP2g9r^uM zpUYQO7b*&bv(c)1`B8(u*45_=G|Z6zaB6#nT94{qyWH&e`5o)TtTrS@j=r$FtA&WQ zjGgJW8hFlu5Om{eONX~juFTB5N|~q0aVQJ0DXYgM;Nr}aE}ed0fVzNnPc)g>%yrz{361_purcm2C_Tg(>^ z6C&<$**O<3Rlmq7LqD>`Wxmw{?}#w3DojZ(JK3sUSInf*#y=d(%DVbn-&pq*tGhww zsiPK;(f2tXOUgm3L2zP5rg@q^=4xT7Q9pJculZtERw3U_tJnn^90o@>V7A=PIr|p_ zKnCGL((cb4Zj_xoDHH4Y-T(ajXyyf(HCxN-t~NJ%yqfxD0|tH0Hush^TF8j5KHYO^ z#2lXlTe1Q;2F&98Q1n#g@IMJlH7Wsvn`IMXNa7^oyQM}fpC~iTZ?nCh=Xq>)Bbmfx zU3d~*JF{$sahhv!MR!NH!iJi&P)*cxN}yU6wrnEHg5hLMG5-p$MpfA|YjZPYHgpO< z{`vg;oM!_jH)Oup3yQ4>2iMTcoZMMCdB`NMc6fEud^)S{JiEiL_GVjFr;f*%Hod0H z;zV0^a^AW&A9@ck*#?$(*g8Xvk@xxS?$7lpDtEgv1=6Y;Dh_13%jl$Lv1Vl0qS^C2 z7VhCKP2TLfu7Q%A1cNZxY{F)$nReYl+HF4^Vm+)P*je4hMp)@3T1YU-F~MfbD&e)m zEO*hvr=oBoF4gSVg`PAcM!R&G396GGM(?m`(;gR}uKAG)JkJ-1>t3^d$yu_i*7Z5( z8AS$QC$q8)v_X=T9Pd4aZcOtx7mMy*5!GFg8%<&8a&((^A_%btXf>M1SgNOKGZ$;j z*Bd80OlE)m5TcIULr`2^HBoPv7}w(PXu4plcG6+7x;9=ij}VuWoiIlBzSf(pq1Uh_*r0gUbZlE*G#`cdO_9ZLCi$&v}7J=fWq>w zZfC$$GN55ko=@C#w%Rqy#O_YQdcfNDCjHU^h#}R>ly~sjLG|&njy&ZL?_` zIJlWhBrc(`HZ7b1*H4^hvd`$8OCkv=oad%;==83D-;$1_C)TI*!B2cTG|p-7U1m znzKwev&-o+0>utcK&x$XcU8*HYu!>gnPtTefo7E4K*mw2S(O6US^yk2R`S^$08RRe z3SUB@n{GXu4|M08DD0~%%l@AGSi>Nn}XYWqQVcB)9 z>tw!CLXc*cqYKz)E((}fse5Jv5KVyl)dMCqX;}7b6lYR751}bWRG07$+H-1EEz+-b zwc5;Qm*{l&SG?R3jbZU(53CzbW7XgP<7^rrfi8P0oi@zS8794tx9p~ZJk^CWvuO^T zTLR%0WREAf(PjavRiitb@n}=+ZV}2FvhdtR{Vnl}X0xCh-6P~i-VAkD^;ipa5q~9q%sx>#n$B$SDHm?a?Ct-~ahPXV2Jbv`AgoO|e@|{QmyAKR-r0&-Zlw`_F&v z^EJ@Jp69e-aRH+7Ip@BD<|-L=&KY;{>AcpeOb;tz9z6}I-wukK?M!u<`J3mC06I^_ z?QA-EDnW1c&?LqL-QDWLxE!#xI?r>;&1wiBRrmcV$*N=)u?kgtW9|enBeMbZv-5Lb zFdC5EE9}p6fc{*!RImjUO3N1bqnsUKA?rg?oyVyJFQfZR`@x&?vMQ*$WPwecVZ3 z;f}7~lSaY3Q~&jIKj&1R5>Ob7;gC!WwBQJx+6U5K!DuH;-pova7DkQkgxx5jv%;ZL zHty^C3!$81e$8E?pACPP;wt!Ub(-Sz(rWgn=d7QFMm3=}$=v; ztgKBDqAzcCK7)H4a0J2VZsXuYG1c_lNW!L=S>Xo{g`gC%wD4?q#oGf>)6?H}(tZu%Jnl=kg z8?RM#lW=)dcjtizpyl51?#%soME3lfK}lM7nv;q~OLfI(BBgq%HUqk5i-pq@t})Vl zt+n@;n7s5PtSwI>5Ehk5GZ+@xGcF_11d<-(C^x9uB8;iww`eB%0LZRQh0mpwR2zjA zJZiMeJZpZbjvjtkONto}y#qa}6wA+WrQ}UOG;|9xsbwUar|VjSXH|A_$dN&SU2Ty2 zDwH6=>XcDtOF9&1 z7qiadN|g<+XR!Gyx=YIHfxk~#y{a;E*+iz<#Mv1n=(ecpml@PuC>Dl4Uc%fC3u%>^mAO z1!&bB5fc@9o37~Auz%*WYA^;PJJEV&YEs0iE*XNxlDW?%gnw`Bgel7|7l{TSGgQqp z`7hy_HYqQf4XYqlWR^`sqn$y#S<&e+8T`%uPn}FegwKLQMX4>Q?y%?=sl-_}1~_|c zXr#qit@rvja(G}l8-J0jBGCrheH@HfLZ4FvjV428f?O-QTb0-S$#c3D>mrerT@~Rp z@A<9T-~XFT$~?pGauU@D0!9hd9Zs~JK5m9atJfMl^n1@BO;ueTYe} zW|n&xSzT}aZB8S6BSlhoTbRZ@4jKe=Rf@n&kKZVrrus6`IORDoTjr(FknhW`V^WV% zi<*ImlcZR^8BW0l+B|)5H=Zs?1KzCa351%NS}=5#)0=IGNpK9z*qz-JFggc|NAEK!Z5u#Pb;i9s%*|7EcBAmxaF)Bf&_mh% z{(hx2Uqof+^WER)7<64jw0B#PnW|2~JvPBOXx)ba+;8-o-a23r zqnZae(3uWmU2*$*)#%`pZNAi;8r)?8`0O5fc123P^(T2O^ARxV=ktjOf>Z-Kxz!@d zX|pCHj6lRXSy$ZGKNpD8+heKQq@U}Khz>RpYlV5Wp1mJ^JGY>c3Ra!Zd46}Q&lo7p zQA5ZokuKP589R$0g8Q_Y$MOY0@>r*{`>62@&2+K5WNauaPqnw)c}~O3oMZFuu13eG z>Eo)boZ36lV-Y^(W)bcUPDrmyZY;~569CT1RGm{tozI53o73R#Xqo5{=bTvAwCPEh zA!4aZ`!Hy}#w8%L7=+J!k4+at4>5n z%1oJ!1xJ^3u_M^w#EsOA$+#(-{GIrQ0-I{S2y#qe0y=ep};p6&GRPL;Cl zbrbr0_KYS0t^2+Qq_9su`#gE%fct2YLG$I$-dW92`Wmm#b${;liCE-_SEe#0xGz#+ zmhA4~QxytvUq(5+>ePHVMFyqHN_3swr#nyfuJguI%sniqR+h}2VNX`(F0>h9Efqy& zPpuxb#<~VLs4jMQ?{o5~c6Y=Y>=K1Zu$(@aMXF#y1C#=+3pxArNzix0jcB6$3Was5 zQ&lo!qfh3b>)hgsnDaZN;9}UdE+bVvmti){7Ys*bpu59t#aP@YN{*QYl5Vu&`ekR< z@rVJWBp?EAT?t@+&(8m#LAT{DcB8whGzuD-2ZK(NaQYdB{(J5*0$nN#8ayJdD=4T+ zYJz!`b);@-GHm8+&sCGJTeqj#;V*H-Fpc<@FdmjR(aC^we5|IH`?4#VW-uaR!7tLC zGJ$3`?E+Rcl5DA~s!*vj1o7FfR5p!hN@5A95-e7@+wfxzW>r8c_-<%WWrHzcsS z4MrJ-2&YHuaKuAZQ{;cSI*D+PD^z(ZHEXdso&bb(Y1cVfM$S#Z&CDaSUwZ?LBJ}qG zPqZP{a^KZs`IGsw!yMq!!v1kYQL98(LI4@s%|bj`bHm_l-1YsJ0Lf>2jK_NeH{pZEsj(SB_ZRE!-R}4+~#&U2^33x+&r!FB^%Udt=}A4oA*fZI!~Hug41^V`U0tH83pqR+NL86# zU8>$YGq>1Xt;$rX(tPkyvwLEWXL+g~Mvuigia~X%iNXx7#^^J59bi%2$Zj0Ms{|pd z2*7Mgmk~xz6Ob0xtv9q_27jx;6U!r6s_*yroE$4zOMmZLRtc(|pez_I)!C=IB*%z) z%`~r+tghk=9g2Dz3&!46#Ei9GZ(6^P0+!GXBjsX%#9E6`XBr9mkfto0(B50sJ{1Ku z+6LG)jG4^r9C|B^9H8qI*9rP~2)ZIxL9$7Op}O`d!|?ND=4&l;iUOuUPm#VnPuDrs zaJz;YJb;~UVsdu$muH$yvv+?(oA}P0a$#VzN{OnjqIxPs8bmsWZ3APg$S73rVk3Mc zI?~8>i7NP_#am^FYt5+}YO*Gwg_i-`*;Q3DtBAOg4FQJbrfR1uYwt4H;@}x$c56jp zCPy5QK6~!9pbxV4|M?&PLn*1Q&y|Tf&*$eSGY4B?5p(DJ-P>r_y)qAgY_JvPpdDrS zW!C4(buBZTa~cYZ>Vg?&ci8YSxS!`S_XWsT)#)A{?KKV0#1UFX@qmH)201qfJfohFm< z$>YAD9`lANi3ytiK6_si3 zY#gP#Q=GF%HE#FjsAg#9Qa$^u`$CUF1I{?lwg`14>*M#c_vfFV&a+RO4*?t}Cm8 z7R$4H@3SI6nU;t4$)3jsarw&g@;cY;5N3{>b!g6lS-^D888o{iNSsbOiEwi7-F-a5 z{mMMuZ45ZWjlh^vl&yi77|%{~{#^f*wDq;7BTgUut-e}Vf_v{UUlF7i^Z9*Dfb-|` zPj{blB!TUSRI|(1<%UXRJw;x_+zIARn68LF-`#co{rBI@HaCrrEo@jBv6dRrnO#SO zR}N>;dc+8Irt)UNrY#!9Cm%r(PI=7%v;e&4x~?(+=0dpz^`gQx0B5i}bLZ#&z)d~v zgqIGHdE9)M;A=U=ELH90tEv>HloR3JW~k0O?gkm%s*W?-z#*$^U6*N)90nr#6#paX;q?dND_cVh>&=k?= zezy7Lrky21rTYpE7)K2Bt_%w||DMO)Nz3Ok67JKKA<&p_-#~2MKd#X==S;}Vi3V(7 zN7uEwb)Gac2Gr`->+@{HwN%wEYhwP(k}v;$_ZS<734Qh+s%2J97X;x!Kj$$HWPoFX zdO1nzNyMF9Yng>rmK(Fn6tV%Y47Z+|-#BDprqy-U<=@|5!S2r|^R&9MoZ&I2qn4B@ z51T!I)|fe9QyGN`7|iS3)+UIBFlN)O1RJoMSSVFhms{Yanld}>-Db?vsAQxW`tLwh z6ZwV#4U)3v?m}ZOUzueV<|2%a^G&I>%w|(Fm*(*2cjw8^&u6k6Agq0yl5T)mXN&VE zl6!RLfO;~!^|#K#p%^U!rJ~SXhUq9xy}Kn;)pcEJWu6t$;=0zePuB?x8OEhRs8xB& zuM2`yMpX@wD3{+LyL;TUNwF})>B+H>IM4;sS9j`#z{<_dtTP$W)k3LyUH5z%gVc*45oFYOK4I zpt(C{%s)5!?(144x>S5+TSGV%U}lT)^q!EChxP1vV6AG*1$xTo?dC&!kKqqbRRz^AVn;d#A zn5xd6-dAP|a*%HRrlf0mkOP)bs$<5?dWB?w0OiS8Yq(ldr|C|#(O8{qi_5dJHS*Go zWsXJJa&!4HTx#6+UCQS-r5XnBT2T^2Gq3FBUY$aldwz3ja+OV;~X*pXb-S^Mt*VfmX|WWj~e^Uv{lM_v)@oVF1(~%Tu^?#ZT2n zmdpnF6QA{co>a+$-QVwakAIwJ)Y-ItHe4Mv=#CE@-*4vL;qJ?gb`PDcTczvY`#-<` zXT{}H%$|c z@?Q3R9=Z^|B5YuVn64MGBD-OX4pE);e1FOJ)I~$AMd8`9(kX zd5n``g}TlWEkwk<&_mjR-z{1d*h-8G@SsemNZRf6J-B+x2&35bOxcF@>x_f6WCoR6` zAvl^R5%;}z9gqkgTtL{o?6LEgGhorO58o2sm>vLd=QDc&4#T0SYJ_9v z2Gwyd6tdIjDrmNr_t8;1yp&@eptCChh6mkHo$Sy0l!_FEN|8O|yQ;3P5aW*8`St-( z9?_Y$Vp8hzv75DP%u z9J;|#NrsV_z`CvF^aiTaXp3{OA0Rf`su~bZZC~rsPge=*k)6FBhe1d;)TEqVu+sLL zpU)E5U7ZD$sLQUGsxlPg?rVLX+DfG*_4kDps_LLUN&}bKnOwI>PT6z{Sv1($r%4w( zUkqhuPyE9M#`1E`EGf0zIr==CojTB!Id^iXKnTk@MCOsMwrT@z3x=$;H;Apc{G7HH zNu-JrYWZa|2!BBWKxhgoW_&fsY)W-fzN*t4vlb)ZW~a(li0V4-k>`vAG$mEG8fr5? zdEhfpEi-p@n3=ELJ7C@2lgizj9(-%y)!7UitE*2gMl`eP2}#JXnh(INV{mv>HoHN1 zbkMU!k2QN&@Z`B{t?To9evKMA+W7c@LI+e~i(%@{KIX<(nwpYK-p+M}x+)AU$9T2u zJ#iA@OTb^Toz_~Vs`qG$hNZX$-uRBwy)@( zD*chu!`O6CkRLj?_O6)o5HlaEv(S1l)wcNtJ8d>czH?ldu^)wJYmMXK-;I=UO zi}0A)oVicfERq;x@C%~sRvN8@hyc20l85Qruw~sjJjt44XC@6};iFs>h?pStxEjWF zJ#Txc(aee!5%<|8_P`N}w3yHAd|~7RD1%iY+}-V^D=SSdu~BHckqx*y)wA2->Plfc zf8_cMF!_77iEadqb;BNB}ZgfjwKF`LJ z?Q#NUfcb#8s;Xzo?5?KEdlEYHL>1hvs!3)YGgfmMVM`|gp^-c&PAc-GmXDLSB}7aJ zjOI4T47w(J->5uOK&qJtxY;QY@MVI!d$7O07LkM)q3Tqr#@$*;~dot6{%8%y3@|VLQ)D zGaeoW6zh@!okz8<;YLo zo)f;pR`-FlRiK6Y=W}1{W8tVqb#@6w$L%+y?n1%&%&wp7XMNW7Iyly4;vE0{ z=Zfs=W|lx(5m}j4qP2RhRo!UAeJ@94JN*Tt)hk5Js?2hCzNd>ekDzyT?fv~eQi_~P z@ZQguUo1kjxMM9xgw0nHvk#m-qqQczou{&@)L1Lbxc3<|XPenP97e7_`V05#=QB}; zZhFM2o*1IcH058)!hA)OPbG>V)O|*mW{mJW`HD!c2#dACY*nkf_df3h)4XzMEtSyn z6>+Z!fKy1SZZpQZSFGnGr0V=XzrRAqTCtWHe@m41KF`_JwfA#+a2NT_Orx#kVYG1i z*Z@2N63i>rS*p_-E+Dd0LZA7ewdOJh%j|=yO!;I+DZvCa zCDxJ_5y z%-w>-OQ!Nzci6HO0ejg#M!11uxbO1_Z8W2dlrUj}`GmbbbfdeABr4VofPWo!gAA)8 z1cS=~sWOMXQ&Q#dM9pEnkE#W?W#7H`*+Mxi25d#({q~Cuu~USkPE|_QlWXek#_1+B zK{*rT#F0#GzXylRN~wy!(Pxt6J$ zK1GrSrdPonk%79Q>g-H$VlE?P(7W27vD65^)KE!alY-mS@ZVrdr^4K?Q2^7!0M%*t z`274d+9ft?LIa#{Fw9z|WoxbF_DUk$yt~Z&x^KGzrM2Q+Te)?2?MA`_shp##2oX(2 z_|QA5MDwh(&-h#0;Gm{{UqH^lhyfxxC#&H#kxe)_Wl8M)tn2a)8CuBa>FA@RWaRIk zUnj%e&D3BBvaZTX0zk{G>rC9=%my9y^Z7{K=KI;y_RH73K3rL{01a89NNg4p>ykiPZR*1A?zqYK?KN13e7pa1;x@4rZu&~+e??q>H| zMSSsc(J9hfUz>s4REb%VkF&ZwEMcIuriOi%m;quIoExswD*Z{VDO`L zue)DlzD>VM)Xr^;>|_dIjuGvF_dJ04>aP zavNg#hhCY@w^mc(E4x(XFMOIh6yF=sz{>}XXzId@fztwBS9y1BRom#sBeM4qjR<dh{V3SUxk1+iZ*3|Hetg2s%LTyf1)1FhY?7mim$}IH9@Auk1?M#b0 z#cR*-Kz5bT=bYUcAl;26Jqp}8Rl74t(aipGB#R0meUvUCSHCI0HjX(T0`BZMx&x; zA#E%{z>D^l+QKTuE?R&v8`VY&<_wTs<>u8ilo@sEKw_Ia1u2(%nVFPFbiIK5)@gNZ7^9fYlz{LXc)-|wTWxL5CEoNAT1{) z*An>R3>75}y8g*t*R8Ho8HO@x_i4mSXE(SHpvY-vRwp5Fu}artuK$Jp&ACrMrPvfT{&`ax})J{Rj&ZXq^3X(j5E zJV@ag%c&-v))6aPDl~_5h0o^(X^ELwFPp|!hq;V(cJo|une*fUSfqEu&=SoCkWy7P z*OF!?1>$-xfu3>9dy*e)dvPn=0Ri}H5-hNK@w3RtXv~4e4FlCjdWN9IcNzmR;wDEb4)R>e% z7eCABY&ZAteI5W|(Q}0yxc-5=HCqky`8dNcTx|=tsve$_M5sshrmA!HS_{&v zGoO`|G_9D4C5&^xY(BoQNmC1*Wi*u#%uKOe-OcPWr{3-KUy0^CWdC zV(mOe32%6q9_HRh;h}DVyB@P>qsf}$|NfuzWMFw8Laat=+mWM|K0AvMJ%DxdxN`G@5Ger*LYEH9CEDywVJ;bG9JT<``O4RuTReLc^ynX<`uC9~tR&`mmM zRXJtv2J)QizOq``*XKHWXJvR?*EJKhu!Z4Fn3VYDzSoDXJ65SQ5(_G`>7ISAxCitu z$it_>Q+4Lic}j!tQx)8Nf|%nR?}B+%d3e11=Bn=Nz6K60L6U*!K9Z_~mzW+@^*p?{ zq^jwX^4)$wno$;JmY{4K)V0CKs1f!(hkEG^*R@V38W26~l$>o?2<6WCY-FFXH5_6> z;gJw#Wk%-Ch(*IW2Y}fu-^+cK+9Vjo?2KI1!#E1vI{g!|HL_#o2Js6GqM z6=)o!Q|B~EUxBLo^Epq^_2)moel3%kGpp7zX9ybPa5fCE704oRD$RZ3cQKnk$Fra5 zaS_BQZWz@Gh;DU``SN9d{_LM?(RfZVAjt|Gj47(J0Ty~)OQ+_=RFX8l%dV4hP+r9C zK8>Q$e)SRTwYne}bcp6KnyM0VH)U4$^6PX8fGX@RWjD+@Th|q94`Q{Z|BS5Ry0x#> z^_B&zjztU~2Ao}!?eCX>+%n5)?i5+-(V7f@`-;yzx6CEs_xJao`yVbt_1OuB+1h7M zNG8#4JbPnep5n|T%~{>&NsD0*dF|t7Fw32AAlt$vUH4Vp&$9u2u3Ko7YO?T{M=MX& z=f2N5(+eyi%*+GQFb&PP!m8QbRfC6vx#fB2Zf&JwVQk{RahqV~30vmcnOWuLYkBSi z52B50;-cL>8+mh<+8QF?<2$;C@yHoewwWzkr}GN`K4-j$s#dUe`ErN*$X;YJoGhBu zz1BT8lCdk=qBUVGhytCpvrFp=0Rp|7;ng*ujMt?sjJ^~+$}MzvSDz%oQ-jNyL$snwa+Upj8wgKpy8&r z-e$Z?HPET)Jh{_&p2s~(ZDtNOpzbMCRpq)@rOd+YJ5)&nA>AY02@ zYAJWB+m=ynu{smx;jZdaMS^H^H!h(DOw9Ukj^UX2YMRIK!s6*>lxY&}lKE2gP|25D zzGAqUO0xP){QJGqI&b%B2*cQ?I63&Lscw^~BG~5Cr~}!m_ndB$2y;`aRD@4;qPqxt zl?&$c*8iJ)D0=i*X}irW3+|%(?7^~9P5$+irrKaFNo8=FhF3ei6A>IC25G?QGFoQN ztaO}lWuMV+3;oj1WWrPnAbTHQ^9xKh4^tSRSINfbq#1;2#cHYY zxW_=LLuT&F^UT?~vx_2^#R6ZD!YXon4a|^JUpEiY1r{q|hp}FzYN~ z{#GnXWq{OX7sjZ~x6Mo$-SZ@k5!NsAW8hz`mI2Kkd#iyX1shO~0CV;!5V2y037w*W zqy|kZBGo4I=q`tS_jdp+Z`3er#j+J$DOy(>&Fme|SEjoQ03FQO1SWDWR^o>dh7g4JDaaeF}(S7QyfmAn;ZzGg~!H^_)es zx?Ap^d8Yp`5e$NYtP}7-BlbD_O?M#AbMAH1xSxm6b>Bg{bD6Jox%sI^72_3Bm}8lT zuiQ^(S2tQ7*9adVu-UZVedfaA!wYKy6VMBSd8*WKT6nii?9$msm5XuT_u0>Wo(8ig z;nDr_bB*H9&rg67mWM?&;o(LPi$8zPl#Nt4UCW~lxsO@cisyOWhpa5SX;Ej_P664K zt?*c}PUY$Hk&DvYT!#`q*T)CpK)uMRa9F&+4%vC0mi#hb>&bj_S9hljA!jVYOyXLX zheJGBd*`#y>#VNsmS3SpnYmka zi#w2w?(E!^X3RZJ;_Gyu&Q7rh63RLmSNOV5A4-c@W-#+>(E`TH_^RFKU|2);M3_gw z2e83>_CC2wJ(xyVghzI1Tzv?bss)p~H&Md(8~_}4La9NxLt5AE7ABIzcZ|-0Pv|`w zJe6+VXt!AR@@tLsc8$MgYA zby8}0aG)+a-DiH%ZDA|!nHEWUo(BcDh`1*IySvZ|+E4*Je16~!TF_pKE2OsYb*&X) zKu^M|6r2{W=5Sm)Q|;^O_KBz#lvVqj_*}9%e)+H?Ymcje;R`5bHhYD4%Zch%_4sQ@ z?(^(@IOJG5s4D^j*`y?eGr|oVB9r?|RXnP1pM(Ial5D4=E32h;k}+Eqv=pOiH87U1 zDHu#X$_j0?@PGksG`sIRR;V!?=kY)K<@bFBgGBZIo?VFu{N1h14DuBW{oHrlA*$Z- zp#e~4zsSltaW&Zv6p-CnWoCEW=cF|(OpRt2>Mvnv;_-lrtvOymJvwL$`uua|OOd0! zNpD~PVxW60*$`AX>F$#n zM@h_6l`1BJ&nc;A%tVWO;3Bd@Qkc(5Sb0CHB?739bG#rNUHM;k?^Ue>e=lAUEbPJ++L_jscDpKxV zNR_f=lMCYn?ThmlQG%O$XsiNibBl1c1q4`&%2s9d>Dl}V1_MLJM!zp9U(z|s0mMR3 zvkh(@VR3oT!>p?22)}caXcc8$73(U@uPuiLKta}2*c=31=M)W!sv}LY0Qbq?)bz_7U0l}2o+}E5I96XgI%y?bV z03E|T=q&)@Yh5v89Xi67hsmbA z@2~4{pL6!ELZPzi&!0cyJYmc|WI@i@gV(hH?K~|IQQy;*MM-dvLQg#;4B-pFT2ZN! zr=ft>nr4Zf%$=R5NV|X5x-OeBfEr*62Rc<|R+()$wbgR-5&Hgf-)=maXgDWS?f?1n z`}_Tm0e$*E`;X20h_GdG`Te=fu67Sn(&xHho>k}jT^>}&wP4NWb$-af9^Y0 z%t_V2<(K^xRm^SH-r%=YSE@T(fAidP1heokGqLKZ65`GW!3b09?4k%ZX_@)mmv zh?q0F4V3Nd%yYcT2i)Ln@!1De>%P}@neo2nzL1%1uL6tL^oRRX$TguB&@Z6ohQ4& zd@@yeD&i8lt@lJAq1F_S-v?lwwjPFzU!QxpsKKDxjp1J11b;sFT5Gb%bCdy@yPZ7M zH2df02SWay?7Huec=AklDTk_P(Q2JKyYe|`o}*JKR6UQGLrtL@zt0y?)9DL61G`x& z8jUnF+2xU$gJ__vPw$WH}3>>EYW?G~YP zvXdNy`IEJ2UVJ~(GKkDdH$%5CAF*T?PM;Nqsu|jKYgnCTHhvTB@hA(p>%-tLf zHRj_}v)h50n*-){`C2Qk>spt`uneWQp%E+0bC-0!PdcDNo-?TijHSFG$ZDECK*I+b z=;(e+v*s2nPFCmPOOMp45$Oztr6(aBTr?-i2xVWssD_H>Yzy-i+}@J4s=+zzF`H!7 zZe@i>c-&VwyfqrOdQK4t7|nL(J{#b*{M1xwva7rE`+Y{n0;052@;ltjz)4s&;LFk7 zEgNdMJAj@OYxi&=M~Sgd&!$3MeW}e#k>uwz}J`gl7}Mb#wOr28i$;DiQ;RD z9W#Jv0XkaCV=_vW1;fOn1m?Ij@v4bPD`>dD0}!&X<(752`p@}gn9XAu>}rRuSQ;bY zTy9>i0SxRaXS;<;aj#f$MTAFJ?e4jRaYWa!om+s1`6wn%){`L3LW4WVbM^sbqS4m9 z+)dD&K+SEx4)eP9d^Q|HNH^-svm zUY?_f9%r4!3VQZD!bg1GRr3chUlGgQcz^EezDv?<8_b}Bi8i!1fK6+@_ZF{rgyo8nY}`;Olg+ZGC3`5QYq8W zpN0hpq1AM#0MNr@T@CK<>9++tv%|RNM1-QI_;0n3qzGGP!#88g2z7QTVB`X7<-yF15S4 zhncJUW1%Ups^k7B9>$^kTLxIsC(Q_x6-66*mijG(pYH+q`P}P@&wOdt>aHg4&lP6-duGRSlwGA=0#4^)mvCPn z!!YF=L|n^!iQ3bid>1tAM4hfG3%l2%yE#wx^Zg3xVI=OgK<<464MxT3IfY-FK^d-C zQ>u%ggW3H&-aj%POKz zW_Qy`^Mao9w3^FTEZU{U_u19eQe~lAa5eVxoZ3z^`p#48ps#fs;dHm?s_a8YvPr^W z5d>o5ux^s}@3Wr_v#yS7iF5ZjPFrz(KDUV6XFtCJ@6Qc-W&b{37^m!Wx~`w=UMr|O zE{khkZkZ`(bvYT=s_sUuun50wggkx9b1i?tlJWzT6wtd1_fy<$iu8A-Ez2 zaM`E7&v%X>6W##E5gnH=x|(uZm(RMvR@)V8tq|G*|J|zttk5)%Wu=m`GSyu=lSD0I zXQpaT0<#ISsB2woIRgS4$ja^xw}1ZmhoTaLN03spen6YhVwz5+k))Z!$s=Jg`{`zc z^RL5{=rGuFlI|;(+Yra9vkS)i`otAfn}LA{W*(ANGIPqz5YBL4SD14#ettei8U(?I zvqI~vUH!UO&Y5@wG5@rMAqKywpzfX~G=?H?f;vx{Ujn+Dv^G0uBtdX9q4I30Rs@B! zhl>P=%`$pXRRgMpyN6vAZx6dxto6_5$7yjb0W(2yb9WL5w^B>$)0O917u_=3*|aGf zBiv4&I(eQn1H)iA^<<}+g$Lo?J&yG6-dRRBT9sbW||XFpYG!`=hT>~p!K$=SzR z@4=z_RMw<>tkiTh-@uRTsll%@+#WRR>1Zlx0Yh z=&70ZVYa&y5U$eO78e9&?vvFM)IyutNHq8Jr<&bWmDQzg21+veb>IK|{A2E2qSGz> z{#?EY?{n&DfmLPBl67l8Rg@7U%?&r0d2kMkW|G;dhOkylf?<9q-AJUA>P$@x=suxlFBkX$VukpKfsGc{K)mYf95~JV^8LECiWdtu7@2qx%&tt?=uys z)0wABv)P(kq8eniL{gny3~P=3Z8qUY>iJJ-T#N1tY@?aK)iX8Ty_2M2j5wRsFTZ~Q zk`pa+#(OxfZtFfaCM=pnx+dV-U4uRf3rVRuC%aD9Q(02m%wr)Dr}FoFvm`J)MsFJy zgVY)gJk)SInHVghaZ2ex(@jlPPR>TK`CQqx)CKD0+jhQ9+6d%yn20sg=( zRE^R&A}5p0DG-n3#aUIzW;N)!i-cb{pl*%Kr)mT^)>SpZK~s;e1TG-|>{3r|=VVhL zP+cdpjXelWff^%c4ahw6WF7&^&Xbs29Z*@ycB4lKWX*V@x;tweKO@#Wa;u)QHA!37 z4PP_^NVDO25mTs@zis{!Mt1u4H?rU>06fq0?1P#hUZn~qS+#PKZ_~8MJXI1~&=`T7 z;|oVgr^;;(>hM?wud2?j(?bRY2hXH;V^*MWx2!8wnL6`ik}d1348JTw z5DT4Mm8J3#n-MhIf?N3InCpu`qaY3>-!QBZ{_p?wzXVq8F5D5_9e%wP{cfi*TmYn; zpRdO`$JRRM*i<0EPsErJ)jWHkgg0QwhY{87z^T0M&pG@3M8vi88IFWm`*M`gUN-bO zdt5x#*~0ht`}4VbXrn@&hp{AfDO_Yo-RRG{1e8+c<|tL~6wzb7iIw|nZrA5?cG>8w zs-|-W4%D6IRP#P?`YNTZD`1ie&uh{PHOc-q~W=Ghc=d3W&3COgc z6K-MNhM+aj=U}oEYSCL2=6Nz!z-H3smAz}*R9m{tVHT7L4OpQjPHGKVNc}wfy4?hL zIQcx!pnlf!Ki}<_@o=p2r+S%@#-NX(#JZ0x3}9v1J&#uA+3UKD_&%qF2!9`yP&b#` zczKJu)?4)@NcY_7?&xkbVM9|s-FHNuf>ThRjynKjca!RJ0yMcVuP15 zcYUr;tDo;NvwL}Vw~7`)Yh-o9W+utFSdE%gTlF~ET2t`t?>^Uc4b;T?rHPi3Fn@&& z>O$tB%}cBVSa_X`2ox0Tnuv>eP_*3XZX&vSrp%x@32J!blu+_8g#|rFtuv`zE@PKX zKelOP%hz2sbO$)ST140TzUw@_rkU18G~Jr?#-z`?dR+i_K#0GWUT~E1_~5^ssxyYRE%(uP~&d{lg2qpLIV$w*(3+b z$gci;?vl>)taUy6#BvqD6oTyTUhB$zIH=EYKMI@>3tH8n4a0Gw`BIB^x!35GDq{e_ zQn&2#JjJ&=PMWm_K=1;^X+EpbaeF=Id#xWguT$Ac_KM5g&)KBG*m>Y)1z5cNO^eL) zxvuKYE~De^i8+ZXOq0gle3r>Qm4DEc{oZvWLfzH|b1~<{yPsTlNOsP5Ff}xv$3UH; zwfiMyXVWn6y~*r$$pBG3dh$-6&+-tfy59FVEY-{Xob$%kgRG&`Hr;8>W_5Wih(k;7 zmLUv138XG8_Xg%y9`dpiNxUbSc6ZpSv!}d1TuV7rqPYPrRpt~M0h4k*m@BTH*N4jNU5HMi zEml-kojs7l7cHa1wqpCV4yF=UZ8iX5%xpfhu4}2sa?x~G*By7MBi1>)&hd41m%EWZ z%|&zQoSFN+^r5g3a#nRrQ*!z2xF&2@Rf0@!<)FI_Epw>cSGQ!cribrST}5Y@2_}r! zZh%EyFiJ5cY?(|8QAp#WA+s92CL@&TVJ}@YMSEpRB`wjsZslszULYHM}v71 zi@zXKtaX74-l> z`q^n_%FHS-HiMMjGuNVU=2jMQ~6WzDJm{(Qn0t<|87LD9tBg4CBg0!N3iVFbHdR*F?;!`x$N zG&Y;SnUw;5#dWQ@f>yUObLItAg_ml!y7h|HAUJ1Nbh*2GSD&mV_sN0uW}Usy7(4SE zyZpX>DwT~?H{omLym+s$dG|}5m7O3>HJdKK%t5!MhFe$(sVBD@7BQ{dnY@|p4dWdep1l2m@_wng6Y70-DvV6=6nIhKI~g<*w7!WSQ(@ zuvsJislG1nW~`gQ$>R}lgYf%J38SxaI)Tr9nLA)}zDYGfxwTlCuu*0+J7spxenzzH zwj#(^jmdz#SD1*&)KpfU&gwcP6`(?!(adVF&y|_e!7xDUT0?FZNg>=}UQ(ajd7i?l zHg|PZ>u6IjQ&v}M-9f;EVT5eJU~{vsOb?f^zo$AG>`I~mKRZnw%M*Q03MMsM0+iLQ zb%%3;sf|j3%dCMb)=094l1{plaGMKvRhx`NS9Yd*ke<~+ugc2Q5Xn1-NtszgTvnwd zx4_E^{{M-3qaDkV9NEr{r29Epb0q;+`VRpD^#4C~r!uxXNz(&&w9pR&^q{LUBhJ~| zoitmk?!8&-Wsp@EGl2f&HI-2y=nbnu10Ks+y1v59zSCGO) z3~=&P-mV_7;aWj-NfvAShBHso@%%i5&8Y|=OQexjx8fJW70yyNn#52jV|xSaQg^uR zwPEw{%OW8yGfp&|_<4Tts=U-{X)Y0I&MXtHIsq~;P0WDZ^QZ@YW2LUHo0l*%KUFY( zVtJT(p!0oO0&Yf&Wy2X%SH5ChG$$-#KHvaDlkM&#-Tb{X69hXe&*l8UiM-cm?2y;` z{U@08ngGc2Bw9`vuy?d-gfBkyGU4q~tGavCKO@W~Sox;*H9RsO*n@@a+!Xq~B~%M& zPJ*9q=EfQIi$WVnbA|`aE7PH6;cggSL8Q!qR)_Bw`QMb9a9hCvcM;|>NJ+r*7OPvQs_red zJVFMV+(wxSG+OG;s=HzVuT82tv%BZ>4DagErxm3}t3kwCgh3OY$*TMDmy>3!>AFxb zV;7#kM^ezI#;R^mVPTKR?YJZ1;y59Zvo?&hqFNCjHcU2abg~FU+#g1 zywoW)d(=eOYrpQ`rW$2-l3v zOX{$InaL)&@3z#ESq<7BoTO^Fzkb&i=W_+C%E}R9V%D}suj*IFYjhD2@ARJ{ky$p` zsp)z+h9V>Rw5?z!=+^XR+9THfL^v(zRQ1hl0kjA+hmRVoYaqz8Wm1DJ5LHchsT@jF zcQ+DhgM#d?>!6UfTe7%;b5;3Io9I zK2QEU=jR-Y*lU}OSnhlNKO+eSV&sLy`iDh;6}uIUtugngx;=q(ZmBJpA5F zy*ilA1k7#qb4UyGd)~Nx#0SK4i_=&KBV17pTwzv7^E{G}c_(G|^PGGCvfJopuGYz? zx^3iqVWpedVXp4%VVu{=Qv;|nuGlbZK#Xq8JiyFtt&eZB$Xif`6Clwi%b?Ras)+8Y zJe}RGr%GxCvy$MS&!?)*xz?W%Ot?p@Did8@Z7Wvn2`1ljp{^>1&xRCwHPPX=_wGj4 zffVkY*PU7S))`1#PA$@~%njIUA^Vrb+dd!AE_eR<^JkieQoDJVrem_k>d=Uo_b^v{ zZ2G`b)dgh!nUdJ8A}mXba5>1p>o=Vx_pdDH3afD{6 z@!WH>jpi`Gnxt7?MTAqdkN_~&dkUQ53T$rU$Se;)1&xb}SGm@p=xt6o`}4_GRvBQ% zRNZ?g$2g&fsm+ZZEjy=R^xC1|Yey^3zmLCoKvh+CR=>-5Ek-Q&Rhd=y?XSGb@-}CD zZ0HI=d)SEL4LLmKwLaurgJm&6VUdU#4#Pxo#Y?-V-JcBD0x8c{SO9Y!YMX3)x7k1* zRE?}+H;nuHg`>spno?>`E@gJ-FWX;PMJNI=yLH2&8+FU}qI~*encb3T;|Cu0kC|6X zlO^tUcbQT4qAQ@!cfF$c!pqt-WVehBN299gMvqS{3-8LR8I|VkytgInSjz&2ZZrxK zJ#N?Y{N*&4s?8y&q3|_CZw;#vt(xgXKbdeFVdu>DU^F^RRWka0j?_Ls`57uh9=7+w zc*O}iW!+Wx+~)YXA#?X-7PAu|O4KQub+f=ujb`gz z*o>f=n4@H+O5-BU*b6qoDMQO%4k06!8>;%8?7~R9hwS$|0q<^@Elm=dH0O|WgP!@s zTBJ7!n5ueC9FE0s$2q5}U=A{t15+~TtlVqcGAGSm%Oq*BBElMwu_v}68wnK9aD;nl zg3h)h96^Azmy9!@WJ2h!CVhxP<7rU7JR@?Lw+-VtkE*K_lYYLf3AOk9^xBLt2kZU# zfj#RPYRC52gw(R-V=80;B6|L^1w+^}ca=QMJz%XF(3GkZ4nk(A$zYIz3q3)DQERQe zVWvi#!Z5hTyt=nqDHCOLoa@BR1GUl6cB^F^PT^X68FKas78>{+cuuNoEo-%UHXz;A z)19E%>lZK(2w%jD=Cf&64nSDSxrJV;yb* zsH}Vb&buCDjF2a9Rih_u(Bu4aF6Vl(GVd=7(lIGgk&w;hM3k`CN7D_HT7C0$>)tYA z?QP`nvd;Od(r1554at5R18l)it$B*^mrL87RqeDc%nC}i}ucf)vNm(~rsLuHb zPrVp4n7Vor8r{gglkcm-`hH}?ajox%sBR0jjAo7|cpC2vSyO zrH851(B@L#%A#9?XgML8yQ#an*8oy{*nVUAbutLdw<)XX;sD;qyWu1HZsUN$N{)a* z%<5Y=>(2Q>QolDG&HvEC5TG?i75hfdK?r+q#G-L6kBH0!=&@;BJB&WkJG5Zo;1JFJ z{Q2km{lW}FCEyxAv#iT(WDBY$XnV_b@~69Q-l=MT|9rbj6y47~PhOe}UfuUTn3CDt zUm_-9)w&-KYz2XanEPp&FYp}jJs)m zC_Z&6j&Q=v1UDdybu(e{`K*!vd#dwZi{(QMgzt}MUe4FJ;j!jBZ8q_hQuj>y!aIWPO?=Zvj92)+7zeaTPIk#}hx0beokR7!gpyhptn2vo+ zpS^qAnl&Y$pk*Ekjk?w77Y{-AT!(qD?1U>c2lfGiLGd5f77W zvMNX1{YGB7PPSRx2^|tMoN&4|+3NN*A@VDXW z&f%gqA>vdCh#64~YZ5c&6-r$*{A{(V4?uXFygxtxlJ2&;8|-k0>6|kOtNA6}9*uza zO@h_Ryao*~)aVmtsLI%3ZLskoa7Dm4n5;%e*fLLnJ$4^?`0{OL&F-wczX$}20TRBH zSO9=jKd&-Knh}m0y52Aw%)@Ejd|w}fiHn#ZY~3&H*kw*y;kL73OAOJBP4HqYH3fY85a_uy4_rK|`^H*dn;OZjAVRs^7~S($cElC9N}dkl+Z=GxsQ6=!TTjRiQw(E*-J zwou4wGsaAMOC}B^Wq{dekv#^6H!n>vY&fSLW{fQ5Bxhz2PN^o(1_$Oe_f}`ij^&E4$V?zTUhoWt_WR=iZ1Nz=VapT5CZ5>Yj!q*vRjtYNeO z0DNfCZbq{cu4VrY`8Ew$Ko$cL%lz~*Cu(YNvrJ7iuF$r zY7^N`J6UW0Xjn<NxU&V5AWJ%HKA)(#kfHnF>@&gY!xN7)_=Qq`r|bF*f3XY2F*zEL+w zG@umi!EXIj4hQ<4G;wJ6G@FPW$?x6->R!r*|6Elw9-dY}6$GRTl@N4qNk4y|d+!Jk z!o$NS#XX3)fKQ-kg%cKL5pL!TYxJ#r?lpsjnY+i1y=a&=&J_x}Ck=EoU}(KK#xC>E z@=%q~wqnPsN+g1;EQ?6%`Fhk%w&rW^=IgUC>>-1??{iA|d&D1Ht)#x^iVYy3Fj|;jp56Q^eo(bxS?*^ypIXOe1MOO)d(|>Dm>?>y4nh;8DYFAr}68o_kz&f zS=nc{4=R+K(T$BdrAjExY{f#Qy6A3UC;_(CH^Q?^knMMDEH%xtGjE>zbT!#wzW1Jg z#~d-{6QQd{le#y@CMJMXm{q5F@4eshA=-_jaS^a=^&H{ev4<^NC%e0YHeEUsCKY5R zx0o2Y`+S?j+(6uWp1w}dtr_DxUg1VgXoL{KF1p$Fm{aWjd`1>2NCbV`3n zWu?cS^`OY=GNYvVbXDgke5OsG&&QXeWu0!4y47{>ituGdbBD-nYq*gVns8{6gWK0@ zM(GBmN=`0X5qrB?&?hw)<|2=-<`08;-M)|AwSDisM{x{Qi7F-PWKSAd5W(Qb{PWqe zt~#c01J!v8;G8NOF!Ro;zVA)HtEVeuMsjpI+0aXe3!qeb4G+-vVT!-WV+_Xdwx}gyfLmva%*i~Im8bm4c5rmi#o(f%6Rc$e6 zj`kP*c3Y(aMu;ia#FE_C+RkuWEZlR?bIlkYVY`)8rD2SYq>a|8tA5TIqTbLqry(k+ ziF>QM!n|(Z$|vv3G-VhjkAm(CpZFz4wjJRl1g{!vz-#JiXf7{Pjvm(nB}^y8VD5lY zU68v=aJN_s0MSOSwXzd^=WjF9v{7rhnb02As)%Kv2-7bv4}AZF>_+Jh|FBW2A~`V( zwiPCufg)Z{OQ)8*N3w zu)lwNxx>0H^j<&q=QDwcnf5x->RE`cwS0LCcVv=XHA5M5HM`{`$;!@KEv~)Y-7$~T z@g;YcXd9+<1oY~Y69vh}YOc0r(4BTm689?|NNg!HQJ3?HN_^AmA9(h+{c++f)l{GcdbRlbN}6+ zuYq0nRssI!vv1?)=kH#zNYHAu7m(=7?3FNQ@32!eSJ2GYzyJQP0oo7|htn*kg(-EN zT;D${RHk{%lL;-b9mHDG5f8WL9-2E?zrEP$QVZm$VPArKbS6a_Jl4<8kEEd| z1E6`{GKgUkx_gM9UH$aqzUNpQVY+2*_`Ttmv|=}IDnIeLSxS{=m}7EIV5Lz2e@XCY zy#UZGg}v6Qa4(34fZw_^)INC(-eC@e+pxPkh4Hn`u1X2Hubp+xIFR@V%TAO|_KtmZ z79E%{r-esKsCL@vi>5o^%Z-_WYOt=76(x8UCz0huyD#ZZX*RqpW zE#F%?^!*71ODzxY%ozZiMR(5Gi9~f#fYBn5eX@M9Z-*~;=3I+=o@nLnox0WE&w`kF zX(5(sGVMTcg|}2WD8A~}jy=)F>#i}z09KWlX{7mbyP0Z)n?Q-Fhw!?` zV_A4Ur^$c*`BwHosjAPIZJ_xJ%iTD~7Y^2lhJl)^A@`W5CLIIc>>dYd0Y1iAb6??e zw^#R^&@0P51fko^2vm<&PKMW&KJ3@{SQP+;1;TV%Y^S9L{7k5gE@~LZ&(B}Fji+v! zTt-6+Gp6mitQTGh6RQPi`GQcWf$YsMKx(JKhPXdWp0{WpYeuXv4ePF~X*SEKwAr7O zhSzLP^i<11X|1vUB0FuoE#Y0+vQbjhZP|DYr&LK~!RC0LbenEaX2S;4%i+jRL>=9O z=o0ld#fRBYJ(ezkT{$jAkX=f(b4KUjDBZ{Ur>2J_b5v=5`}6jbcBUBMFg)RqyYKH89xb@94oitZMBL80 z1?YBHpP@C)yJ-268aA_;#rN}5Yk#V(PLm9ay2n7Zb!wTDKqhG~(oAz*lu{~jrWct~ z`|_}b7$b8(=O}CKJrM>vx^r`xkEZH#ODb#gd!Bm>c|pbAqoSl*z;`XS>ZYX5qVU}- zyPuOHIgmtmh7S*$Kv=Ay6B=!ihEK$bsZ}$dqwW>H=HqpnP-Xtyd%IHV#>t{lS@%9C zpTGGey$Q__KuM#F4eS+yi5)(F-j}m$<^)Q1-VmX4#k~1q#|pExUru1DZ<;fF-8_?Y zpF3z*b!YWy_F9W>5PYv{scU(}3~;6SEmc?Eix;~gsh_?g+#*&~W}X{T<<%q(tF!am z%r14B%))*9K*!;HDd&PRcdRmjjP=RBe6z1_lzezrx9+X%YKd8OyI?eilgsvGQ1hId zmvqqU^z)pPI_I2o1rM7|?Q&m}#nGF1B)Wx8bxOmf7Dt!`Wy>*J)IDoK8puKijJN(% z0BXGIkn{IPv;zJ<&-3%dl=Vgds-;my*>i>Q^dG2*ivDg~e2LGb^*^z&Ae+ zQa0;i1_Hwo9Q$Ea<}J4!9)CU`4}R7*ILu>xs(RvQbmwf$xBa~r-K};CRAracW&jt% z1ScuD)5Dd0^Ufhv7g@qYk=-cKHFEqBaW%CYU&09ymQQ4aCQdaGRRadHfe%&cY>8C z?**zMrz)Q-A-PpBet2G4x_5vB4X4I0waje+RG-6ZwB+V zrhebQ%L?a!elUEzagmatZYagxL0{Xj26Q_FmpSHV<-q8PhMLjJ-@mrOMp*j3ise2K zOb({O16}uAfxykodyhLl>kAB}*C535@7^rTY`(fQdl+y{_&w(6Mgm!?%*xEVqS0-l zXaJ_8HM%L7x{^?{zB{IqNX&Vr%?xI$qEW2@`4<`%!=Er3faSXrBIC2w(~q>Q>f7d~ z?o%}zJb~nrp#@c+pYu9rh?45I3!SC9oi$P$qA``{oQbVCgl^39T<(+Vu@%eRRSnfF z+np{Wrgbx`0vc>BU#07>d0D6G-lT+ANKj^BC=fpULt18?JW?|NOp(;ASm@7M;imZ|VxVjy)T&9% zkDB28JO(UZ5pHul8vZLeA@;((S=r)z6U|4DL-P`E9@7X47~$dWYdeE;VVTdY+cK-_ znogq_5uddhI(bSJpB*b?_P#Pv0%ndg;~FCxU72c9p4qdit+B1COZA#kVws2fB@;B; zEga0s@Ti-ub|B_3(WL^-nk1~NNf~`AQm=*0>2#B!TlXFs){a;~Sfjey&FNlH6MMzp z4wEQi_RZXM5i_lczwQ>_4{6J{$8PjZh--^=IwudNOZ` zw2y746MF8Gs*AqLfA5_hu-UBZn@TrD7+L_`O*S?*spOclC0coIx;sjBJGhO7*Xqzg zXPdW$0i_k*lsUr*a(}kEJMV0ahn{)zX((1m$~z5gW>=?-j98%6T=apg^KG`*an$@-Fv2$F0oR^imtC>M?|U*5~v6PLc;Uua`C%7TvsFl`m;@ z+PEv@W9z%!Eh2nUDCYNM1Q{?`-HyEgJof=OA?0O4DmzKD@bLZ4HgKQ!0&-i|-kPL^ zEppAyz%AT@;f$GbrkSNK24+g5BlDi;NG)TvPIhM*?KyS3J`t?)u)Vhf4azt`-gC3r zqujMmpm|T_&ou|Ba~^;S?zOl7CWfnfHdR^w{(anR83EqRs+xM|MD78Y+E#40M%rYV zR8YIg!&_wzfDN#%jWA`GV|h48sD4h@H068p(=KW4HK77Z&(B{Yx5a0Dx)W1PY=jZU zA(Gv`Fy4CS1vG2p{(Jzy*e2ic>iI}x0A5{YRxOvc>fVHDd3c1xs;Zk)m!M<$vMB&j zGt|$XS`X;Xl!c?J`dX{o?k(aMdO^6`o%|j-8-_|P=XY%qng)h>n{^IFhrfk|xOLC- z$T<>BH=hQ7jQS>CB4xNYqGi>CPw9q0oIG>Gt1c0$G9#UX?Ci>a|Nct>aFx^DDnS;NPxvbCZ7|rtZoP-@d}vQWu2JUT=F%9sU7v^LEvo&V#m>!PN#DGH+Jd9Q;Oo z=JY{H0JCr-fQdk4p1eI}%GXgnQi(al0#hd)&Xpi_4HF?p?I^Qo&T*-eJ-4VSK6)4d zpn+cN6K+$Qjxed_7KeF0`9!Peu!i6h^|v1B0SfMzTw}PI`x=Vl_&4a`GkBW9YL3kX zcJFg5=`>U9CF%B6NtJ_gT>Hz}Kf+=}SMI(hk%Mji<&W<-#1o?~+J z5ZNka76c#0fZo`afKq4P^GFJdwYSsjJZLm0OTsA(xS7Sk)9^NwYdCf8E3$LgqNf_L znEX7-h={PDg*#ncW?1g6swz#Cu%#M5M^zWQeHoN6ti52m=f{Y1Mprm|IQ0viHyCW$ zEJCNr?XP6RTHQ{d+_;vD;T|GL?~)lokWniBzyIg|RoP_6TIc6v<=UUMysDc}l~Qnq z8^CkZ2@$utJHr;C&-e59=QMW|10)$%a;Gbtvzq9&;I%O0ooXHnwblQu9NZE0sdrm)t~)Ib&v4E ztnO_POzIWs`DR_6=j^p_-I=$@aef|?egFB~YNO>%GZ*tMkHPj@|NZmd?oRRcHCvQC z;yGu3R%bV~!a@A~`&gLE2qPK}Qgze&ovPI=I@w7e@_)=H14l-n;DSq5USc%Fx5q`K(KoPN#&4JZ@1BImHO17_|NxGPgJ9-)#Nns_&RZxRcdUY?9S@9tRlIC z45DwB!{{skS)_|np;>Ef6vY;yY8%kx5WGsp2E!?sYqsmHtn1-MN7kL6STwa%*Oq4` znzRYan45Qtz{$I4n8}U=(uMjZm(qP!Ob%}YVTOVEgg6F3x~=E_xVtm@z15J$%Bn2i zUYP>I7O30p4TbUTJ;4YY<5h%!c@Fm+5W2GayT9y4*gaRW?p%AB*}duJg&u?Z+od$t zEz%Hl@Okb?!=xTEd)55lRNXP@WWjw1hW&G{`NS{@6KN-ND1p-g>wE2&;fNU~wdS*p z7MBaJPKTfMJU+SeMe?Z8*fBdDuHeEn+KptDeZ6xgUla#;8YRb^kB

      _ukD`?ey&Rxsq0#lV9cJDDP z&VaXP88T7A_x~!}!)F-*noxDqjLroLKJZUHm0>ntVGw+0*YkjyCth>7?=_$OzIlum z5#6Idb~cio&l9moe`nX`=%U#>9|zP$nlDERv|FdUS1b@!IU7n?fN)@@6@*o{vtd5w zBUQ&|)0j^S16j828m(hOF4=O>PIj28gesE0R%Qwc4|B_NdPqeR?g0U0$&G-zVa_R} zO!vJ7H%$G^!|vsr%%0E;AU}5X@Bl8o1}WR&O@UJ!Xt(?p=xB-UBqqt5@*b zJ*(OgPBdDeWmP!WUMieC0ka)yjk%2U?!;Wby6N631552#ZOulNVvpfjOHrLHb^_hkjXL57aJMI}qnLu9=kTN?~R5z*_9>h5bYQ=7Kp#uvJ zz5CqB7}=Z_TEf(Gdg4uTU)?!3$@zOp4f7S&SudUGC1Lk_OAz3^=bG8z%xB|Eb4j2k zvJA-A%hVnO%Oq1I+U9j*%)fI!`HgqO} zzDTkTEE2L)mDxcqk5fO{{r!BilO;zVR=+<)b(c8{=G~JugUlT{!bV+p^FUy?S!~qs zA~nw-o5oXkWVa5vC){8iQ-L=KPBd$Z@6UN67UuhcXo-`&z3OTM;^Ro$?mH8Bes6(R`s9H_uuF2@P9r7urEj}B2O9wyvU=^a>%Q%41m1-;!eDcY4fB| z_s#zES+{E_!cX4VAIDPV?4w)e{_YApum|U6Rsg#Rx?5$@!XQ~Y?C*Kpxc5?as+%3Y zI#U3Mdy>SH6AO^ZTHTDjVDxh?Tokg4Tq^Oh%hg;X?z7{UfoWIn=h}tRkwKEmek8VGrO*bcge#}A&h1; zkFFF&fM(wv_j&%))uGAUI+cCC>nqgH^Tf2lEKZigEX?3=W0x7b5g=n8USSizUhE>s zO1W9TB?OsygfWZ2oIHGOL7}0_o`Jgz1KY?q_a}Kos&wQlcEnrCg8+8QL*%MXiUp#z zm!JC>SJzaX3v`((6T<#{@+90Uds%}J!JPOabjrCdWal%+j`{y~Iy{69XG3IGCY%Nd8sUsQ9*Xq8%2HUo9 zI?mIod}9PQJPg1;pY-b2EjVmMOH>PXN3wm-U2gGp+D6H3Ew_fFT5k7VxA0JErekA8 zOOqAa)l$31d$t3{A|P`P1-@r{)Feu+qxIbr-;B>zR^BwSs|2mJH0^DeVepI!()MRA ztIv5R`UHdDE|eiG*d$C@2MJC?Xnp#oW>YDjzHF@3T?VUapS}WzF3MMMsrTFc@lQdG zc396ab5w4r1XrfzA_(3i)(7g&=8)MP>u4ni93ce5pG8Ht)7|p z(;009sY8ys5*fs43HeLsDgv- zMq^BvJR2>*5Z*N?Szw;wB!20=AeC>2zL1^m1L4ZHvFOmI2{sOq>Pyh+ug3>Ps2k2f zhP13}aPwm4^ZoPf)^i>+A9sYq3|<9b^$!Rs9M~Q36Xe>lYEw z(%}4ide*a#akt-E2?j8_W`WY#B!*1TQdXPh^AB^OPfodpEe)@;QRsJEFM*DjaZ=T( z+HlYe>@E$hT(DXFt;if#u`-90nA1lHUqs#cw}VDszCbjLF)a}<%`=?7!b-4;HVZ%Z zncrkdRS%cPiea_Mxc+meThY=j85C}LQ*>MQQZvwQ3-(U)mvi(i01JKZ-Rrv|$~sS3 z*judz!pm%-3FLd%;*9=Sjmnk~%V_j*Vsh@|Vt^)Ok1YYDFATzmz+OQ<;DEKKB}!N|UQtN-~rw3p3JI3nr*?uLZMnas`3?mPcVjOv1otqzwj@BbI&b{VJ;9^Wlpv)v#x$ludmmY2%4--CT9Q$8XYH3 zmcHw2t7&~s$6n;ffMCE{PPbc^WEIS;x~yg4&pGa<);w99n}+4au*`d(j1@#bKgUS9 zO?RfcuUgrFeb+}ml+k8F)%(M0wr&f&vd_wt2gcQ~Jz(T5(V%gF4j6=4wbq)NQD(b) z7bxq_{WU6n&QGjwcUB=H%xXud#dmC!?yfd7X&LUjUd%42pPyXY2=`?wAa5I6Z(LPq zG-pVn&Jj+VFsQp~37+|w5q%8~R^BVoU3Ds!S0UyohtZ0V)KhZS3jU}g*)E%uOD7ov z33r+;x!F18)$gW@cJHa-xagNzC-}0etkQSybBj_eJI^z7{VI)SVHp7|k14#V+KeeF zD_jscg-z2vCktyC?&LC~)O15tq8vk8Mt9w8n^dmNh|#9wYCwa5sJ>ovx->OP(5+I% zch8GDULZFa-b$EFwD+fAjsULS@F}lxP96Y>M~^H4qk>Uk#0FFz8qu7xgUmEY>o0Qw4M5vZ!Sy2%D{gWBRR2i(H zPL0H%W#|5UK3jw9hCo!yhSI671_H}htw9oUEh-1KG%&HEm{urjD>H*wb+y){LX52Z z3r+D2)u38V+{et9M|P>j)h3B;=zFw2awi!lQ%|n7OYI({@;+`3jN3!vVm(kzOp^1FJ z{MQ3LAPjj`%sXf?|FMZod04z?x0O)s9D3DG|DGsGn$a4GhZ!V@sL2gL zKChdCc`RqoS!B>-&`;jkT2>L7>|lsBw>t}{)TO*fs~JuTZK{-k9djdG#O`NzA^ zdGX;?C94uzeAjaR`m?)LRe<~NHD{n;uTo~H69Aaq;{cO^3=uc4)MHtZIV7U7c_16jh?dLJI_&e?EWC^MK7?TnEuU^!A~Ac{kWu6EK3W zVdV*J4$)BRN+(if;xZp>rg_W_eG1by!~UG!L;>)ia!jozT(vCB*YXL8LXvf+FRy}O z8M@85z8}(zEadI}?mh3mwc`8ddvD)P#z%d#j{wp>doN#ZYq?wO%Dz>ty7$sSXIDL$ zKyP#3OWP|!;pbkX8)&{{BA`;$QD;|nH}|SasoxCa@_J)gTqH_=pTCl1IIWvvR{|%W z^W5*BZHW7~>mE7Pb+gR8^+Me7x*<4WN3*^;)*+&C2H<-eZlWyVF4g^v>Q~I;srw*uD4uJT7{0tr$N~bq6V_y3NAmK8Iw|OkI7i%Juo@ zpMt6n-Uy=Ztq33flw0tPF+`AN0b#bx>WZK*zB-t(*@tD{X5Z}FWlo_oYhKbmU*9>? z7#pgptC~}V+aNxh^DbOww92ki=0^9=S{^)gO80jEea_7*XzvxydgWXpnuH;j?`3O+ zh$-@fS?eWTaP*nV8s;87QJ)=Vc6wwceBs2B#c$_{A{h>03gMY0c2-}g**3BVn;JIf z;YttBdxIgVs_Q15!@$leYu$U++QS<%nGri;h|Mq`*S**@b}E($&0wMHCR)>is8iV) z2HG^la*9dfrE_uljK-1DT3 zEO^R4!#f$Hw^##=F-vv}w=z?=>*u7AGTiE%43C;(3oF8d5l#<}D8hcx;dw4exf6CP zhiPw9&RgD6Rjchq-VB3nsHr5$zM7HZ06ns@y9cH!suHA@{f-E#Slz%mcgLrNMBl8= zbPlY#vn1fjo3pjO&-0TlJwJc%O(RC=MgX!dRV&tt2xYZY1(nu{y}u+TQ#5hk7P_+Q zUR5gbi$M7$M|h7#=aWWie3wO8fGE%6#sxGsRC&%Faut)s?W{vjbTKRRhJ%tsV*A8nyD*{?p?#A zZ$XLIjSO0LgM)*g*PXj9Q7C5K?s4H+iV)5%6Ul|asr#s}l`~%;2&<}_Eg`$ky;Z7P zU2}5k?i{DM6WeD;{{n^@;~R40#E39Zb)U=Ulb}iV2E{D^W{!c?gYmP3@^o1HDF>Vc_Hh6&4Q`tB&yP-0kPL>J_4j$hNxyDX%^maU;J&&<5L z8Z}@~mu17pDNfKFl)69-l@468K_1C%??~TO)Ck$nfd--72G-2dddL$_z5A7T+EB@R2ACU$dJ6=NX5gYxWGZeJtEGhtb1# z#GaMuRNXibeoY1peUmm}zMcw zi{IRBL+F!E}*qok*aBg-!&v`2GYCBXkzKr1U5zFSAr54R-6wDC- zWf7k*ZT{h-1c|IxX|GSXJJD|(VY~^5&&Rnybd~$SAG*fOnK`=5F>uj8nx9@J=WYp1 zlxQFmX0g`NAn1fSH)nPsHHQu2HDh&kbqK+b>X*Z1!20P8Ju5 z$*r43bvBYvtoN@-_v*ftnVo~?YCtCRll445UCFRfuiodG$CGAdjZ z@6a`w=_YT@YhgxzHP*YEttuEKnV=RZKy1wm$VujXXv%y4eE-?89BfIzz4zz&_o6@c z=jzT@$lX+3ri@GFLdD@An@rdwwnpw7EI5Rm*3-z1_m6KH9f`{{EzL zua({Rc}`}80qth)#*#(EvK=pdr7*0%o>iLezBpA`ci@)berzLhOQf%hB@R!|Dx zdfigA6*h^T@w43f+*4i8Iawt#I}IjvqqeO9x^u)D%~5}xe}7PiuaJ)vs&AVV>(lHxNq|_N z%{4|XqLJ0lxwgU#)@Fo{Ry(ZPWKK78Vxd)RiTLNwKMk+jSqbC*{3*0B{IMKIG~twd zUYEtH4l@VVT4PJ)lnHyXf|y4BxpmJ2ce;J{qPqY_G@7EB0W$iiWZ76onrzwrERyT{ zai4>_yMf^_4ozojmL=URb-M-Bpk~E1`~3mL8AW4tuDt+N_RPFnviIE=>>h;~j+|z4 zNvEr;ClnU}VO}%YY(dli?4lcM=8)T_)#orb-=EL2kfzCLc@snL97xP`TY;&sEq4>w za&vxmsA~X?Kytr2xhA}$k|uxvj4EY|kp8SyC{!0`Jv2Ve`7LCu74CV?J*V^D3*&&& zQ;?|4+m%hIBo@c{1M3=5I@exZT`y#MPCk}ZXk}H_&1@2}7AbTNs=?fs*_4h&b(Sj0 zpu0O|aO3_g!dtD^1#|#3xvr9*)h(N>C9{%}$x{+A` zjYC}JEd2>@Ce(6$_wK5xlsIiL#}+h?!98|Yz+x{$Kyz<5fCdrXlo_GXI93h5(PThp zW)~r4*GO+|Rw~Rlk5t?C-4 z3g3Sr0W8{E{W6bmr;|hrl9A@&=CRC-!PxsVxmlXknS8tBow0(`TzP|pR9EAuVW4>+ za{_H|dx}$lrJ1`!JskyOLF_%G194*CMYP^+!)qr?S<}YnT|%{cwB#!W5a;1RvjHwZ zRdDz$w;`p#lL&|f(TlvNlj&=ILjoA=1k{iH&(d$Bw^Vk zTCsdQvz3*dgWQS;<w0(gc~a!sE7lt79gXxr)uP;9Pzb10WgW~&I_p20 z(rNow-n>_@BZ03-Qi6LMMfreDmKz~!kUCF|1U$$q`J`9zHKpYS}eEFFf1sV z_BKf{X8xGJ(IekswhIkebyXLpfJLaZSEzsUfHzf1(&Mut&P_uDG_zTJ|NQ$?mG`O2 zVp!PTvH$t}Guw{|VASc4#fn9CRyS%?_E2YbWwU854!0s0Zbn<~_?_0d+uC1q2Y8>G z*`o^26sorobaTtRb8$4cQdK9LT`)JZmIE*m zs5j0Gs=BgnlQK29A_V2hVW`c!|K2i-kr9Jx@Z9pT6W{w}R;5MEUN}6ackkv#h56zV zd(xMsdXt5d#gxoFxYcFiKc8=+P`$#34(1Vt5r6j(wP}>$=jW%<-F@={06C2B;&wB)%BQa8-@* zV+!Tq7PpIi6mpsdZ;8sScXO_$FGn!-rn0nPChs?LLp% zD(_3u@VOPhBWBF*Yh<-VTV{33VS_Umpq_%?wVj-hK-j95M*yhdCr^b?61i-Tr&+CY zQiF!6A}qq4{C>VHQ$(X-Ft_KnG?{X5y3-sWbgP?^V|{j5IF0lbAu+Iv71dz5mZ@6mF}D5K$#}3KMS<(&f6|?U_K;+lIa?Wy`H>16udAC z*Cc$K2JBd>rvE;-!V_(<@Atoa-i9c3no(vpq#k-WJ+{j7=DFEzRLdj-UkN?4s+8i( zIs&b;%^+Cb{QLadsJ%A9hRCiu<}6h{Pu`?KRkzdpMI*u(nB{>guSQw|nmO(5Zt7MI zRP%RBCeXQ>82%)Lzt5>mcbGA=s(UD0M%>JE55cv!#LVKLSF=wg$noiRjny7DM@4|% zc!@NmT zz)h&(q`SF9ciXXMRXPKKYUM9w0>5a*bIx;4t7XjYu7N=n9Dsp}SYsLMRy77}$br@r zr2g!P6{V_MK36=T9T-->n04#cy*E|vc(WTu*z0+K+nGZf9YDk;lrF#vgRsGrLmdp0 zk6pKV4@j*`-8ZxD1sc*`YffI{trL-Xhp1rq9T5R)IhTeXJZxTiL-%>AHSsZ`mwQXf zgCSy)l}DZK9yV9gY;+dpR(qa0_tJdgO`_45T~FRSic-v~nI!#1yq2=&2ZqscQ?s_s zR9-EoFSl@vuKa~PG0Z-Dza1&k)^e^I8_GP(rDg6Qsyb`lo|yT2$p)qX*%+CpH|Oyh z4Cl(`u2SFQK*Wx4lcOXU&9_Habyb+78){;`-5$;onP!&vwtDXmjNuAWP~K;zh|8C| zjBr|*tJJ6lr^cDDGXtG?^_Oc+Iv`er`4D(v=Emc3ux<}Y7 z>r}U9w_+}HygcW;&(FUT?V3rghc~4;Z?AYsn9CT}{j|z`t%w!jVO?dU$MSIWJmq*TG>y!R%Dt#I>Z z!TjWfv@8tz&4h(bT{5o?dA6xG6G~cp_1k>Yy;Ye_02pL#;LVf^syzIUMlp3N&-qDJ zc+ebx3kF@yKdvI&{bNIwYtNIn>i4t}d#}C1U=fA_fG{`F_L}f6TB)*_p@~SFO?a1# zVTQV|2&uCYMW5V=xs5hd_qo|K1`!+2dFU=vcPi-ngH}~`U2sHgMbY3;gV<|-KOgg# z#*@nI3&?H7vgNMgNVvX#zWW=`^ZfhwrzZg-o_w;K9x*JS>guv!EXO!$Kg-Q=E=qeZ z%_}yatoxitrijJ2(O)y>hrLfXK?L^lqsb|D-D5C-t(SEWYq_oG{O!sC?f~o;oQ}CR zsHHsJwcKuX_W8Zd$jxa`x50eAB&k->RbXa)S44yWsDFNP#b@oW*f3=$V9-PuKrrGH zW)V~7Z=+Ap)C~oFwFZV@AgR!XF zpj!b1d_j=r8@T^+AJz7!YI_e>aI#RXQMKU%G*FY81A5M*2x@S zz;_24_nvV0{Gl}|IhrxzW01qFV8&FIdU)G2n?b)ZSkinn^+s9uEMA1!38)~|z<*Y_ zyE`rR_85eDs~Zly8Y$GIS3nx7YdAIUuE7KJd&Z!+dx`)%73W#31P0onz*hT~q_mTCrNdl!sREpyZ0EUCS}lg<~Jb!WKbm_Mp@37vDZCs38Mnue8u zL-ZoyU{{O1Kg;6-u~3;;s#$j=sxioS>nfJ&W;gZJH(ghrxf(Q#Fytfs?u$TU~ka(jaGp(lu;nHO$VvJ!#k&wx)%9 zxF-;kvE=AxXR9JW5e_nMnwsYFsX4N{n8RzoHBp>l-@UW5qRE`r#Jq{fSUcRtxcm8h z%sh*LWW(46fzqtTrYFI%Pj`2KlUU(=js;s0{;CqP%jj8>Gu0v@7RKn|?CM*CpKbHk zg+Y;;QJ6k?(S#|Z66Yp?**DGH*~07Po%zXG z?Nn9rO|p(1K4?x_sZZXix497o2A;fAR-R5k-5dy^C^XI84AoN0KTF0!P92~ms+TeQ zRg5?7RE{`Nu(zacR#2AAt--wMG>jl&kknn37o^PJy9mr2_Y@%KZ2bvw6f$aMCt>&f zn|f6>roP3S#pYUT4&qK*9w>6iKQr_PJWQ=<^izWB-dbjRM|-%AbQ)iymfVcJ^%=?NwC3=~5_vQs)BNpLMdxrh!eky|6Lk{kaS?Bk2qbIvetE^M6*>y;YQjTN!n0<~4h5 z$W%}DV8ngJs=EJOLw8WAE6?0fR)i@8W|tQk&c>}4idZMlcKhsw#`Bz(s*)`%BY`4e zL3?g@AI2J{85!oxTNfQfJHr;urD}(3b@zFG!hNq@6bhR7;XCPx=?TrbnFgiWo8}F; z?4pf;UfAM2MKV5iOT7@(?e`87?vOwQ9q@aqD}y$VGAy%M$Ge$_>W15jKbd*^GHkZh zAk|oVyOXcK2`Sq!|Y+KAu&=8i&Kzj9oX~ zY||_5Fn*N)nvjja)>$c_i+S7T*+4?Di998`s@00vFavH?#ajJyv5Y})%uG7fD}3>j zssb+Z4J&-e2qKm_ zi0Tpaa?l7>Z6?vdc12~=P>?yd?HEz0irbalr4@cP?%|ngqwAWlYRwDJ-2t4;AZTdO ztt&e-ZBgR^p8f-U&Y25#I;VC_(&$yV=oJnb>8%cTgSp{W-jiJJGSR!PbAl}y^q1r5 z!yUAHGM2x3+`1STifeS6(;U6$v@_x}6F#LFZoPDyzGDxyel@Gihd`X)^d@()4opP(T55Url+e&h8Ob(`hW#igEO^YK++<_Ohx{ z!^5lE!zDIF&_LNR>!$5}q5gdSnJcm&hbYeHS>W(h--@Kg^Zfi;rT{2tB(kf2#7#GE zS!0;KrY%cVj(5p??O37e+a>5!8r{v6?Xd>q>c)hK4zf8*bhh*6*9YDKv4TsLU=eBOhj?bzmJ7mFDsRxMj`qu$SIdzBU-uZRiN{X8?R=>5Disn8C z%7|zwTj=Q}%bg8JPMsZUjI^6(Gk2xUoKqg|VXYeeA$#Uu!-y61F5ha7q=iB|W0=mE z4PE7#HIzkljyiqqHN(_4dMvdD5m%ism~-M!gu&f~mfh#Nnc(vxzPBUX7DahcRdAa_ zGzj-yc?1MwuF5Hdqe~*fBO=1Bt0x0sVx!Eqn{~BY=F!@rhRI;>wx>EjpC#}I-sWS)m)@4$0dJ))d@n;3o)w=$^vTP4 zCYKBmE?KJ_1moSo7C{PKHQl$#bWrHq8dT3(tJPT@J7&+r|NDRcKScf$yP*ltr?l6e z=g4#K{)B<|q#O=w+1~c^_W?WB*XdN-g`+8+6+wYXQYs$wJHl?pNRAGW3lqqG%4$rgcW|eR;($&to3EKf|X|i9y37!9j(Z{5mSblBqg$$&28X68N_P?}BGZLbZz^3HI-U1lD%Q#Z51qUwl@z3d9x)d|?x zoYcAZ?wSYgzD-{Cnj3gm3pN9F2(2!ZbF*6SR+yQ`5imt~$?_gsVB3F6ZbMv5^jeWO z1q+}}2A@5(uc*>59|r0feL`qw%)7B~xwj)a!X)Kw5kY`A-*1h%3hIJ|t?=`60a&oR zyLwQiS8~knz)#*mj7&Oa#yv80*3A>^)7AD?=;Y>A*DPo>;#83sokC63SOgR+GF6!# z*4=BZ8SFd8I%F2Sb=d^$ofQyao|*fzD)I8FduB^v=7@2yxHl6e_58oCGUy&o@#LwL zxn2+sY&tvUpsyioO6)uV1sRh{><{{R5howG>85Qs{d_p?9L z)F>yuJD9~Z@lBV36N0Z>nr7;_iA4z!-fF|^6RNsuFno?PB!+m?6uN|QkJ12z*c3?+DM?ee*=@?!MJ@1`Md#QdcL$2)nm!&S&T_t5)4~b2v~1n$)d#BX_gV z&2TeQB@9FeGuV-XSzT4%*l@Ny(=-5CsFF# zRaxK9M~!BMhq7*W?EQ+Ir5!OyCcOCod}C)1+m8}Hp8)XlTuFNcL9sJy?N6Pj$+gzB zKBpdUbePyk4fKy)1+`#}0_d`4+qgI&n02Ll5VJP{#%NaPZeMGHH11C8yj9uz^MMgv zH;aV1>n27lFf>hKln$kadc=jpp)t3~jSxIt;pm?9vm`jIN3%G+XP6{=kL>zyu#?9Y}g&?S;;$<0I?)j+J>S*?m+SMIAkdfN@n$#V{L%8ak; zT0qBIl{o`Bh*NDh3$=Wf9^F2z3sNs<#(=5@05>OH$oWFmt@<^bzF(`Bzh?J&s2K(N zXc*MwcCW^B&Un!0{&uU}NN}L8c)JOl59;Lehld`FvBa8DfAgGk&hsEV2x+!4{rP@_ zk?N@poy@ttk!BX*)_n!|jwes4V4}K-n|IjWP9rU=pxQgS8{&%Hoe-9JrAn#Rz0Y>f zth{B*X|{q9OC@u2Gt|%k8e&6MQXT=z3{|as!9r8db~97h2hI}07KsHA=3(K>Xy@F_ z>dL)#izd472IBMi#)my~49-82f_Y3Wrk>^kQ>-SGd9sK3jWCApEPF*5@^@)ke+ z4n%s;{AVSpc{3b<=>b`-#eQJdB3ZZ2$&7FZ%=V@{w7D~blM4Q7PoL*c<|BXrr#aJo z-5dJk{^38*BkvSAZm&dENil_(%n&5bJN>|7DaZD@p zNatv}r)O2~MFyjLy6QP6g0;xCSigzyC87lgm%%H3G z^xtzc&v_nV3mY8z)&;O#JsPGP6VLNx1ksxAJEH}h(H7O?jY0qU{NtIaxz+4-m$V55 z>VDmzvKPjo#UeSO%sA5X`9~R2O5QqXwMSMYEw^hfmxEq2p7*^~^*Ko)$Qkr>SHUK9 z@(~qUG<%D73sY@G1Oj$P94We{YHnRhG~;*eaM9O2ZekkK(_?3z%p;~k zFC!#w}B4HWw~Kfk+`~WW+hiS4D@BqE-l=lj9k*Ti*#2*j?CL$aUY43N#Za_ zDl-tjr$SFCKIe~!nz!$pRL?tdNatimwySUT^p+Kag68M|qY*>D!XP5Znz`>?BWq*q zxpTWmfjG>3jET&XnE^y#ht@)zIDB?9(43wjCnNyf?@S{&W>wGZ@YVC1Y(NCbnjNAA zjrO%idnTXhJCTX$y7ztWbj1?=2Jd~hr;FzEoaa2-_Ukq5I`{Q<_Qum_du#eB3cghY zy-gke2Jm^3_S6u_jJ@E!{l)UQ&=NQLMM{|lGFBtI9Ou#&ngH9~Ek*T6*fMLxW}+r3 z_gnprHm|-%dV4hJ-4+*e)Ij`t|8%VNOvZ-B|*P61o5*gR!aVW~a zE8@76-h4pRzMdoX|geEyGr{usJ_yCx%LL_RQmeXs*OPS5-j%b2R`>Y1LYc5nRD z?!A@Tp6Xf2ByH3k_+N&c>EYm~o{fx}ty3W~XJ#b`kqVIzGXIU2{ECcAsPp_g6rzCG zzb9<0X^ZM!G84pHVK9tUg^Kwr9Fm|;>;ivi5^5lMC}l*DGj;D(Wag2W5qXZsSYDJ( zn`U+IOSe6kA=m5xVc&fG ziLCBnB)R#{E!%a^`)%&w>*qKO28r2a_sl2~{#pFS00WKNMe_3`MdevySVsOZCy_!x zZa4+5*BT6^%j2mjY-%WeO2x_ZQBU=d_Ij;{P~3_oc3+M z?|t`U4g`^TXv)e=Z*^hXqe0Imx`-#v>ltAHH1fnh|9m7cXiRGHMh@nE-~ai(i_;lz zkD_LJZ3#W^0jYJ)#3yy9v9ri~O+wCy?bHYS{r>lkb!23oWgNBJ@2#pX*Pux^h<`^| z0?+yUIe(JzoF_AU`Tl*kvF<5o&(keN-Rqi9M1=A=|M};S7}JQz@tjD*HJ1v=)zkIe z==Q*Yc&oqlwK1+A{-sPibpV``nP(Al8IM7ihtAkgp+8S}{O!N6Wrp&0qmU8Z?d{gj zI=3iAb@yA5&pAibb3#H=8E2U^Rh1df=U~QT1nRzqY_y$}2LW#O6GkXvg^@!M5%G&- zw3CE<-`DMLmw&|6QRD#M>YYl>ltA{bBG|X54aR#f%stgb(6c4Q_aGxDTzuiex4UoEC729V(bjEskM#^*)C8(LBHG zc>d>~KZ6Ocm2_zyvD=i}H=aPmM#KA7-HYH~`cKqk0cE3~F~h@87?-8vZqxJciJwl*_|# z4+oTII9(vXBqXI83(~bnAUm0 zP`vlvJM9_NV7kgbW||2x;wVp?Ti0NSnP-(&@h`K%l-&Wj3cwTjob%^oC^`66(X)Ni zC$ei%{7dS123i%jq?AIc`~6!*jFxui2_-_a)j~TI9vB8SGh}CeB4akFiyU!&cGRBo z#sDOB-~QE_Nd3gRgX)^@>YnF3z>s6|?i(?}-l(2urqN*ETg%HIIAW743JP*?H(j%X z;qID3ckRZf*Os{l_BI%p*v!;^cVtFle}HW=FGIK_gC_6KTfcqhqrm zyHbJ27)``Zqug_`P@o-x2LJV6ySo5HK9qa9ynp^BP5waKir;4y+~^VQW?<>IV~EZ_ zpVYA-ji611amPiyqrh!l>?j7eYm-#VMfG$LLV%GX{~h$+?w-*g&k;nf{JSAxYP#F= zT_{^GQd1t>ducv-pcqgQZ@shY77H`y9BEZWyIEsbaew|ZGrsTjE-z>5TQ%EN0V1R{ z8sPi)TP|NrwHuN7Jeza&a`0!*Mu0*Qv9F0OUvR&~f_6UY3F>*ClaC37QZZP2Fn_la ztkHgUTbNohn=+37m(REicaXxmQ3c*E!#He$&Jt!Ot$MHFT~=dNT+;KT>wg)%^g7Qx9?lf87lA#G z)W1Wtwz2Qqv0Vf0uT@9NBSrYv6?9j65W(Ptc&odMh-z0?1eNE> zgtgFO5+^>~JrQW`32GmbE1=jITtsY^5&~ELT{HKVySFEHrv=YjyYRz!(7+ONXVwa7 zV$Yae{@-Y+f7RKgfp4b{>>s(YtE*?@l?OJEwJR|;ei-k{QLLs^XD_<@;TarJqc?6IgRSb znC|awkZvy=-qq%O&I91@ycEdb#jT4Ve}HX}mh#Cn(l3j*XM%LsOyh)l_|~_b;f%n3GR}?+mI)(eZY1ZS)9>yIskEiLO!x ztsvemM@F7|FVCOuH)T2Y&(NMOS0JeQ--b85t%UHdu^hb~7;(JKzHF2|VZ3#BANc+LrQ%PrZ#Afpmjrjt z``^F$$w|KVf;vGM3f8@iHI{Ir%zZC|W7J&E?-Xq+!RDS$iXjfCuHY@(-i(}uYHtOy zVJI^*>ef^}=ab3r_h#61w;VGv?rra;0`QDdT@x9%n!@i60EXyH*0_Cr#~sR}Xqn*K z-r-1<#Vl_EB@c5Od-xH9q_8W5h(0l?(0 zj~m@1g)CP&y-{e!LDx>@_lMF@V7lBYO&23D20P;X_x&4Gz5fF-GehzH{vBIJS5NuR z=bxYUA%Ss3_@S!@hMA8dK;ZJ)of7_W7G_Qg9MfPV*zc4H0@ty zhQzxCwS&N;QRAAA(4?QEnIoo6Ny`dw~r{y6;=#JQ$PiV4mYtRO|Vi@AuuR z_qTp=#A%<6ITPizqf$d-fu_H>hpm&~~*6*D#cM+RNEgdY7(JwIc<@vSC#2 zVbc+#39N+;_$+999UNfYp0R>tx?ADfrn?8{`4CgLF?k;T&wu|XGYOOjHbT>b9%amL z-VA_U4KPzZP3EA`GdllX;aYM&XR6=7H%>y7Vz%|uc2vf5qR9Xz7*u?3&8>mr_w$;3 z&Yb6y=bh_ykkK@_uc(=jVDv5Fn0iv~jeKeR6*+Z#;(1~}iJNZ}1KKb67u3l!03^4q z(UUP_6Wod9%xuzIq`Qhl2=7}8?yR6@BrlG!rb8@@%)swDMlqB$X6z)vxBSHV)`8!L zaZ|mxT>(eN`@Wb3m!I9Z{rh}#VIG_@5E%bBumgu^@wVaF{=Lz?5;QB6n8}T)gT%OJ z=|1-k*-6}fiC9$N)C71^-?z4^8O+~Jc53gsZUXWSvz7xf5p>3}{t=Ng_5Zc^} zW;(dQ_mQ-_1?=hD2ArYU2CZnLO#nTkKt6HbuAa|{0y#_0cAQ|d`px)&R-mecP;4Q% zDNS2~%$f#&+qUk`INb|}-I77`-#LddQ|_j;<#?EF{bVlF>)%J34do^Aeb6AYs)?C84(1^H<(03aJpp8-T=1U z5-H+-?>Ygxx~mKG{Ei>OEd=4{`2re~i`ns(1w7dIGIVooz!~^!{s#hTlVBp8xqea|C|sYGM|8W>(=e*ftCgk-?>K$ zM!oO7m%V8e{#M~B*gexm2FO)1c2#GlQVmxXXoV#xG*i|6&fkdG*0O|?S?^Uy5sXc} zBQl@QDNNt4zKZ<(`6I<118VB;-&a_yEgX7IgxOuyH&1Xkxm^SP^Upu9b>fg+10s{R z=e56e|NGzX>sh{DdwM%mT4_#^hz!CE-X1K-N1Cc9pMU=OL;BX;FwZ$T_5k_G%m`zu zcaaU#J&egGLpgh%shuuzgC7xmGBzPb5{|lesU7`&r&>Md`D6Rudhd%t-3HvtOP_(U zcV$I*Ck7lD(h))t@2w^E9Kh2$5hurrImRauKNC5KlVBC69);OJkwKm8tY9!&+H(PKoi~5u9eHod)GnMGxz;= z7X$HR#&c2&Ov}uZftidPHqLWSLLAJk-b~fPB{I*3g~{li&-0u-f1W2ZPGqCs z{{F4M_nmudzg+7YTtB<*6k-s;S>5r>6UpA{ZmgUG0?pfv86>OsYc^}6OvZ2N+_O^H z?MR!>1ni8HksxNQcxH!pgPz`FJ|i}4x~lCz|M`5LKQPAi?}pT=RK(!ks(;Bz+Cs3HNj_hu(yam-80Ny)sRrVI96i0+C_mfP(;5pMuXaDV@P z-|wCIHTsaOF)}{Xf;biE>8iTZCuDop%oxd;49)Cv^{Po{$bhxhn+SWzV2VWH)y;2MkEv6HQjSB;n<%5b)F0` zGq#lQgQD&unuZuUBvD@7p(M-gUjIf{Yn@mN=vgLL8?&!D+7rRglf-6gui%2`r4 zu>)9am!OvDOQGC$21WF(ZNV96d!{q==RbcicVE}P2`;8=HzekcU1B>8^WN*_7cc91 z_dO|(duoh$PJTXlRK5NeZ01K9zZ`fxH0_;jdN2m(PSwm51~b(IPTwlQ#xR298teX7 z8rE~CIwJE)hQ@>Pb|yVdF%%oM2Zu(389#pAz9MgR*LTtE+#>{ZGD&LP<*|*RMOI6L zx9)}|PKYGd89Ml#L_yDfA_U`vB6qmt?vc59^Bsh5QZUZJ!X!j+%$8yCt=_-nX#jwh zs&5QO+%X6}UEFg_4+!%oBe?GiaiE@Q;up4=5>YO}3#=FQdxy>trZk@F;^y#3xPJjD zXkPDr@>T&n=locq9+8>PxG=pP9sD4ZTaK~`nCm7L1IG2pGrLq8Y|Lz%ps`Oj!$f-x zzAL#lK_&BN9R624wR3Q)d)p-~aPB*^3sCJjS=ipA4UX%*-}}Bg=Xst;=J@%X*p$sa z9*47LHBPY!5{DdeKR=i*2rG8j8Jo!G`J8hiLi}Bv7cUG@5#`n%JcT2Hz2yf~#b%v^ zpI1A1QttV61?0#LOK{C+=y}eQk-vxjPcsYKx0}K9=g)sW|0r_Tq252pY;a*?Rx^!_ zk8T{mzt3mcqwno|UkZ^rI`6&z-~ayieQy_T-z^qc6eB`0&`~Zp3+$frD2$qV%Wu`a zg_$XLyQ*k?>z%H?WiB`O2$AQBh;>SUVzt#8&Hdg%y_dj|a~lzsgO++dhE&@%Ro^M| zbMm)EU4$D^_bz95c3?r4yEjxW?dRwTo{X9MIiH@n_0DwWTHo(?nnAm1&yVPLXRIfs zqdbw>_a*p=jOW32L&o=8c{0Rl^uUA6?3$AgsVB4E>)IB{Dl}r6DN;ZEInk#zYQs81f}8tu=CGR;GB$5{e9W~d>-2~ zZ|@snXUGP6#E6afZ+5srPj{!zleu+*TW{OVLmBEl^vl3OhEw+agHwQeg6vVP4S1$^Qpf7^FMF!cZvKH9|1oe zlv0fR#7tNFtvl0$QZOU;whRICg6S0M>+$f{Tkq}(Z5uqR=e~dUS?2!1%E!3V_g)ew zWDvl;?|ZKz0s>jp*JB|S0VPz`-|v5U77O62+DAb?f7Wzsm~>-i7?5-@m~s8R?|p~n zuGu9-I50AVo)J?SE55=EBBq(2M{$;?w%5*j@AB)DC&+%gyMj@-%Pnn^!=z2`&p(c^ z=n4;9$sbeCiu<-_s(S_}9}?Ab@68hePbxAAVj5#H;T|&))6-RN6_{JPLwh#jJh3g; zq?B|mNFY4pkd1q<%XH?^pMUN* z$gFYq)O`=bh<2O3ndWXU5u>UDp6R~5-v>x>o;zLM^P?4-pB>Lcd0Lzqceke%tbG+i zv%gEx02ywyF^&JFMQ#NP@+!u87K*pD=0fw1{7$ZZVMn?@3;D%%q=?J`Yr+V z{eH*xW(s%mrR~_w0#`kzB9R-QjFckUjWMJFB2FqJ*83ewX~V>3oS3Q1-4~?*D#Syv z>YbUb2UY(Ps?6Aeh@tA+cc=5XbCGGI3oy!lGJ^sByL%(Xc>h-SE1OhRxtm+irN&-2 z4ly*Ocs_sjTLDueYU?%%#0_JV+fIIV-vXIPhA5Byc1uo?gd2a_nMZu zgRoqA%D=M}keNpcA(q-SJKt@PJWpmsMvBazv=V4f_i%!O)am z`A~_4FiCFD?-u`C^#NG?Nd%w$K)QkTPe|lpm~=tgp5Ffv5cOVU#KFw`5??#v@5Y^eyX-{txU1i}WMl+0G2UOz*xq%O`+voK zqR{Ri_8?b`ey88Jy!Sldy}uX|exG`Jb=T7O?XF(&E0m$Y&@&N=kR$jkXlS#585<99 zTZFK}1E5bF9Z@*vx7y5jXc+8nH@n(1iX_c0TU4$9ayI@dZY$X9O`&Ahd7jTXx2qaK zefG8rAI13`F?MeR&rrAKTi4@1&sljS|HMCkJ_rPV7w+mU#^vohHJ|fg&;zVoa=Nn^|u2%FBkf>%I{8It_AquB~?JM4o+fOf&T7r0gP` zl6|}1pxf8la0^JzZ05!19Ek1i@4ekUt~+^hdmvSw@!QosBS%;wx###uoLXp|s z5PKSytH++cg>DzYJm=Oo^WoBUHy*Tk_c0=>=k|rAr62(uuckE;b!VpUEiraU?-jLi z+QSGN@nmxxd_E7xx2HU}y(GN_+eK^>xfKt>f=uWj&dw>cN%qA|?YI2*Od8DA2JBRN zEI-MlFu}tF+FcY)PK{yxxc3TzG3|{M*{~SKX!GQt33wk|x-*b_>isq#qc<1c)74I8 zq<%FJ+wknJUb&A5k@U>lWuE7OVvm)%A3nyu#e-*>w|p|kQ@4?fz>qZqF_&R3Eg!V2 z24-mM&YqzKgmh-bVO~y=0Wj4r%|!ghtP!EW=d(9TXGC+Lunq6IP-u+1XZh%`jZkU> z(A;vZyp;epT-5^J?bZ!NZN=DBy3dQpZJ#HaiPgDw=mHwUz)C<#XKjs?U3=*_uWuUO=-qp z-7f(}cHi5k^gJi?U{|-fxf4+cMXs^C=XMk5x?Pv#tQmzsgF$F@h%r^GfR2UMtl@4{ zRZOOct^tVXy$k*(&>_W9Qs?)P`xh?*LPAY#gfDjygqS8}27&>1Aoo(;Rrl6y6VkTu ztM-7h8SB_~c0>fLE=+PT*R#lYX7HRGt}u}xrdpYqXQxOD+4xmEjh@S`bZGI#>>i6J zg22gNGyXTUzXQK^a-7_6;O(h}!w@j4`)l^@F5*`xgS|K6=_&CSX9d8JtZGb;dw$IY zFHGu}XyR(;X92x2V>IXcZk`@skE_dFgzI-&1sA0V{#Nv`hSMgvSM-|N5!V3F$_Lq9 z&?qA_Xm{TYV2KhK(2$hud#i5Gy#qQ=+_?(rMDKTRd*A3CqC=o&C*-g*o;*oz;$pM+ zyj8mzS+~r1==p(#H^L2KEn-;cf=NOgxOYhQ3d*;V~(+X;- ziJ-^j+TumeOxgGPHmJ2l0Xvg29URseMpdIRs}i!iEk#Cp=2!m1uZ^rs7^W736_jOo z#m!s_D!8b}84v$o|Cj%3oE-D^?QShHY$ncQ51_ht`u_RP|Izo2h&za2*G(Rzy0%JH zSU}o2Q~f{RzmfXn)72y!i+-Ex+6-vBPd-6J1P1@@ON?g%IYgfPH5;H$o}RWWA{kB0 z6|-OvNzj^m>*VRWk(z}$MSTDM9r!>0{Ks(Bb$h$~F9x8%mzVG{a9su2)8Mh}g)&0)z{<;bnLV%@T4Fh75b$c|_$>8tu zZ@7l!?LHZK^6grOZZddI`3ln>h*FNWQ{kNh3sbX^>>wOW=o-uLelCsIKo)jckdY&LdwMNiM?&*R2S zo&D9kcVD+vBRTV_DJtd`dh}#>r}X#xm!ZQ?x$K7aT_g8B|2*hb3jvgGXX?(&g`Wer z$HB0?j)~vNZ9Yjd_shGJK$n#=h8aP=w}gm2ZHq9w-q7(hCHG|J=!a!>Tk^IC%0yp? zIE~8?yY~%94Oz6<1Lh~Q)@<4)w}zvVkdO_KKU7Um<>~U z-#301oMo*I0S$+UlkiNBwU=smn9l*6nbX~G`Eb!sT{jSM0-!w$#@&OFpaFWi-qpk^ z1Nr>9Z@2qINWAv~%t#*eh0#0c>YkJ7E=tgjgw$>U-PZuQvY$PCh*@YC*wzCoW2p+WA63^5Cf?BDQr1YdCtD>_XGy$MD*D7uMjj~ zEUpa@`u-*|9_LZNFrBIST|t^)0||j_caY>G{-*O8r{7X6utQ^4cPJus-y0d#RaNKt z2sQ&-C&cWos<&s34x+u3uwY2bkZsI; zuaeLC19%ftV(wKK3U8v9f@g^+Z@q#1m7_(weu$L;rV;$;+-_p1L(iQSO(jjUf5vTK zrakyP`HOVJf&GDFWdImsaPK`Q$fsE{dD6Gudw~&iQMXjoy`+I$QAvQWcWD-;lj4bA z+=X68hS61ZG9XP2h>_6F6Fa0zvC0|yM_D8;x*b+~co>T57NgwpBLtcWv|yOCDTe1c z(+$A0XRP1m=kpv}_r9irG#H`n_0tA910~VBY}r21whUlTFxuO=WVJK5I5-1l5?)9F z#`BY$1>g7f)XB%17&6vaGB(Gx5Bq)BB+)hlGo1ULJPu3~fTy%psujchnh=xcGwuPn z9tgBSHi{#wHy#!Nz{`)^aM6A9&u72n^jpqotafv z`Cw+IGqR^8ftu>idH&wN!PF54Gk1vHQ7mJAU>W0%{6kE4E9kbzJ=W2Q=q@n&mLmcU zkc{`f&q;3gfYxR{x!MhlJ)X=X{!s4#7}1028xbJg6M1Sb#bj1rlA+ud*$UHoeD5pb zJfFIEj7UwJ98oRiRxHZEXq&!7oaAq>$R5*pl!fl;jOPcN0=i#q+#qu73{B16?I8AW z>SmnX)V}w7Ld>UUF;nttx_Xwh&P*GchN7n;VmufsxoR{S_g-x^Xn@=Shi4`k7ET0= zSqCUJb!QV^ilBcw?O(Xoq!8gT|DXT&|Jzh&p1N0NJ}0RqJXJ6M6K#La>Af*XNq+C{ z8iE?F26-mWsrT;o?pxmznR))c-=h=Kbz{1w|Ky+V{Th0Xplw|J-Y*Z26K<3{L*Kgp z`TVKwnh}^8o_@R9{O1WbyZd)DB0eV-@qOQUEC2b2nCgc4$@6w?i$%mL3ni_lNf8j) zyqFNWobih{hv_b!6YwnFzfbtp6Lq@Bj5L1Gv}NqPCilX|9-#8-=QMTgF(%gd^9tjp#HjO|L5}`+x6a= zwjzj131GK$rprP=(}pmxezmj8j44mx`~LUy{PTJK{D1yG|L^kz85=jh@3(qBpGP2s z2DtqhF*eT)=~wnu?S+2p(PYNzx@^xyyXK$IpSR1Nh$B!?vlQ{YeSqtskr{ND(>;08 z_V@39&-nw-wf}kY_SC%@&ywKsB*6vgM5+q*71h9x!6u@;RF63Ed~%o49uNBDGt<*1 z6rG17)c+sH?M)=IlfC+ei;Od~6Ut8Z%sP8rwuBCeY^RV-_8DlS-jAv*5F7)OT6f0`+gvUlxS?l7gqI`ML zXaaZ5$Muj%fh7F0!o99|Z|7HdFi|~KZ&LwqinFL}AZ=+NnB4^rZ*se=ik6BJ!ay@( zGE(SVPnZTp{Y-yib-R*?WJ^eGcAbNSrhlbF#9i70a90hTz z%`xT7mvV7~egW0qQ1k+DXyKa27Rdshy#LZXx){gOI#h^cqMY#7Y`j3Aam$ZYjk)Bj zF#@Tw0k!pyCk|T<-iJ|z)zoIoS~M^OeiasTrxNGs(wG-~ow&A;6FfeE*?_uRmy9pZ zyPbUfrxtxZL&)EYHh%DaYOCi_7Om0I5~iChY*Nnuhc8o>{=d^;Ma~CqTef5z87$EA zeR_9ceSt!>#+uQyU|>M$MbuHV+f=4#>>nf&!RK3T%-4Tq!!@Y_tJnO}j(uzR;fvg} zLYy^p80UiRoI8zqA+}6N6Mgb!{tdfy3@~kMA)vnMEw8%~Qcr`HzxJr8QD8ND0)K6M zAZBskd6z3nwQ*fvd&$a%;mRDEv>wZZlH#HA2cjS->|Ene@t>HM+sz z_4)5V4?f%DXri70+yilJZ|(#SOd$G-JjgW-~#S z8{v8rR#t!htJ}KX#JyV%@B7dYHBT2~ezGV?;_CJbAjeBHMb~?=j2BCUGq+SYXy0bQ zKVp#%Wz_M*z8N|yg8{N2b)x&=h6`2ysQX1I^V@Vw;K%ZJmxk`$?W=%v2E&GUJI)>_ z64F#0ZWB2xR4e6ild^vW+y3>rMxUcH$TDqewtA)v0@GGNprjzRpqn8QZ_jV#?)^rE z&}UegPzIt%H}JllJf$bJ`GRCO;`K7-zKGFMbsqbVNiK*FFmIOpJ|};do%1M}khQro zCjCt2ySCXkN;&>LmzOV3ivI=*)L<@ZPhY6PY1LX@SLHRbCd}BPfg2c4iR=+0O1VJy zas-Y>td?p#{D{y~HBb60+bNK=&!QhOQr}7FUwAqa(}!N?2(&+dG17WCOTawMAJ9G6 z8zMh~x##t~qCVL34pK+LU`;i^X>-^_u^OovVk8VD^58H8r0weVcmHstjKcUt%xN?> z2AYW+6>Pc#w#q4~c(T3S{rRKhVeh=Y4C1(MCyj@WvlGXN}# zly7A=o(kKwv6VM%5;Y>G&K6Xb7DN4+j+VeR%k%WxpFPVj-l!UE1j+`AQxL6w_FqGO zT@&A>nZ-|jt=cd6zx;QOE5s?>RV@Q|QKv&;Q2`!^Zd>lkr?{SeBuJa6Dj42MvSCAS zjnscr>2iyD{`uJ-8=Lj|9%V))w1;lYK?db~^=S$8=v=N2d^s`duQTspnkc{|@M1Qy z;(D&@)}yJy@QJFOal!|6+4b#eIOrybgDNb`T)RL#;AlPkI_Z$OF-M@&sW;BCC@cXl zxo1mR?qDgG;b&7iOvOj}F8T%?&83r6j0>OePV@8*yckLbjw~^gdWzC5&$1NXtYtzF zxOASY-A&B*VyMw(v05>64MCSpz6`~E-s95{`Z_H+X*i3Qlki`Kbp5t|5%D1SJ(T!) zr*rzxM)|v?1_6)NxuJqxOBL!njkY);-@7#0%&fEjiv>A257(*J{lvo? z`^=MlE+cOuMAjDmy<|3a*~GR>p9ZQfmMl;SQU6FdDm?3JTNFXy5=zh(;nlyNWGGc$ zL7oKzg!E<1SiVW6#bzQnO z5lACV9$=DN<@s5=@jFCWMmi16Vc=^x$C=C+shj+?0&}{>vR2?)XU4RbBI6Y9=Y-uUE{78B&D3 zP%u!^zg4}Z2x17c#hhP1_%m?RmLQ(5Qu@lq>84H6xa{AEd#MH*frhEn{OIWhcf4qP z8;2$QNA1>U$>O9Xn=S2k97Z%g)49BSG34zLe;VM_A9>-YXE&3^v^8L0cE`L>tw38gLULD8G2c^n4D zMegeTc3?5XS_A>lvn z6!S2=+QkQH)o4}zxS#wg@eBM0<6M}vWHhkY5e@%f%9`=P8j~NVg^y7ABhk7{Gaqkn z9;z#PNAH?Mp zOvyZZCm_T$RxHkZ3f|oxJP%}96kQ8V$o&Cz&+hE3zGEylU|4@9?l!sq*Y}$Z^Mh~Q z-c*K&y-)0txrOFSTZHRwJUsw$J2Gk?FC!1conOXU*@8d$&88VXw&ZDS`Wb@`d4`CP z`hElZ58!08@jxWbTLqhto|?J)pO*$ zG?gH54cMVogyB*T*ZV*1V#WQxQ4$~uivq*{eQb>&=rw)(@^jRCvLKvFUC@2K`gcL|5%Z`jnHU`u=x1# z+M;9goV6IS%|`~Nn~qzQG5FM-2GX|;<@Z*n%AEYoiGb0%SyJbnf1gDbiFybe;NdsO zki&O3-)*6D=Tf}lmG}B~Ms~jGc>}ZaHEi6wH$d8adM(=-P-yl>$(D~EK?JUOKOaOX&M*Vg{!ry_06!n`~iPBi%B^YJ$=BO%Qmbk(`{n(Q<)NLT+ zq?=%BZWh)#`}2_Zj}38M3Lx*Q5vC{^A`DkzSR-T~Gej7Toe}V)BgT!xa}A=(Ru@oj4$#a<`&N>&!&$ zW>pCFHLnDoq42)t&&*)Z^ZeV>A>F*9^0wj!6yMM;#}BkVu8~}L45~t*RXb;45l)(B zzX7Zt#09D!h9>gGEkM!dAGSUY!M>5fI+4bk?KLT8F$mEDd;G)0V;J{rhNuu1zJ~;- z2x#6Gc;GH7bLI-_{OeJs*m*LvelEBaFXNcL_9Vp6IDY>z8;?9BV$DUr?v z&sP5h$yy}yeqrR zhQsNLzhKR?4gn!Y6N2*iA<620tUMpBJWF&eZ1T#I@n8T&Q@QiciDpjWUI*P19{m*F zxexCOdAar$q8mqPLdHk-_*yh{c{mnxdmENSjYKZ$itd7!pzrRNoR*WitYb9C6%RR} z9i-zTzmw3wm>By9@>;i~>VulC&9$Ga?eH?5#4v6^dHPk7!r?h|;>EfJB6P07=uE=F zYO-1i^y%8Z=IpIT05ViyJHL_IAVf)uXG3{o5mF3sAXhnjGs8GG&!YY`xw<=j?9#jO zIOy`Ge{9)hjTTwGGO?A~C=hC*;aM~FFAdX3&luvJm*_QkKq9tO`W@#q#Fsc_4>`b|_yX~zG_>#cr*JT-*RR)Ex zJ#gqrL54ddcL_82x49g%2O!fB$QrYCHSO=t=2rpGI*HNe_)*CYNo7SAjWzrR?!s8nK6xQJ#a;{eyp!%tmb z`_(N%xP^cj}%wPA$tW*U>-d zx-~t%%Bq`}YmK8M%k7BYkZ|#^EntzU$DhJ;Ldd9sUd-SkZ@A6|0=;~{v!plv7rT5D zws_wl?sSdwcnKz?wTV^?MR=|Clh5yuKK+V)U;Jit%sKct50f7vmbzMK$T5E3-zW&i zZ4hj%!`yNa2vs3;zS=uvPH}W5(Sm|bpoQ?8E8@VwaeRAGJT@fK9#||oj7d&{9{8C{ zcA1bJyIik$V81>h$Cf)yzcc^!iUAlCOT1TQ=7_V(9Et`C>}%^-`*Z=kkycsRYxtFB z_!5-ULZK!Fn(be8Db##G|IHU5{H`CS^G;`${^|YNTLqISY|eV-s{Mu}2_XA&F}Fj0 z-?r%;-__9*47Bdt(rd9S@Q-y=H6dVC^mRA(m2}#x4Se)9eJtml2QMLxCVCvh zW0<_eQrBY9Y9G9toYcU`$p|L>&st_9a!%rwK}Jo;R>z;QBpH4oHI*E?jB*e@8J*Ns zE%)0?=Tb&0NrfSW^z;l2=Z;`^sul*FNw}E+G#Z`F|YSrIdtoxtXWLo*Tj^I3^$?f)M)}vo6&@@W70b zk9xh-_f&@#8q3yHwLTjxN1nAx#t~w~5u`_n%a&mhKQcUVz@3F&N4}Q|R?U3kEbZ%m zm@$@=TKM+P6tRL-i8B%T>Cn(tmUDZ%&Sq>3>tKiRj`fm$V&J&QNfwNPa~K3-2lT-^ zZFdh^NJ(R8(*aYbhM8Op<*{F7C?NPbQ2wI)1+|TR{jbTU&pUSQV?pWGu-@^B!_%t= zpXr=1sNXbKQA{rbK8=?d6%Gjxs6@(OB9XXrAPP_41P-OSkP)Q5kTWZ>4PbyhtSe$p zmlW8eii5m;LD^g(J)Ft0x9~{tPABM-Cl0qw4qSL$p$nn7icp(Dob29ZA_Z?{u;wK*%t( z**z$`cbxs&+gdqui4}SrzveVndZk#WlA~7E8*{WXWFfRoPdXEFQyw|dY?*6icS{BL z?Uk3e?1%l;J1SZc-@1Hm&(;$RKF_>zbclY@C3If*+s$o-I8>US09?PAx|a|7A)d7pG-GvdA|%C8gm+jUjTk6D+LOXhJ5{zoJ#R^&ipkFo$+APWS4Q=Z|;=N|gby za2978Yc5s1kj_pEM+*Hb#Lq=8vX8-{1dEcSslMEGlNRemYq>y;|Fb!8nTPuNL($fR z;3T<|NG!}3EFO5+|8qE{MMRh*g>}V{J8>+dEHv7lXz`nNro0n=`dVXhNh(_MBEDv0)RezbflRWuH|-XdRwEBrygq0WOO0 z*WI>(-&CHAEmdLU*-TZ(LOZLkiHvk$F~76DOP}l0Q^f?;gBhXp?zf-8+x5QoHYmX*`$(iiie$s;7#)S#ssCv z4YP)Jt`+s6fwBRCanTc^xDFK($MJM54?imhEIagdZjUKbNO(Q0*Jm5^5|%&xRz{>3 z55|IHRTPB>Njcs@HX?*Gzxdv~WRxDzlNw+WdYuSGJLLU9B6$z42%Y!8ZrEJaDMR}y z)FH#7#SGn%&TLA!s|+F$Y|Ulv`!vyOiue6+6h8DyXkbVfpg973`ZMBo7ym8kII3~h z7k*c^vU``mlelQtDT7qb;ErkSo5o)e=DIwpLKYI<7iJgflQxWA$G|VW>OR};GFvu2NW!vvqiDzrSZVyA8nZdc7mIMMG{{9Yu5P1c%6VN0$y^=2&@4KZ&A2bW8*p{jOk4BhHKjBQW zD225B;y-TE5l4KB919PTSw3U@qIdB8_vMuYY=!AM%oI6&$?LD_G>~o?QR8^K7SjQR zZjX~HwHpt2NqPRqC918@DK=kvGRhA&RT7}^-l71shTXlf18I#HX&BJbdN91sF9F>e zges+sv7#@ZcC3N=GwBQfa&MpC;zFJT_&~P0XCF#glrhdAzH+mq9xB9njA5ZoZX0{A z0~vj<9;)Wfb4x{Ukk-y-hoQ8OFcbiRIKr*JlFv48jW{?g!D?(0&NJV_@u2-9qYO@s zV5DImK>o@4e7Cr;04b4Y5`i*f_Qk_f^_(SDmH!h zAyxJQ^h32BZxq7-r40Q)G$UKYtc`4%A7AcvWkYQKBrvZHmSDx~yE^_Y^B@7pKhwP+ zfrcENw_z1E+@H7aMZQu_+^({&JfPWqXxXqBr;%f${5r(l3Wq|KUC~8+Zp1zKnn9on#<;ynOgFpj>mc5VF_fT!^UR zf_x=9QvMtY2D(;F==zmQpIPWObYTgU+6vKMVe7Z42ktN9H>9HTVLfCw>wWrTV}{RM z*MlQfi@z!*T@t;-@SDqXQIF<9NSH$#p^)0y-;*j??M-Lb;@?>0R6e-<j_mPYPQw#SM5On6 z_$XLcqT%?mNhoJx3h&B~uUiN9v zBUe8>>cK}U&zKkEbjzl27O|qLdGnkS&avKGcym5-7Ms^a3w7014EZXS=>FH=UAIn9 zetX3w)%>6ZPZ^V$bK8oMuz((HExF^KZ;=^i_wQong;}}o{jZra)5l`P`1)o4icNs4 zv*z>Z({CFgpiHtNPJm&Fx5G-Zf{IGB5~&RA<;=el;g`#5m#S{j^toTR#mW85_i49) zh&rsO+JRmQN8*p;rtu`2({@l@A;?iumaJN)U)uOrZp1frfjdQGjyFYcMGHDc39D3B zMU8qo+5;N$_GRNYr$BjI+N$5}vnGD!UNDYRwVR)6u%X;Q%~#VqCJl69ro)kD7zWt(=0_YpiH65#BCp zW)C6xNPa8)j&vveQ+F$LDu+B>ww%bQh}3D+rpBUdD z~;2SwR(VYFXM z?l!mr&q>;^j5>a1d5}CH(nw&{woT8Z5LrS678Na(n!fy+Z-U5V&rZ1I9@9J~86~M) zS9k)8`ss4DSuzD5Z4oWzEXGOw(AIjql9FUnKl!rBz3dU26|oQ2=1E`mXm=1}EIt{q zF(&rMM;BJxL_UBG_ikSc*Lru1f}=hsGD#=aQ1Wzv4NvisZ^3lJ^rxXO*U%$eg<;F} zY?HTXB3Ep>6JC7B61399o1z^rukt&o;h`L!dzl?|@WTK(5(jyf3pDG$7*RmhI59ec zE+l7=f5nHmH3WLu7d6~G z+Oxdn3RVQY0%T2?kz=;&G9}_Y?b+plZ$+DCC5k3(xe|iBTEe|k0)}2M^3jiM9sVmJ znRw-~edeqT*zL)yD968R&#At{c-)0qoG88KYxw;r{!RrP17n{#{T_yGEx+Vx(p-aT^hR{QeIiTToaH^bq?5Twd#A)Fl{<6bCp^vQifF^_kzo~=7ovO|d=|*< za_MzmZhveM=CTl1IK~6JJEnb45;yI~VjfJ7igJAHZ^^n*b-0MTj=alyjDO$++(*5g z@bJ5!Kr%5yZr0RpDw0giMJ7b?TbYPP>5xAZRvt1QWBg?Zwdjx%p+U9tLmkICZrLYZ zo`6iMp+Hy4R#SP|w$&gbRm67H4guf89sMN!N$aQlA~qS4R}IUAo={3w5K{C-KVkX0 z=k~SnO~sANFLvhmFY8O{P&gKxTHoeeN5AzpMd3-G`>r(#{)ggimROtZQ8%npHVFfJ z?;uMR35rDBC8tB5SL}9S1utF71r$oFZIsD&M#*B~(Kp~OHb2{2p4E#^^FD+TJzg!T zUR^CXc3(N=D(qVusm7!U6awL&oelQl0-SEuW~4F<-AB5bCPD3-f?{UK_cEV{b`q9B zsSUUS%t_STvB$#0aG^@y4QL}m4P9WO&x{UKlKEZCqdU5 zg+ID4CTA7XAT+b>H8Kic95AoO9n8U$s_I&0LH{PtLh>#y&jX1CmC2u@NPlqJECqNz z>rXS(h~Awew4v7<2TWA`Wq0Jut~8!YZ{J%AOgc+$)apk`OaY4i`YXs66{pBA6C^&~ z;#AFh`lJ&>WJXN$GM_06*Xs6rB(nQmjDFLL>;e(jbl1=%WhDM&2mH%p`kL`hYl!oL z{6=*i?Q3h7jq41d)7v)oQn3kYS5x_bRBH^`6@3O)vzKIu1e#ga`Ar6Y)tL(Z)0Y1) zBrnv0(_cXaIW7FftNgS5=!8wttKDi@_hw1{IEvd4R-KhllX)S=%TY^#);{O4F}|X? zG-?|bV3pv=`%A7%EfDrf6)jkK*UkBzwQc>8pT%1de?^R(Ro${u$>z048wpEX1=zjk zwr=w`wd9u55JvzdUGRgrY5co$U9m2zARt)6#ktjyB?A@_V?&NR?GFBu1Z44ocTW4X z4Cu9YmcMbg$2%o;Mpj_m>KMr)u%VqbZqCP#%9YyL_6G$S>u|Ijo0<=l%K~LzkdX>y z>VEvJl1eh4#FAsgs!4}4bv%PfFhdOe^mz1Hg%?7@xKVFd0kVkM(rXZdQIO=aE?RS!AEJW~yem zEN)@yZ?8kHx@1e;KWp-w@g#+eX+Q9E`E+TLf=#y0$%DOx7;oyiC8sF?MP3&4?_(0a z=1zJu5l%pP?jgh$KcR4XLMkdP;f5SeTSgzWSEQWo}TOUh4%Z%34SRq8_IUW(BP@(c^i&3OA z(e@CW$6n-kZI-E)LE&==<0t_&w4qH3zee+4H2LU19in`$CtKKqhB$=^sX zO@CfilY2GnCQ3zBRP%a{Fn~V4OlIXwE=prcRGHd`4lSavHgZf(Kb@n%orIofI7k&? z6r}S@&PP0Ckn@A{2IHei9rN&m!Y7_T(BX+4jB%KVqel=OB>W1t_ZmL|t=u98S-k=q zHoh%sqke3A`NA20Dk(on-?zce?D(zrEy-?<5Tkwy?$+)a70_sV*)a&w0(<9M7beoH z2l;tmJtc=)eW}N8mtsuAT>D_33qO_Dz;dV~22J|%v**iYRucW)@A)dHnn& zbD69doyi~*n)_HqlDV!^WjSBYDPl9E+k6%mMZCuTpt=5eloNd#xo$)A-~}AR32QU8 zo|}MMV%bMqO7OFk_~$e)pbGEK(cUXxI!88)M*e!k8GS!aZg#`q_(=2>_J%lIK;06O zZEom*@d!n8)9I9EJ;p&h2Ih~nuE31HWN(@CGOAdqmP%(PVW>_^j_XT|YH{nXIB zYBa|V21Dgz=pyndBha=L5%5(uR1G8r{M_ZvKknxKW!CMW=b_vBmj&qG12d}`c+%kg zKNWGq^R$F^O#@yNm~X8C;b;8njBnA`o}wV;HR!{g9&^Gpz%Bk)%f}Z(mnkZ&hV-1Ajqe{k;1f0; z8fj$VW@(JXt$S9rDdguF_&7#)Gu~NAHVjjL=JP!tt6*`DzIV?zG1)s*-HO@?>}tJu za>qpZulK^Uv?QSW1rt?lpr%=MG-`MMJFU&N0;xj{Vhew|&5o(28eS~n4^R9^1~?QVS?HrrzaVCiPkFuO% z=U9<e(lf&26PQZnA)9Cp<}N?^(x~IJ%&|8+J$z7dv7Ja`K6SfN z#$o8|!gPU&Iv922H_beKhlI()NH#@iYxna)zWL!?&#@o#9x{S1*OB&aA+xly|F)JQ zK%oOnH-{y00wEKh_VX}j=8kL8*HPLdX{;Q_aOMf0`rJVi`0|x$@YDN6{wTr_u8amp z7a+rG+(GR zhYT`tZR7&{>CnZuTy^Zz=p6!oG42xI^I|v(jv}T*oUH}P@pcunTYMEvft|mufV&++ zbo|(snu*L0ot+i<_^To?Gb>5eDajSiYsJO4QQi0y)`L7Bc@hjF=K@Tl{vI}<@fS-V zBTzZ(-hTz$>>!(RfgIGIcpzFGTQc_qODLbxSV|Ke%Oyx0S-85Hz@m@a>e|e^SHfj2 zDmAdJa5?!zas_!3^XNvO_O>6qoN#bbb{Ym`6w(fy}9^XVop*l4Jr>G6UW7 z5Vxf$IfI+RZX)k4>Wi{!x9Gf_Cs&sV4Q<6Sl0(F*0Gca;S3%S3?J_FV`_oN>8R~%EGaz z+VQ|Z4Joh)kqDDfJ4VD-Rvf+R&Le#eAV0i2@sie1#8Q7%OX|&D;nJbJrA>ajy|$mu z(p?z~v+*%c#E%2AJs<4}v$tN?c^9*??my{P%=bq^iVe8==DzrreoQ8)JvOosVcC^-#lDe=^|(cC zI3g3tl2K1=$+D&i5A2fkXp;Xf={ig3F=xAE;oZ+*;q079$@bJ2SFhom3BKajRJ)pi zaLAmB_Q!W6*m_x*>A@~tlmeQCvz=8!J)1uCKC)K90V`k?=QiUTP_?jsS9sYD(Odk* zro@G4rNQQGSx431rKorzLWo)ghrV9?tdBe2+RanaKLM5@6U}KXq22Uoqjs*9a?If6 zHV$%w0<%wRNFQcwQMcsw9IkCS9yS(aiv)J?WVqKQEycNqaj|tpwlY#{&d?S7sfqt? z!923HoyzZedA$~Xd*92vtWIgx=X2h=6g7hV+Vp6IlX|ZMP_Ja;_8_be9>?Xk81GhTH?NjgH`l={rLiV?z74HdY>Ho0;iVN2bUKuz;#dg%=T{~z1w$*| zqHP0nKQ@tlMk=*w4)~{deuW>ehCmFAL$O;-TK_4Z;ND1~dWO48v^i*omA{N)33Vwe zJ#q?X#;HuVm|vs|ntYP>KDs%KzEYc3ZfNYay3_D(!q7KMrbUVeb~$o3@un#;f9}U4 z!CZ6)>T&76RXhq`tQLLxBn0WGhJI~BHH%$5$035H;t8nJ!vUAo3?l&+pR3c2F0&&D>`RR}Aw}BGTPqwzMYGvJ;A& zW)wmvg-KXGS)H`HZv$7SkZOUQW0Uko=gL@^o*pzR|ts`t1zge*~O(hnTOTHQ&5CRROJCd!F z;VT7CuyQP8M2$_=zQ@>RB)(LAKGbq-)*Y#0TbwS;p|y0beL>+eMYK!1us6DtMFa>B z^qm=5)^dt{m*xqZ-khFrVG+!qJa$uRo|=~&g;1+Y?*QR!iqX@zS?4&|I)`5>9wrMM>_k^D!%}|5QXXeq>)&Qa#Zr< zA7U>Usf|puoZUbDwBN=f~Pr?n0D7` zI4WvKk2hn}p;sU=KG7LIbJ(AHDODSs23)k4qr{yT;=7;5BpZx}nM9MNdYNwqA^xLa zE$|*;7%KniL%P9{CPM(wj^CZ;YGs*=i8Y=# zAJv2|__7Rd-f6YD`TjIz`3-w8d+s4Zp7>LOJ!Uaw=`AOqWa>e?Wq~gDRN?S${d^8A z`*torz;f|1rh_-U*W6ol$w6enlPs`X=+keK`FWD$m~Si3p;`H?bS@OJFwlCUTlB*u zdn;)=LNTrG=7re<>S&2+WhHBuU(M4&QVkYQ_$J|Pve9MG>ZZ0DX)+W(@+i3}fdm8D zuJDY=MrQsJ{xG+Yem~knKM?pHj8ysH{!YBqKQd&+36{J2r67q_V|YLDLtc|)VDTRS ztYo13k?US7^V1v{`z`d-$+hYrlj(wgA9+62K>k_0Z1cXiIIRhfXZ=t&dTAniUlKt4 zW^v)3f{@q-$^)10o#w`IsGbS~p9FwcIV`H1^(!Kf__rIecIg0Wy1Dti2DJ#Jr2=!k zp6O=q*EVPkg?z`mW#>7VkWcpI{oaz!xS#g-5l(T(GD+w}@`ZauQC+<)#oA3*s?}P6 zOMvhD|K<>6YlEY|9SbbJZCJL{%QBEW9b#e#IHLH{mjX)`9*aYXqHGC&Me**Wg z%kirrU(KrG$xc{A7H2k=ExFdJH_g)P+Q#SGQzK$>6rVkMA8P^hiN@wY0#i=At0DW# zeVFG$%(>rl325W;L_1tmQA|(1r;+Ai2zg& zTAUlxW!^ok6&4X{;iUCs@^Zu&#BOfaf&6bIXHT|flOxlrlD$a9J}LeIq*R^MxahUfPA)$QRJ(VffCEY4STUzhL*czHG-LzAi#`^W^NzT*4y{C2?Co*>)f0KqS#hm(6y1ZWW{@!X$oXM* z4N|1V(Oa^`tTD1y%nfkTd1{`Ajl2dD-m2wMU0)L(JH>uKn4tJvVI)mSQHplb-%ijy zFHHHa(ies;_{6R=F4X$?yE@50J)|T=wuP9E7U!4>AdhpB&f;QtPn4sQ?4JRoJrQ^uPZBnVE`z28gI4@U)ukkl;#L0MD6$w zO?}caI0_9|(l?J86P^T#d}%VITsXo4tz<&oF5%ZeESS-?sLlgyW=?N4Ko?9->YGiz zm=7I+;?NUJV!ZQY?Aeg6&l*5L6q5RD>4RZB5S(nXBW?kNqR3cEY20KXur8#wrYvTfiM@co(3?G_( zk3@v?zo}pavN=0m7DP)#yqmD88*OhU7x7-R=ZfQm-}*LEJ6&);{}b0usGGo;N3hP+ z0iVICebJ*{P8TwdffhuTVcq^HXzc-fcIp}dLq~#hOd9OH0=ER;;aAbQfKf<-f z(M{(m=bgedS5vA&|CUVF#4_kP?p!*`dfg&W@4az5<-uJAUcsZnrAl@k;f>Tt<(khx1!e@_c$rmvsI%&=he`Cg1&_fN9rrT#>;~!V|$DFDMX4 zdM8%%SVuAAk;@IP5PtPvokVLkU+uhYM#Vetes&Sj{QjV*!jcCx=3P+Btqfe`B(@C_NO z7IzdHKmJzt{L5-CZOw@-g7C9;(A9MMeqU{*cZmW&3RL}C_sjnsPg;tfbb|tzLiYUX znz1nRt1k;0$M1xpJoC(iRhl+@Lo237{NU{4+h?d$rJat9PjG$>$@}ejC&r3f*M*;U z3ZUbu6vyel^ggk9wYyCaD!LqgbA1KoQoJ)Qi>6&7I zuk{L{Ls^)sndWr3mYX3ozVO!v2t$k3M!19dj6MAKkMPs~_+nw68=n;`G2T-jv%Hg!>kCygyg zC`hz8Qv(IUt3+Q9cpApBEkx~0E0Qsq$`(^JiCxWS-Y918ao5<9lHkQ~E^jwl^<1Pg zLn#39{R!&ZKiA@nvSqY%%E{%u(YQ+5GJI{KCzJS;emwWJRDUXEBmeDx5Ra zu}Jt8+JZ$wI2bbvQP0$ky7J`yEG~n))X>gk+sc5@+w{`og{p{mpV^Nk`2&~yMwyFP zpNKxi326FI=4J#N75$z?F;PlA+!8kM?akIvssO&0(D&13hRb|N3<9J~5sDNj2alq7 zJH+N814Du`1-z7g?(J*(SA|w(0tOM_CaCVAfmPhr#EZ;Wfr3QrBSD{K%%!4$dqKFJ zFC`gPOsjdrGgvmyX@X%0j9`#$Yhj#bX>1lul*DUZ-1A6nXufyNBzI!ENuuOO;muH-Kx7eqndKlGov0P)~ zDqm?$z2v$5TyjVsGcH0~{HUzM5u@3yo(ZW75tY$ui-dB?lr56s`CVk4uI_&l`pfZ5 z8h@P6x%1U`=rl@SYmzWjF3rfYS9vQ|XPPC$xyabV`N8jYs{WQfG_cGnxWds=WhgxY zu3I~J^+0{LR5&PqwVkD}Sdv{cj<;h%g4)sTc7Cfl#n%fTiPO7m9Q^E$(ZhO{csY4| zPs3#FU6C1U(f+`ni(mPmtnAiix8fUAjkS5G$~f^aJS9|3=v`mYV!;m@Kl*ksz|5s( z_qH?Y*mfaQnnQhdehrEQYbjDv8h~;XV~pY5wPn(GYOsmFcqzvkPIkS`O`p>e`2b!W zVeK+tBG^P!R?~tWE%j(5D0iZ^C$g#jq54qt+qi|#EV2O@NltBrB&(`5qYQNtMGLby z+EMv{_Z}1~XIOg%_k@vnYQA`mHQI@Kq1F(CAz#(Bmd3yLp1VmJP<|wB%hVT{E(U_^ z<3`pU8)xEPvDFe0o_+FvzOQALJR)iu2qUYm*4u%yjxuLv-;Gee$CNQ0=t2bzXN6P%p|^j z!8L_jw&`~!G*zkpMj3*h=Yje5_o)XoJg4eJ{QJJP>N&tqcx0J5wP9Qj6t}+-$_&%N zRsI?3`1~mxrV^`D5t17Mj`~AbZTsHdCTe9w_hcn9p=QPYjROSd#A$c0$hN{+B%OTrzOK@&r#$M>--r?s>r&!LuI^+S5IjU(E7& zHZl7=8O&EV8E=0h;`8StLo@yU4F)>EMc0(k$-w3gS~o9efgvX2@Au!TX9e)iocmVf zsprmjK^GwJT${QRXN!Fp>v{71-u~u!ion}l5gs}eCu{PZzWwS{1_0iB1K|{*e98hN z+@AkHc&=m3jxLJ9|KI?Dm>6o7#gz89^?WL#dW6>V=b3rCCEUWX$Fh03>?RDEHrt3` z$r?w6`z~<9kTvx@9QL^T#?dG8ucthVL`Nax$tULC-!CEr@#|NETz5|-LRMULRVLTT z?dS9S$3XaPD4wkDR@iPe0G;z`cYtFT+}$K{+06Vcf3N{!q0VWE4aIE7Z6~$X8U=9v z97uj4DFT&`F@cK8_xsoLKid+qLsmxdH#awIaZZfvui)odAjc zfdG&-n%SNqU?hhb9_{=Wq$LWkO8_zn7Nn{bmBNyGQ%Ld8yIm;o_0)6CFNC! zqu*EL`K&%EWBmg}agUPnZqLHOcs&8n@8bh*g<#UH2)Z_zbrGy60CEDoe^z%t=WIru z*jG?6!y059E_w%Wh)@sqJ|ygXa^ooeo%@jt8)3yMFH~V+uRX}Z7PwD7JY!W_GoFYi zL3oJR-xL@W0>VaiHy9R-!KjsmJ$gtzJ>f7qqJ9{82B^DR{R-_FMDzJPf3MROF%Hjn z^3V=*xeV4Q0p^i^vRLDnaj=KT&20p;;>^;;B2C}#T@TlW;CJcCh@MFXvzCCVvC%-< zSRv*v>O6C*6v>RRW*X!QFe1_>SkRc9dwQ z0SpWb&8fP&WM)16zAgq5^vsRSMflwNZ)6Fg+1=Y@IoJ%lu<4_%T&yl<<1!>g&oudA zs1ln0xRws{>dxRvsu2f6ZEQR;cJ*wzl8LyX(9ga)+imlZm@y;TQ_NjRNJfN=u*|ZX z2nLf}<6PfvIE;bH)|heR?!S|#f`QfD{^lbnKKK0!{5+3~jTldCD+@E% zEZaKC1=sAVKZ2Sy74z3;5hR^+bbHj~Fph+b)L2#&_quCS^P@RcK7hvquT#O96djfS z-=*uaC=Dm_)MraT-J%(_JRSD!+D3_x5neLQ$}#}Kb%AnxVlNiFno79kq=WZ+Uw`Y* zBk8@9&32zC1K+=Ydnr`549_4Z0HAs-s6Gb*8j|j9!xc4!Fmb&%nXSaV8qXXjiP|!$ zF(yKlC!f;o2)^I9yYm#EOaKwOf1mTe#$8#mp*u$Y_{aG?hk!J5U(_d<1S!`kR=)rH zUvHb1AZT)=zDpQIM1?gHxIeVLjJ|pPsILGoVcmnR;F*R;s!vfI3JJ`ONdIQHXMp?O zQzTiHZcXbvPi2ng>XOLgdh`3e4*dD^NW9Yla$z{Oji|slGYTBM2anmovb*nuZO-U9 zj8h+Z1Sj&|-XK%IJ+b-J({~?9@j3bT-J^=5aNCtUE|VMmm>G_a5vSc<`)=g;OPEJvNs z^N(ba84QMghNNjb;{d|jj{1E5-1~1aT+hkuR7UY9TEXc0+6VWxV~fGLu+{lJ*eJO& z)A8PR4;Z(dKYqGzPo1aHzI{HQrAD>eF9|EYn|XG?Q}yd>daLRy10zGIimK=K*OLrJ{J>|q+}5Z&jhSS<{Xaq2flQvf zGZHehKC8$vOq|6wj7&&BO^A-?+v- zV-kpf@y=UWf#SZpuY$`okFBwCT3|gNYF>HNc>y9K+Z~yV&}~y{V27s?P)Rm(!hC1O zCKSLZD~Xh5Swqixy1ziqhzQ4j{Pc_kq6GF3zwbgWgP~{8&B%yg@V!I(WKCZX-`JZ@k>5dyjwo8KsmiFLq)`?%RxU#+r#rF?*U3Z#F>t>PBc33Ng&5s#%REO~ zl(=UNl%_cbK3NNBHM^Tn9RA`aJ-37fC2vO;cRGVolUY?W10$;vxHIpaRbNdDiO=)7 z{bIK3rdT121Hg;cZUZu|313&6AaNX9y%%v}8CW z1&0WV?U~VuV&=SGQ~`1$lSn@J45T|x76^~I>-WrYFPD?#lCp2#WbH5_3UDlaE0-cA z*s0!V7P04&5$#S^WoCZgFH(@R^3><{o2U9tR-*5{uBuI5d9FlxvXTsY{+v($NAU;U z^KI8BD$aTT-p}W=#Phkm1e`49@~7a`_Jat!`+D3E$%AmE%w#MeRzzmJnBz<5j1O_W zb&bIQILmW4Jl_=^QT&tsW~qizL>Fr%VDA~Y>bMrM@vSGem}<}wmC_CW&3zxSH1Qx-t? zTx;=w@Q*VB6{T3ofJtd)ded1B%nZO2LB#F%)WayqwkvZ-wPf_tHRDk&CI=9h!P}jv zI)>Gjl{Pc&@O)p*KY!xwKCFx)Jk#}j?%%7Nr_L`taX5Vu1S2ajj`LgfRB{B3D{?pl z7aF!BmwQ#EaELbk3nFf=&-yRZ%F)dYNMuaE=P6<{U`e_?fDdy&(!191j<^}q&Rpct zz}%t0%*_b(2nfXQ!4d@W$M?#Z+mQRZP6;9=f-?wm=E7jcG(j(nfrKe?Rst8ub$PN*wa7T0d&*#s3@0~d(MvP!qy2bs326o$yapsXn zGLi?rcj_ECW*QOCiTnNf$@`s%cO$hHx0U+Nn-QQnvB3u3M_x)f0Y^@|B;%|R#CV?LtAwGZpp*{DG+K6I(ai4rvDmm8Yd|EDOdE5VCVCm4So-ua(@|L61kQNZKMx_y~Ak#pyHp7;AY5Shey=en zKRXOC5E&NQ1EYc(3LYU~i+cNdJBR{`vfKd*)75{PX$T_Y!919clgW7V0F>9u6IA;KqVM?U#y(ZM6iz zfB(LjJXx(7`5Z``+bjj2Eff~gp>P^pxm8xeq|9`;OjN{eWdy<*H5v@gQ?1_NNA5$d zaPqnHh7HE|b}`R6WR&TM3dZ~XHCR>qx6KT5 z?<@1ehGacAf0|W+s`E-uvcqcNmZ}^4(CM6je0k zUVOUks+!yTn)fEy>={SVGJ~3plrq+lli`_S4zwqd8U0A)dx&E!{6P1olN)seiHIle z-#4PxbTu36N;X(C~BWJH0Hn`@V*s&y!~V!l_HXkGJny z9cQ$sR0k*m;;CZJy+~F>4`8ukk!V~eP=e0sn1I>eyz}5Rxl0ldb+`wppW|nUgE~&gsjD zj2g;)Ek>n`4Ff!R8q+fveCVn)Thv(4}Sn#3(|`$${yBz{xRCFJZZ z2ii_*Ea1yw{#V;w4h{3ik|%>9kM>)+fqL~2V5F$!C1=EpnUI|8E|CV4ERy%mj-WF` z_bz(%{r)8@mm2?JHNr;!hBvo;Yg~ z0h1oh?f*1mi!Gkk{2;pXAM}bbklXpGd2dB9a!Imd1!He{`Y?e5P{iLUH&=GhZf16iOjoZy4g6rJ^H?1+04Sw8ARP7Iej|9EQyC%h*QvNj#tDF&$?$VN zF#VlZ{`2`0ksL1wf-vm&c72Yd8>n+E-)T%M&tzZRI;R% zqW=^mb45lyl_w1ld@6(4@136Ye?(=*w%z0Vx8L_=7|8J@HQl%Gecx|?1$V#ye&5DW zh0yjH8Z2i?w+PL zD5$HctWgKz^XEhIoh#}}fB$|llTR_T&F}YhMlR|&7?F|L_x^pq5hQ+P)+-@c8S=!5 zF@zz~!1ul1`!(`82_iE3eKQ$Zm}!6i{rh*4@!#6=XE4Dq%q%{KBDb^j1fcg$&pcJn zc?3Vfgx+h@hb8F&)I2AM&;Rc?w!$`&$Fnzc7qVTU*Y)0@UD07 z%=JF7>cl6rsBT2)r{GAL-2?9E1W^e){ksT(ymuEpyC@F>r*;+Nnb~we>&5?9=l9-< z(oeaBIwy$ULw3-hyifE^3&l1&Z{O}l#_Jw6=oyj$%0VK=)aXp6-yLtv3(4MSd zMq54i$%@FvZvxu7yHKD140I%&Te9OuI%8p`iA+9!KBnJ0RQ{wb7+9HQ&;0xVW$-(H za~r-%I+lf6$N?yG1ExYGGxFq`B_jeSpU5Z41V5h>nf^(sq?rVuf$eD~5a?f_LhFI{ zj%R}v%7icr+wulF7$l{I-tkl}bdx9Sm8aeR1Da$J4k+kF^~AqE4H zC*2bS^5@YLJ%~sGzvvrO?)85^mZ>E1`M1{u#HZ1)C6E|Xd^ z!3*_ForghdDq@e3QK^-oc@g`aMDC<-SPW;F3 zCJ1yVu-fE%yDj`Q^TFrX-alIq|8M{2|MMqnVXNQo%jD-gJ+F!GIdx7h2o{jfbH4oz zr{s~I=ecSaPnI-e&rHVo^XI5v8Co1SdEY+I;eXfdT`|IQ&g0QgBW=$2R0+^P822Em zPS{N9`+iUT>Dv*3s(>KfQ5^=$`o(@v9rYl0JJV}xTZq;4Fn7ic=8j0?(S&@lIQmKoM${E>fUocS)oz;FPu;0Ft(Fd2m}_&9!vra#oF%4 z2)}QyvBm2e`%gj8=hj>WHJc=g+|fZ9JSY&D$;O z^I4FvTQ_3`m8tnLXcj%6m3^;38qf2Ly1U~PP0U@&k_nAYJu~n5e7eUyk!AY5?=q!} zbw1~R|L^~uPkpkkkV`n#kMdhcr!ip0c;=4nIw#2)1FFbQ_w9#I6z`oVd$3f52&x;* z&w2K%#DP`}q*x%;c`71CmL@Y9(ciC)WtBXc4%|CcnN{!mEksl4)BWZl>~lV&xijHy zEl)iU*4-snhU_~7Pvsf<_iKPEAH&`E$wZ_KLD=iX$bkrgm{F2IE~avMDW@o;ta~qj z=f8hoFl;!&>d?9ve_YCaQuSJnccZMd=Tr!6Pa-6oPi`2qB9ZPpL@;S7BD=pt?o@kI z?eEO;WKKTI>)f7hV-XxAX+rXL*($Po5YAwaNBzkoFc_o8qQv4jFmG!npR|`$cq@-F z@S@cL1DX+n%%>ntE6#5evI-}FX6!}OBW8N*$lMVaVR?El?6$J#AHCC2ktl*QckoN% zn$~@*J`BF!@4^y@X!pq-G>LZ9qZt5FM`lFI<3U-!n8pf~Icm)?4hiNK!7<%=Xfw8MYBX5M`wnQrCy$`+36?NP^itE7&}L

      dYUd{&%W+6$LPpfiVv)V)~Ndd(NMp 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 diff --git a/docs/dev_guide/api_reference/endpoints/authentication.rst b/docs/dev_guide/api_reference/endpoints/authentication.rst deleted file mode 100644 index ef10082..0000000 --- a/docs/dev_guide/api_reference/endpoints/authentication.rst +++ /dev/null @@ -1,87 +0,0 @@ -Authentication API -================== - -This section documents the authentication endpoints available in ManagerX. -These endpoints handle Discord OAuth2 login and token refresh for users. - -Available Endpoints -------------------- - -1. **OAuth2 Callback** - - - **Endpoint**: ``/api/auth/callback`` - - **Method**: GET - - **Description**: Exchanges the authorization code from Discord for access and refresh tokens, and returns the authenticated user's info. - - **Query Parameters**: - - - ``code`` (str, required): The authorization code provided by Discord after user login. - - **Response Example**:: - - { - "access_token": "ACCESS_TOKEN_HERE", - "refresh_token": "REFRESH_TOKEN_HERE", - "user": { - "id": "123456789012345678", - "username": "ExampleUser", - "discriminator": "1234", - "avatar": "avatar_hash" - } - } - - **Error Responses**: - - - 400 Bad Request: Discord token exchange failed. - - **Example Usage with Python requests**:: - - import requests - - code = "AUTHORIZATION_CODE_FROM_DISCORD" - response = requests.get(f"https://api.yourdomain.com/api/auth/callback?code={code}") - data = response.json() - print(data) - ---- - -2. **Refresh Access Token** - - - **Endpoint**: ``/api/auth/refresh`` - - **Method**: POST - - **Description**: Refreshes the access token using a valid refresh token. - - **Request Body (JSON)**:: - - { - "refresh_token": "REFRESH_TOKEN_HERE" - } - - **Response Example**:: - - { - "access_token": "NEW_ACCESS_TOKEN", - "refresh_token": "NEW_REFRESH_TOKEN" - } - - **Error Responses**: - - - 400 Bad Request: Missing refresh token. - - 400 Bad Request: Token refresh failed. - - **Example Usage with Python requests**:: - - import requests - - data = {"refresh_token": "REFRESH_TOKEN_HERE"} - response = requests.post("https://api.yourdomain.com/api/auth/refresh", json=data) - tokens = response.json() - print(tokens) - -Notes ------ - -- All responses are returned in **JSON format**. -- Tokens should be stored securely by the client. -- The `/auth/callback` endpoint requires a valid **Discord OAuth2 authorization code**. -- The `/auth/refresh` endpoint requires a **refresh token** previously obtained from `/auth/callback`. diff --git a/docs/dev_guide/api_reference/endpoints/guilds.rst b/docs/dev_guide/api_reference/endpoints/guilds.rst deleted file mode 100644 index 3a5561f..0000000 --- a/docs/dev_guide/api_reference/endpoints/guilds.rst +++ /dev/null @@ -1,155 +0,0 @@ -Guild & Server Management API -============================= - -This section documents the endpoints for managing guild-related settings in ManagerX. -These endpoints require admin permissions on the Discord server and allow retrieving and updating server configurations such as TempVC, Welcome messages, and Levelsystem settings. - -Available Endpoints -------------------- - -1. **Get User Guilds** - - - **Endpoint**: ``/api/user/guilds`` - - **Method**: GET - - **Description**: Returns the list of guilds where the user has admin permissions. - - **Response Example**:: - - [ - { - "id": "123456789012345678", - "name": "Example Server", - "permissions": 8 - } - ] - ---- - -2. **Get Guild Channels** - - - **Endpoint**: ``/api/guild/{guild_id}/channels`` - - **Method**: GET - - **Description**: Returns all text, voice channels and categories for the specified guild. - - **Response Example**:: - - { - "channels": [ - {"id": "111", "name": "general", "type": 0}, - {"id": "222", "name": "voice", "type": 2} - ] - } - ---- - -3. **Get TempVC Settings** - - - **Endpoint**: ``/api/guild/{guild_id}/tempvc`` - - **Method**: GET - - **Description**: Retrieves temporary voice channel settings for the guild. - - **Response Example**:: - - { - "creator_channel_id": "123", - "category_id": "456", - "auto_delete_time": 10, - "ui_enabled": true, - "ui_prefix": "๐Ÿ”ง" - } - ---- - -4. **Save TempVC Settings** - - - **Endpoint**: ``/api/guild/{guild_id}/tempvc`` - - **Method**: POST - - **Request Body**: - - - ``creator_channel_id`` (str) - - ``category_id`` (str) - - ``auto_delete_time`` (int) - - ``ui_enabled`` (bool) - - ``ui_prefix`` (str) - - - **Response Example**:: - - { - "status": "success", - "message": "Daten wurden permanent gespeichert" - } - ---- - -5. **Get Welcome Settings** - - - **Endpoint**: ``/api/guild/{guild_id}/welcome`` - - **Method**: GET - - **Description**: Retrieves the guild's welcome message settings. - - **Response Example**:: - - { - "channel_id": "123456", - "welcome_message": "Willkommen {user} auf {server}!", - "enabled": true, - "embed_enabled": false, - "embed_color": "#00ff00", - "embed_title": "Willkommen!", - "embed_description": "", - "embed_thumbnail": false, - "embed_footer": "", - "ping_user": false, - "delete_after": 0 - } - ---- - -6. **Save Welcome Settings** - - - **Endpoint**: ``/api/guild/{guild_id}/welcome`` - - **Method**: POST - - **Request Body**: All fields as in the GET response. - - **Response Example**:: - - { - "status": "success", - "message": "Welcome-Einstellungen gespeichert" - } - ---- - -7. **Get Levelsystem Settings** - - - **Endpoint**: ``/api/guild/{guild_id}/levelsystem`` - - **Method**: GET - - **Description**: Retrieves leveling system settings for the guild. - - **Response Example**:: - - { - "levelsystem_enabled": true, - "min_xp": 10, - "max_xp": 20, - "xp_cooldown": 30, - "level_up_channel": "123", - "prestige_enabled": true, - "prestige_min_level": 50 - } - ---- - -8. **Save Levelsystem Settings** - - - **Endpoint**: ``/api/guild/{guild_id}/levelsystem`` - - **Method**: POST - - **Request Body**: All fields as in the GET response. - - **Response Example**:: - - { - "status": "success", - "message": "Levelsystem-Einstellungen gespeichert" - } - -Notes ------ - -- All endpoints require a valid Discord admin token. -- Responses are returned in JSON format. -- Features must be enabled in the bot configuration; otherwise, a 403 error is returned. -- Invalid IDs or missing database entries may return 400 or 500 errors. diff --git a/docs/dev_guide/api_reference/endpoints/stats.rst b/docs/dev_guide/api_reference/endpoints/stats.rst deleted file mode 100644 index 1498565..0000000 --- a/docs/dev_guide/api_reference/endpoints/stats.rst +++ /dev/null @@ -1,74 +0,0 @@ -Stats API Endpoint -================== - -This section documents the statistics API endpoints available in ManagerX. -These endpoints provide information about the bot's server count, user count, latency, and status. - -Available Endpoints -------------------- - -- **Version 1 API**:: - - /api/managerx/stats - -- **Version 2 API**:: - - /api/v2/stats - -HTTP Method ------------ - -- **GET**: Retrieve current statistics. - -Response Format ---------------- - -The endpoints return a JSON object with the following structure:: - - { - "stats": { - "server_count": 50, - "user_count": 15000 - }, - "bot_info": { - "latency": 35, - "status": "Online" - } - } - -Fields ------- - -**stats** - -- ``server_count``: Total number of servers the bot is in. -- ``user_count``: Total number of users across all servers. - -**bot_info** - -- ``latency``: Current bot latency in milliseconds. -- ``status``: Current status of the bot (e.g., "Online", "Offline"). - -Example Usage -------------- - -Using **curl**:: - - curl -X GET https://api.yourdomain.com/api/v2/stats - -Using **Python requests**:: - - import requests - - url = "https://api.yourdomain.com/api/v2/stats" - response = requests.get(url) - data = response.json() - print(data) - -Notes ------ - -- If the local `bot_stats.json` file exists, the endpoint will return the stored stats. -- If the file does not exist or is unreadable, default statistics will be returned. -- All responses are in JSON format. -- The endpoint is **read-only** and does not require authentication. diff --git a/docs/dev_guide/api_reference/examples/api_js.rst b/docs/dev_guide/api_reference/examples/api_js.rst deleted file mode 100644 index 3b1d64b..0000000 --- a/docs/dev_guide/api_reference/examples/api_js.rst +++ /dev/null @@ -1,94 +0,0 @@ -Using the API with JavaScript -============================= - -This section demonstrates how to use the ManagerX API from a frontend JavaScript application. -It shows authentication handling, token refresh, and usage of various endpoints like TempVC, Welcome, Levelsystem, and Stats. - -API Base --------- - -All API requests are made relative to the base URL: - -:: - - const API_BASE = "http://127.0.0.1:3002/api"; - -or your Domain. - -Authentication --------------- - -Store and retrieve your Discord OAuth tokens from localStorage: - -- Access token: `discord_token` -- Refresh token: `discord_refresh_token` - -Use `checkTokenStatus()` to inspect token availability: - -:: - - const tokens = checkTokenStatus(); - console.log(tokens.hasToken, tokens.hasRefreshToken); - -Refreshing Tokens ------------------ - -Call `refreshToken()` to refresh an expired access token: - -:: - - await refreshToken(); - -API Fetch Helper ----------------- - -Use `apiFetch(url, options)` to make authorized requests. It automatically attaches the access token -and handles 401 errors by redirecting to the login page. - -:: - - const response = await apiFetch(`${API_BASE}/guild/${guildId}/tempvc`); - -Example Usage -------------- - -- Load guilds (servers where user has admin rights): - -:: - - await loadGuilds(); - -- Load and save TempVC settings: - -:: - - await loadTempVCModule(guildId); - await saveTempVC(guildId); - -- Load and save Welcome settings: - -:: - - await loadWelcomeModule(guildId); - await saveWelcome(guildId); - -- Load and save Levelsystem settings: - -:: - - await loadLevelsystemModule(guildId); - await saveLevelsystem(guildId); - -- Load bot statistics: - -:: - - await loadBotStats(); - -Notes ------ - -- Always use the recommended endpoint `api/managerx/stats` for bot statistics. -- Ensure all features (TempVC, Welcome, Levelsystem) are enabled in the bot config before using them. -- API errors are logged to the console and shown via alert dialogs in this example. - diff --git a/docs/dev_guide/api_reference/index.rst b/docs/dev_guide/api_reference/index.rst deleted file mode 100644 index 44eb9b4..0000000 --- a/docs/dev_guide/api_reference/index.rst +++ /dev/null @@ -1,48 +0,0 @@ -API Reference -============= - -Overview --------- - -The API of ManagerX is built using `FastAPI `_, a modern, fast web framework for building APIs with Python. FastAPI provides automatic interactive API documentation, type validation, and asynchronous support out of the box. - -The API serves as the interface between the website, dashboard, bot, and Discord API. - -API Versioning --------------- - -ManagerX API currently has a single version: - -- **v2**: The current and stable version. All endpoints are technically under `/api/v2/`, but it is **recommended to use `/api/managerx/stats`** for statistics-related requests. This ensures compatibility with future updates and simplifies integration. - -Authentication --------------- -- OAuth2 via Discord -- `/api/auth/callback` - exchange code for access token -- `/api/auth/refresh` - refresh access token -- Admin vs user permissions explained - -Error Handling --------------- -- 400 Bad Request โ†’ invalid IDs or missing parameters -- 401 Unauthorized โ†’ invalid or expired token -- 403 Forbidden โ†’ feature disabled or missing admin rights -- 500 Internal Server Error โ†’ database or Discord API issues - -Notes & Best Practices ----------------------- -- All responses are JSON -- Respect rate limits / cooldowns -- Only admins should call admin-only endpoints -- Store tokens securely - -Contents --------- -.. toctree:: - :maxdepth: 2 - :caption: API Reference: - - endpoints/stats - endpoints/guilds - endpoints/authentication - examples/api_js \ No newline at end of file diff --git a/docs/dev_guide/architecture/cog_system.rst b/docs/dev_guide/architecture/cog_system.rst deleted file mode 100644 index 99b80ab..0000000 --- a/docs/dev_guide/architecture/cog_system.rst +++ /dev/null @@ -1,183 +0,0 @@ -Cog System -==================== -The cog system of ManagerX is designed to modularize bot functionality into separate, manageable components called cogs. Each cog encapsulates a specific set of commands and event listeners, allowing for easier maintenance, scalability, and customization of the bot's features. -Cogs are implemented as Python classes that inherit from the base Cog class provided by the Pycord library. This structure enables developers to add or remove features without affecting the core bot functionality. -Key Features of the Cog System - -- **Modularity:** Each cog represents a distinct feature set, making it easy to enable or disable specific functionalities as needed. -- **Ease of Maintenance:** Isolating features into cogs simplifies debugging and updating individual components without impacting the entire bot. -- **Scalability:** New features can be added as separate cogs, allowing the bot to grow in functionality over time. -- **Event Handling:** Cogs can listen to specific events, enabling them to respond to user actions or other triggers within the Discord server. -- **Command Grouping:** Related commands can be grouped within a single cog, providing a logical organization of functionalities. -To create a new cog, developers typically define a class that extends the Cog base class and implement the desired commands and event listeners. Once defined, the cog can be loaded into the bot using the bot's load_extension method. -Overall, the cog system is a powerful architectural feature of ManagerX that enhances the bot's flexibility and maintainability, making it easier for developers to manage and expand its capabilities. - -Py-cord Emample (without Ezcord) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: python - - from discord import slash_command - from discord.ext import commands - - class MyCog(commands.Cog): - def __init__(self, bot): - self.bot = bot - - @commands.command() - async def my_command(self, ctx): - await ctx.send("This is a command from MyCog!") - - def setup(bot): - bot.add_cog(MyCog(bot)) - -This example demonstrates how to define a simple cog with a command. The `setup` function is used to add the cog to the bot when it is loaded. - -Ezcord Example (With Py-cord) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -With Ezcord, you can simplify cog creation even further: - -.. code-block:: python - - import ezcord - import discord - from discord import slash_command - - class MyCog(ezcord.Cog): - def __init__(self, bot): - self.bot = bot - - @slash_command() - async def my_command(self, ctx: discord.ApplicationContext): - await ctx.respond("This is a command from MyCog!") - - def setup(bot: ezcord.Bot): - bot.add_cog(MyCog(bot)) - -This example demonstrates how to create a cog using the Ezcord extension for Py-Cord, which extends Py-Cord's functionality by simplifying the creation of Discord bots with slash commands. Ezcord builds on top of Py-Cord, allowing developers to define slash commands more easily while maintaining compatibility with Py-Cord's core features. - -Cog Loading System ------------------- - -Cogs are automatically loaded from the `src/cogs/` directory when the bot starts, allowing for seamless integration of new features. ManagerX uses a dynamic cog loading system that recursively scans the cogs directory and loads all Python modules. - -Dynamic Cog Loading Implementation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ManagerX bot implements dynamic cog loading through the following process: - -.. code-block:: python - - def _load_all_cogs(self): - """ - Dynamically loads all cog modules from the src/cogs/ directory. - Returns the total number of successfully loaded cogs. - 1. Scans the cogs directory for Python files. - 2. Normalizes file paths to Python module names. - """ - cogs_dir = "src/cogs" - - # Sucht rekursiv nach allen Python-Dateien in Unterordnern von cogs - cog_files = glob.glob(f"{cogs_dir}/**/[!__]*.py", recursive=True) - total_cogs = 0 - - for file_path in cog_files: - # 1. Normalize the path to a Python module name - # This ensures that the entire path is converted to Python module naming convention. - normalized_path = file_path.replace(os.path.sep, ".").replace("/", ".") - - # 2. Remove the file extension '.py' - module_name = normalized_path[:-3] - - # 3. CHECK: Ensure that the module name begins with 'src.cogs' - if not module_name.startswith("src.cogs"): - logger.warn("COGS SKIP", f"Skipping non-standard cog path: {file_path}") - continue - - try: - self.load_extension(module_name) - logger.info(Category.COGS, f"Loaded: {module_name}") - total_cogs += 1 - except Exception as e: - logger.error("COGS FAIL", f"Laden von {module_name} fehlgeschlagen: {e.__class__.__name__}: {e}") - logger.info("COGS FAIL", "--- Start Traceback ---") - traceback.print_exc() - logger.info("COGS FAIL", "--- Ende Traceback ---") - - logger.success(Category.COGS, f"Insgesamt {total_cogs} Cogs dynamisch geladen.") - return total_cogs - -How It Works -~~~~~~~~~~~~ - -1. **Directory Scanning**: The system uses `glob.glob()` to recursively find all Python files in the `src/cogs/` directory, excluding `__init__.py` files. - -2. **Path Normalization**: File paths are converted to Python module names by: - - - Replacing OS-specific path separators (`\` on Windows, `/` on Unix) with dots - - Removing the `.py` extension - - This ensures cross-platform compatibility - -3. **Module Validation**: Each found module is checked to ensure it starts with `src.cogs`, preventing loading of unintended files. - -4. **Dynamic Loading**: The bot uses `self.load_extension(module_name)` to load each valid cog module, which triggers the `setup()` function defined in each cog file. - -5. **Error Handling**: If a cog fails to load, the error is logged with full traceback information, but the bot continues loading other cogs. - -6. **Success Reporting**: After all cogs are loaded, a success message displays the total number of cogs loaded. - -Calling the Loader -~~~~~~~~~~~~~~~~~~ - -The cog loader is called during the bot's `on_ready()` event: - -.. code-block:: python - - async def on_ready(self): - logger.success("READY", f"Logged in as {self.user}") - - # --- COG LOADING (Short form) --- - logger.loading(Category.COGS, "Starting dynamic cog loading...") - self._load_all_cogs() - # ------- - -This ensures all cogs are loaded after the bot successfully connects to Discord. - -Directory Structure -~~~~~~~~~~~~~~~~~~~ - -The cogs directory structure should follow this pattern: - -.. code-block:: - - src/cogs/ - โ”œโ”€โ”€ fun/ - โ”‚ โ”œโ”€โ”€ __init__.py - โ”‚ โ”œโ”€โ”€ jokes.py - โ”‚ โ”œโ”€โ”€ weather.py - โ”‚ โ””โ”€โ”€ wikipedia.py - โ”œโ”€โ”€ moderation/ - โ”‚ โ”œโ”€โ”€ __init__.py - โ”‚ โ”œโ”€โ”€ antispam.py - โ”‚ โ”œโ”€โ”€ moderation.py - โ”‚ โ””โ”€โ”€ warningsystem.py - โ”œโ”€โ”€ informationen/ - โ”‚ โ”œโ”€โ”€ __init__.py - โ”‚ โ”œโ”€โ”€ botstatus.py - โ”‚ โ””โ”€โ”€ serverinfo.py - โ””โ”€โ”€ Servermanament/ - โ”œโ”€โ”€ __init__.py - โ”œโ”€โ”€ welcome.py - โ””โ”€โ”€ logging.py - -Each subdirectory should contain an `__init__.py` file (can be empty) to mark it as a Python package. - -Best Practices -~~~~~~~~~~~~~~ - -- **Naming Convention**: Use lowercase names for cog directories and files -- **Initialization**: Always include a `setup()` function that adds the cog to the bot -- **Error Handling**: Include try-except blocks in your cogs to handle errors gracefully -- **Logging**: Use the bot's logger to report important events and errors -- **Organization**: Group related commands into the same cog based on functionality \ No newline at end of file diff --git a/docs/dev_guide/architecture/command_handler.rst b/docs/dev_guide/architecture/command_handler.rst deleted file mode 100644 index 76c9d5d..0000000 --- a/docs/dev_guide/architecture/command_handler.rst +++ /dev/null @@ -1,69 +0,0 @@ -Slash Command Handler for ManagerX -================================== - -The **Slash Command Handler** is a core component of ManagerX, responsible for processing and executing user commands as **Slash Commands** (``/command``). It replaces traditional prefix-based commands with Py-cordโ€™s ``@slash_command`` system, enabling modern, native Discord interactions. - -The handler automatically registers all Slash Commands, validates parameters, and routes them to the appropriate cogs or functions for execution. - -Key Features ------------- - -- **Slash Command Registration:** All commands are registered using ``@slash_command`` in Py-cord. -- **Parameter Parsing:** Extracts and checks parameters directly from the Slash Command input. -- **Validation:** Ensures all input parameters meet expected types and formats. -- **Routing:** Directs commands to the correct cog or function for execution. -- **Error Handling:** Provides clear feedback when a command fails due to invalid input or insufficient permissions. -- **Extensibility:** Seamlessly integrates with the cog system, allowing modular command definitions. - -Command Processing Workflow ---------------------------- - -1. **Listening for Slash Commands:** Continuously monitors for Slash Command invocations. -2. **Parsing Input:** Identifies the command name and extracts parameters. -3. **Validation:** Confirms that input parameters match expected types and formats. -4. **Permission Check:** Ensures the user has the necessary permissions to execute the command. -5. **Routing to Cog:** Forwards valid commands with proper permissions to the appropriate cog or function. -6. **Execution:** Executes the command via the designated cog or function. -7. **User Feedback:** Sends a response to the user indicating success or detailing any errors encountered. - -Py-cord Slash Command Structure for ManagerX ---------------------------------------------- -ManagerX uses a modular Cog system with Slash Commands (`@slash_command`) for clean, maintainable command handling. Every command is a slash command with automatic parameter parsing, validation, and permission checks. - -1. Example Cog with Slash Commands ------------------------------------- - -.. code-block:: python - - from dicord import slash_command - from discord.ext import commands - - class FunCommands(commands.Cog): - def __init__(self, bot): - self.bot = bot - - @slash_command(name="connect4", description="Starts a game of Connect 4 with another user.") - async def connect4(self, ctx, user: discord.Member): - # Command logic here - await ctx.respond(f"Starting Connect 4 with {user.mention}!") - - @slash_command(name="tictactoe", description="Starts a game of Tic Tac Toe with another user.") - async def tictactoe(self, ctx, user: discord.Member): - # Command logic here - await ctx.respond(f"Starting Tic Tac Toe with {user.mention}!") - - def setup(bot): - bot.add_cog(FunCommands(bot)) - -This example demonstrates how to define a cog with multiple Slash Commands. Each command is decorated with `@slash_command`, specifying its name and description. The commands accept parameters, which are automatically parsed and validated by Py-cord. - -2. Features Demonstrated ------------------------------ -- **Slash Command Registration:** `@discord.slash_command` or `@slash_command` automatically registers commands with Discord. -- **Parameter Parsing:** Parameters like `user: discord.Member` are automatically parsed and validated. -- **Validation:** Py-cord ensures parameters are of the correct type (e.g., `discord.Member`). -- **Routing:** Commands are routed to the appropriate cog methods. -- **Error Handling:** Py-cord provides built-in error handling for invalid inputs or permission issues. -- **Extensibility:** New commands can be easily added to the cog without modifying existing code. - -This structure allows ManagerX to fully utilize Slash Commands with clean cogs, parameter validation, and user feedback. \ No newline at end of file diff --git a/docs/dev_guide/architecture/database_handler.rst b/docs/dev_guide/architecture/database_handler.rst deleted file mode 100644 index ab38830..0000000 --- a/docs/dev_guide/architecture/database_handler.rst +++ /dev/null @@ -1,43 +0,0 @@ -Database Handler -========================= - -The **Database Handler** is a crucial component of ManagerX, responsible for managing all interactions with the underlying database system. It provides a structured and efficient way to store, retrieve, and manipulate data required by various features of the bot. - -Architecture -------------------------- - -The Database Handler is designed to abstract the complexities of database operations, allowing developers to interact with the database through a simplified interface. It supports various database systems, ensuring flexibility and scalability for different deployment scenarios. - -Key Features -------------------------- - -- **Connection Management:** Handles the establishment and termination of database connections, ensuring optimal resource usage. -- **Query Execution:** Provides methods to execute SQL queries and commands, including support for prepared statements to enhance security and performance. -- **Data Retrieval:** Facilitates the retrieval of data in various formats, making it easy to work with the results of database queries. -- **Error Handling:** Implements robust error handling mechanisms to manage database-related exceptions and ensure data integrity. -- **Transaction Management:** Supports database transactions, allowing for atomic operations and rollback capabilities in case of failures. -- **ORM Integration:** Optionally integrates with Object-Relational Mapping (ORM) libraries to simplify data modeling and manipulation. - -Usage -------------------------- - -Developers can utilize the Database Handler to perform CRUD (Create, Read, Update, Delete) operations on the database. The handler exposes a set of methods that can be called to interact with the database without needing to write raw SQL queries. - -Example -------------------------- - -.. code-block:: python - - # Example of using the Database Handler to fetch user data - db_handler = DatabaseHandler() - - # Fetch user by ID - user_data = db_handler.fetch_one("SELECT * FROM users WHERE id = %s", (user_id,)) - - # Insert a new user - db_handler.execute("INSERT INTO users (username, email) VALUES (%s, %s)", (username, email)) - -Conclusion -------------------------- - -The Database Handler is an essential part of ManagerX's architecture, providing a reliable and efficient way to manage data storage and retrieval. Its design focuses on ease of use, performance, and scalability, making it a vital tool for developers working with the bot's data layer. \ No newline at end of file diff --git a/docs/dev_guide/architecture/error_handler.rst b/docs/dev_guide/architecture/error_handler.rst deleted file mode 100644 index 413dd07..0000000 --- a/docs/dev_guide/architecture/error_handler.rst +++ /dev/null @@ -1,48 +0,0 @@ -Error Handler -================= - -The **Error Handler** in ManagerX is a dedicated component responsible for managing and responding to errors that occur during the bot's operation. It ensures that errors are logged appropriately and that users receive meaningful feedback when something goes wrong. - -Architecture -------------------------- - -The Error Handler is designed to capture exceptions raised during command execution, event handling, and other bot operations. It integrates with the bot's logging system to record error details, including stack traces and contextual information. - -Key Features -------------------------- - -- **Centralized Error Management:** All errors are routed through a single handler, simplifying maintenance and updates. -- **Detailed Logging:** Errors are logged with comprehensive details to facilitate debugging and issue resolution. -- **User Feedback:** Provides informative messages to users when errors occur, enhancing user experience. -- **Custom Exception Handling:** Supports custom exceptions for specific error scenarios, allowing tailored responses. -- **Extensibility:** Easily extendable to handle new types of errors as the bot's functionality grows. - -Usage -------------------------- - -Developers can utilize the Error Handler by raising exceptions within their commands or event listeners. The handler will automatically catch these exceptions and process them according to its configuration. - -Example -------------------------- - -.. code-block:: python - from discord.ext import commands - - class MyCog(commands.Cog): - def __init__(self, bot): - self.bot = bot - - @commands.command() - async def risky_command(self, ctx): - try: - # Some operation that may fail - result = 1 / 0 # This will raise a ZeroDivisionError - except Exception as e: - raise commands.CommandError("An error occurred while executing the command.") from e - def setup(bot): - bot.add_cog(MyCog(bot)) - -Conclusion -------------------------- - -The Error Handler is a vital component of ManagerX's architecture, providing robust error management capabilities. Its design focuses on centralized handling, detailed logging, and user feedback, ensuring that both developers and users can effectively deal with errors that arise during the bot's operation. diff --git a/docs/dev_guide/architecture/event_loop.rst b/docs/dev_guide/architecture/event_loop.rst deleted file mode 100644 index 96b1300..0000000 --- a/docs/dev_guide/architecture/event_loop.rst +++ /dev/null @@ -1,42 +0,0 @@ -Event Loop -================== - -The event loop is a core component of the ManagerX architecture, responsible for handling asynchronous events and tasks. It allows the bot to efficiently manage multiple operations concurrently, ensuring responsiveness and scalability. - -Architecture ------------------- - -The event loop is built on top of Python's asyncio library, which provides the necessary infrastructure for asynchronous programming. ManagerX leverages this library to create an event-driven architecture that can handle various types of events, such as user commands, message events, and background tasks. - -Key Features ------------------- - -- **Asynchronous Execution:** The event loop enables non-blocking execution of tasks, allowing the bot to handle multiple events simultaneously without waiting for each task to complete. -- **Event Handling:** The event loop listens for events from the Discord API and dispatches them to the appropriate handlers, ensuring that user interactions are processed in real-time. -- **Task Scheduling:** The event loop can schedule tasks to run at specific intervals or after certain delays, enabling features like periodic updates and time-based actions. -- **Concurrency Management:** The event loop efficiently manages concurrent tasks, ensuring that resources are utilized optimally and that tasks do not interfere with each other. -Usage ------------------- - -Developers can interact with the event loop by defining asynchronous functions (coroutines) that are executed in response to specific events. These functions can be registered as event handlers or scheduled as background tasks. -Example ------------------- -.. code-block:: python - import asyncio - - async def my_event_handler(): - print("Event handled") - - async def main(): - # Schedule the event handler to run - asyncio.create_task(my_event_handler()) - - # Run the event loop for a short time - await asyncio.sleep(1) - - asyncio.run(main()) - -Conclusion ------------------- - -The event loop is a fundamental part of ManagerX's architecture, enabling efficient and responsive handling of asynchronous events. Its design focuses on concurrency, scalability, and real-time processing, making it a vital component for the bot's operation. diff --git a/docs/dev_guide/architecture/index.rst b/docs/dev_guide/architecture/index.rst deleted file mode 100644 index 2b676f1..0000000 --- a/docs/dev_guide/architecture/index.rst +++ /dev/null @@ -1,17 +0,0 @@ -Architecture -==================== -Architecture of ManagerX. -ManagerX is built with a modular architecture that emphasizes scalability, maintainability, and ease of development. The core components of the architecture include the event loop, command handler, database handler, cog system, logging system, and error handling mechanisms. -Each component is designed to handle specific responsibilities, allowing developers to work on individual parts of the bot without affecting the overall system. This modular approach facilitates collaboration among developers and enables the addition of new features with minimal disruption. - - -.. toctree:: - :maxdepth: 2 - :caption: Architecture Components: - - Event Loop - Command Handler - Database Handler - Cog System - Logging System - Error Handling diff --git a/docs/dev_guide/architecture/logging_system.rst b/docs/dev_guide/architecture/logging_system.rst deleted file mode 100644 index 5ff0170..0000000 --- a/docs/dev_guide/architecture/logging_system.rst +++ /dev/null @@ -1,44 +0,0 @@ -Logging System -================= - -The **Logging System** in ManagerX is a crucial component that handles the recording and management of log messages generated by the bot during its operation. It provides developers and administrators with insights into the bot's behavior, performance, and any issues that may arise. - -Architecture -------------------------- - -The Logging System is designed to capture log messages from various parts of the bot, including command execution, event handling, and system operations. It categorizes logs based on severity levels (e.g., DEBUG, INFO, WARNING, ERROR, CRITICAL) and formats them for easy readability. - -Key Features -------------------------- - -- **Centralized Logging:** All log messages are routed through a central logging handler, ensuring consistency in log formatting and storage. -- **Multiple Log Levels:** Supports various log levels to filter messages based on their importance, allowing developers to focus on critical issues or debug information as needed. -- **File and Console Output:** Logs can be directed to both console output for real-time monitoring and log files for persistent storage and later analysis. -- **Timestamping:** Each log entry is timestamped, providing context for when events occurred. -- **Custom Log Handlers:** Supports custom log handlers for specialized logging needs, such as sending logs to external monitoring services or databases. -- **Rotating Log Files:** Implements log rotation to manage log file sizes and prevent disk space exhaustion. - -Usage -------------------------- - -Developers can utilize the Logging System by importing the logging module and using predefined loggers to record messages at various levels. The system is configurable, allowing for adjustments to log levels and output formats as needed. - -Example -------------------------- - -.. code-block:: python - from logs import logger, LogLevel, Category, LogFormat - - - # Log messages at different levels - logger.debug(Category.DEBUG, "This is a debug message.") - logger.info(Category.INFO, "Bot started successfully.") - logger.warning(Category.API, "This is a warning message.") - logger.error(Category.COMMAND, "An error occurred during command execution.") - logger.critical(Category.API, "Critical issue! Immediate attention required.") - -Conclusion -------------------------- - -Requires the SimpleColoredLogs package for colored console output. -The Logging System is an essential part of ManagerX's architecture, providing robust logging capabilities that enhance the bot's maintainability and debuggability. Its design focuses on flexibility, clarity, and ease of use, making it a valuable tool for developers and administrators alike. \ No newline at end of file diff --git a/docs/dev_guide/contributing/coding_standards.rst b/docs/dev_guide/contributing/coding_standards.rst deleted file mode 100644 index 342c716..0000000 --- a/docs/dev_guide/contributing/coding_standards.rst +++ /dev/null @@ -1,16 +0,0 @@ -Coding Standards -================ - -To maintain high code quality, please follow these guidelines: - -Python Style ------------- -* **PEP8**: Follow the PEP8 style guide strictly. -* **Naming**: Use meaningful variable and function names. -* **Docstrings**: Add docstrings for all public functions and classes. - -Design Principles ------------------ -* Write **modular** and reusable code. -* Ensure **backward compatibility** wherever possible. -* Keep functions small and focused on a single task. \ No newline at end of file diff --git a/docs/dev_guide/contributing/contributing.rst b/docs/dev_guide/contributing/contributing.rst deleted file mode 100644 index 8bd0457..0000000 --- a/docs/dev_guide/contributing/contributing.rst +++ /dev/null @@ -1,17 +0,0 @@ -Contributing to ManagerX -======================== - -Welcome to the ManagerX development community! ๐Ÿš€ -Your contributions help make ManagerX better for everyone. Whether you're fixing bugs, adding features, or improving documentation, we value your help. - -.. note:: - This project is permanently under development. We encourage developers to explore these resources and contribute to the growth and improvement of ManagerX! - - -Additional Information ----------------------- - -* :doc:`code_of_conduct` -* `Issue Tracker (GitHub) `_ - -Thank you for contributing! \ No newline at end of file diff --git a/docs/dev_guide/contributing/documentation.rst b/docs/dev_guide/contributing/documentation.rst deleted file mode 100644 index 50797e5..0000000 --- a/docs/dev_guide/contributing/documentation.rst +++ /dev/null @@ -1,13 +0,0 @@ -Documentation Guide -=================== - -Good documentation is just as important as good code. - -Guidelines ----------- -* **Update Docs**: If your changes affect functionality, update the relevant files. -* **Examples**: Add examples for new commands or features. -* **Format**: Use the same **reStructuredText** format as used here. - -.. hint:: - Always proofread your documentation for clarity and grammar before submitting. \ No newline at end of file diff --git a/docs/dev_guide/contributing/testing.rst b/docs/dev_guide/contributing/testing.rst deleted file mode 100644 index 5e45588..0000000 --- a/docs/dev_guide/contributing/testing.rst +++ /dev/null @@ -1,24 +0,0 @@ -Quality Assurance & Testing -=========================== - -In ManagerX, we focus on manual verification and functional integrity rather than using external testing libraries. - -How to Verify Your Changes --------------------------- - -Before submitting a Pull Request, please ensure the following: - -1. **Manual Functional Test**: - Run the application and manually trigger the feature you changed. Verify that it behaves exactly as described in your PR. - -2. **No Regression**: - Check that your changes do not break existing core functionalities of ManagerX. - -3. **Log Check**: - Monitor the console output or log files while running your changes to ensure no new warnings or errors are being triggered. - -4. **Environment Check**: - Ensure your code runs in the standard development environment without requiring additional, unlisted dependencies. - -.. warning:: - Code that causes the application to crash or introduces obvious logic errors will be sent back for revision. \ No newline at end of file diff --git a/docs/dev_guide/contributing/workflow.rst b/docs/dev_guide/contributing/workflow.rst deleted file mode 100644 index 4ce24db..0000000 --- a/docs/dev_guide/contributing/workflow.rst +++ /dev/null @@ -1,41 +0,0 @@ -Development Workflow -==================== - -Follow these 10 steps to contribute your changes to ManagerX. - -How to Contribute ------------------ - -1. **Fork the Repository**: Create your copy on GitHub. -2. **Clone Your Fork**: - .. code-block:: bash - - git clone https://github.com/Oppro-net-Development/ManagerX.git - -3. **Create a New Branch**: - .. code-block:: bash - - git checkout -b feature/your-feature-name - -4. **Make Your Changes**: Follow our coding standards. -5. **Test Your Changes**: Ensure everything works. -6. **Commit Your Changes**: - .. code-block:: bash - - git add . - git commit -m "Add feature: your description" - -7. **Push Your Changes**: - .. code-block:: bash - - git push origin feature/your-feature-name - -8. **Create a Pull Request**: Navigate to the original ManagerX repo. -9. **Address Feedback**: Collaborate with maintainers. -10. **Celebrate!** ๐ŸŽ‰ - -Issue Reporting ---------------- - -If you encounter any bugs, please report them on the `GitHub Issues `_ tab. -Include steps to reproduce, expected behavior, and logs. \ No newline at end of file diff --git a/docs/dev_guide/database/index.rst b/docs/dev_guide/database/index.rst deleted file mode 100644 index 82d20eb..0000000 --- a/docs/dev_guide/database/index.rst +++ /dev/null @@ -1,514 +0,0 @@ -Database & Database Handler -================================= - -ManagerX uses SQLite databases to persist data for various features. Each database handler is responsible for managing a specific feature's data storage. - -.. toctree:: - :maxdepth: 2 - :caption: Database Handlers: - - AutoDelete Database - Spam Detection Database - Warning System Database - Welcome System Database - Level System Database - Logging Database - Notes Database - Global Chat Database - Voice Channel Database - Stats Database - - -Database Overview ------------------ - -The following databases are used in ManagerX: - -.. list-table:: - :header-rows: 1 - :widths: 20 50 30 - - * - Database File - - Purpose - - Handler Class - * - `autodelete.db` - - Auto-delete messages in channels - - `AutoDeleteDB` - * - `spam.db` - - Anti-spam detection and configuration - - `SpamDB` - * - `warns.db` - - User warning system - - `WarnDatabase` - * - `welcome.db` - - Welcome messages and settings - - `WelcomeDatabase` - * - `levelsystem.db` - - User levels and XP tracking - - `LevelDatabase` - * - `log_channels.db` - - Server logging configuration - - `LoggingDatabase` - * - `notes.db` - - User notes and moderator notes - - `NotesDatabase` - * - `globalchat.db` - - Global chat network settings - - `GlobalChatDB` - * - `vc.db` - - Voice channel management - - `VoiceChannelDB` - * - `stats.db` - - Server statistics - - `StatsDB` - -Detailed Database Documentation --------------------------------- - -AutoDelete Database -~~~~~~~~~~~~~~~~~~~ - -**File:** `data/autodelete.db` - -**Purpose:** Manages auto-deletion of messages in specific channels. - -**Tables:** - -- **autodelete**: Main configuration table - - - `channel_id`: Channel ID (UNIQUE) - - `duration`: Seconds before message deletion - - `exclude_pinned`: Exclude pinned messages (default: 1) - - `exclude_bots`: Exclude bot messages (default: 0) - - `created_at`: Timestamp of creation - - `updated_at`: Last update timestamp - -- **autodelete_whitelist**: User/Role whitelist - - - `channel_id`: Reference to autodelete channel - - `target_id`: User or Role ID - - `target_type`: 'user' or 'role' - - `added_at`: When added to whitelist - -- **autodelete_schedules**: Scheduled deletion timeframes - - - `channel_id`: Reference to autodelete channel - - `start_time`: Start time (HH:MM format) - - `end_time`: End time (HH:MM format) - - `days`: Days of week (JSON array or comma-separated) - -- **autodelete_stats**: Statistics tracking - - - `channel_id`: Reference to autodelete channel - - `deleted_count`: Total messages deleted - - `error_count`: Failed deletion attempts - - `last_deletion`: Timestamp of last deletion - -**Key Methods:** - -.. code-block:: python - - # Add or update auto-delete configuration - add_autodelete(channel_id, duration, exclude_pinned=True, exclude_bots=False) - - # Add user/role to whitelist - add_whitelist(channel_id, target_id, target_type) - - # Get configuration for channel - get_autodelete(channel_id) - ---- - -Spam Detection Database -~~~~~~~~~~~~~~~~~~~~~~~ - -**File:** `data/spam.db` - -**Purpose:** Tracks spam patterns and manages anti-spam settings. - -**Tables:** - -- **spam_settings**: Server spam configuration - - - `guild_id`: Server ID (PRIMARY KEY) - - `max_messages`: Max messages in time window - - `time_window`: Time window in seconds - - `action`: Action to take (kick, mute, delete) - - `created_at`: Configuration creation date - - `updated_at`: Last configuration update - -- **spam_logs**: Spam detection logs - - - `id`: Log entry ID - - `guild_id`: Server ID - - `user_id`: User ID - - `message_count`: Number of messages - - `timestamp`: Detection timestamp - - `action_taken`: Action that was performed - -- **spam_whitelist**: Exempt users/roles - - - `guild_id`: Server ID - - `target_id`: User or Role ID - - `target_type`: 'user' or 'role' - - `added_by`: User ID who added to whitelist - - `reason`: Reason for whitelist - - `added_at`: When added - -**Features:** - -- Context manager for database operations -- Automatic database migration support -- Enhanced error handling and logging -- Support for user and role whitelisting - -**Key Methods:** - -.. code-block:: python - - # Get spam settings for guild - get_spam_settings(guild_id) - - # Update spam detection settings - update_spam_settings(guild_id, max_messages, time_window) - - # Log spam detection - add_spam_log(guild_id, user_id, message_count) - - # Add user to whitelist - add_to_whitelist(guild_id, target_id, target_type, reason) - ---- - -Warning System Database -~~~~~~~~~~~~~~~~~~~~~~~ - -**File:** `data/Datenbanken/warns.db` - -**Purpose:** Stores user warnings for moderation. - -**Tables:** - -- **warns**: Warning records - - - `id`: Warning ID (PRIMARY KEY) - - `guild_id`: Server ID - - `user_id`: User ID - - `moderator_id`: Moderator who issued warning - - `reason`: Warning reason - - `timestamp`: When warning was issued - -**Key Methods:** - -.. code-block:: python - - # Add warning for user - add_warning(guild_id, user_id, moderator_id, reason, timestamp) - - # Get all warnings for user - get_warnings(guild_id, user_id) - - # Get warning by ID - get_warning_by_id(warn_id) - - # Delete warning - delete_warning(warn_id) - - # Get warning count - get_warning_count(guild_id, user_id) - ---- - -Welcome System Database -~~~~~~~~~~~~~~~~~~~~~~~ - -**File:** `data/welcome.db` - -**Purpose:** Manages welcome message configuration and settings. - -**Tables:** - -- **welcome_settings**: Server welcome configuration - - - `guild_id`: Server ID (PRIMARY KEY) - - `channel_id`: Welcome channel ID - - `welcome_message`: Welcome message text - - `enabled`: Whether welcome is enabled - - `embed_enabled`: Use embed format - - `embed_color`: Embed color (HEX format) - - `embed_title`: Embed title - - `embed_description`: Embed description - - `embed_thumbnail`: Show member avatar - - `embed_footer`: Embed footer text - - `ping_user`: Ping the new user - - `delete_after`: Auto-delete after N seconds - - `created_at`: Creation timestamp - - `updated_at`: Last update timestamp - -**Features:** - -- Supports both text and embed messages -- Automatic database migration -- Backward compatibility with older versions -- Asynchronous and synchronous methods - -**Key Methods:** - -.. code-block:: python - - # Update welcome settings - await update_welcome_settings(guild_id, channel_id=None, message=None, ...) - - # Get welcome settings - await get_welcome_settings(guild_id) - - # Enable/disable welcome - await toggle_welcome(guild_id, enabled) - - # Delete welcome settings - await delete_welcome_settings(guild_id) - ---- - -Level System Database -~~~~~~~~~~~~~~~~~~~~~ - -**File:** `data/levelsystem.db` - -**Purpose:** Tracks user XP, levels, and progression. - -**Tables:** - -- **user_levels**: User XP and level data - - - `guild_id`: Server ID - - `user_id`: User ID - - `level`: Current level - - `xp`: Current XP - - `total_xp`: Total XP earned - - `last_message_time`: Last message timestamp - - `prestige_count`: Prestige level - -- **level_roles**: Reward roles for levels - - - `guild_id`: Server ID - - `level`: Level requirement - - `role_id`: Reward role ID - -- **level_settings**: Server configuration - - - `guild_id`: Server ID - - `enabled`: Level system enabled - - `xp_per_message`: XP per message - - `cooldown_seconds`: Message cooldown - -**Features:** - -- Anti-spam detection to prevent XP farming -- Level role rewards -- Prestige system -- Caching for performance -- Comprehensive logging - -**Key Methods:** - -.. code-block:: python - - # Add XP to user (with anti-spam check) - add_xp(guild_id, user_id, xp_amount) - - # Get user level data - get_user_level(guild_id, user_id) - - # Set level role reward - set_level_role(guild_id, level, role_id) - - # Get leaderboard - get_leaderboard(guild_id, limit=10) - ---- - -Logging Database -~~~~~~~~~~~~~~~~ - -**File:** `data/log_channels.db` - -**Purpose:** Stores logging channel configuration for different log types. - -**Tables:** - -- **log_channels**: Log channel configuration - - - `guild_id`: Server ID - - `log_type`: Type of log (member_join, member_leave, message_delete, etc.) - - `channel_id`: Discord channel ID for logs - - `enabled`: Whether this log type is enabled - - `created_at`: Creation timestamp - - `updated_at`: Last update timestamp - -**Log Types Supported:** - -- `member_join`: New member joins -- `member_leave`: Member leaves -- `member_ban`: Member banned -- `member_kick`: Member kicked -- `member_unban`: Member unbanned -- `message_delete`: Message deletion -- `message_edit`: Message editing -- `role_create`: Role created -- `role_delete`: Role deleted -- `channel_create`: Channel created -- `channel_delete`: Channel deleted - -**Key Methods:** - -.. code-block:: python - - # Set log channel for type - set_log_channel(guild_id, log_type, channel_id) - - # Get log channel for type - get_log_channel(guild_id, log_type) - - # Enable/disable log type - set_log_enabled(guild_id, log_type, enabled) - - # Get all logs for guild - get_all_logs(guild_id) - ---- - -Notes Database -~~~~~~~~~~~~~~ - -**File:** `data/notes.db` - -**Purpose:** Stores moderator notes about users. - -**Tables:** - -- **notes**: User notes - - - `id`: Note ID (PRIMARY KEY) - - `guild_id`: Server ID - - `user_id`: User the note is about - - `author_id`: User who created the note - - `author_name`: Name of note author - - `note`: Note content - - `timestamp`: Creation timestamp - -**Key Methods:** - -.. code-block:: python - - # Add note to user - add_note(guild_id, user_id, author_id, author_name, note, timestamp) - - # Get all notes for user - get_notes(guild_id, user_id) - - # Get specific note - get_note_by_id(note_id) - - # Delete note - delete_note(note_id) - ---- - -Database Patterns and Best Practices ------------------------------------- - -Connection Management -~~~~~~~~~~~~~~~~~~~~~ - -All database handlers use context managers for safe connection handling: - -.. code-block:: python - - @contextmanager - def get_cursor(self): - """Context manager for database operations""" - cursor = self.conn.cursor() - try: - yield cursor - except sqlite3.Error as e: - self.conn.rollback() - logger.error(f"Database error: {e}") - raise - finally: - cursor.close() - -Error Handling -~~~~~~~~~~~~~~ - -Databases include comprehensive error handling: - -- Custom exception classes (e.g., `SpamDBError`) -- Automatic rollback on errors -- Detailed logging of all operations -- Graceful degradation when operations fail - -Caching and Performance -~~~~~~~~~~~~~~~~~~~~~~~ - -Some databases implement caching for frequently accessed data: - -.. code-block:: python - - # Example from LevelDatabase - self.level_roles_cache = {} - self.enabled_guilds_cache = set() - self.guild_configs_cache = {} - -Migration Strategy -~~~~~~~~~~~~~~~~~~ - -Databases support automatic schema migration: - -.. code-block:: python - - def _migrate_database(self): - """Handle database migrations for schema changes""" - # Adds new columns to existing tables - # Migrates data from old structure to new - # Maintains backward compatibility - -Directory Structure -~~~~~~~~~~~~~~~~~~~ - -Database files are stored in the `data/` directory: - -.. code-block:: - - data/ - โ”œโ”€โ”€ autodelete.db - โ”œโ”€โ”€ spam.db - โ”œโ”€โ”€ welcome.db - โ”œโ”€โ”€ levelsystem.db - โ”œโ”€โ”€ log_channels.db - โ”œโ”€โ”€ notes.db - โ”œโ”€โ”€ globalchat.db - โ”œโ”€โ”€ vc.db - โ”œโ”€โ”€ stats.db - โ””โ”€โ”€ Datenbanken/ - โ””โ”€โ”€ warns.db - -Access Location -~~~~~~~~~~~~~~~ - -All database handlers are located in: - -.. code-block:: - - src/DevTools/backend/database/ - โ”œโ”€โ”€ __init__.py - โ”œโ”€โ”€ autodelete_db.py - โ”œโ”€โ”€ spam_db.py - โ”œโ”€โ”€ warn_db.py - โ”œโ”€โ”€ welcome_db.py - โ”œโ”€โ”€ levelsystem_db.py - โ”œโ”€โ”€ logging_db.py - โ”œโ”€โ”€ notes_db.py - โ”œโ”€โ”€ globalchat_db.py - โ”œโ”€โ”€ vc_db.py - โ””โ”€โ”€ stats_db.py \ No newline at end of file diff --git a/docs/dev_guide/index.rst b/docs/dev_guide/index.rst deleted file mode 100644 index 5989969..0000000 --- a/docs/dev_guide/index.rst +++ /dev/null @@ -1,50 +0,0 @@ -Developer Guide -========================= - -Welcome to the ManagerX Developer Guide! This section provides in-depth information for developers looking to contribute to or extend ManagerX. - -.. note:: - This project is permanently under development. We recommend checking this guide frequently for updates. - -.. toctree:: - :maxdepth: 2 - :caption: Getting Started: - - Installation - Development Setup - Quickstart Guide - -.. toctree:: - :maxdepth: 2 - :caption: Architecture: - - Architecture Overview - API Reference - -.. toctree:: - :maxdepth: 2 - :titlesonly: - :caption: Contribution: - - Contribution - Workflow - Coding Standards - Testing Procedures - Documentation Guidelines - -.. toctree:: - :maxdepth: 2 - :caption: Advanced Topics: - - Performance Optimization - Security Best Practices - -.. toctree:: - :maxdepth: 1 - :caption: Community & Support: - - FAQ - Glossary - Support Channels - -We encourage all developers to actively participate in the ManagerX community. Your contributions help make ManagerX better for everyone! \ No newline at end of file diff --git a/docs/dev_guide/installation/index.rst b/docs/dev_guide/installation/index.rst deleted file mode 100644 index 8f0b1de..0000000 --- a/docs/dev_guide/installation/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -installation of ManagerX -=============================== - -This guide explains how to install ManagerX on your system. - -.. toctree:: - :maxdepth: 2 - :caption: Installation Methods: - - Install from Source Code - Dependencies & Requirements \ No newline at end of file diff --git a/docs/dev_guide/installation/install_from_source.rst b/docs/dev_guide/installation/install_from_source.rst deleted file mode 100644 index c50f23e..0000000 --- a/docs/dev_guide/installation/install_from_source.rst +++ /dev/null @@ -1,105 +0,0 @@ -============================= -Install from Source Code -============================= - -This guide explains how to install **ManagerX** directly from its source code. This method is ideal for developers looking to contribute or those who require the latest features from the repository. - -.. note:: - If you encounter any issues during installation, please check our Troubleshooting section or open an issue on GitHub. - -Prerequisites -------------- - -Before proceeding, ensure you have the following installed on your system: - -* **Python 3.10** or higher -* **Git** -* A valid **Discord Bot Token** from the `Discord Developer Portal `_ - -Cloning the Repository ----------------------- - -First, clone the ManagerX repository from GitHub and navigate into the project directory: - -.. code-block:: bash - - git clone https://github.com/Oppro-net-Development/ManagerX.git - cd ManagerX - -Setting Up a Virtual Environment --------------------------------- - -It is highly recommended to use a virtual environment to isolate dependencies and avoid conflicts with your system's Python packages. - -**On Linux/macOS:** - -.. code-block:: bash - - python3 -m venv venv - source venv/bin/activate - -**On Windows:** - -.. code-block:: bash - - python -m venv venv - .\venv\Scripts\activate - -Installing Dependencies ------------------------ - -ManagerX uses modular requirement files depending on your use case. Choose **one** of the following options: - -**1. Standard Installation** -Basic requirements for running the application: - -.. code-block:: bash - - pip install -r requirements/req.txt - -**2. Bot Only** -Minimal requirements to run only the Discord bot component: - -.. code-block:: bash - - pip install -r requirements/bot_req.txt - -**3. Development Environment** -Includes testing frameworks and code formatters (e.g., black, pytest): - -.. code-block:: bash - - pip install -r requirements/dev_req.txt - -**4. Documentation Tools** -Includes tools like Sphinx for building the documentation: - -.. code-block:: bash - - pip install -r requirements/docs_req.txt - -Configuration -------------- - -Before running the bot, you need to set up your environment variables. - -1. Create a ``.env`` file in the root directory. -2. Add your bot token as follows: - -.. code-block:: text - - TOKEN=your_discord_bot_token_here - -Running ManagerX ----------------- - -Once the installation and configuration are complete, start the application: - -.. code-block:: bash - - python main.py - -You should see an output indicating that **ManagerX** is successfully connected to Discord. - -.. tip:: - Ensure that **Privileged Gateway Intents** (Member, Presence, Message Content) are enabled in the Discord Developer Portal under the "Bot" tab, or the bot may not function correctly. \ No newline at end of file diff --git a/docs/dev_guide/self_hosting/index.rst b/docs/dev_guide/self_hosting/index.rst deleted file mode 100644 index 7692402..0000000 --- a/docs/dev_guide/self_hosting/index.rst +++ /dev/null @@ -1,29 +0,0 @@ -How to self-host ManagerX? -============================== -This guide will walk you through the steps required to self-host ManagerX on your own server. - -Prerequisites -------------- - -- A server or VPS with at least 2GB of RAM - -- Python 3.8 or higher installed - -- Git installed - -- A Discord bot token (create a bot on the Discord Developer Portal) - -Step 1: Clone the Repository ----------------------------- -First, clone the ManagerX repository from GitHub: - -:: - git clone https://github.com/Oppro-net-Development/ManagerX.git - - -Step 2: Install Dependencies - -:: - pip install -r requirements/req.txt - - diff --git a/docs/make.bat b/docs/make.bat index 954237b..dc1312a 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -7,8 +7,8 @@ REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) -set SOURCEDIR=. -set BUILDDIR=_build +set SOURCEDIR=source +set BUILDDIR=build %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst deleted file mode 100644 index b27cbc7..0000000 --- a/docs/plugins/index.rst +++ /dev/null @@ -1,47 +0,0 @@ -Available Plugins for ManagerX -============================== - -No Plugins Available ๐Ÿ˜ฅ ------------------------ - -At the moment, there are **no plugins available** for ManagerX. -We are actively working on developing a variety of plugins to expand the functionality of ManagerX. -Stay tuned for future releases! - -Code Your Own Plugins ---------------------- - -If you're interested in creating your own plugins for ManagerX, the **Developer Guide** provides detailed instructions, examples, and best practices. -Read the `Own Plugins Guide `_ to get started on building custom plugins tailored to your needs. - -Submitting Your Plugin ----------------------- - -Once your plugin is ready and tested, you can submit it to the ManagerX team for review: - -1. **Ensure your plugin meets all requirements** - - Follows the **ManagerX Plugin Guidelines** (safety, structure, versioning, documentation). - - Verified to be **free of malicious code**. - -2. **Prepare a repository** - - Include your plugin code in a clean GitHub repository. - - Provide a `README.md` and any required metadata (e.g., `pyproject.toml` for PyPI plugins). - -3. **Submit for review via Discord** - - Join the **OPPRO.NET Development** Discord server. - - Go to the `#plugins` channel. - - Submit your plugin repository **with the tag `ManagerX`**. - - The ManagerX team will review your submission for **quality, security, and compliance**. - -4. **Approval & Listing** - - Approved plugins will be listed in the **Official Plugins** section of the docs. - - Plugins that are safe but not officially endorsed may appear in the **Other Plugins** section. - -.. toctree:: - :maxdepth: 2 - :caption: Plugin Documentation: - :hidden: - - Own Plugins Guide - Official Plugins - Other Plugins diff --git a/docs/plugins/official_plugins/managerx_handler.rst b/docs/plugins/official_plugins/managerx_handler.rst deleted file mode 100644 index a6cb9c0..0000000 --- a/docs/plugins/official_plugins/managerx_handler.rst +++ /dev/null @@ -1,50 +0,0 @@ -========================== -ManagerX-Handler (Official) -========================== - -**The Definitive Integration Layer for the ManagerX Ecosystem** - -Official Core Distribution --------------------------- - -The **ManagerX-Handler** is the officially maintained plugin developed and issued by the **OPPRO.NET Development Team (ManagerX)**. It serves as the authoritative bridge between the ManagerX management system and your local platform. - -As an official distribution, this handler is engineered to the exact specifications of the ManagerX core, ensuring 100% compatibility, high-level security, and high-performance resource monitoring. - -Key Features ------------- - -* **Native Integration**: Direct, low-latency communication with the ManagerX API. -* **Official Maintenance**: Guaranteed compatibility with all future ManagerX updates. -* **Resource Monitoring**: Optimized for real-time tracking and seamless data synchronization. -* **Enterprise Standards**: Standardized deployment suitable for both production and development environments. - -Installation ------------- - -The ManagerX-Handler is distributed via PyPi for secure and version-controlled deployment. - -.. code-block:: bash - - pip install managerx-handler - -*Note: To ensure system stability, always verify you are installing the official package from the OPPRO.NET PyPi repository.* - -Usage & Implementation ----------------------- - -Once installed, the ManagerX-Handler integrates as a core component of your environment. It automatically establishes the necessary communication hooks for platform interoperability. - -For detailed API references and advanced implementation guides, please refer to the official documentation provided by the **OPPRO.NET Development Team**. - -Support & Contact ------------------ - -As this is an official product, we provide dedicated support for our ecosystem. - -* **Lead Developers**: OPPRO.NET Development Team -* **Official Support**: development@oppro-network.de -* **Official Website**: https://oppro.net - -Copyright (c) 2026 OPPRO.NET Network | All Rights Reserved. -*This software is an official release. Unauthorized redistribution or modification is strictly prohibited.* \ No newline at end of file diff --git a/docs/plugins/own_plugins/create_local_plugin.rst b/docs/plugins/own_plugins/create_local_plugin.rst deleted file mode 100644 index 2da8bae..0000000 --- a/docs/plugins/own_plugins/create_local_plugin.rst +++ /dev/null @@ -1,103 +0,0 @@ -Local Plugins (Main GitHub Repository) -================================================ - -In addition to PyPI-based plugins, ManagerX also supports **local plugins** that live directly inside the **main GitHub repository**. - -These plugins are intended for: -- experimental features -- optional extensions -- community contributions -- features that may become core plugins later - -Local plugins are **not enabled or shipped by default**. - -Design Principle --------------------------------- - -Local plugins follow the same core philosophy as external plugins: - -- โŒ Not part of the default ManagerX installation -- ๐Ÿ”’ Do not affect the core unless explicitly enabled -- ๐Ÿงช Can evolve independently - -This keeps the ManagerX core clean while still allowing flexibility and experimentation. - -Repository Structure ------------------------------------- - -Local plugins are stored in a dedicated folder inside the main GitHub repository. - -Example structure: - -:: - - plugins/ - โ”œโ”€โ”€ README.md - โ”œโ”€โ”€ example_plugin/ - โ”‚ โ”œโ”€โ”€ plugin.py - โ”‚ โ””โ”€โ”€ README.md - โ”œโ”€โ”€ logging_plugin/ - โ”‚ โ”œโ”€โ”€ plugin.py - โ”‚ โ””โ”€โ”€ README.md - -- Each plugin lives in its own folder -- ``plugin.py`` contains the implementation -- ``README.md`` explains usage, configuration, and behavior - -Local plugins **must not** modify core files directly. - -Enabling Local Plugins --------------------------------------- - -Local plugins are **disabled by default**. - -To enable a local plugin: -1. Place it inside the ``plugins/`` directory -2. Enable it via the ManagerX configuration -3. Restart ManagerX - -Only explicitly enabled plugins are loaded. - -Differences to PyPI Plugins -------------------------------------------- - -+-------------------+------------------------+-------------------------+ -| Feature | Local Plugins | PyPI Plugins | -+===================+========================+=========================+ -| Location | Main GitHub repository | External (PyPI) | -+-------------------+------------------------+-------------------------+ -| Installed via pip | No | Yes | -+-------------------+------------------------+-------------------------+ -| Enabled by default| No | No | -+-------------------+------------------------+-------------------------+ -| Naming scheme | Flexible | ``managerx-*`` required | -+-------------------+------------------------+-------------------------+ -| Intended use | Experimental / optional| Public distribution | -+-------------------+------------------------+-------------------------+ - -Promotion to PyPI ---------------------------------- - -A local plugin can later be **promoted to a PyPI plugin** if it: -- proves stable -- has good documentation -- is useful to a wider audience - -In this case, it must follow the PyPI naming scheme: - -:: - - managerx-[plugin-name] - -Conclusion --------------------------- - -Local plugins provide a **safe space for innovation** without increasing the default footprint of ManagerX. - -They allow contributors to: -- test new ideas -- share optional features -- collaborate inside the main repository - -All without forcing functionality onto every ManagerX user. -Happy coding! ๐Ÿš€ \ No newline at end of file diff --git a/docs/plugins/own_plugins/create_pypi_plugin.rst b/docs/plugins/own_plugins/create_pypi_plugin.rst deleted file mode 100644 index a968f8d..0000000 --- a/docs/plugins/own_plugins/create_pypi_plugin.rst +++ /dev/null @@ -1,102 +0,0 @@ -Create your own PyPI Plugin for ManagerX -====================================================== - -ManagerX provides a flexible **plugin system** that allows developers to extend its functionality without modifying the core project. Plugins are developed as **separate Python packages** and distributed via **PyPI**. - -Plugin Philosophy --------------------------- - -Plugins are **not included by default** in ManagerX. - -This is an intentional design decision to keep ManagerX: -- lightweight -- secure -- easy to maintain - -Every plugin is installed **explicitly by the user** and lives outside the core project. - -Plugin Naming Convention ---------------------------- - -All ManagerX plugins **must** follow this naming scheme: - -:: - - managerx-[your-plugin-name] - -Examples: -- ``managerx-logger`` -- ``managerx-moderation`` -- ``managerx-backup`` - -This naming convention ensures: -- clear identification on PyPI -- no name collisions -- automatic recognition by ManagerX - -Plugin Examples on GitHub ----------------------------------- - -The official ManagerX GitHub repository contains an **examples folder** to help developers get started. - -Structure: - -:: - - examples/ - โ””โ”€โ”€ plugins/ - โ”œโ”€โ”€ basic_plugin/ - โ”‚ โ”œโ”€โ”€ plugin.py - โ”‚ โ””โ”€โ”€ README.md - โ”œโ”€โ”€ advanced_plugin/ - โ”‚ โ”œโ”€โ”€ plugin.py - โ”‚ โ””โ”€โ”€ README.md - -- ``.py`` files show how to implement plugins -- ``.md`` files explain the plugin logic and structure -- examples are **reference implementations**, not production code - -How Plugins Work -------------------- - -A ManagerX plugin is a **standalone Python package** that: - -- is installed via ``pip`` -- exposes a defined entry point -- is detected and loaded automatically by ManagerX - -Once installed, ManagerX scans for compatible plugins and enables them at runtime. - -Installing a Plugin ----------------------------- - -Plugins are installed like any other PyPI package: - -:: - - pip install managerx-your-plugin-name - -After installation, restart ManagerX to activate the plugin. - -Creating Your Own Plugin ------------------------------- - -1. Create a new Python project -2. Name it using the required prefix: ``managerx-`` -3. Implement the plugin interface -4. Add documentation (README.md) -5. Publish the package to PyPI - -By following standard Python packaging rules, plugins remain: -- easy to install -- easy to update -- easy to remove - -Conclusion ----------------- - -The ManagerX plugin system is designed for **modularity and freedom**. -You decide which features you need, and plugins provide them โ€” without bloating the core. - -Build small, focused plugins and share them with the community ๐Ÿš€ -Happy coding! diff --git a/docs/plugins/own_plugins/index.rst b/docs/plugins/own_plugins/index.rst deleted file mode 100644 index 1a64e56..0000000 --- a/docs/plugins/own_plugins/index.rst +++ /dev/null @@ -1,77 +0,0 @@ -Developing Your Own Plugins for ManagerX -======================================== - -Extend ManagerX with your own custom functionality! This guide helps you create plugins, -whether as local Cogs in the bot or as standalone PyPi projects, from setup to deployment. - -Getting Started ---------------- - -Before you begin, make sure you have: - -- Python 3.8+ installed -- A basic understanding of Python -- Familiarity with the ManagerX bot architecture - -1. Set Up Your Development Environment -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- Install all dependencies required by ManagerX. -- Clone the ManagerX repository from GitHub to get the latest codebase. -- For PyPi plugins, ensure you have `setuptools` and `wheel` installed to package your plugin. - -2. Understand the Plugin Structure -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- **Local Cogs**: look inside the `cogs` or `plugins` directory. Each plugin is typically a single Python file or module. -- **PyPi Plugins**: structure your project like a standard Python package with a `setup.py` or `pyproject.toml` file. -- Review existing plugins to understand naming conventions, commands, and event listeners. - -3. Create Your Plugin -~~~~~~~~~~~~~~~~~~~~~~~~ - -**Local Cog Example:** - -.. code-block:: python - - from discord.ext import commands - - class MyPlugin(commands.Cog): - def __init__(self, bot): - self.bot = bot - - @commands.slash_command(name="hello", description="Say hello!") - async def hello(self, ctx): - await ctx.respond(f"Hello, {ctx.author.mention}!") - - def setup(bot): - bot.add_cog(MyPlugin(bot)) - -**PyPi Plugin Tips:** - -- Wrap your plugin in a package structure (`myplugin/`) -- Include a `setup.py` or `pyproject.toml` for distribution -- Make sure your Cog is loaded automatically when installed - -4. Register Your Plugin -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- **Local Cogs**: add the Cog in your botโ€™s `setup` function or main script. -- **PyPi Plugins**: once installed via `pip`, ensure ManagerX can discover and load your plugin dynamically. - -Best Practices ---------------- - -- Keep your plugin modular, documented, and maintainable. -- Use ManagerXโ€™s `SimpleColoredLogs` for logging plugin events and errors. -- Follow existing naming and coding conventions for compatibility. -- For PyPi plugins, include versioning, dependencies, and metadata in your package. - - -.. toctree:: - :maxdepth: 2 - :caption: Next Steps - - Create a PyPi Plugin - Local Cog Development - Plugin Guidelines \ No newline at end of file diff --git a/docs/plugins/own_plugins/plugin_guidelines.rst b/docs/plugins/own_plugins/plugin_guidelines.rst deleted file mode 100644 index 49e36ae..0000000 --- a/docs/plugins/own_plugins/plugin_guidelines.rst +++ /dev/null @@ -1,182 +0,0 @@ -Plugin Policy -============================================ - -This document defines the official rules and requirements for all ManagerX -plugins, including **Local Plugins** and **PyPI Plugins**. - -The goal of this policy is to keep ManagerX: -- stable -- secure -- modular -- lightweight - -Plugins are never part of the core by default. - -------------------------------------------------------------------------------------------------------------------- - -General Principles ----------------------------------- - -- All plugins are **optional**. -- All plugins are **disabled by default**. -- The ManagerX core must never depend on plugins. -- Plugins must not modify or patch core files. - ---------------------------------------------------------------------------------------------------- - -Plugin Types ----------------------------- - -ManagerX supports two types of plugins: - -1. **PyPI Plugins** -2. **Local Plugins** - -**Local Plugins**: -- Live in the main ManagerX repository under the folder: - -:: - - plugins/ - -- Are **not Cogs**, but fully independent plugins -- Can be experimental or optional features -- Are never enabled by default - -**PyPI Plugins**: -- Distributed via PyPI -- Must follow the naming convention: - -:: - - managerx-[plugin-name] - -- Fully independent and always stored in their own GitHub repository - ------------------------------------------------------------------------------------ - -License ------------------------ - -- ManagerX itself is licensed under **GPL-3.0**. -- Local Plugins included in the repository **must also be GPL-3.0 compatible**. -- PyPI Plugins can use any license **compatible with GPL-3.0**. -- Plugins without a clear license will **not be accepted**. - ------------------------------------------------------------------------------------ - -Source Code Separation Requirement --------------------------------------------------- - -All plugins, whether Local or PyPI, must have a **dedicated GitHub repository**. - -- The repository in the main ManagerX repo (`plugins/`) is only a mirror or example. -- The **canonical source** is always the plugin's own repo. -- One plugin = one repository. - -------------------------------------------------------------------- - -Ownership & Responsibility ------------------------------------------- - -- Each plugin must have a clearly defined owner or maintainer. -- The owner is responsible for: - - bugs - - security issues - - legal matters -- ManagerX does **not** provide support for third-party plugins. - ------------------------------------------------------------------------------------ - -Security Requirements -------------------------------------- - -Plugins must not: -- contain malicious code -- collect tokens or credentials -- perform hidden network requests -- auto-update without user consent - -------------------------------------------------------------------- - -Versioning Rules --------------------------------- - -- Every plugin must define a version. -- Breaking changes require a major version bump. -- Plugin versions are independent from ManagerX versions. - ---- - -Documentation Requirement ------------------------------------------ - -Each plugin must include a `README.md` that explains: -- what the plugin does -- how to enable or install it -- configuration options -- dependencies - -Plugins without documentation are not accepted. - -------------------------------------------------------------------- - -Compatibility Rules ------------------------------------ - -- Plugins must declare supported ManagerX versions. -- Plugins must use only public plugin APIs. -- Plugins must not depend on private core interfaces. - ---- - -Enable / Disable & Removal ------------------------------------------- - -- Plugins must be safely disableable. -- Plugins must not block ManagerX startup. -- Uninstalling a plugin must not leave persistent data behind. - ---- - -Official Plugin Status --------------------------------------- - -If a plugin fulfills **all requirements** in this policy, it **may** be: - -- listed in the official ManagerX documentation -- marked as an **Official ManagerX Plugin** - -Official status means: -- recommended by ManagerX -- documented in the main docs -- still optional and not part of the core - -Promotion is evaluated on: -- stability -- code quality -- documentation -- maintenance activity - ---- - -Final Checklist -------------------------------- - -Before a plugin can be accepted or promoted: - -- [ ] Separate GitHub repository -- [ ] Correct naming (PyPI only) -- [ ] License included (GPL-3.0 compatible for Local Plugins) -- [ ] Version defined -- [ ] README.md present -- [ ] No core modifications -- [ ] Disabled by default - ---- - -Conclusion --------------------------- - -Local and PyPI plugins provide **modularity and freedom**. -The core remains clean and minimal, while plugins can evolve independently. \ No newline at end of file diff --git a/docs/releases/alpha/1.7.2a.rst b/docs/releases/alpha/1.7.2a.rst deleted file mode 100644 index 185c443..0000000 --- a/docs/releases/alpha/1.7.2a.rst +++ /dev/null @@ -1,20 +0,0 @@ -Release of Version 1.7.2 Alpha -============================== - -๐Ÿ› ๏ธ **Update:** Version 1.7.2 Alpha - -**Released by:** @Medicopter117 - -**Release Date:** Nov 20 - ---- - -๐Ÿ“ **Description** - -This is the latest Alpha release of ManagerX. - -Full changelog: v1.7.2-beta โ†’ v1.7.2-alpha - - -**Contributors** -- @Medicopter117 diff --git a/docs/releases/beta/1.7.2b.rst b/docs/releases/beta/1.7.2b.rst deleted file mode 100644 index 41282a5..0000000 --- a/docs/releases/beta/1.7.2b.rst +++ /dev/null @@ -1,18 +0,0 @@ -Release of Version 1.7.2 Beta -============================= - -๐Ÿ› ๏ธ **Update:** Version 1.7.2 Beta - -**Released by:** @Medicopter117 - -**Release Date:** Nov 11 - ---- - -๐Ÿ“ **Description** -This is a pre-release Beta version. - -Update includes container added. - -**Contributors** -- @Medicopter117 diff --git a/docs/releases/index.rst b/docs/releases/index.rst deleted file mode 100644 index 53c236a..0000000 --- a/docs/releases/index.rst +++ /dev/null @@ -1,48 +0,0 @@ -Changelog & Releases of ManagerX -=============================================== - -Stable Versions ----------------- - -Here you can find all stable releases of ManagerX. These versions have been thoroughly tested and are recommended for production use. - -.. toctree:: - :maxdepth: 2 - :caption: Stable: - - โœ… 1.7.1 - โœ… 1.7.0 - โœ… 1.6.6 - โœ… 1.6.5 - โœ… 1.6.4 - โœ… 1.6.3 - โœ… 1.6.2 - โœ… 1.6.1 - โœ… 1.6.0 - โœ… 1.5.0 - โœ… 1.4LOG - โœ… 1.3LOG - โœ… 1.1GLO - -Alpha Versions ----------------- - -Alpha releases contain new features and changes that are still under testing. They are primarily for developers or testers who want to try out the latest updates. - -.. toctree:: - :maxdepth: 2 - :caption: Alpha: - - ๐Ÿ…ฐ๏ธ 1.7.2a - ๐Ÿ…ฐ๏ธ 1.0alpha1 - -Beta Versions ----------------- - -Beta releases are more stable than alpha versions but are not fully tested yet. They are intended for early users who want to test new functionality before it is finalized. - -.. toctree:: - :maxdepth: 2 - :caption: Beta: - - ๐Ÿ…ฑ๏ธ 1.7.2b diff --git a/docs/releases/version/1.1glo.rst b/docs/releases/version/1.1glo.rst deleted file mode 100644 index a2c5157..0000000 --- a/docs/releases/version/1.1glo.rst +++ /dev/null @@ -1,34 +0,0 @@ -Release of Version 1.1GLO -========================== - -๐Ÿ› ๏ธ **Update:** Version 1.1GLO - -**Released by:** @Medicopter117 - -**Release Date:** Jul 19 - -**Commits since last release:** 208 commits to main - ---- - -๐Ÿ“ฆ **New Files** - -- `FastCoding/backend/database/levelroles_db.py` โ€“ New database module for storing and managing level roles - -- `cogs/levelsystem/levelsystem.py` โ€“ New cog for managing the leveling system (XP, progress, role assignment) - -โœ๏ธ **Modified Files** - -- `FastCoding/backend/database/__init__.py` โ€“ Database initialization extended for new modules - -- `cogs/Servermanament/globalchat.py` โ€“ Improved global chat logic and minor bug fixes - -- `FastCoding/backend/database/globalchat_db.py` โ€“ Optimized database queries & structures - -๐Ÿ“ **Description** - -This update introduces a new leveling system including level roles, as well as important improvements and fixes for the global chat system. - -The backend has been modularized and prepared for future features. - -โœจ **Developed by:** OPPRO.NET Development diff --git a/docs/releases/version/1.3log.rst b/docs/releases/version/1.3log.rst deleted file mode 100644 index 8c62a61..0000000 --- a/docs/releases/version/1.3log.rst +++ /dev/null @@ -1,30 +0,0 @@ -Release of Version 1.3LOG -========================== - -๐Ÿ› ๏ธ **Update:** Version 1.3LOG - -**Released by:** @Medicopter117 - ---- - -๐Ÿ“ฆ **New Files** - -- `FastCoding/backend/database/logging_db.py` โ€“ New database module for logging functions - -- `cogs/Servermanament/logging.py` โ€“ New cog for logging management - -โœ๏ธ **Modified Files** - -- `FastCoding/backend/database/__init__.py` - -- `FastCoding/backend/database/globalchat_db.py` - -- `FastCoding/backend/logging.py` - -- `cogs/informationen/botstatus.py` - -๐Ÿ“ **Description** - -This update extends the backend with a new logging system including database integration and a bot cog. Existing modules were also improved and optimized. - -โœจ **Developed by:** OPPRO.NET Development diff --git a/docs/releases/version/1.4log.rst b/docs/releases/version/1.4log.rst deleted file mode 100644 index 2f082f3..0000000 --- a/docs/releases/version/1.4log.rst +++ /dev/null @@ -1,30 +0,0 @@ -Release of Version 1.4LOG -========================== - -๐Ÿ› ๏ธ **Update:** Version 1.4LOG - -**Released by:** @Medicopter117 - ---- - -๐Ÿ“ฆ **New Files** - -- `cogs/informationen/serverinfo.py` โ€“ New cog for server information - -โœ๏ธ **Modified Files** - -- `cogs/Servermanament/globalchat.py` - -- `cogs/Servermanament/logging.py` - -- `main.py` - -๐Ÿž **Bugfixes** - -- Fixed issue with duplicate messages when editing in `cogs/Servermanament/logging.py` - -๐Ÿ“ **Description** - -This update adds a new information cog, improves global chat and logging modules, and fixes a critical logging cog bug that caused message duplication. - -โœจ **Developed by:** OPPRO.NET Development diff --git a/docs/releases/version/1.5.0.rst b/docs/releases/version/1.5.0.rst deleted file mode 100644 index 6c0b1a6..0000000 --- a/docs/releases/version/1.5.0.rst +++ /dev/null @@ -1,42 +0,0 @@ -Release of Version 1.5 -======================= - -๐Ÿ› ๏ธ **Update:** Version 1.5 - -**Released by:** @Medicopter117 - ---- - -๐Ÿ“ฆ **New Files** - -- `cogs/Servermanament/autodelete.py` โ€“ Automatic message deletion cog - -- `FastCoding/backend/database/autodelete_db.py` โ€“ Database module for autodelete - -โœ๏ธ **Modified Files** - -- `FastCoding/backend/database/__init__.py` - -- `FastCoding/ui/templates/embeds.py` - -- `cogs/Servermanament/stats.py` - -- `cogs/fun/wikipedia.py` - -- `cogs/levelsystem/levelsystem.py` - -- `cogs/moderation/moderation.py` - -๐Ÿž **Bugfixes** - -- No specific bugfixes reported - -๐Ÿ“ **Description** - -This update extends server management with an automatic message system, improves existing modules, and further structures database connections. - -โœจ **Developed by:** OPPRO.NET Development, @Medicopter117 - -**Contributors** - -- @Medicopter117 diff --git a/docs/releases/version/1.6.0.rst b/docs/releases/version/1.6.0.rst deleted file mode 100644 index deddd06..0000000 --- a/docs/releases/version/1.6.0.rst +++ /dev/null @@ -1,31 +0,0 @@ -Release of Version 1.6 -======================= - -๐Ÿ› ๏ธ **Update:** Version 1.6 - -**Released by:** @Oppro-net-Development, @Medicopter117 - ---- - -โœ๏ธ **Modified Files** - -- `FastCoding/backend/database/autodelete_db.py` - -- `FastCoding/backend/database/logging_db.py` - -- `cogs/Servermanament/autodelete.py` - -- `cogs/moderation/moderation.py` - -- `main.py` - -๐Ÿ“ **Description** - -This update extends server management with an automatic message system, improves existing modules, and further structures database connections. - -โœจ **Developed by:** @Oppro-net-Development, @Medicopter117 - -**Contributors** - -- @Medicopter117 -- @Oppro-net-Development diff --git a/docs/releases/version/1.6.1.rst b/docs/releases/version/1.6.1.rst deleted file mode 100644 index cfc54ca..0000000 --- a/docs/releases/version/1.6.1.rst +++ /dev/null @@ -1,32 +0,0 @@ -Release of Version 1.6.1 -========================= - -๐Ÿ› ๏ธ **Update:** Version 1.6.1 - -**Released by:** @Medicopter117 - -**Release Date:** Jul 30 - -โœ๏ธ **Modified Files** - -- `.gitignore` - -- `cogs/Servermanament/globalchat.py` - -- `cogs/Servermanament/logging.py` - -- `cogs/Servermanament/stats.py` - -- `cogs/Temp/tempvc.py` - -- `cogs/levelsystem/levelsystem.py` - -- `cogs/moderation/moderation.py` - -๐Ÿ“ **Description** - -Mainly adds slash command groups. - -**Contributors** - -- @Medicopter117 diff --git a/docs/releases/version/1.6.2.rst b/docs/releases/version/1.6.2.rst deleted file mode 100644 index eb1130d..0000000 --- a/docs/releases/version/1.6.2.rst +++ /dev/null @@ -1,26 +0,0 @@ -Release of Version 1.6.2 -========================= - -๐Ÿ› ๏ธ **Update:** Version 1.6.2 - -**Released by:** @Medicopter117 - -**Release Date:** Aug 4 - -โœ๏ธ **Modified Files** -- `.CHANGELOG.md` - - -- `CONTRIBUTING.md` - -- `cogs/levelsystem/levelsystem.py` - -- `README.md` - -๐Ÿ“ **Description** - -Mainly adds .md files. - -**Contributors** - -- @Medicopter117 diff --git a/docs/releases/version/1.6.3.rst b/docs/releases/version/1.6.3.rst deleted file mode 100644 index 31fd3f6..0000000 --- a/docs/releases/version/1.6.3.rst +++ /dev/null @@ -1,30 +0,0 @@ -Release of Version 1.6.3 -========================= - -๐Ÿ› ๏ธ **Update:** Version 1.6.3 - -**Released by:** @Medicopter117 - -**Release Date:** Aug 6 - ---- - -๐Ÿ“ฆ **New Files** - -- `cogs/informationen/usermanagemt.py` - -- `template.env` - -- `cogs/moderation/anticapslock.py` *(may be faulty, report if errors occur)* - -โœ๏ธ **Modified Files** - -- `CHANGELOG.md` - - -โญ• **Deleted Files** -- `user.py` - -**Contributors** - -- @Medicopter117 diff --git a/docs/releases/version/1.6.4.rst b/docs/releases/version/1.6.4.rst deleted file mode 100644 index 60259f5..0000000 --- a/docs/releases/version/1.6.4.rst +++ /dev/null @@ -1,23 +0,0 @@ -Release of Version 1.6.4 -========================= - -๐Ÿ› ๏ธ **Update:** Version 1.6.4 - -**Released by:** @Medicopter117 - -**Release Date:** Aug 15 - ---- - -๐Ÿ“ฆ **New Files** - -- `cogs/Servermanament/welcome.py` -- `FastCoding/backend/database/welcome_db.py` - -โœ๏ธ **Modified Files** - -- `FastCoding/backend/database/__init__.py` - -**Contributors** - -- @Medicopter117 diff --git a/docs/releases/version/1.6.5.rst b/docs/releases/version/1.6.5.rst deleted file mode 100644 index 47aae83..0000000 --- a/docs/releases/version/1.6.5.rst +++ /dev/null @@ -1,32 +0,0 @@ -Release of Version 1.6.5 -========================= - -๐Ÿ› ๏ธ **Update:** Version 1.6.5 - -**Released by:** @Medicopter117 - -**Release Date:** Sep 10 - ---- - -๐Ÿ“ฆ **New Files** - -- `cogs/Servermanament/welcome.py` -- `FastCoding/backend/database/welcome_db.py` - -โœ๏ธ **Modified Files** - -- `FastCoding/backend/database/__init__.py` -- `cogs/Servermanament/stats.py` -- `cogs/fun/wikipedia.py` -- `cogs/levelsystem/levelsystem.py` -- `cogs/moderation/moderation.py` - -๐Ÿ“ **Description** - -Db memory patch and updates to welcome_db.py and welcome.py. Full changelog: V1.6.4 โ†’ V1.6.5 - -**New Contributors** - -- @verleihernix -- @Medicopter117 diff --git a/docs/releases/version/1.6.6.rst b/docs/releases/version/1.6.6.rst deleted file mode 100644 index 7f20733..0000000 --- a/docs/releases/version/1.6.6.rst +++ /dev/null @@ -1,16 +0,0 @@ -Release of Version 1.6.6 -========================= - -๐Ÿ› ๏ธ **Update:** Version 1.6.6 - -**Released by:** @Medicopter117 - -**Release Date:** Sep 11 - -๐Ÿ“ **Description** - -Minor fixes and updates. Full changelog: V1.6.5 โ†’ V1.6.6 - -**Contributors** - -- @Medicopter117 diff --git a/docs/releases/version/1.7.0.rst b/docs/releases/version/1.7.0.rst deleted file mode 100644 index 432f979..0000000 --- a/docs/releases/version/1.7.0.rst +++ /dev/null @@ -1,50 +0,0 @@ -Release of Version 1.7 -======================= - -๐Ÿ› ๏ธ **Update:** Version 1.7 - -**Released by:** @Medicopter117 - -**Release Date:** Sep 17 - ---- - -โœ๏ธ **Modified Files** - -**Backend / Database** - -- `FastCoding/backend/database/__init__.py` - -- `FastCoding/backend/database/levelsystem_db.py` - -- `FastCoding/backend/database/logging_db.py` - -- `FastCoding/backend/database/vc_db.py` - -**Cogs** - -- `cogs/Servermanament/logging.py` - -- `cogs/Servermanament/welcome.py` - -- `cogs/Temp/tempvc.py` - -- `cogs/informationen/botstatus.py` - -- `cogs/moderation/moderation.py` - -- `cogs/moderation/warningsystem.py` - -**Others** - -- `main.py` - -- `req.txt` - -**New** - -- `resources/ManagerX.png` - -**Contributors** - -- @Medicopter117 diff --git a/docs/releases/version/1.7.1.rst b/docs/releases/version/1.7.1.rst deleted file mode 100644 index 9e1ad88..0000000 --- a/docs/releases/version/1.7.1.rst +++ /dev/null @@ -1,65 +0,0 @@ -Release of Version 1.7.1 -========================= - -๐Ÿ› ๏ธ **Update:** Version 1.7.1 - -**Released by:** @Medicopter117 - -**Release Date:** Oct 10 - ---- - -โœ๏ธ **Modified Files** - -- `.gitignore` - -- `DevTools/backend/database/welcome_db.py` - -- `DevTools/ui/emojis.py` - -- `DevTools/ui/templates/embeds.py` - -- `README.md` - -- `cogs/Servermanament/autodelete.py` - -- `cogs/Servermanament/levelsystem.py` - -- `cogs/Servermanament/logging.py` - -- `cogs/Servermanament/stats.py` - -- `cogs/Servermanament/tempvc.py` - -- `cogs/Servermanament/welcome.py` - -- `cogs/fun/gewinnt.py` - -- `cogs/fun/tictactoe.py` - -- `cogs/fun/weather.py` - -- `cogs/fun/wikipedia.py` - -- `cogs/informationen/serverinfo.py` - -- `cogs/informationen/usermanagemt.py` - -- `cogs/moderation/antispam.py` - -- `cogs/moderation/moderation.py` - -- `cogs/moderation/notes.py` - -- `cogs/moderation/warningsystem.py` - -- `version.txt` - - -๐Ÿ“ **Description** - -Update & docs changes, Pycache removed. Full changelog: V1.7 โ†’ V1.7.1 - -**Contributors** - -- @Medicopter117 diff --git a/docs/req.txt b/docs/req.txt deleted file mode 100644 index 11062cd..0000000 --- a/docs/req.txt +++ /dev/null @@ -1,5 +0,0 @@ -sphinx==7.3.2 -pydata-sphinx-theme==0.16.1 -sphinx-autodoc-typehints==1.25.0 -myst-parser==2.0.0 -sphinx-copybutton==0.6.0 diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css new file mode 100644 index 0000000..4b4c030 --- /dev/null +++ b/docs/source/_static/custom.css @@ -0,0 +1,1058 @@ +/* ========================================================================== + MANAGERX PREMIUM DOCS THEME + PyData Sphinx Theme - Optimized & Refined + ========================================================================== */ + +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Space+Grotesk:wght@500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap'); + +:root { + /* ManagerX Premium Color System */ + --mx-red-primary: #dc2626; + --mx-red-dark: #991b1b; + --mx-red-darker: #7f1d1d; + --mx-red-light: #fef2f2; + --mx-red-accent: #f87171; + --mx-red-glow: rgba(220, 38, 38, 0.1); + + /* Neutral Palette */ + --mx-gray-50: #f8fafc; + --mx-gray-100: #f1f5f9; + --mx-gray-200: #e2e8f0; + --mx-gray-300: #cbd5e1; + --mx-gray-400: #94a3b8; + --mx-gray-500: #64748b; + --mx-gray-600: #475569; + --mx-gray-700: #334155; + --mx-gray-800: #1e293b; + --mx-gray-900: #0f172a; + + /* Semantic Colors */ + --mx-success: #059669; + --mx-warning: #d97706; + --mx-danger: #dc2626; + --mx-info: #0284c7; + + /* Typography System */ + --pst-font-family-base: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --pst-font-family-heading: 'Space Grotesk', 'Inter', sans-serif; + --pst-font-family-monospace: 'JetBrains Mono', 'Consolas', 'Monaco', monospace; + + /* PyData Theme Overrides */ + --pst-color-primary: var(--mx-red-primary); + --pst-color-secondary: var(--mx-gray-600); + --pst-color-link: var(--mx-red-primary); + --pst-color-link-hover: var(--mx-red-dark); + --pst-color-target: #fbbf24; + + /* Shadows & Effects */ + --mx-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05); + --mx-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.06); + --mx-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08); + --mx-shadow-lg: 0 10px 24px rgba(0, 0, 0, 0.1); + --mx-shadow-xl: 0 20px 40px rgba(0, 0, 0, 0.12); + + /* Transitions */ + --mx-transition-fast: 0.15s cubic-bezier(0.4, 0, 0.2, 1); + --mx-transition-base: 0.25s cubic-bezier(0.4, 0, 0.2, 1); + --mx-transition-slow: 0.4s cubic-bezier(0.4, 0, 0.2, 1); + + /* Border Radius */ + --mx-radius-sm: 6px; + --mx-radius-md: 10px; + --mx-radius-lg: 14px; + --mx-radius-xl: 20px; + --mx-radius-full: 9999px; +} + +/* ========================================================================== + 1. GLOBAL FOUNDATION & TYPOGRAPHY + ========================================================================== */ + +body { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; + letter-spacing: -0.011em; + line-height: 1.65; +} + +/* Premium Scrollbar Design */ +::-webkit-scrollbar { + width: 14px; + height: 14px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: var(--mx-gray-300); + border-radius: var(--mx-radius-full); + border: 3px solid var(--mx-gray-50); + transition: background var(--mx-transition-base); +} + +::-webkit-scrollbar-thumb:hover { + background: var(--mx-red-primary); +} + +[data-theme="dark"] ::-webkit-scrollbar-thumb { + background: var(--mx-gray-600); + border-color: var(--mx-gray-900); +} + +[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { + background: var(--mx-red-accent); +} + +/* Improved Typography Hierarchy */ +h1, h2, h3, h4, h5, h6 { + font-family: var(--pst-font-family-heading); + font-weight: 700; + letter-spacing: -0.025em; + color: var(--mx-gray-900); + line-height: 1.25; +} + +[data-theme="dark"] h1, +[data-theme="dark"] h2, +[data-theme="dark"] h3, +[data-theme="dark"] h4 { + color: var(--mx-gray-50); +} + +h1 { + font-size: 2.5rem; + margin-top: 0 !important; + margin-bottom: 2rem !important; +} + +h2 { + font-size: 2rem; + margin-top: 3rem !important; + margin-bottom: 1.5rem !important; + padding-bottom: 0.5rem; + border-bottom: 2px solid var(--mx-gray-100); +} + +[data-theme="dark"] h2 { + border-bottom-color: var(--mx-gray-700); +} + +h3 { + font-size: 1.5rem; + margin-top: 2rem !important; + margin-bottom: 1rem !important; +} + +h4 { + font-size: 1.25rem; + margin-top: 1.5rem !important; + margin-bottom: 0.75rem !important; +} + +/* Subtle Section Indicators */ +h2::before { + content: ""; + display: inline-block; + width: 4px; + height: 1.5rem; + background: linear-gradient(180deg, var(--mx-red-primary), var(--mx-red-accent)); + margin-right: 1rem; + border-radius: var(--mx-radius-sm); + vertical-align: middle; +} + +/* ========================================================================== + 2. HEADER & NAVIGATION + ========================================================================== */ + +/* Premium Glassmorphic Header */ +.bd-header { + background: rgba(255, 255, 255, 0.85) !important; + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); + border-bottom: 1px solid rgba(220, 38, 38, 0.1) !important; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(220, 38, 38, 0.03); + transition: all var(--mx-transition-base); +} + +[data-theme="dark"] .bd-header { + background: rgba(15, 23, 42, 0.9) !important; + border-bottom-color: rgba(220, 38, 38, 0.2) !important; +} + +/* Logo & Brand Styling */ +.navbar-brand { + font-family: var(--pst-font-family-heading); + font-weight: 700; + font-size: 1.25rem; + letter-spacing: -0.02em; + transition: transform var(--mx-transition-fast); +} + +.navbar-brand:hover { + transform: translateX(2px); +} + +/* Mobile Toggle */ +.bd-header .navbar-toggler { + border: 2px solid var(--mx-red-primary); + border-radius: var(--mx-radius-md); + color: var(--mx-red-primary); + transition: all var(--mx-transition-base); +} + +.bd-header .navbar-toggler:hover { + background: var(--mx-red-light); + transform: scale(1.05); +} + +/* ========================================================================== + 3. SIDEBAR NAVIGATION + ========================================================================== */ + +/* Primary Sidebar Styling */ +.bd-sidebar-primary { + border-right: 1px solid var(--mx-gray-100); +} + +[data-theme="dark"] .bd-sidebar-primary { + border-right-color: var(--mx-gray-700); +} + +/* Section Headers */ +.bd-sidebar-primary .caption-text { + color: var(--mx-red-dark); + font-family: var(--pst-font-family-heading); + font-weight: 700; + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.1em; + margin-top: 1.5rem; + margin-bottom: 0.75rem; + padding-left: 1rem; +} + +/* Navigation Links */ +.bd-sidebar-primary .nav-link { + border-radius: var(--mx-radius-md); + margin: 2px 0; + padding: 0.5rem 1rem; + transition: all var(--mx-transition-base); + font-size: 0.9rem; +} + +.bd-sidebar-primary .nav-link:hover { + background: var(--mx-gray-50); + color: var(--mx-red-primary); + transform: translateX(4px); +} + +[data-theme="dark"] .bd-sidebar-primary .nav-link:hover { + background: var(--mx-gray-800); +} + +/* Active Navigation Item */ +.bd-sidebar-primary .nav-item.current > a, +.bd-sidebar-primary .nav-item.active > a { + background: linear-gradient(90deg, var(--mx-red-light) 0%, transparent 100%); + color: var(--mx-red-primary) !important; + font-weight: 600; + border-left: 3px solid var(--mx-red-primary); + padding-left: calc(1rem - 3px); +} + +[data-theme="dark"] .bd-sidebar-primary .nav-item.current > a { + background: linear-gradient(90deg, rgba(220, 38, 38, 0.15) 0%, transparent 100%); +} + +/* Nested Navigation */ +.bd-sidebar-primary .nav-item .nav-item .nav-link { + font-size: 0.85rem; + padding-left: 2rem; +} + +/* ========================================================================== + 4. MAIN CONTENT AREA + ========================================================================== */ + +/* Content Container */ +.bd-main { + padding-top: 2rem; + padding-bottom: 4rem; +} + +article.bd-article { + max-width: 850px; +} + +/* Paragraph Spacing */ +article p { + margin-bottom: 1.25rem; + line-height: 1.75; +} + +/* Target Highlighting */ +:target { + scroll-margin-top: 120px; + animation: highlight-pulse 2s ease-out; +} + +@keyframes highlight-pulse { + 0%, 50% { + background-color: var(--mx-red-glow); + box-shadow: 0 0 0 8px var(--mx-red-glow); + } + 100% { + background-color: transparent; + box-shadow: 0 0 0 0 transparent; + } +} + +/* ========================================================================== + 5. ADMONITIONS & CALLOUTS + ========================================================================== */ + +/* Base Admonition Styling */ +.admonition { + border: none !important; + border-left: 4px solid var(--mx-red-primary) !important; + border-radius: var(--mx-radius-lg) !important; + background: var(--mx-gray-50) !important; + box-shadow: var(--mx-shadow-sm) !important; + padding: 1.5rem !important; + margin: 2rem 0 !important; + transition: all var(--mx-transition-base); +} + +.admonition:hover { + box-shadow: var(--mx-shadow-md) !important; + transform: translateY(-2px); +} + +[data-theme="dark"] .admonition { + background: var(--mx-gray-800) !important; +} + +/* Admonition Title */ +.admonition-title { + background: transparent !important; + color: var(--mx-red-primary) !important; + font-family: var(--pst-font-family-heading) !important; + font-weight: 700 !important; + font-size: 0.875rem !important; + text-transform: uppercase; + letter-spacing: 0.05em; + margin-bottom: 0.75rem !important; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.admonition-title::before { + content: "โ—"; + font-size: 0.6em; +} + +/* Admonition Variants */ +.admonition.note { + border-left-color: var(--mx-info) !important; +} + +.admonition.note .admonition-title { + color: var(--mx-info) !important; +} + +.admonition.warning { + border-left-color: var(--mx-warning) !important; +} + +.admonition.warning .admonition-title { + color: var(--mx-warning) !important; +} + +.admonition.danger, +.admonition.error { + border-left-color: var(--mx-danger) !important; +} + +.admonition.danger .admonition-title, +.admonition.error .admonition-title { + color: var(--mx-danger) !important; +} + +.admonition.tip, +.admonition.hint { + border-left-color: var(--mx-success) !important; +} + +.admonition.tip .admonition-title, +.admonition.hint .admonition-title { + color: var(--mx-success) !important; +} + +/* ========================================================================== + 6. CODE BLOCKS & SYNTAX HIGHLIGHTING + ========================================================================== */ + +/* Code Block Container */ +div.highlight { + border: 1px solid var(--mx-gray-200) !important; + border-radius: var(--mx-radius-lg) !important; + background: var(--mx-gray-50) !important; + box-shadow: var(--mx-shadow-sm); + padding: 0 !important; + margin: 1.5rem 0; + overflow: hidden; + transition: all var(--mx-transition-base); +} + +div.highlight:hover { + box-shadow: var(--mx-shadow-md); +} + +[data-theme="dark"] div.highlight { + background: var(--mx-gray-900) !important; + border-color: var(--mx-gray-700) !important; +} + +/* Code Block Pre */ +div.highlight pre { + padding: 1.25rem !important; + margin: 0 !important; + overflow-x: auto; + font-size: 0.875rem; + line-height: 1.6; + background: transparent !important; +} + +/* Inline Code */ +code.literal { + background: var(--mx-red-light); + color: var(--mx-red-dark); + padding: 0.15em 0.4em; + border-radius: var(--mx-radius-sm); + font-size: 0.875em; + font-weight: 500; + border: 1px solid rgba(220, 38, 38, 0.1); +} + +[data-theme="dark"] code.literal { + background: rgba(220, 38, 38, 0.15); + color: var(--mx-red-accent); + border-color: rgba(220, 38, 38, 0.2); +} + +/* Keyboard Shortcuts */ +kbd { + background: linear-gradient(180deg, var(--mx-gray-50), var(--mx-gray-100)); + border: 1px solid var(--mx-gray-300); + border-radius: var(--mx-radius-sm); + box-shadow: 0 2px 0 var(--mx-gray-300), inset 0 1px 0 rgba(255, 255, 255, 0.8); + color: var(--mx-gray-700); + font-family: var(--pst-font-family-monospace); + font-size: 0.85em; + padding: 0.2em 0.5em; + font-weight: 500; +} + +[data-theme="dark"] kbd { + background: linear-gradient(180deg, var(--mx-gray-700), var(--mx-gray-800)); + border-color: var(--mx-gray-600); + box-shadow: 0 2px 0 var(--mx-gray-600); + color: var(--mx-gray-200); +} + +/* Syntax Highlighting Customization */ +.highlight .k, +.highlight .kd { + color: var(--mx-red-primary); + font-weight: 600; +} + +.highlight .nc, +.highlight .nn { + color: var(--mx-red-dark); + font-weight: 600; +} + +.highlight .s, +.highlight .s2, +.highlight .s1 { + color: #059669; +} + +.highlight .c1, +.highlight .cm { + color: var(--mx-gray-400); + font-style: italic; +} + +.highlight .nf { + color: #0284c7; +} + +.highlight .mi, +.highlight .mf { + color: #7c3aed; +} + +/* ========================================================================== + 7. TABLES + ========================================================================== */ + +table.docutils { + width: 100%; + border-collapse: separate !important; + border-spacing: 0; + border-radius: var(--mx-radius-lg); + overflow: hidden; + border: 1px solid var(--mx-gray-200) !important; + margin: 2rem 0; + box-shadow: var(--mx-shadow-sm); +} + +[data-theme="dark"] table.docutils { + border-color: var(--mx-gray-700) !important; +} + +/* Table Header */ +table.docutils thead { + background: linear-gradient(180deg, var(--mx-red-primary), var(--mx-red-dark)); +} + +table.docutils thead th { + color: white !important; + font-family: var(--pst-font-family-heading); + font-weight: 600 !important; + font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.05em; + padding: 1rem !important; + border: none !important; + text-align: left; +} + +/* Table Body */ +table.docutils tbody tr { + transition: background-color var(--mx-transition-fast); +} + +table.docutils tbody tr:hover { + background-color: var(--mx-gray-50); +} + +[data-theme="dark"] table.docutils tbody tr:hover { + background-color: var(--mx-gray-800); +} + +table.docutils tbody td { + padding: 0.875rem 1rem !important; + border-bottom: 1px solid var(--mx-gray-100) !important; + font-size: 0.9rem; +} + +[data-theme="dark"] table.docutils tbody td { + border-bottom-color: var(--mx-gray-700) !important; +} + +table.docutils tbody tr:last-child td { + border-bottom: none !important; +} + +/* ========================================================================== + 8. LINKS & REFERENCES + ========================================================================== */ + +/* Internal & External Links */ +article a.reference.internal, +article a.reference.external { + color: var(--mx-red-primary); + text-decoration: none; + font-weight: 500; + position: relative; + transition: color var(--mx-transition-fast); +} + +article a.reference:hover { + color: var(--mx-red-dark); +} + +/* Animated Underline */ +article a.reference::after { + content: ''; + position: absolute; + width: 100%; + height: 2px; + bottom: -2px; + left: 0; + background: linear-gradient(90deg, var(--mx-red-primary), var(--mx-red-accent)); + transform: scaleX(0); + transform-origin: bottom right; + transition: transform var(--mx-transition-base); + border-radius: var(--mx-radius-full); +} + +article a.reference:hover::after { + transform: scaleX(1); + transform-origin: bottom left; +} + +/* External Link Icon */ +article a.reference.external::before { + content: "โ†—"; + font-size: 0.7em; + margin-left: 0.2em; + opacity: 0.6; +} + +/* ========================================================================== + 9. IMAGES & FIGURES + ========================================================================== */ + +/* Figure Container */ +figure.align-default, +figure.align-center { + margin: 3rem auto; + padding: 1.5rem; + background: white; + border-radius: var(--mx-radius-xl); + box-shadow: var(--mx-shadow-md); + text-align: center; + transition: all var(--mx-transition-base); +} + +figure.align-default:hover, +figure.align-center:hover { + box-shadow: var(--mx-shadow-lg); + transform: translateY(-4px); +} + +[data-theme="dark"] figure.align-default, +[data-theme="dark"] figure.align-center { + background: var(--mx-gray-800); +} + +/* Figure Image */ +figure.align-default img, +figure.align-center img { + border-radius: var(--mx-radius-md); + max-width: 100%; + height: auto; +} + +/* Figure Caption */ +figcaption, +.caption-text { + margin-top: 1rem; + font-size: 0.875rem; + color: var(--mx-gray-500); + font-style: italic; + line-height: 1.5; +} + +/* ========================================================================== + 10. API DOCUMENTATION (Autodoc) + ========================================================================== */ + +/* Function/Class/Method Containers */ +dl.py.function, +dl.py.class, +dl.py.method, +dl.py.attribute { + background: var(--mx-gray-50); + border: 1px solid var(--mx-gray-200); + border-left: 4px solid var(--mx-red-primary); + border-radius: var(--mx-radius-lg); + padding: 1.5rem; + margin: 2rem 0; + box-shadow: var(--mx-shadow-sm); + transition: all var(--mx-transition-base); +} + +dl.py.function:hover, +dl.py.class:hover, +dl.py.method:hover { + box-shadow: var(--mx-shadow-md); +} + +[data-theme="dark"] dl.py.function, +[data-theme="dark"] dl.py.class, +[data-theme="dark"] dl.py.method { + background: var(--mx-gray-800); + border-color: var(--mx-gray-700); +} + +/* Signature */ +dt.sig { + font-family: var(--pst-font-family-monospace); + font-size: 1rem; + color: var(--mx-red-primary); + background: rgba(220, 38, 38, 0.05); + padding: 0.75rem; + border-radius: var(--mx-radius-md); + margin-bottom: 1rem; + font-weight: 500; +} + +/* Parameters */ +.sig-param { + color: var(--mx-gray-700); +} + +[data-theme="dark"] .sig-param { + color: var(--mx-gray-300); +} + +/* Return Type */ +.sig-return { + color: var(--mx-success); +} + +/* ========================================================================== + 11. SEARCH + ========================================================================== */ + +/* Search Input */ +.bd-search .form-control { + border-radius: var(--mx-radius-full) !important; + border: 2px solid var(--mx-gray-200) !important; + padding: 0.625rem 1.25rem !important; + transition: all var(--mx-transition-base); + font-size: 0.9rem; +} + +.bd-search .form-control:focus { + border-color: var(--mx-red-primary) !important; + box-shadow: 0 0 0 4px var(--mx-red-glow) !important; + outline: none; +} + +[data-theme="dark"] .bd-search .form-control { + border-color: var(--mx-gray-700) !important; + background: var(--mx-gray-800) !important; +} + +/* Search Keyboard Shortcut */ +.search-button__kbd-shortcut { + background: var(--mx-red-light) !important; + color: var(--mx-red-primary) !important; + border: 1px solid rgba(220, 38, 38, 0.2) !important; + border-radius: var(--mx-radius-sm) !important; + font-weight: 600; +} + +/* ========================================================================== + 12. PAGINATION & NAVIGATION + ========================================================================== */ + +/* Previous/Next Navigation */ +.prev-next-area { + margin-top: 4rem; + padding-top: 2rem; + border-top: 2px solid var(--mx-gray-100); +} + +[data-theme="dark"] .prev-next-area { + border-top-color: var(--mx-gray-700); +} + +.prev-next-area a { + border: 1px solid var(--mx-gray-200) !important; + border-radius: var(--mx-radius-lg) !important; + padding: 1.5rem !important; + transition: all var(--mx-transition-base) !important; + background: white; +} + +[data-theme="dark"] .prev-next-area a { + background: var(--mx-gray-800); + border-color: var(--mx-gray-700) !important; +} + +.prev-next-area a:hover { + border-color: var(--mx-red-primary) !important; + box-shadow: 0 8px 24px var(--mx-red-glow) !important; + transform: translateY(-4px); +} + +.prev-next-area .prev-next-title { + color: var(--mx-red-primary) !important; + font-family: var(--pst-font-family-heading); + font-weight: 600; + font-size: 1.125rem; +} + +/* ========================================================================== + 13. BUTTONS + ========================================================================== */ + +/* Primary Buttons */ +.btn-primary { + background: linear-gradient(135deg, var(--mx-red-primary), var(--mx-red-dark)) !important; + border: none !important; + color: white !important; + font-family: var(--pst-font-family-heading); + font-weight: 600; + padding: 0.625rem 1.5rem; + border-radius: var(--mx-radius-md); + transition: all var(--mx-transition-base); + box-shadow: var(--mx-shadow-sm); +} + +.btn-primary:hover, +.btn-primary:focus { + transform: translateY(-2px); + box-shadow: 0 6px 20px var(--mx-red-glow) !important; +} + +.btn-primary:active { + transform: translateY(0); +} + +/* Outline Buttons */ +.btn-outline-primary { + color: var(--mx-red-primary) !important; + border: 2px solid var(--mx-red-primary) !important; + background: transparent !important; + font-weight: 600; + border-radius: var(--mx-radius-md); + transition: all var(--mx-transition-base); +} + +.btn-outline-primary:hover { + background: var(--mx-red-primary) !important; + color: white !important; + transform: translateY(-2px); + box-shadow: 0 6px 20px var(--mx-red-glow); +} + +/* ========================================================================== + 14. FOOTER + ========================================================================== */ + +.bd-footer { + margin-top: 6rem; + padding: 3rem 0 2rem; + border-top: 2px solid var(--mx-gray-100); + font-size: 0.875rem; +} + +[data-theme="dark"] .bd-footer { + border-top-color: var(--mx-gray-700); +} + +.footer-items__end { + color: var(--mx-gray-500); +} + +.footer-items__end strong { + color: var(--mx-red-primary); + font-weight: 600; +} + +/* ========================================================================== + 15. CUSTOM COMPONENTS + ========================================================================== */ + +/* Hero Section */ +.mx-hero { + text-align: center; + padding: 5rem 2rem; + background: radial-gradient( + circle at center, + var(--mx-red-glow) 0%, + transparent 70% + ); + border-radius: var(--mx-radius-xl); + margin: 3rem 0; +} + +/* Grid Layout Helper */ +.mx-grid-2 { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.5rem; + margin: 2rem 0; +} + +@media (max-width: 768px) { + .mx-grid-2 { + grid-template-columns: 1fr; + } +} + +/* Card Component */ +.mx-box { + padding: 2rem; + border-radius: var(--mx-radius-lg); + background: white; + border: 1px solid var(--mx-gray-200); + box-shadow: var(--mx-shadow-sm); + transition: all var(--mx-transition-base); +} + +.mx-box:hover { + box-shadow: var(--mx-shadow-md); + transform: translateY(-4px); +} + +[data-theme="dark"] .mx-box { + background: var(--mx-gray-800); + border-color: var(--mx-gray-700); +} + +/* Accent Border */ +.mx-box-accent { + border-bottom: 4px solid var(--mx-red-primary); +} + +/* ========================================================================== + 16. VERSION SWITCHER & DROPDOWNS + ========================================================================== */ + +.bd-version-switcher__button { + border-radius: var(--mx-radius-md) !important; + border: 1px solid var(--mx-gray-200) !important; + transition: all var(--mx-transition-base); +} + +[data-theme="dark"] .bd-version-switcher__button { + border-color: var(--mx-gray-700) !important; +} + +.bd-version-switcher__button:hover { + background: var(--mx-red-light) !important; + color: var(--mx-red-primary) !important; + border-color: var(--mx-red-primary) !important; +} + +/* ========================================================================== + 17. ANNOUNCEMENT BANNER + ========================================================================== */ + +.bd-header-announcement { + background: linear-gradient(135deg, var(--mx-red-dark), var(--mx-red-primary)) !important; + color: white !important; + font-weight: 600; + padding: 0.75rem; + text-align: center; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +} + +/* ========================================================================== + 18. RESPONSIVE DESIGN + ========================================================================== */ + +@media (max-width: 992px) { + h1 { + font-size: 2rem; + } + + h2 { + font-size: 1.65rem; + } + + h3 { + font-size: 1.35rem; + } + + .bd-main { + padding-top: 1rem; + } + + .mx-hero { + padding: 3rem 1.5rem; + } +} + +@media (max-width: 768px) { + h1 { + font-size: 1.75rem; + } + + h2 { + font-size: 1.5rem; + } + + .admonition { + padding: 1.25rem !important; + } + + table.docutils { + font-size: 0.85rem; + } + + .prev-next-area a { + padding: 1.25rem !important; + } +} + +/* ========================================================================== + 19. PRINT STYLES + ========================================================================== */ + +@media print { + .bd-header, + .bd-sidebar-primary, + .bd-sidebar-secondary, + .bd-footer, + .prev-next-area { + display: none !important; + } + + article { + max-width: 100% !important; + } + + .admonition { + page-break-inside: avoid; + } +} + +/* ========================================================================== + 20. ACCESSIBILITY IMPROVEMENTS + ========================================================================== */ + +/* Focus Visible States */ +a:focus-visible, +button:focus-visible, +input:focus-visible { + outline: 3px solid var(--mx-red-primary); + outline-offset: 2px; + border-radius: var(--mx-radius-sm); +} + +/* Skip to Content Link */ +.skip-link { + position: absolute; + top: -40px; + left: 0; + background: var(--mx-red-primary); + color: white; + padding: 0.5rem 1rem; + text-decoration: none; + border-radius: 0 0 var(--mx-radius-md) 0; + z-index: 100; +} + +.skip-link:focus { + top: 0; +} + +/* Reduced Motion */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} + +/* ========================================================================== + END OF MANAGERX PREMIUM DOCS THEME + ========================================================================== */ \ No newline at end of file diff --git a/docs/conf.py b/docs/source/conf.py similarity index 89% rename from docs/conf.py rename to docs/source/conf.py index 33c561f..c1b17ee 100644 --- a/docs/conf.py +++ b/docs/source/conf.py @@ -11,8 +11,8 @@ # -- Project information ----------------------------------------------------- project = 'ManagerX' -copyright = '2025, OPPRO.NET Network' -author = 'OPPRO.NET Development' +copyright = '2026 ManagerX Development' +author = 'ManagerX Development' release = '2.0.0' version = '2.0' # Kurzversion language = 'en' @@ -54,7 +54,6 @@ # -- Options for HTML output ------------------------------------------------- html_theme = 'pydata_sphinx_theme' -html_favicon = "_static/managerx.png" html_static_path = ['_static'] html_css_files = [ 'custom.css', @@ -63,9 +62,10 @@ "icon_links": [ { "name": "GitHub", - "url": "https://github.com/Oppro-net-Development/ManagerX", # required + "url": "https://github.com/ManagerX-Development/ManagerX", "icon": "fa-brands fa-square-github", "type": "fontawesome", } ], + } \ No newline at end of file diff --git a/docs/source/dev_guide/getting_start/installation.rst b/docs/source/dev_guide/getting_start/installation.rst new file mode 100644 index 0000000..955e5f1 --- /dev/null +++ b/docs/source/dev_guide/getting_start/installation.rst @@ -0,0 +1,65 @@ +Installation +============ + +A powerful Discord bot for server management and fun. + +---- + +Installation Methods +-------------------- + +GitHub Installation (Recommended) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Get the latest version directly from the source:** + +.. code-block:: bash + + git clone https://github.com/ManagerX-Development/ManagerX + cd ManagerX + pip install . + +.. note:: + โœจ **Latest Version:** This method always provides the most current version with all the latest features and updates. + +---- + +PyPI Installation +~~~~~~~~~~~~~~~~~ + +Install via pip with different configurations: + +**Standard Installation:** + +.. code-block:: bash + + pip install managerx + +**With Developer Tools:** + +.. code-block:: bash + + pip install "managerx[dev]" + +**With Documentation Tools:** + +.. code-block:: bash + + pip install "managerx[docs]" + +**Full Installation (All Features):** + +.. code-block:: bash + + pip install "managerx[all]" + +.. warning:: + PyPI releases may not always contain the absolute latest version. For the most up-to-date code, use the GitHub installation method. + +---- + +Requirements +------------ + +* Python 3.8 or higher +* pip (Python package installer) \ No newline at end of file diff --git a/docs/source/dev_guide/index.rst b/docs/source/dev_guide/index.rst new file mode 100644 index 0000000..15e5eab --- /dev/null +++ b/docs/source/dev_guide/index.rst @@ -0,0 +1,20 @@ +Developer Guide +======================== + +Welcome to the ManagerX Developer Guide! + +.. note:: + This project is permanently under development. We recommend checking this guide frequently for updates. + +.. toctree:: + :maxdepth: 2 + :caption: Getting Started: + +.. toctree:: + :maxdepth: 2 + :caption: Architecture: + +.. toctree:: + :maxdepth: 2 + :caption: Contribution: + \ No newline at end of file diff --git a/docs/index.rst b/docs/source/index.rst similarity index 95% rename from docs/index.rst rename to docs/source/index.rst index 4770f20..f28de32 100644 --- a/docs/index.rst +++ b/docs/source/index.rst @@ -4,9 +4,8 @@ ManagerX Documentation .. container:: mx-hero - .. image:: https://img.shields.io/badge/Version-1.7.2-e11d48?style=for-the-badge - :target: https://github.com/Oppro-net-Development/ManagerX - :alt: Version 1.7.2 + .. image:: https://img.shields.io/badge/Version-2.0.0-e11d48?style=for-the-badge + :alt: Version 2.0.0 .. image:: https://img.shields.io/badge/Python-3.8+-green.svg?style=for-the-badge :alt: Python 3.8+ @@ -118,5 +117,5 @@ We welcome contributions from the community! Whether it's bug reports, feature r --- -**ยฉ 2025 OPPRO.NET Network** +**ยฉ 2026 ManagerX Development** *Version 2.0.0-dev | Last Updated: December 7, 2025* \ No newline at end of file diff --git a/docs/user_guide/commands/index.rst b/docs/user_guide/commands/index.rst deleted file mode 100644 index 340bff4..0000000 --- a/docs/user_guide/commands/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -User Guide - Commands -============================= -This section of the User Guide provides detailed information about the various commands available in ManagerX. Each command is explained with its purpose, usage syntax, and examples to help you understand how to effectively utilize them in your projects. - -.. toctree:: - :maxdepth: 2 - :caption: Commands: - - Moderation - Fun Commands Overview \ No newline at end of file diff --git a/docs/user_guide/commands/moderation.rst b/docs/user_guide/commands/moderation.rst deleted file mode 100644 index e69de29..0000000 diff --git a/docs/user_guide/index.rst b/docs/user_guide/index.rst deleted file mode 100644 index 66648c0..0000000 --- a/docs/user_guide/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -User Guide -======================= -Welcome to the ManagerX User Guide! This section provides detailed information on how to use ManagerX, including tutorials, feature explanations, and best practices. - -.. toctree:: - :maxdepth: 2 - :caption: Guide: - - Commands - Setup diff --git a/examples/plugins/README.md b/examples/plugins/README.md deleted file mode 100644 index 15166d4..0000000 --- a/examples/plugins/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# ManagerX Plugin-System - -Das Plugin-System von **ManagerX** erlaubt es Entwicklern und der Community, den Bot flexibel zu erweitern. -Jedes Plugin ist eine **Extension**, die neue Funktionen bereitstellt und in den Bot integriert werden kann. - -## Wie Plugins funktionieren - -- **Freiwillige Entwicklung:** Jeder kann Plugins fรผr ManagerX erstellen, sei es fรผr neue Befehle, Automatisierungen oder Utility-Funktionen. -- **Modularer Aufbau:** Plugins sind von Haus aus **separat vom Hauptcode**. Das sorgt fรผr Stabilitรคt und einfache Updates. -- **Manuelles Laden:** Im Gegensatz zu manchen Bot-Systemen werden Plugins in ManagerX manuell in Cogs oder direkt im Bot geladen โ€“ so behรคlt der Betreiber volle Kontrolle. -- **PyPI & Local Plugins:** - - **PyPI Plugins**: Externe Plugins, die รผber PyPI installiert werden kรถnnen. - - **Local Plugins**: Plugins, die lokal im Projekt gespeichert und direkt vom Bot geladen werden. - -## Vorteile des Systems - -1. **Community-getrieben** โ€“ Jeder kann Ideen umsetzen. -2. **Sauber & modular** โ€“ Plugins stรถren den Kern-Bot nicht. -3. **Erweiterbar** โ€“ Neue Funktionen kรถnnen einfach hinzugefรผgt oder entfernt werden. -4. **Sicher** โ€“ Trennung von Kern-Bot und Plugins reduziert das Risiko von Fehlern. - -## Offizielle Plugins - -Damit ein Plugin als offizielle Extension gilt, muss es alle Anforderungen des **ManagerX Plugin Guidelines** erfรผllen. -Nur so kann es in die **offizielle Dokumentation** aufgenommen und vom Bot als โ€žoffizielles Pluginโ€œ behandelt werden. - ---- - -### Mehr dazu - -Weitere Informationen, Beispiele und detaillierte Anleitungen zu Plugins findest du **bald in unseren offiziellen Docs**. -Bleib dran, um zu erfahren, wie du eigene Plugins entwickeln und verรถffentlichen kannst! diff --git a/examples/plugins/example__init__.py b/examples/plugins/example__init__.py deleted file mode 100644 index 2b2e17a..0000000 --- a/examples/plugins/example__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -ManagerX Example Plugin - -This package exposes functions for ManagerX bots. -No automatic bot registration is done here. -""" - -from .functions import hello, add_numbers, multiply_numbers, format_user_message -from .utils import current_time, is_even - -__all__ = [ - "hello", - "add_numbers", - "multiply_numbers", - "format_user_message", - "current_time", - "is_even" -] \ No newline at end of file diff --git a/examples/plugins/example_plugin.py b/examples/plugins/example_plugin.py deleted file mode 100644 index 29e2725..0000000 --- a/examples/plugins/example_plugin.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -This Cog loads the functions from the PyPI plugin -and exposes them as Discord commands. -""" - -from discord.ext import commands -from managerx_example_plugin import ( - hello, - add_numbers, - multiply_numbers, - format_user_message, - current_time, - is_even -) - -class ExamplePlugin(commands.Cog): - """Example Cog that uses the ManagerX Example Plugin functions.""" - - def __init__(self, bot): - self.bot = bot - - @commands.command(name="sayhello") - async def say_hello(self, ctx): - user = ctx.author.name - result = hello(user) - await ctx.send(result) - - @commands.command(name="add") - async def add(self, ctx, a: int, b: int): - result = add_numbers(a, b) - await ctx.send(f"{a} + {b} = {result}") - - @commands.command(name="multiply") - async def multiply(self, ctx, a: int, b: int): - result = multiply_numbers(a, b) - await ctx.send(f"{a} ร— {b} = {result}") - - @commands.command(name="formatmsg") - async def formatmsg(self, ctx, *, message: str): - user = ctx.author.name - formatted = format_user_message(user, message) - await ctx.send(formatted) - - @commands.command(name="time") - async def time(self, ctx): - await ctx.send(f"Current time: {current_time()}") - - @commands.command(name="iseven") - async def is_even_cmd(self, ctx, number: int): - result = is_even(number) - await ctx.send(f"{number} is even? {result}") - -# Setup function for bot -async def setup(bot): - await bot.add_cog(ExamplePlugin(bot)) \ No newline at end of file diff --git a/examples/plugins/example_pyproject.toml b/examples/plugins/example_pyproject.toml deleted file mode 100644 index fa1f167..0000000 --- a/examples/plugins/example_pyproject.toml +++ /dev/null @@ -1,29 +0,0 @@ -[project] -name = "managerx-example-plugin" # Name muss managerx-* sein -version = "0.1.0" # Startversion -description = "An example plugin for ManagerX demonstrating PyPI plugin structure" -readme = "README.md" # Fรผr PyPI / Dokumentation -authors = [ - { name = "Your Name", email = "you@example.com" } -] -license = { text = "GPL-3.0-or-later" } -keywords = ["managerx", "plugin", "example"] -classifiers = [ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", - "Operating System :: OS Independent" -] -requires-python = ">=3.10" - -[project.dependencies] -# Beispielabhรคngigkeiten, falls dein Plugin externe Bibliotheken benรถtigt -# requests = ">=2.30.0" -# aiohttp = ">=3.8.0" - -[build-system] -requires = ["setuptools>=42", "wheel"] -build-backend = "setuptools.build_meta" - -# Optional: entry points fรผr Plugins, falls spรคter automatische Discovery genutzt wird -[project.scripts] -# hello-plugin = "managerx_example_plugin.functions:hello" diff --git a/examples/plugins/functions.py b/examples/plugins/functions.py deleted file mode 100644 index c880583..0000000 --- a/examples/plugins/functions.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -This file contains the main plugin functions. -These functions are independent and can be used in any bot Cog. -""" - -def hello(user: str) -> str: - """ - Example greeting function. - """ - return f"Hello {user}! Welcome to ManagerX Example Plugin." - -def add_numbers(a: int, b: int) -> int: - """ - Example calculation function. - """ - return a + b - -def multiply_numbers(a: int, b: int) -> int: - """ - Another example function for multiplication. - """ - return a * b - -def format_user_message(user: str, message: str) -> str: - """ - Formats a message with the user's name. - """ - return f"{user} says: {message}" \ No newline at end of file diff --git a/examples/plugins/utils.py b/examples/plugins/utils.py deleted file mode 100644 index dd172ff..0000000 --- a/examples/plugins/utils.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -Utility functions for ManagerX Example Plugin. -""" - -from datetime import datetime - -def current_time() -> str: - """ - Returns the current time as a formatted string. - """ - return datetime.now().strftime("%Y-%m-%d %H:%M:%S") - -def is_even(number: int) -> bool: - """ - Returns True if the number is even, False otherwise. - """ - return number % 2 == 0 \ No newline at end of file diff --git a/main.py b/main.py index cc5e344..6dc07c8 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,8 @@ -# Copyright (c) 2025 OPPRO.NET Network """ ManagerX Discord Bot - Main Entry Point ======================================== +Copyright (c) 2025 OPPRO.NET Network Version: 2.0.0 """ @@ -10,276 +10,124 @@ # IMPORTS # ============================================================================= import discord -import os -import asyncio -import logging -import re import sys -import glob -import json -from datetime import datetime -from dotenv import load_dotenv +from pathlib import Path from colorama import Fore, Style, init as colorama_init -import aiohttp -import traceback -from pathlib import Path +from dotenv import load_dotenv import ezcord from ezcord import CogLog -import yaml -from discord.ext import tasks -from logger import logger, LogLevel, LogFormat, Category +# Logger (muss existieren!) +from logger import logger +# Lokale Module aus src/bot/core +from src.bot.core.config import ConfigLoader, BotConfig +from src.bot.core.bot_setup import BotSetup +from src.bot.core.cog_manager import CogManager +from src.bot.core.database import DatabaseManager +from src.bot.core.dashboard import DashboardTask +from src.bot.core.utils import print_logo + +# ============================================================================= +# SETUP +# ============================================================================= BASEDIR = Path(__file__).resolve().parent load_dotenv(dotenv_path=BASEDIR / 'config' / '.env') +colorama_init(autoreset=True) - -# โ— LOKALE BIBLIOTHEKEN -try: - from DevTools import SettingsDB - - class BotConfig: - TOKEN = os.getenv("TOKEN") - -except ImportError as e: - print(f"[{Fore.RED}CRITICAL{Style.RESET_ALL}] [STARTUP] Fataler Fehler beim Import der lokalen Bibliotheken: {e.__class__.__name__}: {e}") - sys.exit(1) - - -if os.path.dirname(os.path.abspath(__file__)) not in sys.path: - sys.path.append(os.path.dirname(os.path.abspath(__file__))) - +# Sys-Path +if str(BASEDIR) not in sys.path: + sys.path.append(str(BASEDIR)) # ============================================================================= -# INITIALISIERUNG & CONFIG LOADING +# MAIN EXECUTION # ============================================================================= - -colorama_init(autoreset=True) - -config_path = BASEDIR / 'config' / 'config.yaml' -try: - with open(config_path, 'r', encoding='utf-8') as f: - config = yaml.safe_load(f) - - if not config.get('enabled', True): - print(f"[{Fore.YELLOW}INFO{Style.RESET_ALL}] Bot ist in config.yaml deaktiviert. Beende...") - sys.exit(0) - - config_version = config.get('version', '1.0.0') - BotConfig.VERSION = config_version - - features = config.get('features', {}) - update_checker_enabled = features.get('update_checker', True) - bot_status_enabled = features.get('bot_status', True) - cogs_config = features.get('cogs', {}) +if __name__ == '__main__': + # Logo ausgeben + print_logo() - bot_behavior = config.get('bot_behavior', {}) - command_prefix = bot_behavior.get('command_prefix', '!') - global_cooldown = bot_behavior.get('global_cooldown_seconds', 5) - max_messages_per_minute = bot_behavior.get('max_messages_per_minute', 10) - maintenance_mode = bot_behavior.get('maintenance_mode', False) + # Konfiguration laden + logger.info("BOT", "Lade Konfiguration...") + config_loader = ConfigLoader(BASEDIR) + config = config_loader.load() + logger.success("BOT", "Konfiguration geladen") - ui_config = config.get('ui', {}) - embed_color = ui_config.get('embed_color', '#00ff00') - footer_text = ui_config.get('footer_text', 'ManagerX Bot') - theme = ui_config.get('theme', 'dark') - show_timestamps = ui_config.get('show_timestamps', True) + # Bot erstellen + logger.info("BOT", "Initialisiere Bot...") + bot_setup = BotSetup(config) + bot = bot_setup.create_bot() - security_config = config.get('security', {}) - required_permissions = security_config.get('required_permissions', []) - blacklist_servers = security_config.get('blacklist_servers', []) - whitelist_users = security_config.get('whitelist_users', []) - enable_command_logging = security_config.get('enable_command_logging', True) + # Datenbank initialisieren (optional - Bot lรคuft auch ohne) + db_manager = DatabaseManager() + if not db_manager.initialize(bot): + logger.warning("DATABASE", "Bot lรคuft ohne Datenbank weiter...") + else: + logger.success("DATABASE", "Datenbank erfolgreich initialisiert") - performance_config = config.get('performance', {}) - max_concurrent_tasks = performance_config.get('max_concurrent_tasks', 10) - task_timeout = performance_config.get('task_timeout_seconds', 30) - memory_limit = performance_config.get('memory_limit_mb', 512) - enable_gc_optimization = performance_config.get('enable_gc_optimization', True) + # Dashboard-Task registrieren + dashboard = DashboardTask(bot, BASEDIR) + dashboard.register() -except Exception as e: - print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] Fehler beim Laden der config.yaml: {e}") - sys.exit(1) - -# ============================================================================= -# COG LOGIK -# ============================================================================= - -def get_ignored_list(cogs_config): - """ - Erstellt eine Liste von Dateinamen (ohne .py), die EzCord ignorieren soll. - """ - # 1. Manuelle Liste von Hilfsdateien, die KEINE Cogs sind - ignored = [ - "autocomplete", - "cache", - "components", - "config", - "containers", - "utils", - "backend", # Falls DevTools Ordner gescannt werden wรผrden - "emojis" - ] - - # Mapping fรผr Deaktivierung via config.yaml - # Hier prรผfen wir nur, welche Cogs laut Config auf 'false' stehen - cog_mapping = { - 'fun': { - 'gewinnt': 'gewinnt', - 'tictactoe': 'tictactoe', - 'weather': 'weather', - 'wikipedia': 'cog' # Die Wikipedia Hauptdatei heiรŸt 'cog.py' - }, - 'information': { - 'botstatus': 'botstatus', - 'serverinfo': 'serverinfo', - 'usermanagemt': 'usermanagemt' - }, - 'moderation': { - 'antispam': 'antispam', - 'moderation': 'moderation', - 'notes': 'notes', - 'warningsystem': 'warningsystem' - }, - 'server_management': { - 'autodelete': 'autodelete', - 'globalchat': 'globalchat', - 'levelsystem': 'levelsystem', - 'logging': 'logging', - 'stats': 'stats', - 'tempvc': 'tempvc', - 'welcome': 'welcome' - }, - 'other': { - 'setlang': 'setlang' - } - } + # Event Handler + @bot.event + async def on_ready(): + logger.success("BOT", f"Logged in as {bot.user.name}") + + # Dashboard starten + dashboard.start() + + # Bot-Status + if config['features'].get('bot_status', True): + await bot.change_presence( + activity=discord.Activity( + type=discord.ActivityType.watching, + name=f"ManagerX v{BotConfig.VERSION}" + ) + ) + + # Commands sync + await bot.sync_commands() + logger.success("COMMANDS", "Application Commands synchronisiert") - for category, cogs in cog_mapping.items(): - category_config = cogs_config.get(category, {}) - for cog_key, file_name in cogs.items(): - if not category_config.get(cog_key, True): - ignored.append(file_name) - - return ignored - -# ============================================================================= -# BOT INITIALISIERUNG -# ============================================================================= - -intents = discord.Intents.default() -intents.members = True -intents.message_content = True - -bot = ezcord.Bot( - intents=intents, - language="de" -) - -bot.config = { - 'embed_color': embed_color, - 'footer_text': footer_text, - 'theme': theme, - 'show_timestamps': show_timestamps, - 'maintenance_mode': maintenance_mode, - 'global_cooldown': global_cooldown, - 'max_messages_per_minute': max_messages_per_minute, - 'required_permissions': required_permissions, - 'blacklist_servers': blacklist_servers, - 'whitelist_users': whitelist_users, - 'enable_command_logging': enable_command_logging, - 'max_concurrent_tasks': max_concurrent_tasks, - 'task_timeout': task_timeout, - 'memory_limit': memory_limit, - 'enable_gc_optimization': enable_gc_optimization -} - -# ============================================================================= -# DASHBOARD EXPORT TASK -# ============================================================================= - -@tasks.loop(minutes=1) -async def update_dashboard_data(): - try: - stats = { - "bot_info": { - "name": str(bot.user.name), - "status": "online", - "latency": round(bot.latency * 1000, 1) - }, - "stats": { - "server_count": len(bot.guilds), - "user_count": sum(g.member_count for g in bot.guilds if g.member_count), - "shards": bot.shard_count or 1 - }, - "updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") - } - with open(BASEDIR / 'bot_stats.json', 'w', encoding='utf-8') as f: - json.dump(stats, f, indent=4, ensure_ascii=False) - except: - pass - -# ============================================================================= -# EVENTS -# ============================================================================= - -@bot.event -async def on_ready(): - logger.success(Category.BOT, f"Logged in as {bot.user.name}") - if not update_dashboard_data.is_running(): - update_dashboard_data.start() + # Minimaler KeepAlive Cog - damit Bot immer online bleibt + class KeepAlive(discord.ext.commands.Cog): + """Minimal Cog to keep bot online""" + def __init__(self, bot): + self.bot = bot + + @discord.ext.commands.Cog.listener() + async def on_ready(self): + logger.info("KEEPALIVE", "KeepAlive Cog aktiv - Bot bleibt online") - if bot_status_enabled: - await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name=f"ManagerX v{BotConfig.VERSION}")) - - await bot.sync_commands() - logger.success(Category.COMMANDS, "Application Commands synchronisiert.") - -# ============================================================================= -# MAIN EXECUTION -# ============================================================================= - -if __name__ == '__main__': - # Definieren des Logos als Liste von Strings, um Formatierungsprobleme zu umgehe - logo_lines = [ - r" _____ ______ ________ ________ ________ ________ _______ ________ ___ ___ ", - r"|\ _ \ _ \|\ __ \|\ ___ \|\ __ \|\ ____\|\ ___ \ |\ __ \ |\ \ / /|", - r"\ \ \\\__\ \ \ \ \|\ \ \ \\ \ \ \ \|\ \ \ \___|\ \ __/|\ \ \|\ \ \ \ \/ / /", - r" \ \ \\|__| \ \ \ __ \ \ \\ \ \ \ __ \ \ \ __\ \ _|/_\ \ _ _\ \ \ / / ", - r" \ \ \ \ \ \ \ \ \ \ \ \\ \ \ \ \ \ \ \ \|\ \ \ \_|\ \ \ \\ \| / \/ ", - r" \ \__\ \ \__\ \__\ \__\ \__\\ \__\ \__\ \__\ \_______\ \_______\ \__\\ _\ / /\ \ ", - r" \|__| \|__|\|__|\|__|\|__| \|__|\|__|\|__|\|_______|\|_______|\|__|\|__|/__/ /\ __\ ", - r" |__|/ \|__| " - ] - - # Ausgabe - print(Fore.CYAN) - for line in logo_lines: - print(line) - print(f"{'=' * 91}") - print(f" ManagerX Discord Bot v{BotConfig.VERSION}") - print(f"{'=' * 91}{Style.RESET_ALL}\n") + # KeepAlive Cog immer laden + bot.add_cog(KeepAlive(bot)) + logger.success("BOT", "KeepAlive Cog geladen") - try: - db = SettingsDB() - bot.settings_db = db - logger.info(Category.DATABASE, "Settings Database initialized โœ“") - except Exception as e: - logger.critical(Category.DATABASE, f"Datenbankfehler: {e}") - - # --- GEFIXTER LOAD-PROZESS --- - ignored = get_ignored_list(cogs_config) + # Cogs laden + logger.info("BOT", "Lade Cogs...") + cog_manager = CogManager(config['cogs']) + ignored = cog_manager.get_ignored_cogs() bot.load_cogs( - "src/cogs", - subdirectories=True, + "src/bot/cogs", + subdirectories=True, ignored_cogs=ignored, log=CogLog.sum ) - + logger.success("BOT", "Cogs geladen") + + # Token prรผfen if not BotConfig.TOKEN: - logger.critical(Category.DEBUG, "Kein TOKEN gefunden!") - import sys + logger.critical("DEBUG", "Kein TOKEN in .env gefunden!") sys.exit(1) - bot.run(BotConfig.TOKEN) \ No newline at end of file + # Bot starten + logger.info("BOT", "Starte Bot...") + try: + bot.run(BotConfig.TOKEN) + except discord.LoginFailure: + logger.critical("BOT", "Ungรผltiger Token!") + sys.exit(1) + except Exception as e: + logger.critical("BOT", f"Bot-Start fehlgeschlagen: {e}") + sys.exit(1) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index d3e6b88..6e5ae71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "ManagerX" -version = "2026.0.1" +version = "2.2026.01.11" description = "A powerful Discord bot for server management and fun." readme = "README.md" requires-python = ">=3.8" @@ -45,8 +45,8 @@ dependencies = [ "MarkupSafe==3.0.3", "starlette==0.50.0", "timedelta==2020.12.3", - "ManagerX-Handler==1.0.4", - "ManagerX-DevTools==1.0.0" + "ManagerX-Handler==1.2026.01.10", + "ManagerX-DevTools==1.2026.01.11.1" ] [project.urls] diff --git a/renovate.json b/renovate.json deleted file mode 100644 index 2eebada..0000000 --- a/renovate.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "extends": [ - "config:recommended" - ], - "labels": [ - "dependencies" - ], - "prHourlyLimit": 1, - "prConcurrentLimit": 3, - "dependencyDashboard": true, - "dependencyDashboardTitle": "ManagerX โ€“ Dependency Updates", - "automerge": false, - "rangeStrategy": "pin", - "timezone": "Europe/Berlin", - - "schedule": ["immediately"], - "pip_requirements": { - "fileMatch": ["requirements/.*\\.txt"] - }, - "packageRules": [ - { - "matchDepTypes": ["dependencies"], - "matchUpdateTypes": ["patch", "minor"], - "groupName": "All Patch & Minor Python Updates" - }, - { - "matchDepTypes": ["dependencies"], - "matchUpdateTypes": ["major"], - "groupName": "All Major Python Updates" - }, - { - "matchDepTypes": ["github-actions"], - "groupName": "All GitHub Actions Updates" - } - ] - -} diff --git a/requirements/bot_req.txt b/requirements/bot_req.txt deleted file mode 100644 index c57a8c7..0000000 --- a/requirements/bot_req.txt +++ /dev/null @@ -1,16 +0,0 @@ -ezcord==0.7.4 -py-cord==2.7.0 -aiosqlite==0.22.1 -aiohttp==3.13.2 -aiocache==0.12.3 -propcache==0.4.1 -requests==2.32.5 -wikipedia==1.4.0 -beautifulsoup4==4.14.3 -soupsieve==2.8.1 -yarl==1.22.0 -frozenlist==1.8.0 -h11==0.16.0 -multidict==6.7.0 -ManagerX-Handler==1.0.1 -ManagerX-DevTools==1.0.0 \ No newline at end of file diff --git a/requirements/dev_req.txt b/requirements/dev_req.txt deleted file mode 100644 index 069cae8..0000000 --- a/requirements/dev_req.txt +++ /dev/null @@ -1,21 +0,0 @@ -python-dotenv==1.2.1 -click==8.3.1 -colorama==0.4.6 -typing_extensions==4.15.0 -typing-inspection==0.4.2 -attrs==25.4.0 -annotated-types==0.7.0 -anyio==4.12.0 -certifi==2025.11.12 -charset-normalizer==3.4.4 -idna==3.11 -urllib3==2.6.2 -Jinja2==3.1.6 -MarkupSafe==3.0.3 -starlette==0.50.0 -FastAPI -uvicorn -SimpleColoredLogs -timedelta==2020.12.3 -ManagerX-Handler==1.0.1 -ManagerX-DevTools==1.0.0 \ No newline at end of file diff --git a/requirements/docs_req.txt b/requirements/docs_req.txt deleted file mode 100644 index 57b3817..0000000 --- a/requirements/docs_req.txt +++ /dev/null @@ -1,7 +0,0 @@ -# You need to install Sphinx with `pip install sphinx` and these extensions to build the docs -pydata-sphinx-theme # for a modern documentation theme -sphinx-autodoc-typehints # for better type hinting support -myst-parser # for Markdown support -sphinx-copybutton # adds copy buttons to code blocks -sphinx-autobuild # optional: live preview during development - # (remove this before pushing; ReadTheDocs doesn't need it) diff --git a/requirements/req.txt b/requirements/req.txt deleted file mode 100644 index ef43f5d..0000000 --- a/requirements/req.txt +++ /dev/null @@ -1,47 +0,0 @@ -ezcord==0.7.4 -py-cord==2.7.0 -aiosqlite==0.22.1 -aiohttp==3.13.2 -aiocache==0.12.3 -propcache==0.4.1 -requests==2.32.5 -wikipedia==1.4.0 -beautifulsoup4==4.14.3 -soupsieve==2.8.1 -yarl==1.22.0 -frozenlist==1.8.0 -h11==0.16.0 -multidict==6.7.0 -FastAPI==0.128.0 -uvicorn==0.22.0 -ManagerX-Handler==1.0.1 -ManagerX-DevTools==1.0.0 - -# Dev -python-dotenv==1.2.1 -click==8.3.1 -colorama==0.4.6 -typing_extensions==4.15.0 -typing-inspection==0.4.2 -attrs==25.4.0 -annotated-types==0.7.0 -anyio==4.12.0 -certifi==2025.11.12 -charset-normalizer==3.4.4 -idna==3.11 -urllib3==2.6.2 -Jinja2==3.1.6 -MarkupSafe==3.0.3 -starlette==0.50.0 -FastAPI -uvicorn -SimpleColoredLogs -timedelta==2020.12.3 - -# Docs -sphinx -pydata-sphinx-theme -sphinx-autodoc-typehints -myst-parser -sphinx-copybutton -sphinx-autobuild \ No newline at end of file diff --git a/site/callback.html b/site/callback.html deleted file mode 100644 index 836ab52..0000000 --- a/site/callback.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Logging in... - - -

      Authentifizierung erfolgreich. Leite weiter...

      - - - - \ No newline at end of file diff --git a/site/css/styles.css b/site/css/styles.css deleted file mode 100644 index 6be28ad..0000000 --- a/site/css/styles.css +++ /dev/null @@ -1,481 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap'); - -:root { - --primary: #5865F2; - --primary-glow: rgba(88, 101, 242, 0.4); - --bg: #0b0e14; - --card-bg: rgba(255, 255, 255, 0.03); - --border: rgba(255, 255, 255, 0.08); - --text: #ffffff; - --text-muted: #a0a0a0; -} - -* { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', sans-serif; } -body { background: var(--bg); color: var(--text); line-height: 1.6; overflow-x: hidden; } - -#particleCanvas { position: fixed; top: 0; left: 0; z-index: -1; opacity: 0.5; pointer-events: none; } - -/* NAVIGATION - Modern & Clean */ -nav { - display: flex; justify-content: space-between; align-items: center; - padding: 20px 10%; background: rgba(11, 14, 20, 0.8); - backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); - border-bottom: 1px solid var(--border); - position: sticky; top: 0; z-index: 100; -} - -.nav-content { display: flex; justify-content: space-between; align-items: center; width: 100%; } - -.logo { - font-size: 1.6rem; font-weight: 800; - background: linear-gradient(90deg, #fff, var(--primary)); - -webkit-background-clip: text; -webkit-text-fill-color: transparent; -} - -.links { display: flex; align-items: center; gap: 20px; } -.links a { color: var(--text-muted); text-decoration: none; font-weight: 600; transition: 0.3s; } -.links a:hover { color: var(--primary); text-shadow: 0 0 10px var(--primary-glow); } - -.user-profile { display: flex; align-items: center; color: var(--text); font-weight: 600; } - -/* HERO SECTION - Starker Fokus */ -.hero { - height: 65vh; display: flex; flex-direction: column; - justify-content: center; align-items: center; text-align: center; - padding: 0 10%; -} - -.hero h1 { - font-size: 4rem; font-weight: 800; margin-bottom: 15px; - letter-spacing: -2px; line-height: 1.1; - background: linear-gradient(to bottom, #fff 0%, #a0a0a0 100%); - -webkit-background-clip: text; -webkit-text-fill-color: transparent; -} - -.hero p { color: var(--text-muted); font-size: 1.2rem; max-width: 600px; margin-bottom: 35px; } - -/* STATS - Schickes Grid */ -.stats-container { - display: flex; justify-content: center; gap: 50px; - padding: 80px 10%; background: linear-gradient(180deg, rgba(88, 101, 242, 0.05) 0%, transparent 100%); -} - -.stat-card { text-align: center; padding: 20px; } -.stat-value { font-size: 3.5rem; font-weight: 800; color: var(--primary); display: block; text-shadow: 0 0 20px var(--primary-glow); } -.stat-label { color: var(--text-muted); text-transform: uppercase; letter-spacing: 2px; font-size: 0.8rem; } - -/* GLASS CARDS - Das Herzstรผck */ -.glass-card { - background: rgba(255, 255, 255, 0.03); - border: 1px solid var(--border); - border-radius: 24px; - padding: 40px; - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - box-shadow: 0 20px 40px rgba(0,0,0,0.3); - margin-bottom: 30px; - transition: 0.3s ease; -} - -.glass-card:hover { - transform: translateY(-2px); - box-shadow: 0 25px 50px rgba(0,0,0,0.4); -} - -/* GUILD CARDS */ -.guild-grid { - display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 20px; margin-top: 30px; -} - -.guild-card { - background: rgba(255, 255, 255, 0.05); - border: 1px solid var(--border); - border-radius: 16px; - padding: 20px; - text-align: center; - transition: 0.3s ease; - cursor: pointer; -} - -.guild-card:hover { - transform: translateY(-5px); - box-shadow: 0 15px 30px rgba(88, 101, 242, 0.2); - border-color: var(--primary); -} - -.guild-card img { width: 64px; height: 64px; border-radius: 50%; margin-bottom: 15px; } -.guild-card h3 { margin-bottom: 10px; color: var(--text); } -.guild-card a { text-decoration: none; } - -/* MODULE CARDS */ -.module-grid { - display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 25px; margin-top: 30px; -} - -.module-card { - background: rgba(255, 255, 255, 0.05); - border: 1px solid var(--border); - border-radius: 20px; - padding: 30px; - text-align: center; - transition: 0.3s ease; - position: relative; - overflow: hidden; -} - -.module-card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 4px; - background: linear-gradient(90deg, var(--primary), transparent); - opacity: 0; - transition: 0.3s ease; -} - -.module-card:hover { - transform: translateY(-8px); - box-shadow: 0 20px 40px rgba(88, 101, 242, 0.15); - border-color: var(--primary); -} - -.module-card:hover::before { - opacity: 1; -} - -.module-card.disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.module-card.disabled:hover { - transform: none; - box-shadow: none; -} - -.module-icon { - font-size: 2.5rem; margin-bottom: 15px; - display: block; -} - -.module-card h3 { - margin-bottom: 15px; color: var(--text); font-size: 1.3rem; -} - -.module-card p { - color: var(--text-muted); font-size: 0.95rem; line-height: 1.5; margin-bottom: 20px; -} - -/* SERVER HEADER */ -.server-header { - display: flex; - align-items: center; - gap: 20px; - margin-bottom: 40px; -} - -.guild-avatar { - width: 80px; - height: 80px; - border-radius: 50%; - border: 3px solid var(--primary); - box-shadow: 0 0 20px var(--primary-glow); -} - -.guild-info h1 { - font-size: 2.2rem; - margin-bottom: 5px; -} - -.guild-info p { - color: var(--text-muted); -} - -/* MODULE PAGES */ -.module-header { - text-align: center; - margin-bottom: 40px; -} - -.module-icon-large { - font-size: 4rem; - margin-bottom: 20px; - display: block; -} - -.module-header h1 { - font-size: 2.5rem; - margin-bottom: 10px; -} - -.module-header p { - color: var(--text-muted); - font-size: 1.1rem; -} - -/* FORM ELEMENTS */ -.form-section { - margin-bottom: 40px; -} - -.form-section h3 { - color: var(--primary); - margin-bottom: 20px; - font-size: 1.3rem; -} - -.form-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 20px; -} - -.input-group { - margin-bottom: 20px; -} - -.input-group label { - display: block; - margin-bottom: 8px; - color: var(--text); - font-weight: 600; -} - -.input-group input, -.input-group select { - width: 100%; - padding: 12px 16px; - background: rgba(255, 255, 255, 0.05); - border: 1px solid var(--border); - border-radius: 12px; - color: var(--text); - font-size: 1rem; - transition: 0.3s ease; -} - -.input-group input:focus, -.input-group select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px var(--primary-glow); -} - -.input-group small { - display: block; - margin-top: 5px; - color: var(--text-muted); - font-size: 0.85rem; -} - -/* CHECKBOX STYLING */ -.checkbox-label { - display: flex; - align-items: center; - cursor: pointer; - font-weight: 600; -} - -.checkbox-label input[type="checkbox"] { - display: none; -} - -.checkmark { - width: 20px; - height: 20px; - border: 2px solid var(--border); - border-radius: 4px; - margin-right: 10px; - position: relative; - transition: 0.3s ease; -} - -.checkbox-label input[type="checkbox"]:checked + .checkmark { - background: var(--primary); - border-color: var(--primary); -} - -.checkbox-label input[type="checkbox"]:checked + .checkmark::after { - content: 'โœ“'; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - color: white; - font-size: 12px; - font-weight: bold; -} - -/* FORM ACTIONS */ -.form-actions { - display: flex; - align-items: center; - gap: 20px; - margin-top: 30px; -} - -.save-status { - font-weight: 600; - transition: 0.3s ease; -} - -/* BUTTONS - Der Glow ist zurรผck */ -.btn-primary { - background: var(--primary); color: white !important; - padding: 16px 36px; border-radius: 14px; text-decoration: none; - font-weight: 700; font-size: 1.1rem; display: inline-block; - transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); - box-shadow: 0 8px 25px var(--primary-glow); - will-change: transform; -} - -.btn-primary:hover { - transform: translateY(-4px) scale(1.02); - box-shadow: 0 12px 35px var(--primary-glow); -} - -/* CONTAINER */ -.container { - max-width: 1200px; margin: 0 auto; padding: 0 20px; -} - -/* RESPONSIVE */ -@media (max-width: 768px) { - .hero h1 { font-size: 2.5rem; } - .module-grid { grid-template-columns: 1fr; } - .guild-grid { grid-template-columns: 1fr; } - .form-grid { grid-template-columns: 1fr; } - .server-header { flex-direction: column; text-align: center; } - nav { padding: 15px 5%; } - .glass-card { padding: 20px; } -} - -/* OPTIMIERTE LEGAL PAGES */ -.legal-container { - max-width: 900px; - margin: 60px auto; - background: rgba(255, 255, 255, 0.02); - border: 1px solid var(--border); - border-radius: 32px; - padding: 60px; - backdrop-filter: blur(20px); - box-shadow: 0 40px 100px rgba(0,0,0,0.5); - position: relative; -} - -.legal-header { - text-align: center; - margin-bottom: 50px; - border-bottom: 1px solid var(--border); - padding-bottom: 30px; -} - -.legal-header h1 { - font-size: 3.2rem; - font-weight: 800; - background: linear-gradient(to bottom, #fff, #888); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - margin-bottom: 10px; -} - -.legal-header p { - color: var(--primary); - text-transform: uppercase; - letter-spacing: 3px; - font-weight: 700; - font-size: 0.9rem; -} - -.legal-content section { - margin-bottom: 40px; - padding: 20px; - border-radius: 16px; - transition: background 0.3s ease; -} - -.legal-content section:hover { - background: rgba(255, 255, 255, 0.015); -} - -.legal-content h2 { - color: var(--primary); - font-size: 1.5rem; - margin-bottom: 15px; - display: flex; - align-items: center; - gap: 12px; -} - -.legal-content h2::before { - content: ''; - width: 4px; - height: 24px; - background: var(--primary); - border-radius: 2px; - display: inline-block; -} - -.legal-content p, .legal-content li { - color: var(--text-muted); - font-size: 1.05rem; - line-height: 1.8; -} - -.legal-content ul { - list-style: none; - margin-top: 15px; -} - -.legal-content li { - margin-bottom: 12px; - padding-left: 25px; - position: relative; -} - -.legal-content li::after { - content: 'โ†’'; - position: absolute; - left: 0; - color: var(--primary); -} - -.contact-link { - display: flex; - align-items: center; - justify-content: center; - gap: 15px; - background: rgba(88, 101, 242, 0.1); - border: 1px solid var(--primary); - padding: 20px; - border-radius: 16px; - color: #fff; - text-decoration: none; - font-weight: 600; - transition: 0.3s; - margin-top: 20px; -} - -.contact-link:hover { - background: var(--primary); - transform: scale(1.02); - box-shadow: 0 10px 30px var(--primary-glow); -} - -@media (max-width: 768px) { - .legal-container { padding: 30px; margin: 20px; } - .legal-header h1 { font-size: 2.2rem; } -} - -/* FOOTER */ -footer { padding: 60px 10% 40px; border-top: 1px solid var(--border); text-align: center; color: var(--text-muted); } -footer a { color: var(--text-muted); text-decoration: none; margin: 0 15px; font-weight: 600; transition: 0.3s; } -footer a:hover { color: var(--primary); } - -@media (max-width: 768px) { - .hero h1 { font-size: 2.8rem; } - .stats-container { flex-direction: column; gap: 30px; } -} \ No newline at end of file diff --git a/site/dashboard.html b/site/dashboard.html deleted file mode 100644 index d08b66d..0000000 --- a/site/dashboard.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - ManagerX - Dashboard - - - - - - - - - -
      -
      -

      Server Dashboard

      -

      Wรคhle einen Server aus, um die Einstellungen zu verwalten

      -
      - -
      -

      ๐ŸŽฏ Deine Server

      -

      Nur Server mit Administrator-Rechten werden angezeigt.

      -
      -
      -
      - - - - \ No newline at end of file diff --git a/site/guild.html b/site/guild.html deleted file mode 100644 index df3184b..0000000 --- a/site/guild.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - - ManagerX - Server Hub - - - - - - - - - -
      -
      - -
      -

      Lade Server...

      -

      Verwalte die Bot-Einstellungen fรผr diesen Server

      -
      -
      - -
      -

      ๐Ÿš€ Verfรผgbare Module

      -
      -
      -
      ๐Ÿ”Š
      -

      TempVC

      -

      Kanรคle, Kategorien und Interface-Einstellungen fรผr temporรคre Voice-Channels.

      - Konfigurieren -
      - -
      -
      ๐Ÿ‘‹
      -

      Welcome

      -

      Willkommensnachrichten und Embed-Einstellungen fรผr neue Mitglieder.

      - Konfigurieren -
      - -
      -
      โญ
      -

      Levelsystem

      -

      XP-System, Level-Ups und Prestige-Einstellungen.

      - Konfigurieren -
      - -
      -
      ๐Ÿ›ก๏ธ
      -

      Security

      -

      Anti-Spam, Moderation und Sicherheitsfeatures.

      - Bald verfรผgbar -
      - -
      -
      ๐Ÿ“Š
      -

      Analytics

      -

      Server-Statistiken und Nutzungsanalysen.

      - Bald verfรผgbar -
      - -
      -
      ๐ŸŽฎ
      -

      Fun

      -

      SpaรŸ-Commands und Unterhaltungsfeatures.

      - Bald verfรผgbar -
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/site/index.html b/site/index.html deleted file mode 100644 index 8c9222a..0000000 --- a/site/index.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - ManagerX | Dashboard - - - - - - - - -
      -

      ManagerX

      -

      Willkommen zu ManagerX!

      -

      Dein Bot fรผr Discord-Server

      - -
      - -
      -
      -
      0
      -
      Server
      -
      -
      -
      0
      -
      Nutzer
      -
      -
      -
      --ms
      -
      Latenz (Ping)
      -
      -
      -
      Offline
      -
      System-Status
      -
      -
      - - - - - - - - \ No newline at end of file diff --git a/site/js/api.js b/site/js/api.js deleted file mode 100644 index 853b42f..0000000 --- a/site/js/api.js +++ /dev/null @@ -1,494 +0,0 @@ -// Konfiguriere hier deine Server-URL fรผr die API -// Fรผr lokale Entwicklung: "http://127.0.0.1:3002/api" -// Fรผr Produktion: "https://deine-domain.com/api" -const API_BASE = "https://managerx-api.oppro.net/api"; - -// Hilfsfunktion: Token holen -const getToken = () => localStorage.getItem('discord_token'); -const getRefreshToken = () => localStorage.getItem('discord_refresh_token'); - -// Token-Status prรผfen -function checkTokenStatus() { - const token = getToken(); - const refreshToken = getRefreshToken(); - console.log("๐Ÿ” Token-Status:"); - console.log(" - Access Token:", token ? "Vorhanden (" + token.substring(0, 10) + "...)" : "Nicht vorhanden"); - console.log(" - Refresh Token:", refreshToken ? "Vorhanden (" + refreshToken.substring(0, 10) + "...)" : "Nicht vorhanden"); - return { hasToken: !!token, hasRefreshToken: !!refreshToken }; -} - -// Debug-Funktion global verfรผgbar machen -window.checkTokenStatus = checkTokenStatus; - -async function refreshToken() { - const refreshToken = getRefreshToken(); - console.log("๐Ÿ”‘ Refresh-Token vorhanden:", refreshToken ? "Ja" : "Nein"); - if (!refreshToken) { - throw new Error("Kein Refresh-Token verfรผgbar"); - } - - const response = await fetch(`${API_BASE}/auth/refresh`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ refresh_token: refreshToken }) - }); - console.log("๐Ÿ”„ Refresh-API Response Status:", response.status); - - if (!response.ok) { - const errorText = await response.text(); - console.error("โŒ Refresh-API Fehler:", errorText); - throw new Error("Token-Refresh fehlgeschlagen"); - } - - const data = await response.json(); - console.log("โœ… Neuer Token erhalten:", data.access_token ? "Ja" : "Nein"); - localStorage.setItem('discord_token', data.access_token); - if (data.refresh_token) { - localStorage.setItem('discord_refresh_token', data.refresh_token); - } - return data.access_token; -} - -// --- API FETCH HELPER (vereinfacht - bei 401 zur Login-Seite) --- -async function apiFetch(url, options = {}) { - const token = getToken(); - if (!token) { - console.log("โŒ Kein Token gefunden - Weiterleitung zur Login-Seite"); - window.location.href = 'index.html'; - throw new Error("Kein Token gefunden"); - } - - // Authorization header fรผr alle Requests - const headers = { ...options.headers, "Authorization": `Bearer ${token}` }; - - let res = await fetch(url, { ...options, headers }); - - // Wenn 401, direkt zur Login-Seite (kein Refresh mehr) - if (res.status === 401) { - console.log("๐Ÿ”„ Token abgelaufen - Weiterleitung zur Login-Seite"); - // Tokens lรถschen - localStorage.removeItem('discord_token'); - localStorage.removeItem('discord_refresh_token'); - localStorage.removeItem('user_info'); - // Zur Login-Seite mit Hinweis - window.location.href = 'index.html?logged_out=true'; - throw new Error("Token abgelaufen"); - } - - return res; -} - -document.addEventListener('DOMContentLoaded', async () => { - const params = new URLSearchParams(window.location.search); - const guildId = params.get('id'); - const path = window.location.pathname; - - console.log("ManagerX JS geladen auf:", path); - - // --- Seite: dashboard.html --- - if (path.includes('dashboard.html')) { - console.log("Lade Server-Liste"); - await loadGuilds(); - } - - // --- Seite: tempvc.html --- - if (path.includes('tempvc.html')) { - if (!guildId) return window.location.href = '../dashboard.html'; - - console.log("Initialisiere TempVC Modul fรผr Guild:", guildId); - loadTempVCModule(guildId); - - const form = document.getElementById('tempvc-form'); - if (form) { - form.onsubmit = async (e) => { - e.preventDefault(); - await saveTempVC(guildId); - }; - } - } - - // --- Seite: welcome.html --- - if (path.includes('welcome.html')) { - if (!guildId) return window.location.href = '../dashboard.html'; - - console.log("Initialisiere Welcome Modul fรผr Guild:", guildId); - loadWelcomeModule(guildId); - - const form = document.getElementById('welcome-form'); - if (form) { - form.onsubmit = async (e) => { - e.preventDefault(); - await saveWelcome(guildId); - }; - } - } - - // --- Seite: levelsystem.html --- - if (path.includes('levelsystem.html')) { - if (!guildId) return window.location.href = '../dashboard.html'; - - console.log("Initialisiere Levelsystem Modul fรผr Guild:", guildId); - loadLevelsystemModule(guildId); - - const form = document.getElementById('levelsystem-form'); - if (form) { - form.onsubmit = async (e) => { - e.preventDefault(); - await saveLevelsystem(guildId); - }; - } - } -}); - -// --- FUNKTION: Speichern (Ungekรผrzt) --- -async function saveTempVC(guildId) { - console.log("Speichervorgang fรผr Guild ausgelรถst:", guildId); - - const payload = { - creator_channel_id: document.getElementById('creator_channel_id').value, - category_id: document.getElementById('category_id').value, - auto_delete_time: parseInt(document.getElementById('auto_delete_time').value) || 0, - ui_enabled: document.getElementById('ui_enabled').checked, - ui_prefix: document.getElementById('ui_prefix').value || "๐Ÿ”ง" - }; - - try { - const response = await apiFetch(`${API_BASE}/guild/${guildId}/tempvc`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload) - }); - - const data = await response.json(); - - if (response.ok) { - alert("โœ… Erfolg: " + (data.message || "Gespeichert!")); - } else { - if (response.status === 403 && data.detail && data.detail.includes("deaktiviert")) { - alert("โŒ Dieses Feature ist in der Bot-Config deaktiviert."); - return; - } - alert("โŒ Fehler: " + (data.detail || "Unbekannter Fehler")); - } - } catch (error) { - console.error("Netzwerkfehler beim Speichern:", error); - alert("โŒ Netzwerkfehler: Backend unter http://127.0.0.1:3002 erreichbar?"); - } -} - -// --- FUNKTION: Laden --- -async function loadTempVCModule(guildId) { - try { - const res = await apiFetch(`${API_BASE}/guild/${guildId}/tempvc`); - if (!res.ok) { - if (res.status === 403) { - const errorData = await res.json(); - if (errorData.detail && errorData.detail.includes("deaktiviert")) { - alert("โŒ Dieses Feature ist in der Bot-Config deaktiviert."); - window.location.href = `../guild.html?id=${guildId}`; - return; - } - } - throw new Error("Laden fehlgeschlagen: " + (await res.text())); - } - - const data = await res.json(); - - // Lade Kanรคle fรผr Dropdowns - await loadChannels(guildId); - - // Felder befรผllen - document.getElementById('creator_channel_id').value = data.creator_channel_id || ""; - document.getElementById('category_id').value = data.category_id || ""; - document.getElementById('auto_delete_time').value = data.auto_delete_time || 0; - document.getElementById('ui_enabled').checked = data.ui_enabled || false; - document.getElementById('ui_prefix').value = data.ui_prefix || "๐Ÿ”ง"; - } catch (err) { - console.error("Fehler beim Laden der Daten:", err); - alert("โŒ Fehler beim Laden: " + err.message); - } -} - -// --- FUNKTION: Kanรคle laden --- -async function loadChannels(guildId) { - try { - const res = await apiFetch(`${API_BASE}/guild/${guildId}/channels`); - if (!res.ok) { - const errorText = await res.text(); - throw new Error(`Kanรคle laden fehlgeschlagen (${res.status}): ${errorText}`); - } - - const data = await res.json(); - const channels = data.channels; - - // Creator Channel Dropdown (Voice-Kanรคle, type 2) - const creatorSelect = document.getElementById('creator_channel_id'); - if (creatorSelect) { - creatorSelect.innerHTML = ''; - channels.filter(ch => ch.type === 2).forEach(ch => { - const option = document.createElement('option'); - option.value = ch.id; - option.textContent = ch.name; - creatorSelect.appendChild(option); - }); - } - - // Kategorie Dropdown (Kategorien, type 4) - const categorySelect = document.getElementById('category_id'); - if (categorySelect) { - categorySelect.innerHTML = ''; - channels.filter(ch => ch.type === 4).forEach(ch => { - const option = document.createElement('option'); - option.value = ch.id; - option.textContent = ch.name; - categorySelect.appendChild(option); - }); - } - - // Level Up Channel Dropdown (Text-Kanรคle, type 0) - const levelSelect = document.getElementById('level_up_channel'); - if (levelSelect) { - levelSelect.innerHTML = ''; - channels.filter(ch => ch.type === 0).forEach(ch => { - const option = document.createElement('option'); - option.value = ch.id; - option.textContent = ch.name; - levelSelect.appendChild(option); - }); - } - } catch (err) { - console.error("Fehler beim Laden der Kanรคle:", err); - alert("โŒ Kanรคle konnten nicht geladen werden: " + err.message); - } -} - -// --- FUNKTION: Welcome laden --- -async function loadWelcomeModule(guildId) { - try { - const res = await apiFetch(`${API_BASE}/guild/${guildId}/welcome`); - if (!res.ok) { - if (res.status === 403) { - const errorData = await res.json(); - if (errorData.detail && errorData.detail.includes("deaktiviert")) { - alert("โŒ Dieses Feature ist in der Bot-Config deaktiviert."); - window.location.href = `../guild.html?id=${guildId}`; - return; - } - } - throw new Error("Laden fehlgeschlagen: " + (await res.text())); - } - - const data = await res.json(); - - // Lade Kanรคle fรผr Dropdowns - await loadChannels(guildId); - - // Felder befรผllen - document.getElementById('channel_id').value = data.channel_id || ""; - document.getElementById('welcome_message').value = data.welcome_message || ""; - document.getElementById('enabled').checked = data.enabled || false; - document.getElementById('embed_enabled').checked = data.embed_enabled || false; - document.getElementById('embed_color').value = data.embed_color || "#00ff00"; - document.getElementById('embed_title').value = data.embed_title || ""; - document.getElementById('embed_description').value = data.embed_description || ""; - document.getElementById('embed_thumbnail').checked = data.embed_thumbnail || false; - document.getElementById('embed_footer').value = data.embed_footer || ""; - document.getElementById('ping_user').checked = data.ping_user || false; - document.getElementById('delete_after').value = data.delete_after || 0; - } catch (err) { - console.error("Fehler beim Laden der Welcome-Daten:", err); - alert("โŒ Fehler beim Laden: " + err.message); - } -} - -// --- FUNKTION: Levelsystem laden --- -async function loadLevelsystemModule(guildId) { - try { - const res = await apiFetch(`${API_BASE}/guild/${guildId}/levelsystem`); - if (!res.ok) { - if (res.status === 403) { - const errorData = await res.json(); - if (errorData.detail && errorData.detail.includes("deaktiviert")) { - alert("โŒ Dieses Feature ist in der Bot-Config deaktiviert."); - window.location.href = `../guild.html?id=${guildId}`; - return; - } - } - throw new Error("Laden fehlgeschlagen: " + (await res.text())); - } - - const data = await res.json(); - - // Lade Kanรคle fรผr Dropdowns - await loadChannels(guildId); - - // Felder befรผllen - document.getElementById('levelsystem_enabled').checked = data.levelsystem_enabled || false; - document.getElementById('min_xp').value = data.min_xp || 10; - document.getElementById('max_xp').value = data.max_xp || 20; - document.getElementById('xp_cooldown').value = data.xp_cooldown || 30; - document.getElementById('level_up_channel').value = data.level_up_channel || ""; - document.getElementById('prestige_enabled').checked = data.prestige_enabled || false; - document.getElementById('prestige_min_level').value = data.prestige_min_level || 50; - } catch (err) { - console.error("Fehler beim Laden der Levelsystem-Daten:", err); - alert("โŒ Fehler beim Laden: " + err.message); - } -} - -// --- FUNKTION: Levelsystem speichern --- -async function saveLevelsystem(guildId) { - console.log("Speichervorgang fรผr Levelsystem ausgelรถst:", guildId); - - const payload = { - levelsystem_enabled: document.getElementById('levelsystem_enabled').checked, - min_xp: parseInt(document.getElementById('min_xp').value) || 10, - max_xp: parseInt(document.getElementById('max_xp').value) || 20, - xp_cooldown: parseInt(document.getElementById('xp_cooldown').value) || 30, - level_up_channel: document.getElementById('level_up_channel').value, - prestige_enabled: document.getElementById('prestige_enabled').checked, - prestige_min_level: parseInt(document.getElementById('prestige_min_level').value) || 50 - }; - - try { - const response = await apiFetch(`${API_BASE}/guild/${guildId}/levelsystem`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload) - }); - - const data = await response.json(); - - if (response.ok) { - alert("โœ… Erfolg: " + (data.message || "Gespeichert!")); - } else { - if (response.status === 403 && data.detail && data.detail.includes("deaktiviert")) { - alert("โŒ Dieses Feature ist in der Bot-Config deaktiviert."); - return; - } - alert("โŒ Fehler: " + (data.detail || "Unbekannter Fehler")); - } - } catch (error) { - console.error("Netzwerkfehler beim Speichern:", error); - alert("โŒ Netzwerkfehler: Backend unter http://127.0.0.1:3002 erreichbar?"); - } -} - -// --- FUNKTION: Server-Liste laden --- -async function loadGuilds() { - try { - const res = await apiFetch(`${API_BASE}/user/guilds`); - if (!res.ok) throw new Error("Server laden fehlgeschlagen"); - - const guilds = await res.json(); - const guildList = document.getElementById('guild-list'); - - if (guilds.length === 0) { - guildList.innerHTML = '

      Keine Server mit Admin-Rechten gefunden.

      '; - return; - } - - guildList.innerHTML = ''; - guilds.forEach(guild => { - const guildCard = document.createElement('div'); - guildCard.className = 'guild-card'; - guildCard.innerHTML = ` - ${guild.name} -

      ${guild.name}

      - Verwalten - `; - guildList.appendChild(guildCard); - }); - } catch (err) { - console.error("Fehler beim Laden der Server:", err); - document.getElementById('guild-list').innerHTML = '

      โŒ Fehler beim Laden der Server.

      '; - } -} - -// --- FUNKTION: Guild-Details laden (fรผr guild.html) --- -async function fetchGuildDetails(guildId) { - const token = getToken(); - try { - // Hole Guild-Info von Discord API รผber unseren Endpoint - const res = await fetch(`${API_BASE}/user/guilds?token=${token}`); - if (!res.ok) throw new Error("Guild-Details laden fehlgeschlagen"); - - const guilds = await res.json(); - const guild = guilds.find(g => g.id == guildId); - - if (guild) { - document.getElementById('guild-icon').src = `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.png`; - document.getElementById('guild-icon').onerror = () => this.src = 'https://via.placeholder.com/64x64?text=?'; - document.getElementById('guild-name').textContent = guild.name; - } else { - document.getElementById('guild-name').textContent = 'Server nicht gefunden'; - } - } catch (err) { - console.error("Fehler beim Laden der Guild-Details:", err); - document.getElementById('guild-name').textContent = 'Fehler beim Laden'; - } -} - -// --- FUNKTION: Welcome speichern --- -async function saveWelcome(guildId) { - console.log("Speichervorgang fรผr Welcome ausgelรถst:", guildId); - - const payload = { - channel_id: document.getElementById('channel_id').value, - welcome_message: document.getElementById('welcome_message').value, - enabled: document.getElementById('enabled').checked, - embed_enabled: document.getElementById('embed_enabled').checked, - embed_color: document.getElementById('embed_color').value, - embed_title: document.getElementById('embed_title').value, - embed_description: document.getElementById('embed_description').value, - embed_thumbnail: document.getElementById('embed_thumbnail').checked, - embed_footer: document.getElementById('embed_footer').value, - ping_user: document.getElementById('ping_user').checked, - delete_after: parseInt(document.getElementById('delete_after').value) || 0 - }; - - try { - const response = await apiFetch(`${API_BASE}/guild/${guildId}/welcome`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload) - }); - - const data = await response.json(); - - if (response.ok) { - alert("โœ… Erfolg: " + (data.message || "Gespeichert!")); - } else { - if (response.status === 403 && data.detail && data.detail.includes("deaktiviert")) { - alert("โŒ Dieses Feature ist in der Bot-Config deaktiviert."); - return; - } - alert("โŒ Fehler: " + (data.detail || "Unbekannter Fehler")); - } - } catch (error) { - console.error("Netzwerkfehler beim Speichern:", error); - alert("โŒ Netzwerkfehler: Backend unter http://127.0.0.1:3002 erreichbar?"); - } -} - -// --- FUNKTION: Bot-Stats laden (fรผr index.html) --- -async function loadBotStats() { - try { - const response = await fetch(`${API_BASE}/managerx/stats`); - const data = await response.json(); - - document.getElementById('server-count').textContent = data.stats?.server_count || '0'; - document.getElementById('user-count').textContent = data.stats?.user_count || '0'; - document.getElementById('bot-ping').textContent = data.bot_info?.latency ? data.bot_info.latency + 'ms' : '--ms'; - document.getElementById('bot-status').textContent = data.bot_info?.status || 'Offline'; - - console.log("โœ… Bot-Stats erfolgreich geladen"); - } catch (error) { - console.error('โŒ Fehler beim Laden der Bot-Stats:', error); - // Bei Fehler Standardwerte setzen - document.getElementById('server-count').textContent = '--'; - document.getElementById('user-count').textContent = '--'; - document.getElementById('bot-ping').textContent = '--ms'; - document.getElementById('bot-status').textContent = 'Offline'; - } -} \ No newline at end of file diff --git a/site/js/particles.js b/site/js/particles.js deleted file mode 100644 index ed47069..0000000 --- a/site/js/particles.js +++ /dev/null @@ -1,66 +0,0 @@ -const canvas = document.getElementById('particleCanvas'); -const ctx = canvas.getContext('2d'); - -let particlesArray = []; -// Weniger Partikel = mehr FPS -const numberOfParticles = 50; - -canvas.width = window.innerWidth; -canvas.height = window.innerHeight; - -class Particle { - constructor() { - this.reset(); - } - reset() { - this.x = Math.random() * canvas.width; - this.y = Math.random() * canvas.height; - this.size = Math.random() * 1.5 + 0.5; - this.speedX = (Math.random() - 0.5) * 0.5; - this.speedY = (Math.random() - 0.5) * 0.5; - } - update() { - this.x += this.speedX; - this.y += this.speedY; - - if (this.x > canvas.width || this.x < 0) this.speedX *= -1; - if (this.y > canvas.height || this.y < 0) this.speedY *= -1; - } - draw() { - ctx.fillStyle = 'rgba(88, 101, 242, 0.3)'; - ctx.beginPath(); - ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); - ctx.fill(); - } -} - -function init() { - particlesArray = []; - for (let i = 0; i < numberOfParticles; i++) { - particlesArray.push(new Particle()); - } -} - -function animate() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - for (let i = 0; i < particlesArray.length; i++) { - particlesArray[i].update(); - particlesArray[i].draw(); - } - // Verhindert unnรถtiges Rechnen, wenn man den Tab wechselt - requestAnimationFrame(animate); -} - -// Performance-Check beim Resize -let resizeTimeout; -window.addEventListener('resize', () => { - clearTimeout(resizeTimeout); - resizeTimeout = setTimeout(() => { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; - init(); - }, 200); -}); - -init(); -animate(); \ No newline at end of file diff --git a/site/modules/index.html b/site/modules/index.html deleted file mode 100644 index 2d256c5..0000000 --- a/site/modules/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - ManagerX - Module - - -

      Weiterleitung zu Server-Modulen...

      - - \ No newline at end of file diff --git a/site/modules/levelsystem.html b/site/modules/levelsystem.html deleted file mode 100644 index d7aec5b..0000000 --- a/site/modules/levelsystem.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - ManagerX - Levelsystem Einstellungen - - - - - - -
      -

      โญ Levelsystem Einstellungen

      - -
      -
      -

      Grundeinstellungen

      -
      - - -
      -
      - -
      -
      - -
      -

      XP-Einstellungen

      -
      - - -
      -
      - - -
      -
      - - -
      -
      - -
      -

      Prestige-System

      -
      - -
      -
      - - -
      -
      - - -
      -
      - - - - \ No newline at end of file diff --git a/site/modules/tempvc.html b/site/modules/tempvc.html deleted file mode 100644 index f1a8867..0000000 --- a/site/modules/tempvc.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - ManagerX - TempVC Einstellungen - - - - - - - - -
      -
      -
      ๐Ÿ”Š
      -

      TempVC Konfiguration

      -

      Verwalte temporรคre Voice-Channels fรผr deinen Server

      -
      - -
      -
      -

      ๐ŸŽฏ Kern-Einstellungen

      -
      -
      - - - Wรคhle den Channel, bei dem Mitglieder Voice-Channels erstellen kรถnnen -
      - -
      - - - Kategorie, in der die temporรคren Channels erstellt werden -
      - -
      - - - Zeit bis zum automatischen Lรถschen leerer Channels (0 = deaktiviert) -
      -
      -
      - -
      -

      ๐ŸŽจ UI / Interface

      -
      -
      - - Zeigt Interface-Buttons in Voice-Channels an -
      - -
      - - - Emoji oder Text fรผr Interface-Buttons -
      -
      -
      - -
      - -
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/site/modules/welcome.html b/site/modules/welcome.html deleted file mode 100644 index d2aa14a..0000000 --- a/site/modules/welcome.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - ManagerX - Welcome Einstellungen - - - - - - -
      -

      ๐Ÿ‘‹ Welcome Einstellungen

      - -
      -
      -

      Grundeinstellungen

      -
      - - -
      -
      - - -
      -
      - -
      -
      - -
      -

      Embed-Einstellungen

      -
      - -
      -
      - - -
      -
      - - -
      -
      - - -
      -
      - -
      -
      - - -
      -
      - -
      -

      Zusรคtzliche Optionen

      -
      - -
      -
      - - -
      -
      - - -
      -
      - - - - \ No newline at end of file diff --git a/site/privacy.html b/site/privacy.html deleted file mode 100644 index a91f1de..0000000 --- a/site/privacy.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - ManagerX | Datenschutz - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/site/tos.html b/site/tos.html deleted file mode 100644 index 9a04f79..0000000 --- a/site/tos.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - ManagerX | Nutzungsbedingungen - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/bot/__init__.py b/src/bot/__init__.py new file mode 100644 index 0000000..a8ce586 --- /dev/null +++ b/src/bot/__init__.py @@ -0,0 +1 @@ +from .core import * \ No newline at end of file diff --git a/src/bot/core/__init__.py b/src/bot/core/__init__.py new file mode 100644 index 0000000..a269625 --- /dev/null +++ b/src/bot/core/__init__.py @@ -0,0 +1,26 @@ +""" +ManagerX Core Module +==================== + +Zentrale Module fรผr Bot-Initialisierung und -Verwaltung +""" + +from .config import ConfigLoader, BotConfig +from .bot_setup import BotSetup +from .cog_manager import CogManager +from .database import DatabaseManager +from .dashboard import DashboardTask +from .utils import print_logo, format_uptime, truncate_text +from .groups import * + +__all__ = [ + 'ConfigLoader', + 'BotConfig', + 'BotSetup', + 'CogManager', + 'DatabaseManager', + 'DashboardTask', + 'print_logo', + 'format_uptime', + 'truncate_text' +] \ No newline at end of file diff --git a/src/bot/core/bot_setup.py b/src/bot/core/bot_setup.py new file mode 100644 index 0000000..9c81795 --- /dev/null +++ b/src/bot/core/bot_setup.py @@ -0,0 +1,76 @@ +""" +ManagerX - Bot Setup +==================== + +Initialisiert und konfiguriert die Discord Bot-Instanz +Pfad: src/bot/core/bot_setup.py +""" + +import discord +import ezcord + +class BotSetup: + """Verwaltet die Bot-Initialisierung""" + + def __init__(self, config: dict): + self.config = config + + def create_bot(self) -> ezcord.Bot: + """ + Erstellt und konfiguriert die Bot-Instanz. + + Returns: + ezcord.Bot: Konfigurierte Bot-Instanz + """ + # Intents konfigurieren + intents = discord.Intents.default() + intents.members = True + intents.message_content = True + + # Bot erstellen + bot = ezcord.Bot( + intents=intents, + language="de" + ) + + # Bot-Konfiguration anhรคngen + bot.config = self._build_bot_config() + + return bot + + def _build_bot_config(self) -> dict: + """ + Erstellt die Bot-Config aus der geladenen Konfiguration. + + Returns: + dict: Bot-Konfiguration fรผr Runtime + """ + ui = self.config.get('ui', {}) + behavior = self.config.get('bot_behavior', {}) + security = self.config.get('security', {}) + performance = self.config.get('performance', {}) + + return { + # UI Settings + 'embed_color': ui.get('embed_color', '#00ff00'), + 'footer_text': ui.get('footer_text', 'ManagerX Bot'), + 'theme': ui.get('theme', 'dark'), + 'show_timestamps': ui.get('show_timestamps', True), + + # Behavior + 'maintenance_mode': behavior.get('maintenance_mode', False), + 'global_cooldown': behavior.get('global_cooldown_seconds', 5), + 'max_messages_per_minute': behavior.get('max_messages_per_minute', 10), + + # Security + 'required_permissions': security.get('required_permissions', []), + 'blacklist_servers': security.get('blacklist_servers', []), + 'whitelist_users': security.get('whitelist_users', []), + 'enable_command_logging': security.get('enable_command_logging', True), + + # Performance + 'max_concurrent_tasks': performance.get('max_concurrent_tasks', 10), + 'task_timeout': performance.get('task_timeout_seconds', 30), + 'memory_limit': performance.get('memory_limit_mb', 512), + 'enable_gc_optimization': performance.get('enable_gc_optimization', True) + } \ No newline at end of file diff --git a/src/bot/core/cog_manager.py b/src/bot/core/cog_manager.py new file mode 100644 index 0000000..6d5932c --- /dev/null +++ b/src/bot/core/cog_manager.py @@ -0,0 +1,116 @@ +""" +ManagerX - Cog Manager +====================== + +Verwaltet das Laden und Deaktivieren von Cogs +Pfad: src/bot/core/cog_manager.py +""" + +from logger import logger, Category + +class CogManager: + """Verwaltet Cog-Loading und Ignore-Liste""" + + # Hilfs-/Utility-Dateien, die keine Cogs sind + UTILITY_FILES = [ + "autocomplete", + "cache", + "components", + "config", + "containers", + "utils", + "backend", + "emojis" + ] + + # Mapping: Config-Key -> Dateiname + COG_MAPPING = { + 'fun': { + 'gewinnt': 'gewinnt', + 'tictactoe': 'tictactoe', + 'weather': 'weather', + 'wikipedia': 'cog' + }, + 'information': { + 'botstatus': 'botstatus', + 'serverinfo': 'serverinfo', + 'usermanagemt': 'usermanagemt' + }, + 'moderation': { + 'antispam': 'antispam', + 'moderation': 'moderation', + 'notes': 'notes', + 'warningsystem': 'warningsystem' + }, + 'server_management': { + 'autodelete': 'autodelete', + 'globalchat': 'globalchat', + 'levelsystem': 'levelsystem', + 'logging': 'logging', + 'stats': 'stats', + 'tempvc': 'tempvc', + 'welcome': 'welcome' + }, + 'other': { + 'setlang': 'setlang' + } + } + + def __init__(self, cogs_config: dict): + self.cogs_config = cogs_config + + def get_ignored_cogs(self) -> list: + """ + Erstellt Liste von zu ignorierenden Cogs basierend auf config.yaml. + + Returns: + list: Dateinamen (ohne .py) der zu ignorierenden Cogs + """ + ignored = self.UTILITY_FILES.copy() + + # Deaktivierte Cogs hinzufรผgen + for category, cogs in self.COG_MAPPING.items(): + category_config = self.cogs_config.get(category, {}) + + for cog_key, file_name in cogs.items(): + if not category_config.get(cog_key, True): + ignored.append(file_name) + logger.info(Category.BOT, f"Cog '{file_name}' deaktiviert (config.yaml)") + + return ignored + + def is_cog_enabled(self, category: str, cog_name: str) -> bool: + """ + Prรผft ob ein bestimmter Cog aktiviert ist. + + Args: + category: Kategorie des Cogs (z.B. 'fun', 'moderation') + cog_name: Name des Cogs + + Returns: + bool: True wenn aktiviert, sonst False + """ + category_config = self.cogs_config.get(category, {}) + return category_config.get(cog_name, True) + + def get_enabled_cogs(self) -> dict: + """ + Gibt alle aktivierten Cogs nach Kategorie zurรผck. + + Returns: + dict: Dictionary mit Kategorien und aktivierten Cogs + """ + enabled = {} + + for category, cogs in self.COG_MAPPING.items(): + category_config = self.cogs_config.get(category, {}) + enabled_in_category = [] + + for cog_key, file_name in cogs.items(): + if category_config.get(cog_key, True): + enabled_in_category.append(file_name) + + if enabled_in_category: + enabled[category] = enabled_in_category + + return enabled \ No newline at end of file diff --git a/src/bot/core/config.py b/src/bot/core/config.py new file mode 100644 index 0000000..1240754 --- /dev/null +++ b/src/bot/core/config.py @@ -0,0 +1,74 @@ +""" +ManagerX - Configuration Loader +================================ + +Lรคdt und verwaltet die Bot-Konfiguration aus config.yaml +""" + +import os +import sys +import yaml +from pathlib import Path +from colorama import Fore, Style +from dotenv import load_dotenv +base_path = Path(__file__).resolve().parent.parent.parent.parent +env_path = base_path / "config" / ".env" + +# Lade die .env Datei +load_dotenv(dotenv_path=env_path) + +class BotConfig: + """Zentrale Konfigurationsklasse""" + TOKEN = os.getenv("TOKEN") + VERSION = "2.0.0" + +class ConfigLoader: + """Lรคdt die Bot-Konfiguration aus config.yaml""" + + def __init__(self, basedir: Path): + self.basedir = basedir + self.config_path = basedir / 'config' / 'config.yaml' + + def load(self) -> dict: + """ + Lรคdt die Konfigurationsdatei und gibt alle Einstellungen zurรผck. + + Returns: + dict: Vollstรคndige Konfiguration + + Raises: + SystemExit: Bei kritischen Fehlern + """ + try: + with open(self.config_path, 'r', encoding='utf-8') as f: + config = yaml.safe_load(f) + + # Bot deaktiviert? + if not config.get('enabled', True): + print(f"[{Fore.YELLOW}INFO{Style.RESET_ALL}] Bot ist in config.yaml deaktiviert. Beende...") + sys.exit(0) + + # Version รผbernehmen + BotConfig.VERSION = config.get('version', '2.0.0') + + # Strukturierte Rรผckgabe + return { + 'enabled': config.get('enabled', True), + 'version': BotConfig.VERSION, + 'features': config.get('features', {}), + 'bot_behavior': config.get('bot_behavior', {}), + 'ui': config.get('ui', {}), + 'security': config.get('security', {}), + 'performance': config.get('performance', {}), + 'cogs': config.get('features', {}).get('cogs', {}) + } + + except FileNotFoundError: + print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] config.yaml nicht gefunden: {self.config_path}") + sys.exit(1) + except yaml.YAMLError as e: + print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] YAML-Parsing-Fehler: {e}") + sys.exit(1) + except Exception as e: + print(f"[{Fore.RED}ERROR{Style.RESET_ALL}] Fehler beim Laden der config.yaml: {e}") + sys.exit(1) \ No newline at end of file diff --git a/src/bot/core/dashboard.py b/src/bot/core/dashboard.py new file mode 100644 index 0000000..e39f610 --- /dev/null +++ b/src/bot/core/dashboard.py @@ -0,0 +1,101 @@ +""" +ManagerX - Dashboard Task +========================== + +Verwaltet das Dashboard-Update-System +Pfad: src/bot/core/dashboard.py +""" + +import json +from datetime import datetime +from pathlib import Path +from discord.ext import tasks +from logger import logger, Category + +class DashboardTask: + """Verwaltet periodische Dashboard-Updates""" + + def __init__(self, bot, basedir: Path): + self.bot = bot + self.basedir = basedir + self.stats_file = basedir / 'bot_stats.json' + self._task = None + + # Task definieren + @tasks.loop(minutes=1) + async def update_dashboard(): + await self._update_stats() + + self._task = update_dashboard + + async def _update_stats(self): + """Aktualisiert die Dashboard-Statistiken""" + try: + # Basis-Statistiken sammeln + stats = { + "bot_info": { + "name": str(self.bot.user.name) if self.bot.user else "Unknown", + "id": str(self.bot.user.id) if self.bot.user else "0", + "status": "online", + "latency": round(self.bot.latency * 1000, 1) + }, + "stats": { + "server_count": len(self.bot.guilds), + "user_count": sum(g.member_count for g in self.bot.guilds if g.member_count), + "shards": self.bot.shard_count or 1, + "commands": len(self.bot.tree.get_commands()) if hasattr(self.bot, 'tree') else 0 + }, + "system": { + "uptime": self._get_uptime(), + "python_version": self._get_python_version() + }, + "updated_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") + } + + # In Datei schreiben + with open(self.stats_file, 'w', encoding='utf-8') as f: + json.dump(stats, f, indent=4, ensure_ascii=False) + + except Exception as e: + logger.error(Category.BOT, f"Dashboard-Update fehlgeschlagen: {e}") + + def _get_uptime(self) -> str: + """Berechnet die Bot-Uptime""" + if hasattr(self.bot, 'start_time'): + delta = datetime.now() - self.bot.start_time + hours, remainder = divmod(int(delta.total_seconds()), 3600) + minutes, seconds = divmod(remainder, 60) + return f"{hours}h {minutes}m {seconds}s" + return "Unknown" + + def _get_python_version(self) -> str: + """Gibt die Python-Version zurรผck""" + import sys + return f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}" + + def register(self): + """Registriert den Task (startet ihn noch nicht)""" + # Startzeit speichern + self.bot.start_time = datetime.now() + logger.info(Category.DISCORD_BOT, "Dashboard-Task registriert") + + def start(self): + """Startet den Dashboard-Update-Task""" + if self._task and not self._task.is_running(): + self._task.start() + logger.success(Category.DISCORD_BOT, "Dashboard-Task gestartet") + + def stop(self): + """Stoppt den Dashboard-Update-Task""" + if self._task and self._task.is_running(): + self._task.cancel() + logger.info(Category.DISCORD_BOT, "Dashboard-Task gestoppt") + + def is_running(self) -> bool: + """ + Prรผft ob der Task lรคuft. + + Returns: + bool: True wenn Task lรคuft + """ + return self._task.is_running() if self._task else False \ No newline at end of file diff --git a/src/bot/core/database.py b/src/bot/core/database.py new file mode 100644 index 0000000..6d1e695 --- /dev/null +++ b/src/bot/core/database.py @@ -0,0 +1,75 @@ +""" +ManagerX - Database Manager +============================ + +Verwaltet Datenbankverbindungen und Initialisierung +Pfad: src/bot/core/database.py +""" + +import sys +from logger import logger, Category + +try: + from DevTools import SettingsDB +except ImportError as e: + logger.critical(Category.DATABASE, f"SettingsDB Import fehlgeschlagen: {e}") + SettingsDB = None + +class DatabaseManager: + """Verwaltet die Datenbank-Initialisierung""" + + def __init__(self): + self.db = None + + def initialize(self, bot) -> bool: + """ + Initialisiert die Datenbank und hรคngt sie an den Bot an. + + Args: + bot: Bot-Instanz + + Returns: + bool: True bei Erfolg, False bei Fehler + """ + if SettingsDB is None: + logger.critical(Category.DATABASE, "SettingsDB nicht verfรผgbar!") + return False + + try: + self.db = SettingsDB() + bot.settings_db = self.db + logger.success(Category.DATABASE, "Settings Database initialized โœ“") + return True + + except Exception as e: + logger.critical(Category.DATABASE, f"Datenbankfehler: {e}") + return False + + def get_database(self): + """ + Gibt die Datenbankinstanz zurรผck. + + Returns: + SettingsDB: Datenbankinstanz oder None + """ + return self.db + + def close(self): + """SchlieรŸt die Datenbankverbindung""" + if self.db: + try: + # Falls SettingsDB eine close()-Methode hat + if hasattr(self.db, 'close'): + self.db.close() + logger.info(Category.DATABASE, "Datenbankverbindung geschlossen") + except Exception as e: + logger.error(Category.DATABASE, f"Fehler beim SchlieรŸen der DB: {e}") + + def is_connected(self) -> bool: + """ + Prรผft ob die Datenbank verbunden ist. + + Returns: + bool: True wenn verbunden, sonst False + """ + return self.db is not None \ No newline at end of file diff --git a/src/bot/core/utils.py b/src/bot/core/utils.py new file mode 100644 index 0000000..c7a7d72 --- /dev/null +++ b/src/bot/core/utils.py @@ -0,0 +1,73 @@ +""" +ManagerX - Utility Functions +============================= + +Hilfsfunktionen fรผr den Bot +""" + +from colorama import Fore, Style +from .config import BotConfig + +def print_logo(): + """Gibt das ManagerX ASCII-Logo in der Konsole aus""" + logo_lines = [ + r" _____ ______ ________ ________ ________ ________ _______ ________ ___ ___ ", + r"|\ _ \ _ \|\ __ \|\ ___ \|\ __ \|\ ____\|\ ___ \ |\ __ \ |\ \ / /|", + r"\ \ \\\__\ \ \ \ \|\ \ \ \\ \ \ \ \|\ \ \ \___|\ \ __/|\ \ \|\ \ \ \ \/ / /", + r" \ \ \\|__| \ \ \ __ \ \ \\ \ \ \ __ \ \ \ __\ \ _|/_\ \ _ _\ \ \ / / ", + r" \ \ \ \ \ \ \ \ \ \ \ \\ \ \ \ \ \ \ \ \|\ \ \ \_|\ \ \ \\ \| / \/ ", + r" \ \__\ \ \__\ \__\ \__\ \__\\ \__\ \__\ \__\ \_______\ \_______\ \__\\ _\ / /\ \ ", + r" \|__| \|__|\|__|\|__|\|__| \|__|\|__|\|__|\|_______|\|_______|\|__|\|__|/__/ /\ __\ ", + r" |__|/ \|__| " + ] + + print(Fore.CYAN) + for line in logo_lines: + print(line) + print(f"{'=' * 91}") + print(f" ManagerX Discord Bot v{BotConfig.VERSION}") + print(f"{'=' * 91}{Style.RESET_ALL}\n") + + +def format_uptime(seconds: int) -> str: + """ + Formatiert Sekunden in lesbare Uptime. + + Args: + seconds: Anzahl Sekunden + + Returns: + str: Formatierte Uptime (z.B. "2d 5h 30m") + """ + days, remainder = divmod(seconds, 86400) + hours, remainder = divmod(remainder, 3600) + minutes, seconds = divmod(remainder, 60) + + parts = [] + if days > 0: + parts.append(f"{int(days)}d") + if hours > 0: + parts.append(f"{int(hours)}h") + if minutes > 0: + parts.append(f"{int(minutes)}m") + if seconds > 0 or not parts: + parts.append(f"{int(seconds)}s") + + return " ".join(parts) + + +def truncate_text(text: str, max_length: int = 100, suffix: str = "...") -> str: + """ + Kรผrzt Text auf maximale Lรคnge. + + Args: + text: Zu kรผrzender Text + max_length: Maximale Lรคnge + suffix: Suffix bei gekรผrztem Text + + Returns: + str: Gekรผrzter Text + """ + if len(text) <= max_length: + return text + return text[:max_length - len(suffix)] + suffix \ No newline at end of file diff --git a/src/cogs/Servermanament/autodelete.py b/src/cogs/Servermanament/autodelete.py deleted file mode 100644 index 9ba365c..0000000 --- a/src/cogs/Servermanament/autodelete.py +++ /dev/null @@ -1,309 +0,0 @@ -from DevTools import AutoDeleteDB -import discord -from discord.ext import tasks -from discord.commands import SlashCommandGroup, Option -import ezcord -import asyncio -from datetime import datetime, timedelta -import logging - -logger = logging.getLogger(__name__) - - -class AutoDelete(ezcord.Cog): - def __init__(self, bot): - self.bot = bot - self.delete_task.start() - self.processing_channels = set() # Verhindert doppelte Verarbeitung - - autodelete = SlashCommandGroup("autodelete", "Automatische Nachrichtenlรถschung") - - @autodelete.command(name="setup", description="Richtet AutoDelete fรผr einen Kanal ein.") - async def setup(self, ctx, - channel: Option(discord.TextChannel, "Kanal", required=True), - duration: Option(int, "Zeit in Sekunden (min: 60, max: 604800)", required=True), - exclude_pinned: Option(bool, "Angepinnte Nachrichten ausschlieรŸen", default=True), - exclude_bots: Option(bool, "Bot-Nachrichten ausschlieรŸen", default=False)): - - # Validierung - if duration < 60: - await ctx.respond("โŒ Mindestdauer ist 60 Sekunden (1 Minute).", ephemeral=True) - return - if duration > 604800: - await ctx.respond("โŒ Maximaldauer ist 604800 Sekunden (7 Tage).", ephemeral=True) - return - - # Permissions prรผfen - if not channel.permissions_for(ctx.guild.me).manage_messages: - await ctx.respond("โŒ Ich habe keine Berechtigung, Nachrichten in diesem Kanal zu lรถschen.", ephemeral=True) - return - - db = AutoDeleteDB() - db.add_autodelete(channel.id, duration, exclude_pinned, exclude_bots) - - duration_str = self._format_duration(duration) - await ctx.respond( - f"โœ… AutoDelete fรผr {channel.mention} wurde aktiviert!\n" - f"๐Ÿ“… Dauer: {duration_str}\n" - f"๐Ÿ“Œ Angepinnte Nachrichten: {'Ausgeschlossen' if exclude_pinned else 'Eingeschlossen'}\n" - f"๐Ÿค– Bot-Nachrichten: {'Ausgeschlossen' if exclude_bots else 'Eingeschlossen'}", - ephemeral=True - ) - - @autodelete.command(name="list", description="Zeigt alle aktiven AutoDelete-Kanรคle.") - async def list(self, ctx): - db = AutoDeleteDB() - channels = db.get_all() - if not channels: - await ctx.respond("โŒ Keine AutoDelete-Kanรคle gefunden.", ephemeral=True) - return - - embed = discord.Embed( - title="๐Ÿ—‘๏ธ Aktive AutoDelete-Kanรคle", - color=discord.Color.blue(), - timestamp=datetime.utcnow() - ) - - for chan_id, duration, exclude_pinned, exclude_bots in channels: - channel = self.bot.get_channel(chan_id) - if channel: - duration_str = self._format_duration(duration) - settings = [] - if exclude_pinned: - settings.append("๐Ÿ“Œ Angepinnte ausgeschlossen") - if exclude_bots: - settings.append("๐Ÿค– Bots ausgeschlossen") - - settings_str = "\n".join(settings) if settings else "Keine besonderen Einstellungen" - - embed.add_field( - name=f"#{channel.name}", - value=f"โฑ๏ธ {duration_str}\n{settings_str}", - inline=True - ) - else: - embed.add_field( - name="โŒ Unbekannter Kanal", - value=f"ID: {chan_id}\nโฑ๏ธ {self._format_duration(duration)}", - inline=True - ) - - await ctx.respond(embed=embed, ephemeral=True) - - @autodelete.command(name="remove", description="Entfernt AutoDelete von einem Kanal.") - async def remove(self, ctx, - channel: Option(discord.TextChannel, "Kanal", required=True)): - db = AutoDeleteDB() - if db.get_autodelete(channel.id): - db.remove_autodelete(channel.id) - await ctx.respond(f"๐Ÿ—‘๏ธ AutoDelete fรผr {channel.mention} wurde entfernt.", ephemeral=True) - else: - await ctx.respond(f"โŒ AutoDelete war fรผr {channel.mention} nicht aktiviert.", ephemeral=True) - - @autodelete.command(name="stats", description="Zeigt Statistiken fรผr einen AutoDelete-Kanal.") - async def stats(self, ctx, - channel: Option(discord.TextChannel, "Kanal", required=True)): - db = AutoDeleteDB() - config = db.get_autodelete_full(channel.id) - if not config: - await ctx.respond(f"โŒ AutoDelete ist fรผr {channel.mention} nicht aktiviert.", ephemeral=True) - return - - duration, exclude_pinned, exclude_bots = config - stats = db.get_stats(channel.id) - - embed = discord.Embed( - title=f"๐Ÿ“Š AutoDelete Statistiken - #{channel.name}", - color=discord.Color.green(), - timestamp=datetime.utcnow() - ) - - embed.add_field(name="โฑ๏ธ Lรถschzeit", value=self._format_duration(duration), inline=True) - embed.add_field(name="๐Ÿ“Œ Angepinnte", value="Ausgeschlossen" if exclude_pinned else "Eingeschlossen", - inline=True) - embed.add_field(name="๐Ÿค– Bots", value="Ausgeschlossen" if exclude_bots else "Eingeschlossen", inline=True) - - if stats: - embed.add_field(name="๐Ÿ—‘๏ธ Gelรถschte Nachrichten", value=str(stats['deleted_count']), inline=True) - embed.add_field(name="โŒ Fehler", value=str(stats['error_count']), inline=True) - if stats['last_deletion']: - embed.add_field(name="๐Ÿ•’ Letzte Lรถschung", value=f"", inline=True) - - await ctx.respond(embed=embed, ephemeral=True) - - @autodelete.command(name="test", description="Testet die AutoDelete-Funktion fรผr einen Kanal.") - async def test(self, ctx, - channel: Option(discord.TextChannel, "Kanal", required=True)): - db = AutoDeleteDB() - config = db.get_autodelete_full(channel.id) - if not config: - await ctx.respond(f"โŒ AutoDelete ist fรผr {channel.mention} nicht aktiviert.", ephemeral=True) - return - - await ctx.defer(ephemeral=True) - - try: - deleted_count = await self._process_channel_deletion(channel.id, test_mode=True) - await ctx.followup.send( - f"โœ… Test erfolgreich!\n" - f"๐Ÿ“ {deleted_count} Nachrichten wรผrden gelรถscht werden.", - ephemeral=True - ) - except Exception as e: - await ctx.followup.send(f"โŒ Test fehlgeschlagen: {str(e)}", ephemeral=True) - - @tasks.loop(seconds=30) # Erhรถht auf 30 Sekunden fรผr bessere Performance - async def delete_task(self): - try: - db = AutoDeleteDB() - channels = db.get_all() - - # Verarbeite Kanรคle parallel, aber begrenzt - semaphore = asyncio.Semaphore(3) # Max 3 Kanรคle gleichzeitig - tasks = [] - - for chan_id, duration, exclude_pinned, exclude_bots in channels: - if chan_id not in self.processing_channels: - task = self._process_channel_with_semaphore(semaphore, chan_id) - tasks.append(task) - - if tasks: - await asyncio.gather(*tasks, return_exceptions=True) - - except Exception as e: - logger.error(f"Fehler im delete_task: {e}") - - async def _process_channel_with_semaphore(self, semaphore, channel_id): - async with semaphore: - await self._process_channel_deletion(channel_id) - - async def _process_channel_deletion(self, channel_id, test_mode=False): - if channel_id in self.processing_channels and not test_mode: - return 0 - - if not test_mode: - self.processing_channels.add(channel_id) - - try: - db = AutoDeleteDB() - config = db.get_autodelete_full(channel_id) - if not config: - return 0 - - duration, exclude_pinned, exclude_bots = config - - # Zeitplan-Prรผfung - if not self._is_in_schedule(channel_id): - return 0 - - channel = self.bot.get_channel(channel_id) - if not channel: - return 0 - - deleted_count = 0 - error_count = 0 - cutoff_time = datetime.utcnow() - timedelta(seconds=duration) - - try: - messages_to_delete = [] - async for msg in channel.history(limit=200, oldest_first=True): - if msg.created_at >= cutoff_time: - break - - # Filterlogik - if exclude_pinned and msg.pinned: - continue - if exclude_bots and msg.author.bot: - continue - - # Whitelist-Prรผfung - if self._check_whitelist(msg, channel_id): - continue - - messages_to_delete.append(msg) - - # Batch-Lรถschung fรผr bessere Performance - if len(messages_to_delete) >= 10: - if not test_mode: - deleted, errors = await self._bulk_delete_messages(channel, messages_to_delete) - deleted_count += deleted - error_count += errors - else: - deleted_count += len(messages_to_delete) - messages_to_delete.clear() - - # Restliche Nachrichten lรถschen - if messages_to_delete: - if not test_mode: - deleted, errors = await self._bulk_delete_messages(channel, messages_to_delete) - deleted_count += deleted - error_count += errors - else: - deleted_count += len(messages_to_delete) - - # Statistiken aktualisieren - if not test_mode and (deleted_count > 0 or error_count > 0): - db.update_stats(channel_id, deleted_count, error_count) - - except discord.errors.Forbidden: - logger.warning(f"Keine Berechtigung fรผr Kanal {channel_id}") - except Exception as e: - logger.error(f"Fehler beim Verarbeiten von Kanal {channel_id}: {e}") - if not test_mode: - db.update_stats(channel_id, 0, 1) - - return deleted_count - - finally: - if not test_mode: - self.processing_channels.discard(channel_id) - - async def _bulk_delete_messages(self, channel, messages): - deleted_count = 0 - error_count = 0 - - # Trenne alte und neue Nachrichten (Discord API Limitation) - old_messages = [] - new_messages = [] - two_weeks_ago = datetime.utcnow() - timedelta(days=14) - - for msg in messages: - if msg.created_at < two_weeks_ago: - old_messages.append(msg) - else: - new_messages.append(msg) - - # Bulk delete fรผr neue Nachrichten - if new_messages: - try: - await channel.delete_messages(new_messages) - deleted_count += len(new_messages) - except Exception as e: - logger.error(f"Bulk delete Fehler: {e}") - - return deleted_count, error_count - - # Platzhalter fรผr fehlende Methoden, um den Code lauffรคhig zu machen - def _format_duration(self, duration: int) -> str: - """Formatiert die Dauer in eine lesbare Zeichenkette (z.B. '1 Stunde').""" - if duration >= 86400 and duration % 86400 == 0: - return f"{duration // 86400} Tage" - if duration >= 3600 and duration % 3600 == 0: - return f"{duration // 3600} Stunden" - if duration >= 60 and duration % 60 == 0: - return f"{duration // 60} Minuten" - return f"{duration} Sekunden" - - def _is_in_schedule(self, channel_id: int) -> bool: - """Platzhalter: Prรผft, ob der Kanal gerade gelรถscht werden soll (immer True im Platzhalter).""" - # Da diese Methode in Ihrem Originalcode nicht definiert ist, aber aufgerufen wird, - # muss sie entweder in der DB/Config abrufbar sein oder als Platzhalter existieren. - # Wir lassen sie hier True zurรผckgeben, um die Lรถschlogik nicht zu blockieren. - return True - - def _check_whitelist(self, message: discord.Message, channel_id: int) -> bool: - """Platzhalter: Prรผft, ob die Nachricht von der Lรถschung ausgenommen ist (immer False im Platzhalter).""" - return False - -def setup(bot): - bot.add_cog(AutoDelete(bot)) \ No newline at end of file diff --git a/src/cogs/Servermanament/autorole.py b/src/cogs/Servermanament/autorole.py deleted file mode 100644 index 6d5944c..0000000 --- a/src/cogs/Servermanament/autorole.py +++ /dev/null @@ -1,273 +0,0 @@ -import discord -from discord.ext import commands -from discord import option -from DevTools import AutoRoleDatabase -from handler import TranslationHandler as TH - -class AutoRole(commands.Cog): - def __init__(self, bot): - self.bot = bot - self.db = AutoRoleDatabase() - - async def cog_load(self): - """Wird aufgerufen, wenn der Cog geladen wird""" - await self.db.init_db() - - autorole = discord.SlashCommandGroup( - name="autorole", - description="Verwalte das Autorole-System", - default_member_permissions=discord.Permissions(administrator=True) - ) - - @autorole.command(name="add", description="Fรผge eine neue Autorole hinzu") - @option( - name="rolle", - description="Die Rolle, die vergeben werden soll", - type=discord.Role, - required=True - ) - async def autorole_add(self, ctx: discord.ApplicationContext, rolle: discord.Role): - """Fรผgt eine neue Autorole hinzu""" - - # Prรผfe, ob der Bot die Rolle vergeben kann - if rolle.position >= ctx.guild.me.top_role.position: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_to_high.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_to_high.desc"), - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if rolle.managed: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_managed.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_managed.desc"), - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - # Fรผge die Autorole hinzu - autorole_id = await self.db.add_autorole(ctx.guild.id, rolle.id) - - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.add_success.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.add_success.desc", role=rolle.mention, autorole_id=autorole_id), - color=discord.Color.green() - ) - await ctx.respond(embed=embed) - - @autorole.command(name="remove", description="Entferne eine Autorole") - @option( - name="autorole_id", - description="Die ID der Autorole (z.B. 26-25-153)", - type=str, - required=True - ) - async def autorole_remove(self, ctx: discord.ApplicationContext, autorole_id: str): - """Entfernt eine Autorole anhand der ID""" - - config = await self.db.get_autorole(autorole_id) - - if not config: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.desc", autorole_id=autorole_id), - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if config["guild_id"] != ctx.guild.id: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.desc"), - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - await self.db.remove_autorole(autorole_id) - - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.remove_success.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.remove_success.desc", autorole_id=autorole_id), - color=discord.Color.green() - ) - await ctx.respond(embed=embed) - - @autorole.command(name="toggle", description="Aktiviere oder deaktiviere eine Autorole") - @option( - name="autorole_id", - description="Die ID der Autorole (z.B. 26-25-153)", - type=str, - required=True - ) - @option( - name="status", - description="Status der Autorole", - type=str, - choices=["aktivieren", "deaktivieren"], - required=True - ) - async def autorole_toggle(self, ctx: discord.ApplicationContext, autorole_id: str, status: str): - """Aktiviert oder deaktiviert eine Autorole""" - - config = await self.db.get_autorole(autorole_id) - - if not config: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.desc", autorole_id=autorole_id), - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if config["guild_id"] != ctx.guild.id: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.desc"), - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - enabled = status == "aktivieren" - await self.db.toggle_autorole(autorole_id, enabled) - - status_text = "enabled" if enabled else "disabled" - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, f"cog_autorole.messages.toggle_success.{status_text}_title"), - description=await TH.get_for_user(self.bot, ctx.author.id, f"cog_autorole.messages.toggle_success.{status_text}_desc", autorole_id=autorole_id), - color=discord.Color.green() - ) - await ctx.respond(embed=embed) - - @autorole.command(name="list", description="Zeige alle Autoroles auf diesem Server") - async def autorole_list(self, ctx: discord.ApplicationContext): - """Zeigt alle Autoroles fรผr den Server""" - - autoroles = await self.db.get_all_autoroles(ctx.guild.id) - - if not autoroles: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.no_roles.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.no_roles.desc"), - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.list.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.list.desc", guild_name=ctx.guild.name), - color=discord.Color.blue() - ) - - for ar in autoroles: - role = ctx.guild.get_role(ar["role_id"]) - if role: - status = "๐ŸŸข Aktiv" if ar["enabled"] else "๐Ÿ”ด Inaktiv" - embed.add_field( - name=f"ID: `{ar['autorole_id']}`", - value=f"**Rolle:** {role.mention}\n**Status:** {status}\n**Mitglieder:** {len(role.members)}", - inline=False - ) - else: - embed.add_field( - name=f"ID: `{ar['autorole_id']}`", - value=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.list.role_deleted"), - inline=False - ) - - await ctx.respond(embed=embed) - - @autorole.command(name="info", description="Zeige Details zu einer spezifischen Autorole") - @option( - name="autorole_id", - description="Die ID der Autorole (z.B. 26-25-153)", - type=str, - required=True - ) - async def autorole_info(self, ctx: discord.ApplicationContext, autorole_id: str): - """Zeigt Details zu einer spezifischen Autorole""" - - config = await self.db.get_autorole(autorole_id) - - if not config: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.desc", autorole_id=autorole_id), - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if config["guild_id"] != ctx.guild.id: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.desc"), - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - role = ctx.guild.get_role(config["role_id"]) - - if not role: - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_deleted.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_deleted.desc", autorole_id=autorole_id), - color=discord.Color.orange() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - embed = discord.Embed( - title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.info.title"), - description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.info.desc", autorole_id=autorole_id), - color=discord.Color.blue() - ) - embed.add_field(name="Rolle", value=role.mention, inline=True) - embed.add_field(name="Status", value="๐ŸŸข Aktiviert" if config["enabled"] else "๐Ÿ”ด Deaktiviert", inline=True) - embed.add_field(name="Mitglieder mit dieser Rolle", value=str(len(role.members)), inline=True) - embed.add_field(name="Rollen-ID", value=f"`{role.id}`", inline=True) - embed.add_field(name="Autorole-ID", value=f"`{autorole_id}`", inline=True) - - await ctx.respond(embed=embed) - - @commands.Cog.listener() - async def on_member_join(self, member: discord.Member): - """Event: Wird ausgelรถst, wenn ein neues Mitglied dem Server beitritt""" - - role_ids = await self.db.get_enabled_autoroles(member.guild.id) - - if not role_ids: - return - - roles_to_add = [] - - for role_id in role_ids: - role = member.guild.get_role(role_id) - if role and role.position < member.guild.me.top_role.position: - roles_to_add.append(role) - - if not roles_to_add: - return - - try: - audit_reason = TH.get("de", "cog_autorole.system.audit_reason") - await member.add_roles(*roles_to_add, reason=audit_reason) - - role_names = ", ".join([r.name for r in roles_to_add]) - log_msg = TH.get("de", "cog_autorole.system.console_log", role_names=role_names, member_name=member.name) - print(log_msg) - except discord.Forbidden: - print(TH.get("de", "cog_autorole.system.error_forbidden")) - except discord.HTTPException as e: - print(TH.get("de", "cog_autorole.system.error_http", error=str(e))) - -def setup(bot): - bot.add_cog(AutoRole(bot)) \ No newline at end of file diff --git a/src/cogs/Servermanament/globalchat.py b/src/cogs/Servermanament/globalchat.py deleted file mode 100644 index 295ad0b..0000000 --- a/src/cogs/Servermanament/globalchat.py +++ /dev/null @@ -1,1517 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import discord -from discord.ext import commands, tasks -from discord import slash_command, Option, SlashCommandGroup -from DevTools.backend.database.globalchat_db import GlobalChatDatabase, db -import asyncio -import logging -import re -import time -from typing import List, Optional, Dict, Tuple -import aiohttp -import io -import json -from datetime import datetime, timedelta -import ezcord -from collections import defaultdict -from discord.ui import Container - -# Logger konfigurieren -logger = logging.getLogger(__name__) - - -class GlobalChatConfig: - """Zentrale Konfiguration fรผr GlobalChat""" - RATE_LIMIT_MESSAGES = 15 - RATE_LIMIT_SECONDS = 60 - CACHE_DURATION = 180 # 3 Minuten - CLEANUP_DAYS = 30 - MIN_MESSAGE_LENGTH = 0 # Erlaube Nachrichten ohne Text (nur Medien) - DEFAULT_MAX_MESSAGE_LENGTH = 1900 - DEFAULT_EMBED_COLOR = '#5865F2' - - # Medien-Limits - MAX_FILE_SIZE_MB = 25 # Discord-Standard - MAX_ATTACHMENTS = 10 - ALLOWED_IMAGE_FORMATS = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp'] - ALLOWED_VIDEO_FORMATS = ['mp4', 'mov', 'webm', 'avi', 'mkv'] - ALLOWED_AUDIO_FORMATS = ['mp3', 'wav', 'ogg', 'm4a', 'flac'] - ALLOWED_DOCUMENT_FORMATS = ['pdf', 'txt', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', '7z'] - - # Bot Owner IDs - BOT_OWNERS = [1093555256689959005, 1427994077332373554] - - # Content Filter Patterns - DISCORD_INVITE_PATTERN = r'(?i)\b(discord\.gg|discord\.com/invite|discordapp\.com/invite)/[a-zA-Z0-9]+\b' - URL_PATTERN = r'(?i)\bhttps?://(?:[a-zA-Z0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F]{2}))+\b' - - # NSFW Keywords - NSFW_KEYWORDS = [ - 'nsfw', 'porn', 'sex', 'xxx', 'nude', 'hentai', - 'dick', 'pussy', 'cock', 'tits', 'ass', 'fuck' - ] - - -class MediaHandler: - """Verarbeitet alle Arten von Medien und Anhรคngen""" - - def __init__(self, config: GlobalChatConfig): - self.config = config - - def validate_attachments(self, attachments: List[discord.Attachment]) -> Tuple[bool, str, List[discord.Attachment]]: - """Validiert Attachments und gibt valide zurรผck""" - if not attachments: - return True, "", [] - - if len(attachments) > self.config.MAX_ATTACHMENTS: - return False, f"Zu viele Anhรคnge (max. {self.config.MAX_ATTACHMENTS})", [] - - valid_attachments = [] - max_size_bytes = self.config.MAX_FILE_SIZE_MB * 1024 * 1024 - - for attachment in attachments: - # GrรถรŸe prรผfen - if attachment.size > max_size_bytes: - return False, f"Datei '{attachment.filename}' ist zu groรŸ (max. {self.config.MAX_FILE_SIZE_MB}MB)", [] - - # Dateiformat prรผfen - file_ext = attachment.filename.split('.')[-1].lower() if '.' in attachment.filename else '' - - all_allowed = ( - self.config.ALLOWED_IMAGE_FORMATS + - self.config.ALLOWED_VIDEO_FORMATS + - self.config.ALLOWED_AUDIO_FORMATS + - self.config.ALLOWED_DOCUMENT_FORMATS - ) - - if file_ext and file_ext not in all_allowed: - return False, f"Dateiformat '.{file_ext}' nicht erlaubt", [] - - valid_attachments.append(attachment) - - return True, "", valid_attachments - - def categorize_attachment(self, attachment: discord.Attachment) -> str: - """Kategorisiert einen Anhang nach Typ""" - if not attachment.filename or '.' not in attachment.filename: - return 'other' - - file_ext = attachment.filename.split('.')[-1].lower() - - if file_ext in self.config.ALLOWED_IMAGE_FORMATS: - return 'image' - elif file_ext in self.config.ALLOWED_VIDEO_FORMATS: - return 'video' - elif file_ext in self.config.ALLOWED_AUDIO_FORMATS: - return 'audio' - elif file_ext in self.config.ALLOWED_DOCUMENT_FORMATS: - return 'document' - else: - return 'other' - - def get_attachment_icon(self, attachment: discord.Attachment) -> str: - """Gibt passendes Icon fรผr Attachment-Typ zurรผck""" - category = self.categorize_attachment(attachment) - - icons = { - 'image': '๐Ÿ–ผ๏ธ', - 'video': '๐ŸŽฅ', - 'audio': '๐ŸŽต', - 'document': '๐Ÿ“„', - 'other': '๐Ÿ“Ž' - } - - return icons.get(category, '๐Ÿ“Ž') - - def format_file_size(self, size_bytes: int) -> str: - """Formatiert DateigrรถรŸe leserlich""" - for unit in ['B', 'KB', 'MB']: - if size_bytes < 1024.0: - return f"{size_bytes:.1f} {unit}" - size_bytes /= 1024.0 - return f"{size_bytes:.1f} GB" - - -class MessageValidator: - """Validiert und filtert Nachrichten""" - - def __init__(self, config: GlobalChatConfig): - self.config = config - self.media_handler = MediaHandler(config) - self._compile_patterns() - - def _compile_patterns(self): - """Kompiliert Regex-Patterns fรผr bessere Performance""" - self.invite_pattern = re.compile(self.config.DISCORD_INVITE_PATTERN) - self.url_pattern = re.compile(self.config.URL_PATTERN) - - def validate_message(self, message: discord.Message, settings: Dict) -> Tuple[bool, str]: - """Hauptvalidierung fรผr Nachrichten""" - # Bot-Nachrichten ignorieren - if message.author.bot: - return False, "Bot-Nachricht" - - # Blacklist prรผfen - if db.is_blacklisted('user', message.author.id): - return False, "User auf Blacklist" - - if db.is_blacklisted('guild', message.guild.id): - return False, "Guild auf Blacklist" - - # Leere Nachrichten (ohne Text UND ohne Anhรคnge/Sticker) - if not message.content and not message.attachments and not message.stickers: - return False, "Leere Nachricht" - - # Nachrichtenlรคnge (nur wenn Text vorhanden) - if message.content: - content_length = len(message.content.strip()) - - # Mindestlรคnge nur bei reinen Text-Nachrichten - if content_length < self.config.MIN_MESSAGE_LENGTH and not message.attachments and not message.stickers: - return False, "Zu kurze Nachricht" - - max_length = settings.get('max_message_length', self.config.DEFAULT_MAX_MESSAGE_LENGTH) - if content_length > max_length: - return False, f"Nachricht zu lang (max. {max_length} Zeichen)" - - # Attachments validieren - if message.attachments: - valid, reason, _ = self.media_handler.validate_attachments(message.attachments) - if not valid: - return False, f"Ungรผltige Anhรคnge: {reason}" - - # Content Filter - if settings.get('filter_enabled', True): - is_filtered, filter_reason = self.check_filtered_content(message.content) - if is_filtered: - return False, f"Gefilterte Inhalte: {filter_reason}" - - # NSFW Filter - if settings.get('nsfw_filter', True): - if self.check_nsfw_content(message.content): - return False, "NSFW Inhalt erkannt" - - return True, "OK" - - def check_filtered_content(self, content: str) -> Tuple[bool, str]: - """Prรผft auf gefilterte Inhalte mit detailliertem Grund""" - if not content: - return False, "" - - # Discord Invites - if self.invite_pattern.search(content): - return True, "Discord Invite" - - return False, "" - - def check_nsfw_content(self, content: str) -> bool: - """Erweiterte NSFW-Erkennung""" - if not content: - return False - - content_lower = content.lower() - - # Keyword-Check mit Wortgrenzen - for keyword in self.config.NSFW_KEYWORDS: - pattern = r'\b' + re.escape(keyword) + r'\b' - if re.search(pattern, content_lower): - return True - - return False - - def clean_content(self, content: str) -> str: - """Bereinigt Nachrichteninhalt""" - if not content: - return "" - - # @everyone und @here neutralisieren - content = content.replace('@everyone', '๏ผ everyone') - content = content.replace('@here', '๏ผ here') - - # Rolle-Mentions neutralisieren - content = re.sub(r'<@&(\d+)>', r'๏ผ role', content) - - return content - - -class EmbedBuilder: - """Erstellt formatierte Embeds fรผr GlobalChat mit vollstรคndigem Medien-Support""" - - def __init__(self, config: GlobalChatConfig, bot=None): - self.config = config - self.media_handler = MediaHandler(config) - self.bot = bot # Bot fรผr Message-Fetching - - async def create_message_embed(self, message: discord.Message, settings: Dict, attachment_data: List[Tuple[str, bytes, str]] = None) -> Tuple[discord.Embed, List[Tuple[str, bytes]]]: - """Erstellt ein verbessertes Embed mit vollstรคndigem Medien-Support - - attachment_data: Liste von (filename, bytes, content_type) - schon heruntergeladene Dateien - Gibt (embed, [(filename, bytes), ...]) zurรผck - Bytes statt discord.File! - """ - if attachment_data is None: - attachment_data = [] - - content = self._clean_content(message.content) - - # Embed-Farbe - embed_color = self._parse_color(settings.get('embed_color', self.config.DEFAULT_EMBED_COLOR)) - - # Beschreibung - if content: - description = content - elif message.attachments or message.stickers or attachment_data: - description = "*Medien-Nachricht*" - else: - description = "*Keine Beschreibung*" - - # Embed erstellen - embed = discord.Embed( - description=description, - color=embed_color, - timestamp=message.created_at - ) - - # Author mit Badges - author_text, badges = self._build_author_info(message.author) - embed.set_author( - name=author_text, - icon_url=message.author.display_avatar.url - ) - - # Footer mit Server-Info UND Original-Message-ID (fรผr Reply-Tracking) - footer_text = f"๐Ÿ“ {message.guild.name} โ€ข #{message.channel.name} โ€ข ID:{message.id}" - embed.set_footer( - text=footer_text, - icon_url=message.guild.icon.url if message.guild.icon else None - ) - - # Reply-Kontext hinzufรผgen (robust, ohne invasive ร„nderungen) - if message.reference: - try: - # Versuche zuerst die gecachte referenzierte Nachricht - replied_msg = message.reference.resolved - - # Falls nicht im Cache, versuche die referenzierte Nachricht aus dem referenzierten Kanal zu holen - if not replied_msg and getattr(message.reference, 'message_id', None): - ref_channel = None - ref_chan_id = getattr(message.reference, 'channel_id', None) - if ref_chan_id: - # Versuche zuerst den Kanal vom Bot-Cache - ref_channel = self.bot.get_channel(ref_chan_id) - # Fallback auf Guild-Kanal - if not ref_channel and message.guild: - try: - ref_channel = message.guild.get_channel(ref_chan_id) - except Exception: - ref_channel = None - if not ref_channel: - ref_channel = message.channel - - if ref_channel: - try: - replied_msg = await ref_channel.fetch_message(message.reference.message_id) - except Exception: - replied_msg = None - - # Wenn wir eine referenzierte Nachricht haben, bereite Vorschau vor - if isinstance(replied_msg, discord.Message): - # Text-Vorschau (bevorzuge echten content) - preview = replied_msg.content or "" - - # Wenn die referenzierte Nachricht das Relay-Bot-Embed ist, versuche Text aus dem Embed - if not preview and replied_msg.embeds: - try: - preview = replied_msg.embeds[0].description or "" - except Exception: - preview = "" - - # Fallback auf Anhรคnge/Sticker - if not preview: - if replied_msg.attachments: - preview = f"๐Ÿ“Ž {len(replied_msg.attachments)} Datei(en)" - elif replied_msg.stickers: - preview = "๐ŸŽจ Sticker" - else: - preview = "*(Leere Nachricht)*" - - preview = self._clean_content(preview) - preview_short = (preview[:200] + "...") if len(preview) > 200 else preview - - # Author bestimmen: falls die referenzierte Nachricht vom Bot ist, versuche embed.author - author_display = None - try: - if replied_msg.author and replied_msg.author.id == getattr(self.bot, 'user', None).id and replied_msg.embeds: - emb = replied_msg.embeds[0] - if emb.author and emb.author.name: - author_display = emb.author.name - except Exception: - author_display = None - - if not author_display: - try: - author_display = replied_msg.author.display_name - except Exception: - author_display = "Unbekannter User" - - # Herkunft (Server โ€ข #channel) - origin = None - try: - if getattr(replied_msg, 'guild', None) and getattr(replied_msg, 'channel', None): - origin = f"{replied_msg.guild.name} โ€ข #{replied_msg.channel.name}" - except Exception: - origin = None - - reply_field = f"**{author_display}:** {preview_short}" - if origin: - reply_field += f"\n_{origin}_" - - embed.add_field(name="โ†ฉ๏ธ Antwort (Vorschau)", value=reply_field, inline=False) - except Exception: - # Never fail building the embed just because reply resolution failed - pass - - # Medien verarbeiten mit heruntergeladenen Dateien - files_to_upload = await self._process_media(embed, message, attachment_data) - - # Rรผckgabe: Embed + Liste von discord.File Objekten - return embed, files_to_upload - - async def _process_media(self, embed: discord.Embed, message: discord.Message, attachment_data: List[Tuple[str, bytes, str]] = None) -> List[Tuple[str, bytes]]: - """Verarbeitet alle Medien-Typen mit heruntergeladenen Anhรคngen - - attachment_data: Liste von (filename, bytes, content_type) - bereits heruntergeladen - Gibt Liste von (filename, bytes) zurรผck - NOT discord.File! - """ - if attachment_data is None: - attachment_data = [] - - attachment_bytes: List[Tuple[str, bytes]] = [] - - # === HERUNTERGELADENE ATTACHMENTS === - if attachment_data: - attachment_bytes.extend(self._process_downloaded_attachments(embed, attachment_data)) - - # === STICKERS === - if message.stickers: - self._process_stickers(embed, message.stickers) - - # === ORIGINAL EMBEDS (z.B. von Links) === - if message.embeds: - self._process_embeds(embed, message.embeds) - - return attachment_bytes - - def _process_downloaded_attachments(self, embed: discord.Embed, attachment_data: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes]]: - """Verarbeitet heruntergeladene Anhรคnge und gibt (filename, bytes) zurรผck - - attachment_data: [(filename, bytes_data, content_type), ...] - Gibt [(filename, bytes), ...] zurรผck - NICHT discord.File! - """ - attachment_bytes: List[Tuple[str, bytes]] = [] - - # Kategorisiere nach Typ - images = [] - videos = [] - audios = [] - documents = [] - others = [] - - for filename, data, content_type in attachment_data: - # Bestimme Dateityp anhand von content_type und Dateiendung - category = self._get_attachment_category(filename, content_type) - - if category == 'image': - images.append((filename, data)) - elif category == 'video': # HIER wurde der Code vervollstรคndigt - videos.append((filename, data)) - elif category == 'audio': - audios.append((filename, data)) - elif category == 'document': - documents.append((filename, data)) - else: - others.append((filename, data)) # Vervollstรคndigt - - # === IMAGE (NUR das erste Bild als embed.image) === - if images: - # Das erste Bild als Embed-Bild setzen - embed.set_image(url=f"attachment://{images[0][0]}") - # Alle Bilder fรผr den Upload vorbereiten - for filename, data in images: - attachment_bytes.append((filename, data)) - - if len(images) > 1: - # Fรผge einen Hinweis hinzu, dass weitere Bilder angehรคngt sind - embed.add_field( - name="๐Ÿ–ผ๏ธ Weitere Bilder", - value=f"_{len(images)-1} zusรคtzliche Bilder angehรคngt._", - inline=False - ) - - # === VIDEOS === - if videos: - video_links = [] - for video_name, video_data in videos: - size = len(video_data) - size_str = self.media_handler.format_file_size(size) - video_links.append(f"๐ŸŽฅ {video_name} ({size_str})") - attachment_bytes.append((video_name, video_data)) - - if video_links: - embed.add_field( - name="๐ŸŽฌ Videos", - value="\n".join(video_links[:3]), # Max 3 - inline=False - ) - - # === AUDIO === - if audios: - audio_links = [] - for audio_name, audio_data in audios: - size = len(audio_data) - size_str = self.media_handler.format_file_size(size) - audio_links.append(f"๐ŸŽต {audio_name} ({size_str})") - attachment_bytes.append((audio_name, audio_data)) - - if audio_links: - embed.add_field( - name="๐ŸŽง Audio-Dateien", - value="\n".join(audio_links[:3]), # Max 3 - inline=False - ) - - # === DOKUMENTE === - if documents: - doc_links = [] - for doc_name, doc_data in documents: - size = len(doc_data) - size_str = self.media_handler.format_file_size(size) - doc_links.append(f"๐Ÿ“„ {doc_name} ({size_str})") - attachment_bytes.append((doc_name, doc_data)) - - if doc_links: - embed.add_field( - name="๐Ÿ“„ Dokumente", - value="\n".join(doc_links[:3]), # Max 3 - inline=False - ) - - # === SONSTIGE === - if others: - other_links = [] - for other_name, other_data in others: - size = len(other_data) - size_str = self.media_handler.format_file_size(size) - other_links.append(f"๐Ÿ“Ž {other_name} ({size_str})") - attachment_bytes.append((other_name, other_data)) - - if other_links: - embed.add_field( - name="๐Ÿ“Ž Sonstige", - value="\n".join(other_links[:3]), # Max 3 - inline=False - ) - - return attachment_bytes # Wichtig: bytes zurรผckgeben - - def _process_stickers(self, embed: discord.Embed, stickers: List[discord.StickerItem]): - """Verarbeitet Discord Sticker""" - if not stickers: - return - - sticker_info = [] - for sticker in stickers: - sticker_type = "Standard" if sticker.url.endswith('.png') else "Animiert" - sticker_info.append(f"๐ŸŽจ **{sticker.name}** ({sticker_type})") - - embed.add_field( - name="๐ŸŽจ Sticker", - value="\n".join(sticker_info[:3]), - inline=False - ) - - # Versuche, das erste Bild (falls vorhanden) als Thumbnail zu setzen - if stickers[0].format.name in ['PNG', 'LOTTIE']: - embed.set_thumbnail(url=stickers[0].url) - - def _process_embeds(self, main_embed: discord.Embed, embeds: List[discord.Embed]): - """Verarbeitet Original-Embeds (z.B. Link-Vorschauen)""" - if not embeds: - return - - link_embeds = [] - for embed in embeds: - # Nur Embeds mit Titeln oder Beschreibungen, die keine eigenen Attachments sind, verarbeiten - if embed.type not in ['image', 'video', 'gifv'] and (embed.title or embed.description or embed.url): - - title = embed.title or "Unbekannter Link" - description = (embed.description[:100] + "...") if embed.description else "" - url = embed.url or "" - - link_embeds.append(f"**[{title}]({url})**\n_{description}_") - - if link_embeds: - main_embed.add_field( - name="๐Ÿ”— Verlinkte Inhalte", - value="\n\n".join(link_embeds), - inline=False - ) - - def _get_attachment_category(self, filename: str, content_type: str) -> str: - """Hilfsfunktion zur Kategorisierung basierend auf Name und Content-Type""" - if content_type.startswith('image/'): - return 'image' - elif content_type.startswith('video/'): - return 'video' - elif content_type.startswith('audio/'): - return 'audio' - - # Fallback auf Dateiendung - if not filename or '.' not in filename: - return 'other' - - file_ext = filename.split('.')[-1].lower() - if file_ext in self.config.ALLOWED_IMAGE_FORMATS: - return 'image' - elif file_ext in self.config.ALLOWED_VIDEO_FORMATS: - return 'video' - elif file_ext in self.config.ALLOWED_AUDIO_FORMATS: - return 'audio' - elif file_ext in self.config.ALLOWED_DOCUMENT_FORMATS: - return 'document' - else: - return 'other' - - def _clean_content(self, content: str) -> str: - """Bereinigt Nachrichteninhalt""" - if not content: - return "" - content = content.replace('@everyone', '๏ผ everyone') - content = content.replace('@here', '๏ผ here') - content = re.sub(r'<@&(\d+)>', r'๏ผ role', content) - return content.strip() - - def _parse_color(self, color_hex: str) -> discord.Color: - """Parst Hex-Farbe zu discord.Color""" - try: - color_hex = color_hex.lstrip('#') - return discord.Color(int(color_hex, 16)) - except (ValueError, TypeError): - return discord.Color.blurple() - - def _build_author_info(self, author: discord.Member) -> Tuple[str, List[str]]: - """Baut Author-Text mit Badges""" - badges = [] - roles = [] - # Bot Owner - if author.id in self.config.BOT_OWNERS: - badges.append("๐Ÿ‘‘") - roles.append("Bot Owner") - # Server Admin/Mod - if author.guild_permissions.administrator: - badges.append("โšก") - roles.append("Admin") - elif author.guild_permissions.manage_guild: - badges.append("๐Ÿ”ง") - roles.append("Mod") - - badge_text = " ".join(badges) - author_text = f"{badge_text} {author.display_name}".strip() - - # Hinzufรผgen von Discord System Badges (z.B. Bot, Verified Bot) - if author.bot: - author_text += " [BOT]" - - return author_text, roles - - -class GlobalChatSender: - """Verantwortlich fรผr das Senden der Nachricht an alle verbundenen Kanรคle""" - def __init__(self, bot, config: GlobalChatConfig, embed_builder: EmbedBuilder, cache_ref: List[int]): - self.bot = bot - self.config = config - self.embed_builder = embed_builder - self._cached_channels = cache_ref # Referenz zum Cache in der Cog - - async def _get_all_active_channels(self) -> List[int]: - """Ruft alle aktiven Channel-IDs ab, nutzt den Cache""" - if self._cached_channels is None: - # Cache initial fรผllen - self._cached_channels = await self._fetch_all_channels() - return self._cached_channels - - async def _fetch_all_channels(self) -> List[int]: - """Holt Channel IDs direkt aus der Datenbank""" - try: - channel_ids = db.get_all_channels() - return channel_ids - except Exception as e: - logger.error(f"โŒ Fehler beim Abrufen aller Channel-IDs: {e}", exc_info=True) - return [] - - async def _send_to_channel(self, channel_id: int, embed: discord.Embed, attachment_bytes: List[Tuple[str, bytes]]) -> bool: - """Sendet die Embed-Nachricht an einen spezifischen Channel mit Error-Handling - attachment_bytes: Liste von (filename, bytes) - wird zu discord.File konvertiert - Wichtig: Raw bytes, nicht discord.File, da File-Streams verbraucht sind! - """ - try: - channel = self.bot.get_channel(channel_id) - if not channel: - logger.warning(f"โš ๏ธ Channel {channel_id} nicht gefunden") - return False - - # Permissions prรผfen - perms = channel.permissions_for(channel.guild.me) - if not perms.send_messages or not perms.embed_links: - logger.warning(f"โš ๏ธ Keine Permissions in {channel_id}") - return False - - # Erstelle NEUE discord.File Objekte fรผr diesen Channel (wichtig!) - # Jeder Channel bekommt seine eigenen frischen Files! - files = [] - if attachment_bytes: - for filename, data in attachment_bytes: - try: - files.append(discord.File(io.BytesIO(data), filename=filename)) - except Exception as e: - logger.warning(f"โš ๏ธ Error creating file {filename}: {e}") - - # Sende mit Retry-Logik - max_retries = 3 - for attempt in range(max_retries): - try: - if files: - await channel.send(embed=embed, files=files) - else: - await channel.send(embed=embed) - return True - except (ConnectionResetError, aiohttp.ClientConnectorError, asyncio.TimeoutError) as e: - logger.warning(f"โŒ Sendefehler (Retry {attempt+1}/{max_retries}) in {channel_id}: {e}") - await asyncio.sleep(1 + attempt * 2) - except discord.Forbidden: - logger.warning(f"โŒ Bot hat Senderechte in {channel_id} verloren. Enferne aus Cache.") - if channel_id in self._cached_channels: - self._cached_channels.remove(channel_id) - return False - except Exception as e: - logger.error(f"โŒ Unerwarteter Sendefehler in {channel_id}: {e}") - return False - - # Wenn alle Retries fehlschlagen - logger.error(f"โŒ Senden nach {max_retries} Retries in {channel_id} fehlgeschlagen.") - return False - - except Exception as e: - logger.error(f"โŒ Generischer Fehler im _send_to_channel: {e}", exc_info=True) - return False - - async def send_global_message(self, message: discord.Message, attachment_data: List[Tuple[str, bytes, str]] = None) -> Tuple[int, int]: - """Sendet eine Nachricht global an alle verbundenen Channels""" - settings = db.get_guild_settings(message.guild.id) - - embed, files_to_upload = await self.embed_builder.create_message_embed(message, settings, attachment_data) - - active_channels = await self._get_all_active_channels() - successful_sends = 0 - failed_sends = 0 - - # Berechne, wie viele Tasks gleichzeitig laufen sollen (z.B. 10) - tasks = [] - for channel_id in active_channels: - # Sende nicht an den Ursprungskanal zurรผck - if channel_id == message.channel.id: - continue - - tasks.append(self._send_to_channel(channel_id, embed, files_to_upload)) - - results = await asyncio.gather(*tasks, return_exceptions=True) - - for result in results: - if result is True: - successful_sends += 1 - else: - failed_sends += 1 - if isinstance(result, Exception): - logger.error(f"โŒ Task-Fehler beim Senden: {result}") - - return successful_sends, failed_sends - - -class GlobalChatCog(ezcord.Cog): - """Haupt-Cog fรผr das GlobalChat-System""" - - globalchat = SlashCommandGroup("globalchat", "GlobalChat Verwaltung") - - def __init__(self, bot): - self.bot = bot - self.config = GlobalChatConfig() - self.validator = MessageValidator(self.config) - self.embed_builder = EmbedBuilder(self.config, bot) - self.message_cooldown = commands.CooldownMapping.from_cooldown( - self.config.RATE_LIMIT_MESSAGES, - self.config.RATE_LIMIT_SECONDS, - commands.BucketType.user - ) - self._cached_channels: Optional[List[int]] = None - self.sender = GlobalChatSender(self.bot, self.config, self.embed_builder, self._cached_channels) - self.cleanup_task.start() - - @tasks.loop(hours=12) - async def cleanup_task(self): - """Task zur Bereinigung abgelaufener Blacklist-Eintrรคge und Cache-Aktualisierung""" - # db.delete_expired_blacklist_entries() <--- DIESE ZEILE AUSKOMMENTIEREN - # logger.info("๐Ÿ—‘๏ธ GlobalChat: Abgelaufene Blacklist-Eintrรคge bereinigt.") - - # Cache neu laden, um ร„nderungen in der DB zu sehen - self._cached_channels = await self.sender._fetch_all_channels() - logger.info("๐Ÿง  GlobalChat: Channel-Cache neu geladen.") - - @ezcord.Cog.listener() - async def on_message(self, message: discord.Message): - """Haupt-Listener fรผr eingehende GlobalChat-Nachrichten""" - if not message.guild or message.author.bot: - return - - # Prรผfen ob Channel ein GlobalChat-Channel ist - global_chat_channel_id = db.get_globalchat_channel(message.guild.id) - if message.channel.id != global_chat_channel_id: - return - - # Guild-Settings laden - settings = db.get_guild_settings(message.guild.id) - - # Message validieren - is_valid, reason = self.validator.validate_message(message, settings) - if not is_valid: - logger.debug(f"โŒ Nachricht abgelehnt: {reason} (User: {message.author.id})") - - # User benachrichtigen bei bestimmten Grรผnden - if any(keyword in reason for keyword in ["Blacklist", "NSFW", "Gefilterte", "Ungรผltige Anhรคnge", "zu groรŸ"]): - try: - await message.add_reaction("โŒ") - # Info-Nachricht fรผr spezifische Fehler - if "Ungรผltige Anhรคnge" in reason or "zu groรŸ" in reason: - info_msg = await message.reply( - f"โŒ **Fehler:** {reason}\n" - f"**Max. GrรถรŸe:** {self.config.MAX_FILE_SIZE_MB}MB pro Datei\n" - f"**Max. Anhรคnge:** {self.config.MAX_ATTACHMENTS}", - delete_after=7 - ) - await asyncio.sleep(2) - await message.delete() - except (discord.Forbidden, discord.NotFound): - pass # Kann Nachricht nicht lรถschen/reagieren - return - - # Rate Limiting prรผfen - bucket = self.message_cooldown.get_bucket(message) - retry_after = bucket.update_rate_limit() - if retry_after: - try: - await message.add_reaction("โฐ") - await asyncio.sleep(2) - await message.delete() - logger.debug(f"โฐ Nachricht von {message.author.id} wegen Rate Limit entfernt.") - except (discord.Forbidden, discord.NotFound): - pass - return - - # === Medien herunterladen (wenn vorhanden) === - attachment_data: List[Tuple[str, bytes, str]] = [] - if message.attachments: - try: - await message.channel.trigger_typing() - for attachment in message.attachments: - # Maximal 25MB (Discord-Limit) - if attachment.size <= self.config.MAX_FILE_SIZE_MB * 1024 * 1024: - data = await attachment.read() - attachment_data.append((attachment.filename, data, attachment.content_type)) - except Exception as e: - logger.error(f"โŒ Fehler beim Herunterladen von Attachments: {e}") - # Wenn Download fehlschlรคgt, Nachricht trotzdem ohne Medien senden - attachment_data = [] - - # Nachricht senden - successful, failed = await self.sender.send_global_message(message, attachment_data) - - # Ursprรผngliche Nachricht lรถschen, wenn Relaying erfolgreich war - if settings.get('delete_original', False): - try: - await message.delete() - except discord.Forbidden: - logger.warning(f"โš ๏ธ Keine Permissions zum Lรถschen der Original-Nachricht in {message.channel.id}") - except discord.NotFound: - pass - - logger.info(f"๐ŸŒ GlobalChat: Nachricht von {message.guild.name} | User: {message.author.name} | โœ… {successful} | โŒ {failed}") - - - # ==================== Slash Commands ==================== - - @globalchat.command( - name="setup", - description="Richtet einen GlobalChat-Channel ein" - ) - async def setup_globalchat( - self, - ctx: discord.ApplicationContext, - channel: discord.TextChannel = Option(discord.TextChannel, "Der GlobalChat-Channel", required=True) - ): - """Setup-Command fรผr GlobalChat""" - if not ctx.author.guild_permissions.manage_guild: - await ctx.respond("โŒ Du benรถtigst die **Server verwalten** Berechtigung!", ephemeral=True) - return - - # Bot Permissions prรผfen - bot_perms = channel.permissions_for(ctx.guild.me) - missing_perms = [] - if not bot_perms.send_messages: missing_perms.append("Nachrichten senden") - if not bot_perms.manage_messages: missing_perms.append("Nachrichten verwalten") - if not bot_perms.embed_links: missing_perms.append("Links einbetten") - if not bot_perms.read_message_history: missing_perms.append("Nachrichten-Historie lesen") - if not bot_perms.attach_files: missing_perms.append("Dateien anhรคngen") # Wichtig fรผr Medien - - if missing_perms: - perms_list = "\n".join([f"โ€ข {p}" for p in missing_perms]) - await ctx.respond( - f"โŒ Mir fehlen wichtige Berechtigungen in {channel.mention}:\n{perms_list}", - ephemeral=True - ) - return - - try: - db.set_globalchat_channel(ctx.guild.id, channel.id) - - # Cache aktualisieren - self._cached_channels = await self.sender._fetch_all_channels() - - # UI Container fรผr eine schรถnere Antwort (falls vorhanden) - container = Container() - - status_text = f"โœ… **GlobalChat eingerichtet!**\n\n" - status_text += f"Der GlobalChat ist nun in {channel.mention} aktiv.\n" - status_text += f"Aktuell verbunden: **{len(self._cached_channels)}** Server." - - container.add_text(status_text) - container.add_separator() - - # Feature-Liste - feature_text = ( - "**Unterstรผtzte Features:**\n" - "โ€ข ๐Ÿ–ผ๏ธ Bilder, ๐ŸŽฅ Videos, ๐ŸŽต Audio\n" - "โ€ข ๐Ÿ“„ Dokumente (Office, PDF, Archive)\n" - "โ€ข ๐ŸŽจ Discord Sticker\n" - "โ€ข ๐Ÿ”— Automatische Link-Previews\n" - "โ€ข โ†ฉ๏ธ Reply auf andere Nachrichten\n\n" - "**Nรคchste Schritte:**\n" - "โ€ข `/globalchat settings` - Einstellungen anpassen\n" - "โ€ข `/globalchat stats` - Statistiken anzeigen\n" - "โ€ข `/globalchat media-info` - Medien-Limits anzeigen" - ) - container.add_text(feature_text) - - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - - except Exception as e: - logger.error(f"โŒ Setup-Fehler: {e}", exc_info=True) - await ctx.respond("โŒ Ein Fehler ist aufgetreten!", ephemeral=True) - - @globalchat.command( - name="remove", - description="Entfernt den GlobalChat-Channel" - ) - async def remove_globalchat(self, ctx: discord.ApplicationContext): - """Entfernt GlobalChat vom Server""" - if not ctx.author.guild_permissions.manage_guild: - await ctx.respond("โŒ Du benรถtigst die **Server verwalten** Berechtigung!", ephemeral=True) - return - - # Prรผfen ob Channel existiert - channel_id = db.get_globalchat_channel(ctx.guild.id) - if not channel_id: - await ctx.respond("โŒ GlobalChat ist auf diesem Server nicht eingerichtet.", ephemeral=True) - return - - try: - db.set_globalchat_channel(ctx.guild.id, None) - - # Cache aktualisieren - self._cached_channels = await self.sender._fetch_all_channels() - - await ctx.respond( - f"โœ… **GlobalChat entfernt!**\n\n" - f"Der GlobalChat wurde von diesem Server entfernt.\n" - f"Es sind nun noch **{len(self._cached_channels)}** Server verbunden.", - ephemeral=True - ) - except Exception as e: - logger.error(f"โŒ Remove-Fehler: {e}", exc_info=True) - await ctx.respond("โŒ Ein Fehler ist aufgetreten!", ephemeral=True) - - @globalchat.command( - name="settings", - description="Verwaltet Server-spezifische GlobalChat-Einstellungen" - ) - async def settings_globalchat( - self, - ctx: discord.ApplicationContext, - filter_enabled: Optional[bool] = Option(bool, "Content-Filter aktivieren/deaktivieren (Invites, etc.)", required=False), - nsfw_filter: Optional[bool] = Option(bool, "NSFW-Filter aktivieren/deaktivieren", required=False), - embed_color: Optional[str] = Option(str, "Hex-Farbcode fรผr Embeds (z.B. #FF00FF)", required=False), - max_message_length: Optional[int] = Option( - int, - "Maximale Nachrichtenlรคnge", - required=False, - min_value=50, - max_value=2000 - ) - ): - """Verwaltet Server-spezifische Einstellungen""" - if not ctx.author.guild_permissions.manage_guild: - await ctx.respond("โŒ Du benรถtigst die **Server verwalten** Berechtigung!", ephemeral=True) - return - - # Prรผfen ob GlobalChat aktiv - if not db.get_globalchat_channel(ctx.guild.id): - await ctx.respond( - "โŒ Dieser Server nutzt GlobalChat nicht!\n" - "Nutze `/globalchat setup` zuerst.", - ephemeral=True - ) - return - - updated = [] - # Filter aktivieren/deaktivieren - if filter_enabled is not None: - if db.update_guild_setting(ctx.guild.id, 'filter_enabled', filter_enabled): - updated.append(f"Content-Filter: {'โœ… An' if filter_enabled else 'โŒ Aus'}") - - if nsfw_filter is not None: - if db.update_guild_setting(ctx.guild.id, 'nsfw_filter', nsfw_filter): - updated.append(f"NSFW-Filter: {'โœ… An' if nsfw_filter else 'โŒ Aus'}") - - if embed_color: - # Hex-Validierung - if not re.match(r'^#[0-9a-fA-F]{6}$', embed_color): - await ctx.respond("โŒ Ungรผltiger Hex-Farbcode. Erwarte z.B. `#5865F2`.", ephemeral=True) - return - if db.update_guild_setting(ctx.guild.id, 'embed_color', embed_color): - updated.append(f"Embed-Farbe: `{embed_color}`") - - if max_message_length is not None: - if db.update_guild_setting(ctx.guild.id, 'max_message_length', max_message_length): - updated.append(f"Max. Lรคnge: **{max_message_length}** Zeichen") - - if not updated: - await ctx.respond("โ„น๏ธ Keine ร„nderungen vorgenommen.", ephemeral=True) - return - - # Erfolgs-Embed - embed = discord.Embed( - title="โœ… GlobalChat Einstellungen aktualisiert", - description="\n".join(updated), - color=discord.Color.green() - ) - await ctx.respond(embed=embed, ephemeral=True) - - - @globalchat.command( - name="ban", - description="๐Ÿ”จ Bannt einen User oder Server vom GlobalChat" - ) - async def globalchat_ban( - self, - ctx: discord.ApplicationContext, - entity_id: str = Option(str, "ID des Users oder Servers (Guild-ID)", required=True), - entity_type: str = Option(str, "Typ der Entitรคt", choices=["user", "guild"], required=True), - reason: str = Option(str, "Grund fรผr den Ban", required=True), - duration: Optional[int] = Option(int, "Dauer in Stunden (optional, permanent wenn leer)", required=False) - ): - """Bannt eine Entitรคt aus dem GlobalChat""" - if ctx.author.id not in self.config.BOT_OWNERS: - await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) - return - - try: - entity_id_int = int(entity_id) - except ValueError: - await ctx.respond("โŒ Ungรผltige ID. Erwarte eine Zahl.", ephemeral=True) - return - - # Ban ausfรผhren - try: - success = db.add_to_blacklist( - entity_type, - entity_id_int, - reason, - ctx.author.id, - duration - ) - if not success: - await ctx.respond("โŒ Fehler beim Bannen!", ephemeral=True) - return - - # Success-Response - duration_text = f"{duration} Stunden" if duration else "Permanent" - embed = discord.Embed( - title="๐Ÿ”จ GlobalChat-Ban verhรคngt", - color=discord.Color.red(), - timestamp=datetime.utcnow() - ) - embed.add_field(name="Typ", value=entity_type.title(), inline=True) - embed.add_field(name="ID", value=f"`{entity_id_int}`", inline=True) - embed.add_field(name="Dauer", value=duration_text, inline=True) - embed.add_field(name="Grund", value=reason, inline=False) - embed.add_field(name="Von", value=ctx.author.mention, inline=True) - - if duration: - expires = datetime.utcnow() + timedelta(hours=duration) - embed.add_field( - name="Lรคuft ab", - value=f"", - inline=True - ) - - await ctx.respond(embed=embed) - logger.info( - f"๐Ÿ”จ Ban: {entity_type} {entity_id_int} | Grund: {reason} | Dauer: {duration_text} | Von: {ctx.author.id}" - ) - - except Exception as e: - logger.error(f"โŒ Ban-Fehler: {e}", exc_info=True) - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Bannen!", ephemeral=True) - - - @globalchat.command( - name="unban", - description="๐Ÿ”“ Entfernt einen User oder Server von der GlobalChat-Blacklist" - ) - async def globalchat_unban( - self, - ctx: discord.ApplicationContext, - entity_id: str = Option(str, "ID des Users oder Servers", required=True), - entity_type: str = Option(str, "Typ der Entitรคt", choices=["user", "guild"], required=True) - ): - """Entfernt eine Entitรคt von der GlobalChat Blacklist""" - if ctx.author.id not in self.config.BOT_OWNERS: - await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) - return - - try: - entity_id_int = int(entity_id) - except ValueError: - await ctx.respond("โŒ Ungรผltige ID. Erwarte eine Zahl.", ephemeral=True) - return - - try: - if not db.is_blacklisted(entity_type, entity_id_int): - await ctx.respond(f"โ„น๏ธ {entity_type.title()} `{entity_id_int}` ist nicht auf der Blacklist.", ephemeral=True) - return - - if db.remove_from_blacklist(entity_type, entity_id_int): - embed = discord.Embed( - title="๐Ÿ”“ GlobalChat-Unban erfolgreich", - description=f"{entity_type.title()} mit ID `{entity_id_int}` wurde von der Blacklist entfernt.", - color=discord.Color.green(), - timestamp=datetime.utcnow() - ) - await ctx.respond(embed=embed) - logger.info(f"๐Ÿ”“ Unban: {entity_type} {entity_id_int} | Von: {ctx.author.id}") - else: - await ctx.respond("โŒ Fehler beim Entfernen von der Blacklist!", ephemeral=True) - - except Exception as e: - logger.error(f"โŒ Unban-Fehler: {e}", exc_info=True) - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Unbannen!", ephemeral=True) - - - @globalchat.command( - name="info", - description="Zeigt Informationen รผber den GlobalChat" - ) - async def globalchat_info(self, ctx: discord.ApplicationContext): - """Zeigt allgemeine Informationen""" - active_servers = await self.sender._get_all_active_channels() - - embed = discord.Embed( - title="๐ŸŒ GlobalChat - Vollstรคndiger Medien-Support", - description=( - "Ein serverรผbergreifendes Chat-System mit vollstรคndigem Medien-Support.\n\n" - f"**๐Ÿ“Š Aktuell verbunden:** **{len(active_servers)}** Server\n\n" - "**๐ŸŽฏ Hauptfeatures:**\n" - "โ€ข Nachrichten werden an alle verbundenen Server gesendet\n" - "โ€ข Vollstรคndiger Medien-Support (Bilder, Videos, Audio, Dokumente)\n" - "โ€ข Discord Sticker und Link-Previews\n" - "โ€ข Reply-Unterstรผtzung mit Kontext\n" - "โ€ข Automatische Moderation und Filter\n" - "โ€ข Rate-Limiting gegen Spam\n" - "โ€ข Individuelle Server-Einstellungen" - ), - color=discord.Color.blue(), - timestamp=datetime.utcnow() - ) - - embed.add_field( - name="๐Ÿ“ Unterstรผtzte Medien (Details: `/globalchat media-info`)", - value=( - "โ€ข ๐Ÿ–ผ๏ธ Bilder\n" - "โ€ข ๐ŸŽฅ Videos\n" - "โ€ข ๐ŸŽต Audio\n" - "โ€ข ๐Ÿ“„ Dokumente (PDF, Office, Archive)" - ), - inline=True - ) - - embed.add_field( - name="๐Ÿ›ก๏ธ Moderation", - value=( - f"โ€ข **Content-Filter:** {db.get_guild_settings(ctx.guild.id).get('filter_enabled', True) and 'โœ… An' or 'โŒ Aus'}\n" - f"โ€ข **NSFW-Filter:** {db.get_guild_settings(ctx.guild.id).get('nsfw_filter', True) and 'โœ… An' or 'โŒ Aus'}\n" - f"โ€ข **Nachrichtenlรคnge:** {db.get_guild_settings(ctx.guild.id).get('max_message_length', self.config.DEFAULT_MAX_MESSAGE_LENGTH)} Zeichen\n" - ), - inline=True - ) - - await ctx.respond(embed=embed, ephemeral=True) - - @globalchat.command( - name="stats", - description="Zeigt GlobalChat-Statistiken" - ) - async def globalchat_stats(self, ctx: discord.ApplicationContext): - """Zeigt Statistiken (z.B. Blacklist-Eintrรคge)""" - if ctx.author.id not in self.config.BOT_OWNERS: - await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) - return - - user_bans, guild_bans = db.get_blacklist_stats() - active_servers = await self.sender._get_all_active_channels() - - embed = discord.Embed( - title="๐Ÿ“Š GlobalChat System-Statistiken", - color=discord.Color.gold(), - timestamp=datetime.utcnow() - ) - - embed.add_field(name="๐ŸŒ Verbundene Server", value=f"**{len(active_servers)}**", inline=True) - embed.add_field(name="๐Ÿ‘ฅ Gebannte User", value=f"**{user_bans}**", inline=True) - embed.add_field(name="๐Ÿ›ก๏ธ Gebannte Server", value=f"**{guild_bans}**", inline=True) - embed.add_field(name="โณ Cache-Dauer", value=f"{self.config.CACHE_DURATION} Sekunden", inline=True) - embed.add_field(name="๐Ÿ“œ Protokoll Bereinigung", value=f"Alle {self.config.CLEANUP_DAYS} Tage", inline=True) - embed.add_field( - name="โฐ Rate-Limit", - value=f"{self.config.RATE_LIMIT_MESSAGES} Nachrichten / {self.config.RATE_LIMIT_SECONDS} Sekunden", - inline=True - ) - - await ctx.respond(embed=embed, ephemeral=True) - - - @globalchat.command( - name="media-info", - description="Zeigt Details zu Medien-Limits und erlaubten Formaten" - ) - async def globalchat_media_info(self, ctx: discord.ApplicationContext): - """Zeigt Medien-Limits und unterstรผtzte Formate""" - embed = discord.Embed( - title="๐Ÿ“ GlobalChat Medien-Limits & Formate", - description="Details zu den maximal erlaubten DateigrรถรŸen und unterstรผtzten Formaten.", - color=discord.Color.purple(), - timestamp=datetime.utcnow() - ) - - # Limits - embed.add_field( - name="โš ๏ธ Wichtige Limits", - value=( - f"โ€ข **Max. {self.config.MAX_ATTACHMENTS} Anhรคnge** pro Nachricht\n" - f"โ€ข **Max. {self.config.MAX_FILE_SIZE_MB} MB** pro Datei (Discord-Limit)\n" - f"โ€ข **Max. {self.config.DEFAULT_MAX_MESSAGE_LENGTH} Zeichen** Textlรคnge\n" - f"โ€ข **Rate-Limit:** {self.config.RATE_LIMIT_MESSAGES} Nachrichten pro {self.config.RATE_LIMIT_SECONDS} Sekunden" - ), - inline=False - ) - - # Unterstรผtzte Formate - embed.add_field( - name="๐Ÿ–ผ๏ธ Bilder", - value=", ".join(self.config.ALLOWED_IMAGE_FORMATS).upper(), - inline=True - ) - embed.add_field( - name="๐ŸŽฅ Videos", - value=", ".join(self.config.ALLOWED_VIDEO_FORMATS).upper(), - inline=True - ) - embed.add_field( - name="๐ŸŽต Audio", - value=", ".join(self.config.ALLOWED_AUDIO_FORMATS).upper(), - inline=True - ) - embed.add_field( - name="๐Ÿ“„ Dokumente/Archive", - value=", ".join(self.config.ALLOWED_DOCUMENT_FORMATS).upper(), - inline=False - ) - - await ctx.respond(embed=embed, ephemeral=True) - - - @globalchat.command( - name="help", - description="Zeigt die Hilfe-Seite fรผr GlobalChat" - ) - async def globalchat_help(self, ctx: discord.ApplicationContext): - """Zeigt eine รœbersicht aller verfรผgbaren Commands und Features.""" - embed = discord.Embed( - title="โ“ GlobalChat Hilfe & รœbersicht", - description="รœbersicht aller verfรผgbaren Commands und Features.", - color=discord.Color.blue(), - timestamp=datetime.utcnow() - ) - - # Setup & Verwaltung - embed.add_field( - name="โš™๏ธ Setup & Verwaltung", - value=( - "`/globalchat setup` - Channel einrichten\n" - "`/globalchat remove` - Channel entfernen\n" - "`/globalchat settings` - Einstellungen anpassen" - ), - inline=False - ) - - # Informationen - embed.add_field( - name="๐Ÿ“Š Informationen", - value=( - "`/globalchat info` - Allgemeine Infos\n" - "`/globalchat stats` - Statistiken anzeigen\n" - "`/globalchat media-info` - Medien-Details\n" - "`/globalchat help` - Diese Hilfe" - ), - inline=False - ) - - # Moderation (Admin) - Nur fรผr Bot Owner - if ctx.author.id in self.config.BOT_OWNERS: - embed.add_field( - name="๐Ÿ›ก๏ธ Moderation (Bot Owner)", - value=( - "`/globalchat ban` - User/Server bannen\n" - "`/globalchat unban` - User/Server entbannen" - ), - inline=False - ) - - # Test & Debug (Admin) - if ctx.author.id in self.config.BOT_OWNERS: - embed.add_field( - name="๐Ÿงช Test & Debug (Bot Owner)", - value=( - "`/globalchat test-media` - Medien-Test\n" - "`/globalchat broadcast` - Nachricht an alle senden\n" - "`/globalchat reload-cache` - Cache neu laden\n" - "`/globalchat debug` - Debug-Info" - ), - inline=False - ) - - await ctx.respond(embed=embed, ephemeral=True) - - - @globalchat.command( - name="test-media", - description="๐Ÿงช Test-Command fรผr Medien-Upload und -Anzeige" - ) - async def globalchat_test_media(self, ctx: discord.ApplicationContext): - """Zeigt Anweisungen fรผr den Medien-Test""" - channel_id = db.get_globalchat_channel(ctx.guild.id) - if not channel_id: - await ctx.respond("โŒ GlobalChat ist auf diesem Server nicht eingerichtet.", ephemeral=True) - return - - embed = discord.Embed( - title="๐Ÿงช GlobalChat Medien-Test", - description=( - "Dieser Test zeigt dir, welche Medien-Typen erfolgreich รผbermittelt werden kรถnnen.\n\n" - "**Unterstรผtzte Medien:**\n" - "โ€ข Bilder, Videos, Audio, Dokumente\n" - "โ€ข Discord Sticker\n" - "โ€ข Antworten auf andere Nachrichten\n\n" - "**So testest du:**\n" - f"1. Gehe zu <#{channel_id}> und sende eine Nachricht mit Anhรคngen.\n" - "2. Die Nachricht erscheint auf allen verbundenen Servern.\n\n" - "Probiere verschiedene Kombinationen aus! (Mehrere Dateien, Sticker + Text, Reply + Datei)" - ), - color=discord.Color.green(), - timestamp=datetime.utcnow() - ) - - embed.add_field( - name="๐Ÿ“Š Aktuelle Limits", - value=( - f"โ€ข Max. {self.config.MAX_ATTACHMENTS} Anhรคnge\n" - f"โ€ข Max. {self.config.MAX_FILE_SIZE_MB} MB pro Datei\n" - f"โ€ข {self.config.RATE_LIMIT_MESSAGES} Nachrichten / {self.config.RATE_LIMIT_SECONDS} Sekunden" - ), - inline=True - ) - - embed.add_field( - name="โœ… Unterstรผtzte Formate", - value=( - "Bilder, Videos, Audio,\n" - "Dokumente, Archive,\n" - "Office-Dateien, PDFs" - ), - inline=True - ) - - embed.set_footer(text=f"Test von {ctx.author}", icon_url=ctx.author.display_avatar.url) - - await ctx.respond(embed=embed, ephemeral=True) - - - @globalchat.command( - name="broadcast", - description="๐Ÿ“ข Sendet eine Nachricht an alle verbundenen GlobalChat-Server" - ) - async def globalchat_broadcast( - self, - ctx: discord.ApplicationContext, - title: str = Option(str, "Der Titel der Broadcast-Nachricht", required=True), - message: str = Option(str, "Die Nachricht selbst", required=True) - ): - """Sendet einen Broadcast (nur Bot Owner)""" - if ctx.author.id not in self.config.BOT_OWNERS: - await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) - return - - await ctx.defer(ephemeral=True) - - try: - # Broadcast Embed erstellen - embed = discord.Embed( - title=f"๐Ÿ“ข GlobalChat Broadcast: {title}", - description=message, - color=discord.Color.red(), - timestamp=datetime.utcnow() - ) - embed.set_footer( - text=f"GlobalChat Broadcast von {ctx.author}", - icon_url=ctx.author.display_avatar.url - ) - - # An alle Channels senden - successful, failed = await self.sender.send_global_broadcast_message(embed) # Annahme: Eine separate Broadcast-Methode in Sender - - # Response - result_embed = discord.Embed( - title="โœ… Broadcast gesendet", - color=discord.Color.green(), - timestamp=datetime.utcnow() - ) - result_embed.add_field( - name="๐Ÿ“Š Ergebnis", - value=( - f"**Erfolgreich:** {successful}\n" - f"**Fehlgeschlagen:** {failed}\n" - f"**Gesamt:** {successful + failed}" - ), - inline=False - ) - result_embed.add_field( - name="๐Ÿ“ Nachricht", - value=f"**{title}**\n{message[:100]}{'...' if len(message) > 100 else ''}", - inline=False - ) - await ctx.respond(embed=result_embed, ephemeral=True) - logger.info( - f"๐Ÿ“ข Broadcast: '{title}' | Von: {ctx.author} | " - f"โœ… {successful} | โŒ {failed}" - ) - except Exception as e: - logger.error(f"โŒ Broadcast-Fehler: {e}", exc_info=True) - await ctx.respond("โŒ Fehler beim Senden des Broadcasts!", ephemeral=True) - - @globalchat.command( - name="reload-cache", - description="๐Ÿง  Lรคdt alle Cache-Daten neu (Admin)" - ) - async def globalchat_reload_cache(self, ctx: discord.ApplicationContext): - """Lรคdt den Channel-Cache neu (Bot Owner)""" - if ctx.author.id not in self.config.BOT_OWNERS: - await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) - return - - await ctx.defer(ephemeral=True) - try: - old_count = len(self._cached_channels or []) - self._cached_channels = await self.sender._fetch_all_channels() - new_count = len(self._cached_channels) - - await ctx.respond( - f"โœ… **Cache neu geladen!**\n\n" - f"Alte Channel-Anzahl: **{old_count}**\n" - f"Neue Channel-Anzahl: **{new_count}**", - ephemeral=True - ) - logger.info(f"๐Ÿง  GlobalChat Cache manuell neu geladen. {old_count} -> {new_count}") - - except Exception as e: - logger.error(f"โŒ Cache Reload Fehler: {e}", exc_info=True) - await ctx.respond("โŒ Ein Fehler ist aufgetreten!", ephemeral=True) - - - @globalchat.command( - name="debug", - description="๐Ÿ› Zeigt Debug-Informationen an (Admin)" - ) - async def globalchat_debug(self, ctx: discord.ApplicationContext): - """Zeigt Debug-Informationen (Bot Owner)""" - if ctx.author.id not in self.config.BOT_OWNERS: - await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) - return - - await ctx.defer(ephemeral=True) - try: - cached_channels = len(self._cached_channels or []) - all_settings = db.get_all_guild_settings() - - debug_info = ( - f"**Bot-Status:**\n" - f"โ€ข Latency: `{round(self.bot.latency * 1000)}ms`\n" - f"โ€ข Guilds: `{len(self.bot.guilds)}`\n" - f"โ€ข Uptime: ``\n\n" - f"**GlobalChat-Status:**\n" - f"โ€ข Aktive Channels (Cache): `{cached_channels}`\n" - f"โ€ข DB Settings Eintrรคge: `{len(all_settings)}`\n" - f"โ€ข Cleanup Task: `{'Aktiv' if self.cleanup_task.is_running() else 'Inaktiv'}`\n" - ) - - # Beispiel fรผr Blacklist-Info - user_bans, guild_bans = db.get_blacklist_stats() - debug_info += ( - f"โ€ข Gebannte User/Server: `{user_bans} / {guild_bans}`" - ) - - embed = discord.Embed( - title="๐Ÿ› GlobalChat Debug-Informationen", - description=debug_info, - color=discord.Color.orange(), - timestamp=datetime.utcnow() - ) - await ctx.respond(embed=embed, ephemeral=True) - except Exception as e: - logger.error(f"โŒ Debug Fehler: {e}", exc_info=True) - await ctx.respond("โŒ Ein Fehler ist aufgetreten!", ephemeral=True) - - -# ==================== Setup Funktion ==================== -def setup(bot): - """Setup-Funktion fรผr the cog when loaded by classic...""" - # Stelle sicher, dass die Datenbank initialisiert wird, falls nicht schon geschehen - GlobalChatDatabase().create_tables() - # Fรผge die Cog hinzu - bot.add_cog(GlobalChatCog(bot)) \ No newline at end of file diff --git a/src/cogs/Servermanament/levelsystem.py b/src/cogs/Servermanament/levelsystem.py deleted file mode 100644 index e669b69..0000000 --- a/src/cogs/Servermanament/levelsystem.py +++ /dev/null @@ -1,974 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import discord -from discord import SlashCommandGroup, Option -from discord.ext import commands, tasks -import time -import random -from DevTools import LevelDatabase -import asyncio -import io -import csv -from typing import Optional -from discord.ui import Container - - -class PrestigeConfirmView(discord.ui.View): - def __init__(self, db, user, guild): - super().__init__(timeout=300) - self.db = db - self.user = user - self.guild = guild - - @discord.ui.button(label="Bestรคtigen", style=discord.ButtonStyle.danger, emoji="โš ๏ธ") - async def confirm_prestige(self, interaction: discord.Interaction, button: discord.ui.Button): - if interaction.user != self.user: - await interaction.response.send_message("Nur der User kann sein eigenes Prestige bestรคtigen!", ephemeral=True) - return - - success = self.db.prestige_user(self.user.id, self.guild.id) - if success: - embed = discord.Embed( - title="โœจ Prestige erfolgreich!", - description=f"{self.user.mention} hat ein Prestige durchgefรผhrt!\nDu startest wieder bei Level 0, aber behรคltst deinen Prestige-Rang!", - color=0xff69b4 - ) - embed.set_footer(text="Gratulation zu deinem Prestige!") - else: - embed = discord.Embed( - title="โŒ Prestige fehlgeschlagen", - description="Prestige konnte nicht durchgefรผhrt werden. Mรถglicherweise erfรผllst du nicht die Anforderungen.", - color=0xff0000 - ) - - await interaction.response.edit_message(embed=embed, view=None) - - @discord.ui.button(label="Abbrechen", style=discord.ButtonStyle.secondary) - async def cancel_prestige(self, interaction: discord.Interaction, button: discord.ui.Button): - if interaction.user != self.user: - await interaction.response.send_message("Nur der User kann seine eigene Aktion abbrechen!", ephemeral=True) - return - - embed = discord.Embed( - title="โŒ Prestige abgebrochen", - description="Das Prestige wurde abgebrochen.", - color=0x999999 - ) - await interaction.response.edit_message(embed=embed, view=None) - - -class LevelSystem(commands.Cog): - def __init__(self, bot): - self.bot = bot - self.db = LevelDatabase() - self.xp_cooldowns = {} # User-ID -> Timestamp - - # Starte Background Tasks - self.cleanup_expired_boosts.start() - self.cleanup_temporary_roles.start() - - def cog_unload(self): - """Cleanup beim Entladen der Cog""" - self.cleanup_expired_boosts.cancel() - self.cleanup_temporary_roles.cancel() - - levelsystem = SlashCommandGroup("levelsystem", "Verwalte das Levelsystem") - levelrole = SlashCommandGroup("levelrole", "Verwalte Level-Rollen") - xpboost = SlashCommandGroup("xpboost", "Verwalte XP-Boosts") - levelconfig = SlashCommandGroup("levelconfig", "Konfiguriere das Levelsystem") - - @tasks.loop(hours=1) - async def cleanup_expired_boosts(self): - """Entfernt abgelaufene XP-Boosts""" - # Hier wรผrde die DB-Cleanup Logik implementiert werden - pass - - @tasks.loop(hours=1) - async def cleanup_temporary_roles(self): - """Entfernt abgelaufene temporรคre Rollen""" - # Hier wรผrde die temporรคre Rollen Cleanup Logik implementiert werden - pass - - def create_level_up_embed(self, user: discord.Member, level: int, is_role_reward: bool = False, role: Optional[discord.Role] = None): - """Erstellt ein verbessertes Level-Up Embed""" - embed = discord.Embed(color=0x00ff00) - embed.set_author(name="๐ŸŽ‰ Level Up!", icon_url=user.avatar.url if user.avatar else user.default_avatar.url) - embed.description = f"**{user.mention}** erreichte **Level {level}**!" - - if is_role_reward and role: - embed.add_field(name="๐Ÿ† Neue Rolle erhalten", value=f"**{role.name}**", inline=False) - embed.color = 0xffff00 - - embed.set_thumbnail(url=user.avatar.url if user.avatar else user.default_avatar.url) - return embed - - @commands.Cog.listener() - async def on_message(self, message): - # Ignoriere Bot-Nachrichten - if message.author.bot: - return - - # Nur in Servern, nicht in DMs - if message.guild is None: - return - - # Prรผfe ob Levelsystem aktiviert ist - if not self.db.is_levelsystem_enabled(message.guild.id): - return - - # Prรผfe ob Kanal auf Blacklist steht - if self.db.is_channel_blacklisted(message.guild.id, message.channel.id): - return - - user_id = message.author.id - guild_id = message.guild.id - current_time = time.time() - - # Guild-Konfiguration holen - config = self.db.get_guild_config(guild_id) - cooldown = config.get('cooldown', 30) - - # XP-Cooldown prรผfen - if user_id in self.xp_cooldowns: - if current_time - self.xp_cooldowns[user_id] < cooldown: - return - - # Kanal-spezifischen Multiplikator anwenden - channel_multiplier = self.db.get_channel_multiplier(guild_id, message.channel.id) - - # XP berechnen - min_xp = config.get('min_xp', 10) - max_xp = config.get('max_xp', 20) - base_xp = random.randint(min_xp, max_xp) - final_xp = int(base_xp * channel_multiplier) - - # XP hinzufรผgen mit Anti-Spam Protection - level_up, new_level = self.db.add_xp(user_id, guild_id, final_xp, message.content) - - if not level_up and new_level == 0: - return # Anti-Spam blockierte die XP - - # Cooldown setzen - self.xp_cooldowns[user_id] = current_time - - # Level Up Behandlung - if level_up: - # Bestimme Zielkanal fรผr Level-Up Nachrichten - target_channel = message.channel - level_up_channel_id = config.get('level_up_channel') - - if level_up_channel_id: - level_up_channel = message.guild.get_channel(level_up_channel_id) - if level_up_channel: - target_channel = level_up_channel - - embed = self.create_level_up_embed(message.author, new_level) - await target_channel.send(embed=embed) - - # Level-Rolle vergeben - role_id = self.db.get_role_for_level(guild_id, new_level) - if role_id: - role = message.guild.get_role(role_id) - if role: - try: - await message.author.add_roles(role, reason=f"Level {new_level} erreicht") - role_embed = discord.Embed( - title="๐Ÿ† Neue Rolle erhalten!", - description=f"{message.author.mention} hat die Rolle **{role.name}** erhalten!", - color=0xffff00 - ) - role_embed.set_thumbnail(url=message.author.avatar.url if message.author.avatar else message.author.default_avatar.url) - await target_channel.send(embed=role_embed) - except discord.Forbidden: - # Log oder Nachricht an Admins falls Bot keine Berechtigung hat - pass - - @levelsystem.command(description="Zeigt das Server-Leaderboard mit Paginierung") - async def leaderboard(self, ctx, - anzahl: discord.Option(int, "Anzahl der User", default=10, min_value=1, max_value=50)): - if not self.db.is_levelsystem_enabled(ctx.guild.id): - embed = discord.Embed( - title="โŒ Levelsystem deaktiviert", - description="Das Levelsystem ist auf diesem Server deaktiviert.", - color=0xff0000 - ) - await ctx.respond(embed=embed) - return - - leaderboard_data = self.db.get_leaderboard(ctx.guild.id, anzahl) - - if not leaderboard_data: - embed = discord.Embed( - title="๐Ÿ“Š Leaderboard", - description="Noch keine User im Leaderboard!", - color=0x0099ff - ) - await ctx.respond(embed=embed) - return - - embed = discord.Embed( - title=f"๐Ÿ“Š Leaderboard - Top {len(leaderboard_data)}", - color=0x0099ff, - timestamp=discord.utils.utcnow() - ) - - description = "" - for i, (user_id, xp, level, messages, prestige) in enumerate(leaderboard_data, 1): - user = self.bot.get_user(user_id) - username = user.display_name if user else f"User {user_id}" - - if i == 1: - medal = "๐Ÿฅ‡" - elif i == 2: - medal = "๐Ÿฅˆ" - elif i == 3: - medal = "๐Ÿฅ‰" - else: - medal = f"**{i}.**" - - prestige_text = f"โญ{prestige} " if prestige > 0 else "" - description += f"{medal} {prestige_text}**{username}** - Level {level} ({xp:,} XP)\n" - - embed.description = description - embed.set_footer(text=f"Server: {ctx.guild.name}") - - await ctx.respond(embed=embed) - - @levelsystem.command(description="Zeigt erweiterte Benutzerstatistiken") - async def profil(self, ctx, - user: discord.Option(discord.Member, "User dessen Profil angezeigt werden soll", default=None)): - if not self.db.is_levelsystem_enabled(ctx.guild.id): - embed = discord.Embed( - title="โŒ Levelsystem deaktiviert", - description="Das Levelsystem ist auf diesem Server deaktiviert.", - color=0xff0000 - ) - await ctx.respond(embed=embed) - return - - target_user = user or ctx.author - user_stats = self.db.get_user_stats(target_user.id, ctx.guild.id) - - if not user_stats: - embed = discord.Embed( - title="โŒ Kein Profil gefunden", - description=f"{target_user.display_name} hat noch keine XP gesammelt!", - color=0xff0000 - ) - await ctx.respond(embed=embed) - return - - xp, level, messages, xp_needed, prestige, total_earned = user_stats - rank = self.db.get_user_rank(target_user.id, ctx.guild.id) - - embed = discord.Embed( - title=f"๐Ÿ“Š Profil von {target_user.display_name}", - color=target_user.color or 0x0099ff, - timestamp=discord.utils.utcnow() - ) - - # Erste Zeile - embed.add_field(name="๐Ÿ† Level", value=str(level), inline=True) - embed.add_field(name="โญ XP", value=f"{xp:,}", inline=True) - embed.add_field(name="๐Ÿ“ˆ Rang", value=f"#{rank}", inline=True) - - # Zweite Zeile - embed.add_field(name="๐Ÿ’ฌ Nachrichten", value=f"{messages:,}", inline=True) - embed.add_field(name="๐ŸŽฏ XP bis nรคchstes Level", value=f"{xp_needed:,}", inline=True) - - if prestige > 0: - embed.add_field(name="โœจ Prestige", value=f"โญ{prestige}", inline=True) - - # Dritte Zeile - embed.add_field(name="๐Ÿ’ฐ Gesamt verdiente XP", value=f"{total_earned:,}", inline=True) - - # XP pro Nachricht berechnen - xp_per_msg = total_earned / messages if messages > 0 else 0 - embed.add_field(name="๐Ÿ“Š ร˜ XP/Nachricht", value=f"{xp_per_msg:.1f}", inline=True) - - # Aktiver XP-Multiplikator - multiplier = self.db.get_active_xp_multiplier(ctx.guild.id, target_user.id) - if multiplier > 1.0: - embed.add_field(name="๐Ÿš€ Aktiver Boost", value=f"{multiplier}x", inline=True) - - # Fortschrittsbalken - current_level_xp = xp - self.db.xp_for_level(level) - next_level_xp = self.db.xp_for_level(level + 1) - self.db.xp_for_level(level) - progress = current_level_xp / next_level_xp if next_level_xp > 0 else 1 - - progress_bar = "โ–ˆ" * int(progress * 15) + "โ–‘" * (15 - int(progress * 15)) - embed.add_field( - name="๐Ÿ“Š Level-Fortschritt", - value=f"`{progress_bar}` {progress * 100:.1f}%\n`{current_level_xp:,} / {next_level_xp:,} XP`", - inline=False - ) - - embed.set_thumbnail(url=target_user.avatar.url if target_user.avatar else target_user.default_avatar.url) - embed.set_footer(text=f"Server: {ctx.guild.name}") - - await ctx.respond(embed=embed) - - @levelsystem.command(description="Fรผhrt ein Prestige durch (Level 50+)") - async def prestige(self, ctx): - if not self.db.is_levelsystem_enabled(ctx.guild.id): - embed = discord.Embed( - title="โŒ Levelsystem deaktiviert", - description="Das Levelsystem ist auf diesem Server deaktiviert.", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - config = self.db.get_guild_config(ctx.guild.id) - if not config.get('prestige_enabled', True): - embed = discord.Embed( - title="โŒ Prestige deaktiviert", - description="Das Prestige-System ist auf diesem Server deaktiviert.", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - user_stats = self.db.get_user_stats(ctx.author.id, ctx.guild.id) - min_level = config.get('prestige_min_level', 50) - - if not user_stats or user_stats[1] < min_level: - embed = discord.Embed( - title="โŒ Prestige nicht verfรผgbar", - description=f"Du musst mindestens Level {min_level} erreichen!", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - # Bestรคtigung erforderlich - view = PrestigeConfirmView(self.db, ctx.author, ctx.guild) - embed = discord.Embed( - title="โš ๏ธ Prestige Bestรคtigung", - description=f"Mรถchtest du wirklich dein Level zurรผcksetzen?\n\n**Was passiert:**\nโ€ข Dein Level wird auf 0 zurรผckgesetzt\nโ€ข Deine XP werden auf 0 zurรผckgesetzt\nโ€ข Du erhรคltst einen Prestige-Rang (โญ)\nโ€ข Du behรคltst deine Nachrichten-Anzahl\n\n**Aktuelles Level:** {user_stats[1]}", - color=0xffff00 - ) - embed.set_footer(text="Diese Aktion kann nicht rรผckgรคngig gemacht werden!") - await ctx.respond(embed=embed, view=view, ephemeral=True) - - @levelsystem.command(description="Zeigt erweiterte Server-Analytics") - async def analytics(self, ctx): - if not self.db.is_levelsystem_enabled(ctx.guild.id): - embed = discord.Embed( - title="โŒ Levelsystem deaktiviert", - description="Das Levelsystem ist auf diesem Server deaktiviert.", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - analytics = self.db.get_detailed_analytics(ctx.guild.id) - - embed = discord.Embed( - title="๐Ÿ“Š Server Analytics", - color=0x0099ff, - timestamp=discord.utils.utcnow() - ) - - # Grundlegende Statistiken - embed.add_field(name="๐Ÿ‘ฅ Aktive User", value=f"{analytics['total_users']:,}", inline=True) - embed.add_field(name="๐Ÿ“ˆ Durchschnittslevel", value=f"{analytics['avg_level']:.1f}", inline=True) - embed.add_field(name="๐Ÿ† Hรถchstes Level", value=f"{analytics['max_level']}", inline=True) - - embed.add_field(name="โšก Gesamt XP", value=f"{analytics['total_xp']:,}", inline=True) - embed.add_field(name="๐Ÿ’ฌ Gesamt Nachrichten", value=f"{analytics['total_messages']:,}", inline=True) - embed.add_field(name="๐Ÿ•’ Heute aktiv", value=f"{analytics['active_today']}", inline=True) - - # Level-Verteilung - distribution = analytics['level_distribution'] - embed.add_field( - name="๐Ÿ“Š Level-Verteilung", - value=f"๐ŸŒฑ Anfรคnger (1-10): {distribution['novice']}\n" - f"๐Ÿ“š Fortgeschrittene (11-25): {distribution['intermediate']}\n" - f"๐ŸŽฏ Experten (26-50): {distribution['advanced']}\n" - f"๐Ÿ‘‘ Meister (50+): {distribution['expert']}", - inline=False - ) - - embed.set_footer(text=f"Server: {ctx.guild.name}") - await ctx.respond(embed=embed) - - @levelsystem.command(description="Exportiert Leveldaten als CSV") - @commands.has_permissions(administrator=True) - async def export_data(self, ctx): - if not self.db.is_levelsystem_enabled(ctx.guild.id): - embed = discord.Embed( - title="โŒ Levelsystem deaktiviert", - description="Das Levelsystem ist auf diesem Server deaktiviert.", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - await ctx.defer(ephemeral=True) - - data = self.db.export_guild_data(ctx.guild.id) - - output = io.StringIO() - writer = csv.writer(output) - writer.writerow(['User ID', 'Username', 'Level', 'XP', 'Messages', 'Prestige', 'Total XP Earned']) - - for row in data: - user_id, xp, level, messages, prestige, total_earned = row - user = self.bot.get_user(user_id) - username = user.display_name if user else "Unbekannt" - writer.writerow([user_id, username, level, xp, messages, prestige, total_earned]) - - file_content = output.getvalue().encode('utf-8') - file = discord.File(io.BytesIO(file_content), filename=f"leveldata_{ctx.guild.id}_{int(time.time())}.csv") - - embed = discord.Embed( - title="โœ… Datenexport erfolgreich", - description=f"Daten von {len(data)} Usern exportiert.", - color=0x00ff00 - ) - - await ctx.followup.send(embed=embed, file=file) - - # Level-Rollen Commands - @levelrole.command(description="Fรผgt eine Level-Rolle hinzu") - @commands.has_permissions(manage_roles=True) - async def add(self, ctx, - level: discord.Option(int, "Level fรผr die Rolle", min_value=1), - rolle: discord.Option(discord.Role, "Die Rolle die vergeben werden soll"), - temporaer: discord.Option(bool, "Temporรคre Rolle", default=False), - dauer_stunden: discord.Option(int, "Dauer in Stunden (nur bei temporรคren Rollen)", default=0)): - - if rolle.position >= ctx.author.top_role.position and ctx.author != ctx.guild.owner: - embed = discord.Embed( - title="โŒ Keine Berechtigung", - description="Du kannst keine Rolle hinzufรผgen, die hรถher oder gleich deiner hรถchsten Rolle ist!", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if rolle.position >= ctx.guild.me.top_role.position: - embed = discord.Embed( - title="โŒ Bot-Berechtigung fehlt", - description="Ich kann diese Rolle nicht vergeben, da sie hรถher oder gleich meiner hรถchsten Rolle ist!", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if temporaer and dauer_stunden <= 0: - embed = discord.Embed( - title="โŒ Ungรผltige Dauer", - description="Temporรคre Rollen benรถtigen eine Dauer > 0 Stunden!", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - self.db.add_level_role(ctx.guild.id, level, rolle.id, temporaer, dauer_stunden) - - temp_text = f" (temporรคr fรผr {dauer_stunden}h)" if temporaer else "" - embed = discord.Embed( - title="โœ… Level-Rolle hinzugefรผgt", - description=f"Die Rolle **{rolle.name}** wird nun bei **Level {level}**{temp_text} vergeben!", - color=0x00ff00 - ) - await ctx.respond(embed=embed) - - @levelrole.command(description="Fรผgt mehrere Rollen fรผr ein Level hinzu") - @commands.has_permissions(manage_roles=True) - async def add_multiple(self, ctx, level: int, *roles: discord.Role): - if not roles: - await ctx.respond("Du musst mindestens eine Rolle angeben!", ephemeral=True) - return - - added_roles = [] - failed_roles = [] - - for role in roles: - if role.position >= ctx.author.top_role.position and ctx.author != ctx.guild.owner: - failed_roles.append(f"{role.name} (keine Berechtigung)") - continue - - if role.position >= ctx.guild.me.top_role.position: - failed_roles.append(f"{role.name} (Bot-Berechtigung fehlt)") - continue - - self.db.add_level_role(ctx.guild.id, level, role.id) - added_roles.append(role.name) - - embed = discord.Embed(color=0x00ff00 if added_roles else 0xff0000) - - if added_roles: - embed.title = "โœ… Level-Rollen hinzugefรผgt" - embed.description = f"**Level {level}:** {', '.join(added_roles)}" - - if failed_roles: - if added_roles: - embed.add_field(name="โŒ Fehlgeschlagen", value='\n'.join(failed_roles), inline=False) - else: - embed.title = "โŒ Keine Rollen hinzugefรผgt" - embed.description = '\n'.join(failed_roles) - - await ctx.respond(embed=embed) - - @levelrole.command(description="Bearbeitet eine bestehende Level-Rolle") - @commands.has_permissions(manage_roles=True) - async def edit(self, ctx, - level: discord.Option(int, "Level der zu bearbeitenden Rolle", min_value=1), - neue_rolle: discord.Option(discord.Role, "Die neue Rolle")): - # Prรผfen ob Level-Rolle existiert - level_roles = self.db.get_level_roles(ctx.guild.id) - if not any(l == level for l, r, t, d in level_roles): - embed = discord.Embed( - title="โŒ Level-Rolle nicht gefunden", - description=f"Fรผr Level {level} ist keine Rolle konfiguriert!", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if neue_rolle.position >= ctx.author.top_role.position and ctx.author != ctx.guild.owner: - embed = discord.Embed( - title="โŒ Keine Berechtigung", - description="Du kannst keine Rolle setzen, die hรถher oder gleich deiner hรถchsten Rolle ist!", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if neue_rolle.position >= ctx.guild.me.top_role.position: - embed = discord.Embed( - title="โŒ Bot-Berechtigung fehlt", - description="Ich kann diese Rolle nicht vergeben, da sie hรถher oder gleich meiner hรถchsten Rolle ist!", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - self.db.add_level_role(ctx.guild.id, level, neue_rolle.id) - - embed = discord.Embed( - title="โœ… Level-Rolle bearbeitet", - description=f"Die Rolle fรผr **Level {level}** wurde zu **{neue_rolle.name}** geรคndert!", - color=0x00ff00 - ) - await ctx.respond(embed=embed) - - @levelrole.command(description="Entfernt eine Level-Rolle") - @commands.has_permissions(manage_roles=True) - async def remove(self, ctx, level: discord.Option(int, "Level der zu entfernenden Rolle", min_value=1)): - # Prรผfen ob Level-Rolle existiert - level_roles = self.db.get_level_roles(ctx.guild.id) - if not any(l == level for l, r, t, d in level_roles): - embed = discord.Embed( - title="โŒ Level-Rolle nicht gefunden", - description=f"Fรผr Level {level} ist keine Rolle konfiguriert!", - color=0xff0000 - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - self.db.remove_level_role(ctx.guild.id, level) - - embed = discord.Embed( - title="โœ… Level-Rolle entfernt", - description=f"Die Level-Rolle fรผr **Level {level}** wurde entfernt!", - color=0x00ff00 - ) - await ctx.respond(embed=embed) - - @levelrole.command(description="Zeigt alle konfigurierten Level-Rollen") - async def list(self, ctx): - level_roles = self.db.get_level_roles(ctx.guild.id) - - if not level_roles: - embed = discord.Embed( - title="๐Ÿ“ Level-Rollen", - description="Keine Level-Rollen konfiguriert!", - color=0x0099ff - ) - await ctx.respond(embed=embed) - return - - embed = discord.Embed( - title="๐Ÿ“ Level-Rollen", - color=0x0099ff, - timestamp=discord.utils.utcnow() - ) - - description = "" - for level, role_id, is_temp, duration in level_roles: - role = ctx.guild.get_role(role_id) - role_name = role.name if role else f"Gelรถschte Rolle ({role_id})" - - temp_text = f" โฐ({duration}h)" if is_temp else "" - description += f"**Level {level}:** {role_name}{temp_text}\n" - - embed.description = description - embed.set_footer(text=f"Server: {ctx.guild.name}") - - await ctx.respond(embed=embed) - - # XP-Boost Commands - @xpboost.command(description="Fรผgt einen globalen XP-Boost hinzu") - @commands.has_permissions(manage_guild=True) - async def add_global(self, ctx, - multiplier: discord.Option(float, "XP-Multiplikator", min_value=1.1, max_value=5.0), - dauer_stunden: discord.Option(int, "Dauer in Stunden", min_value=1, max_value=168)): - - self.db.add_xp_boost(ctx.guild.id, None, multiplier, dauer_stunden) - - embed = discord.Embed( - title="๐Ÿš€ Globaler XP-Boost aktiviert", - description=f"**{multiplier}x** XP-Multiplikator fรผr **{dauer_stunden} Stunden**\n" - f"Alle Server-Mitglieder erhalten mehr XP!", - color=0x00ff00 - ) - embed.set_footer(text="Der Boost ist sofort aktiv!") - await ctx.respond(embed=embed) - - @xpboost.command(description="Fรผgt einen persรถnlichen XP-Boost hinzu") - @commands.has_permissions(manage_guild=True) - async def add_user(self, ctx, - user: discord.Option(discord.Member, "Benutzer fรผr den Boost"), - multiplier: discord.Option(float, "XP-Multiplikator", min_value=1.1, max_value=5.0), - dauer_stunden: discord.Option(int, "Dauer in Stunden", min_value=1, max_value=168)): - - self.db.add_xp_boost(ctx.guild.id, user.id, multiplier, dauer_stunden) - - embed = discord.Embed( - title="๐Ÿš€ Persรถnlicher XP-Boost aktiviert", - description=f"**{user.mention}** erhรคlt **{multiplier}x** XP fรผr **{dauer_stunden} Stunden**!", - color=0x00ff00 - ) - embed.set_footer(text="Der Boost ist sofort aktiv!") - await ctx.respond(embed=embed) - - # Konfiguration Commands - @levelconfig.command(description="Konfiguriert XP-Einstellungen") - @commands.has_permissions(manage_guild=True) - async def xp_settings(self, ctx, - min_xp: discord.Option(int, "Minimum XP pro Nachricht", default=None, min_value=1, max_value=50), - max_xp: discord.Option(int, "Maximum XP pro Nachricht", default=None, min_value=1, max_value=100), - cooldown: discord.Option(int, "Cooldown in Sekunden", default=None, min_value=5, max_value=300)): - - config_updates = {} - if min_xp is not None: - config_updates['min_xp'] = min_xp - if max_xp is not None: - config_updates['max_xp'] = max_xp - if cooldown is not None: - config_updates['xp_cooldown'] = cooldown - - if max_xp and min_xp and max_xp < min_xp: - await ctx.respond("โŒ Maximum XP kann nicht kleiner als Minimum XP sein!", ephemeral=True) - return - - if not config_updates: - await ctx.respond("โŒ Du musst mindestens einen Wert รคndern!", ephemeral=True) - return - - self.db.set_guild_config(ctx.guild.id, **config_updates) - - current_config = self.db.get_guild_config(ctx.guild.id) - - embed = discord.Embed( - title="โœ… XP-Einstellungen aktualisiert", - color=0x00ff00 - ) - - embed.add_field(name="๐Ÿ’ฐ XP-Bereich", value=f"{current_config['min_xp']}-{current_config['max_xp']}", inline=True) - embed.add_field(name="โฑ๏ธ Cooldown", value=f"{current_config['xp_cooldown']}s", inline=True) - - await ctx.respond(embed=embed) - - @levelconfig.command(description="Setzt XP-Multiplikator fรผr einen Kanal") - @commands.has_permissions(manage_guild=True) - async def channel_multiplier(self, ctx, - channel: discord.Option(discord.TextChannel, "Kanal"), - multiplier: discord.Option(float, "Multiplikator (0.0 = keine XP)", min_value=0.0, max_value=5.0)): - - self.db.set_channel_multiplier(ctx.guild.id, channel.id, multiplier) - - if multiplier == 0: - description = f"{channel.mention} gibt keine XP mehr." - color = 0xff0000 - else: - description = f"{channel.mention} hat **{multiplier}x** XP-Multiplikator." - color = 0x00ff00 - - embed = discord.Embed( - title="โœ… Kanal-Multiplikator gesetzt", - description=description, - color=color - ) - await ctx.respond(embed=embed) - - @levelconfig.command(description="Fรผgt einen Kanal zur XP-Blacklist hinzu") - @commands.has_permissions(manage_guild=True) - async def blacklist_channel(self, ctx, - channel: discord.Option(discord.TextChannel, "Kanal zum AusschlieรŸen")): - - self.db.add_blacklisted_channel(ctx.guild.id, channel.id) - - embed = discord.Embed( - title="โœ… Kanal ausgeschlossen", - description=f"{channel.mention} wurde vom Levelsystem ausgeschlossen.", - color=0x00ff00 - ) - await ctx.respond(embed=embed) - - @levelconfig.command(description="Setzt den Level-Up Nachrichten-Kanal") - @commands.has_permissions(manage_guild=True) - async def levelup_channel(self, ctx, - channel: discord.Option(discord.TextChannel, "Kanal fรผr Level-Up Nachrichten", default=None)): - - if channel: - self.db.set_guild_config(ctx.guild.id, level_up_channel=channel.id) - embed = discord.Embed( - title="โœ… Level-Up Kanal gesetzt", - description=f"Level-Up Nachrichten werden in {channel.mention} gesendet.", - color=0x00ff00 - ) - else: - self.db.set_guild_config(ctx.guild.id, level_up_channel=None) - embed = discord.Embed( - title="โœ… Level-Up Kanal zurรผckgesetzt", - description="Level-Up Nachrichten werden wieder im ursprรผnglichen Kanal gesendet.", - color=0x00ff00 - ) - - await ctx.respond(embed=embed) - - @levelconfig.command(description="Konfiguriert Prestige-Einstellungen") - @commands.has_permissions(manage_guild=True) - async def prestige_settings(self, ctx, - aktiviert: discord.Option(bool, "Prestige-System aktivieren/deaktivieren"), - min_level: discord.Option(int, "Minimum Level fรผr Prestige", default=50, min_value=10, max_value=200)): - - self.db.set_guild_config(ctx.guild.id, prestige_enabled=aktiviert, prestige_min_level=min_level) - - embed = discord.Embed( - title="โœ… Prestige-Einstellungen aktualisiert", - color=0x00ff00 - ) - - status = "aktiviert" if aktiviert else "deaktiviert" - embed.add_field(name="โœจ Status", value=status.title(), inline=True) - if aktiviert: - embed.add_field(name="๐ŸŽฏ Minimum Level", value=str(min_level), inline=True) - - await ctx.respond(embed=embed) - - # System Commands - @levelsystem.command(description="Aktiviert das Levelsystem") - @commands.has_permissions(manage_guild=True) - async def enable(self, ctx): - if self.db.is_levelsystem_enabled(ctx.guild.id): - embed = discord.Embed( - title="โ„น๏ธ Bereits aktiviert", - description="Das Levelsystem ist bereits aktiviert!", - color=0x0099ff - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - self.db.set_levelsystem_enabled(ctx.guild.id, True) - - embed = discord.Embed( - title="โœ… Levelsystem aktiviert", - description="Das Levelsystem wurde erfolgreich aktiviert!\n\nBenutze `/levelconfig` um weitere Einstellungen vorzunehmen.", - color=0x00ff00 - ) - await ctx.respond(embed=embed) - - @levelsystem.command(description="Deaktiviert das Levelsystem") - @commands.has_permissions(manage_guild=True) - async def disable(self, ctx): - if not self.db.is_levelsystem_enabled(ctx.guild.id): - embed = discord.Embed( - title="โ„น๏ธ Bereits deaktiviert", - description="Das Levelsystem ist bereits deaktiviert!", - color=0x0099ff - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - self.db.set_levelsystem_enabled(ctx.guild.id, False) - - embed = discord.Embed( - title="โœ… Levelsystem deaktiviert", - description="Das Levelsystem wurde erfolgreich deaktiviert!\n\n*Hinweis: Alle Daten bleiben erhalten und kรถnnen bei Reaktivierung wiederhergestellt werden.*", - color=0x00ff00 - ) - await ctx.respond(embed=embed) - - @levelsystem.command(description="Zeigt den detaillierten Status des Levelsystems") - async def status(self, ctx): - enabled = self.db.is_levelsystem_enabled(ctx.guild.id) - config = self.db.get_guild_config(ctx.guild.id) - - embed = discord.Embed( - title="๐Ÿ“Š Levelsystem Status", - description=f"Das Levelsystem ist **{'aktiviert' if enabled else 'deaktiviert'}**", - color=0x00ff00 if enabled else 0xff0000, - timestamp=discord.utils.utcnow() - ) - - if enabled: - # Grundkonfiguration - embed.add_field( - name="โš™๏ธ Konfiguration", - value=f"**XP-Bereich:** {config['min_xp']}-{config['max_xp']}\n" - f"**Cooldown:** {config['xp_cooldown']}s\n" - f"**Prestige:** {'โœ…' if config['prestige_enabled'] else 'โŒ'} (Level {config['prestige_min_level']}+)", - inline=True - ) - - # Statistiken - leaderboard = self.db.get_leaderboard(ctx.guild.id, 1) - level_roles = self.db.get_level_roles(ctx.guild.id) - total_users = len(self.db.get_leaderboard(ctx.guild.id, 1000)) - - embed.add_field( - name="๐Ÿ“ˆ Statistiken", - value=f"**Aktive User:** {total_users:,}\n" - f"**Level-Rollen:** {len(level_roles)}\n" - f"**XP-Boosts:** Aktiv", - inline=True - ) - - if leaderboard: - top_user = self.bot.get_user(leaderboard[0][0]) - top_username = top_user.display_name if top_user else f"User {leaderboard[0][0]}" - prestige_text = f"โญ{leaderboard[0][4]} " if leaderboard[0][4] > 0 else "" - - embed.add_field( - name="๐Ÿ‘‘ Top User", - value=f"{prestige_text}**{top_username}**\nLevel {leaderboard[0][2]} ({leaderboard[0][1]:,} XP)", - inline=True - ) - - # Level-Up Kanal - if config['level_up_channel']: - channel = ctx.guild.get_channel(config['level_up_channel']) - channel_text = channel.mention if channel else "Gelรถschter Kanal" - else: - channel_text = "Standard (Nachrichtenkanal)" - - embed.add_field(name="๐Ÿ“ข Level-Up Kanal", value=channel_text, inline=True) - - embed.set_footer(text=f"Server: {ctx.guild.name}") - await ctx.respond(embed=embed) - - # Admin Commands - @levelsystem.command(description="Setzt das Level eines Users (Admin)") - @commands.has_permissions(administrator=True) - async def set_level(self, ctx, - user: discord.Option(discord.Member, "Benutzer"), - level: discord.Option(int, "Neues Level", min_value=0, max_value=1000)): - - required_xp = self.db.xp_for_level(level) - - # User in Datenbank erstellen/aktualisieren - conn = self.db.db_path - import sqlite3 - conn = sqlite3.connect(self.db.db_path) - cursor = conn.cursor() - - cursor.execute(''' - INSERT OR REPLACE INTO user_levels (user_id, guild_id, xp, level, messages, last_message, total_xp_earned) - VALUES (?, ?, ?, ?, - COALESCE((SELECT messages FROM user_levels WHERE user_id = ? AND guild_id = ?), 0), - ?, - COALESCE((SELECT total_xp_earned FROM user_levels WHERE user_id = ? AND guild_id = ?), 0) + ?) - ''', (user.id, ctx.guild.id, required_xp, level, user.id, ctx.guild.id, time.time(), user.id, ctx.guild.id, required_xp)) - - conn.commit() - conn.close() - - embed = discord.Embed( - title="โœ… Level gesetzt", - description=f"{user.mention} ist jetzt **Level {level}** ({required_xp:,} XP)", - color=0x00ff00 - ) - await ctx.respond(embed=embed) - - @levelsystem.command(description="Fรผgt einem User XP hinzu (Admin)") - @commands.has_permissions(administrator=True) - async def add_xp(self, ctx, - user: discord.Option(discord.Member, "Benutzer"), - xp_amount: discord.Option(int, "XP-Menge", min_value=1, max_value=100000)): - - level_up, new_level = self.db.add_xp(user.id, ctx.guild.id, xp_amount, "Admin XP Grant") - - embed = discord.Embed( - title="โœ… XP hinzugefรผgt", - description=f"{user.mention} hat **{xp_amount:,} XP** erhalten!", - color=0x00ff00 - ) - - if level_up: - embed.add_field(name="๐ŸŽ‰ Level Up!", value=f"Neues Level: **{new_level}**", inline=False) - - await ctx.respond(embed=embed) - - @levelsystem.command(description="Setzt die Nachrichten-Anzahl eines Users (Admin)") - @commands.has_permissions(administrator=True) - async def set_messages(self, ctx, - user: discord.Option(discord.Member, "Benutzer"), - messages: discord.Option(int, "Anzahl Nachrichten", min_value=0, max_value=1000000)): - - import sqlite3 - conn = sqlite3.connect(self.db.db_path) - cursor = conn.cursor() - - cursor.execute(''' - UPDATE user_levels SET messages = ? - WHERE user_id = ? AND guild_id = ? - ''', (messages, user.id, ctx.guild.id)) - - conn.commit() - conn.close() - - embed = discord.Embed( - title="โœ… Nachrichten-Anzahl gesetzt", - description=f"{user.mention} hat jetzt **{messages:,} Nachrichten**", - color=0x00ff00 - ) - await ctx.respond(embed=embed) - - @levelsystem.command(description="Lรถscht die Leveldaten eines Users (Admin)") - @commands.has_permissions(administrator=True) - async def reset_user(self, ctx, - user: discord.Option(discord.Member, "Benutzer zum Zurรผcksetzen")): - - import sqlite3 - conn = sqlite3.connect(self.db.db_path) - cursor = conn.cursor() - - cursor.execute('DELETE FROM user_levels WHERE user_id = ? AND guild_id = ?', (user.id, ctx.guild.id)) - - affected_rows = cursor.rowcount - conn.commit() - conn.close() - - if affected_rows > 0: - embed = discord.Embed( - title="โœ… User zurรผckgesetzt", - description=f"Alle Leveldaten von {user.mention} wurden gelรถscht.", - color=0x00ff00 - ) - else: - embed = discord.Embed( - title="โ„น๏ธ Keine Daten gefunden", - description=f"{user.mention} hat keine Leveldaten auf diesem Server.", - color=0x0099ff - ) - - await ctx.respond(embed=embed, ephemeral=True) - - -def setup(bot): - bot.add_cog(LevelSystem(bot)) \ No newline at end of file diff --git a/src/cogs/Servermanament/logging.py b/src/cogs/Servermanament/logging.py deleted file mode 100644 index 818a863..0000000 --- a/src/cogs/Servermanament/logging.py +++ /dev/null @@ -1,1465 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# File: logging_cog.py - -import discord -from discord import SlashCommandGroup -from discord.ext import commands -from datetime import datetime, timedelta -from typing import Dict, Set, Optional, List -import asyncio -import logging - -# Import our separate database class -from DevTools import LoggingDatabase - -# Setup logging -logger = logging.getLogger(__name__) - -class LoggingCog(commands.Cog): - """ - Comprehensive Discord logging system with improved performance and features - """ - - def __init__(self, bot): - self.bot = bot - self.db = LoggingDatabase() - - # Improved caching system - self._edit_tasks: Dict[int, asyncio.Task] = {} - self._bulk_deletes: Dict[int, Dict[str, any]] = {} - self._voice_cache: Dict[int, Dict[int, Optional[discord.VoiceState]]] = {} - - # Configuration - self.config = { - 'edit_debounce_time': 3.0, # Sekunden - 'bulk_delete_threshold': 3, # Anzahl fรผr Bulk-Erkennung - 'bulk_delete_window': 2.0, # Sekunden Zeitfenster - 'max_content_length': 1500, # Max Content-Lรคnge in Embeds - 'max_embed_fields': 25, # Discord Limit - 'cleanup_interval': 300, # 5 Minuten Cache-Cleanup - 'max_attachment_display': 5, # Max Attachments in Embed - 'max_role_display': 10, # Max Roles in Embed - } - - # Performance tracking - self._stats = { - 'events_processed': 0, - 'logs_sent': 0, - 'errors': 0, - 'cache_hits': 0, - 'startup_time': datetime.utcnow(), - } - - # Start background tasks - self._cleanup_task = None - self.bot.loop.create_task(self._start_background_tasks()) - - logger.info("LoggingCog initialized successfully") - - async def _start_background_tasks(self): - """Startet Background-Tasks nachdem der Bot bereit ist""" - await self.bot.wait_until_ready() - self._cleanup_task = self.bot.loop.create_task(self._cleanup_loop()) - logger.info("Background tasks started") - - def cog_unload(self): - """Cleanup beim Entladen der Cog""" - logger.info("Unloading LoggingCog...") - - if self._cleanup_task and not self._cleanup_task.done(): - self._cleanup_task.cancel() - - # Cancel all edit tasks - for task in self._edit_tasks.values(): - if not task.done(): - task.cancel() - - # Close database connection - self.db.close() - logger.info("LoggingCog unloaded successfully") - - async def _cleanup_loop(self): - """RegelmรครŸige Cache-Bereinigung mit verbesserter Logik""" - while not self.bot.is_closed(): - try: - await asyncio.sleep(self.config['cleanup_interval']) - await self._cleanup_caches() - except asyncio.CancelledError: - logger.info("Cleanup loop cancelled") - break - except Exception as e: - logger.error(f"Cleanup loop error: {e}") - self._stats['errors'] += 1 - - async def _cleanup_caches(self): - """Bereinigt alle Caches""" - try: - cleanup_count = 0 - - # Edit Tasks bereinigen - completed_tasks = [ - msg_id for msg_id, task in self._edit_tasks.items() - if task.done() - ] - for msg_id in completed_tasks: - del self._edit_tasks[msg_id] - cleanup_count += 1 - - # Bulk Delete Cache bereinigen (รคlter als 5 Minuten) - current_time = datetime.utcnow() - expired_guilds = [] - - for guild_id, data in self._bulk_deletes.items(): - if 'timestamp' in data: - age = (current_time - data['timestamp']).total_seconds() - if age > 300: # 5 Minuten - expired_guilds.append(guild_id) - - for guild_id in expired_guilds: - del self._bulk_deletes[guild_id] - cleanup_count += 1 - - # Voice Cache fรผr offline Mitglieder bereinigen - for guild_id in list(self._voice_cache.keys()): - guild = self.bot.get_guild(guild_id) - if not guild: - del self._voice_cache[guild_id] - cleanup_count += 1 - continue - - offline_members = [] - for member_id in self._voice_cache[guild_id]: - member = guild.get_member(member_id) - if not member or not member.voice: - offline_members.append(member_id) - - for member_id in offline_members: - del self._voice_cache[guild_id][member_id] - cleanup_count += 1 - - if cleanup_count > 0: - logger.debug(f"Cache cleanup: {cleanup_count} items removed") - - except Exception as e: - logger.error(f"Cache cleanup error: {e}") - self._stats['errors'] += 1 - - async def send_log(self, guild_id: int, embed: discord.Embed, log_type: str = "general") -> bool: - """Verbesserte Log-Versendung mit Retry-Logik""" - try: - channel_id = await self.db.get_log_channel(guild_id, log_type) - if not channel_id: - return False - - channel = self.bot.get_channel(channel_id) - if not channel: - # Channel nicht mehr vorhanden, aus DB entfernen - await self.db.remove_log_channel(guild_id, log_type) - logger.warning(f"Removed invalid channel {channel_id} for guild {guild_id}") - return False - - # Embed validieren und anpassen - if len(embed) > 6000: # Discord Limit - embed.description = "โš ๏ธ Inhalt zu lang fรผr Anzeige" - # Felder reduzieren falls nรถtig - while len(embed.fields) > 10: - embed.remove_field(-1) - - # Embed senden - await channel.send(embed=embed) - self._stats['logs_sent'] += 1 - return True - - except discord.Forbidden: - logger.warning(f"No permission for log channel in guild {guild_id}") - await self.db.remove_log_channel(guild_id, log_type) - return False - except discord.NotFound: - logger.warning(f"Log channel not found in guild {guild_id}") - await self.db.remove_log_channel(guild_id, log_type) - return False - except discord.HTTPException as e: - if e.code == 50035: # Invalid form body - logger.error(f"Invalid embed content for guild {guild_id}: {e}") - # Fallback embed senden - try: - fallback_embed = discord.Embed( - title="โš ๏ธ Log-Fehler", - description="Originale Log-Nachricht konnte nicht angezeigt werden (zu lang oder ungรผltig)", - color=discord.Color.orange(), - timestamp=datetime.utcnow() - ) - await channel.send(embed=fallback_embed) - except: - pass - else: - logger.error(f"HTTP error sending log to guild {guild_id}: {e}") - except Exception as e: - logger.error(f"Unexpected error sending log to guild {guild_id}: {e}") - self._stats['errors'] += 1 - - return False - - def _create_user_embed(self, title: str, user: discord.User, color: discord.Color, - extra_fields: Dict[str, str] = None, - description: str = None) -> discord.Embed: - """Verbesserte User-Embed Erstellung""" - embed = discord.Embed( - title=title, - description=description, - color=color, - timestamp=datetime.utcnow() - ) - - # User Info - immer als erstes - embed.add_field( - name="๐Ÿ‘ค User", - value=f"{user.mention}\n`{user}`", - inline=True - ) - embed.add_field( - name="๐Ÿ†” ID", - value=f"`{user.id}`", - inline=True - ) - embed.add_field( - name="๐Ÿ“… Erstellt", - value=f"", - inline=True - ) - - # Extra Felder hinzufรผgen - if extra_fields: - for name, value in extra_fields.items(): - if len(embed.fields) < self.config['max_embed_fields']: - embed.add_field(name=name, value=str(value)[:1000], inline=True) - - # Avatar und Footer - if user.display_avatar: - embed.set_thumbnail(url=user.display_avatar.url) - - embed.set_footer(text=f"User ID: {user.id}") - return embed - - def _truncate_content(self, content: str, max_length: int = None) -> str: - """Kรผrzt Content intelligent""" - if not content: - return "*Leer*" - - max_length = max_length or self.config['max_content_length'] - - if len(content) <= max_length: - return content - - # An Wort-Grenzen kรผrzen wenn mรถglich - truncated = content[:max_length-3] - last_space = truncated.rfind(' ') - - if last_space > max_length * 0.8: # Nur wenn nicht zu viel verloren geht - truncated = truncated[:last_space] - - return f"{truncated}..." - - def _format_content_for_embed(self, content: str, escape_markdown: bool = True) -> str: - """Formatiert Content sicher fรผr Embeds""" - if not content: - return "*Leer*" - - content = self._truncate_content(content) - - if escape_markdown: - # Escape problematische Zeichen - content = content.replace("```", "'''") - content = content.replace("`", "'") - - return f"```\n{content}\n```" - - # ============================================================================= - # SLASH COMMANDS - Improved - # ============================================================================= - - logging = SlashCommandGroup("logging", description="Setze die Logging Systeme") - - @logging.command(name="channel", description="Setzt den Log-Channel fรผr verschiedene Events") - @discord.default_permissions(administrator=True) - async def set_log_channel(self, ctx, - channel: discord.TextChannel, - log_type: discord.Option(str, - choices=["general", "moderation", "voice", "messages", "all"], - description="Art der Logs", - default="general")): - """Verbesserte Log-Channel Konfiguration""" - try: - # Berechtigungen prรผfen - perms = channel.permissions_for(ctx.guild.me) - if not perms.send_messages: - embed = discord.Embed( - title="โŒ Keine Berechtigung", - description=f"Ich kann keine Nachrichten in {channel.mention} senden.", - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if not perms.embed_links: - embed = discord.Embed( - title="โš ๏ธ Fehlende Berechtigung", - description=f"Ich benรถtige die 'Embed Links' Berechtigung in {channel.mention}.", - color=discord.Color.orange() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - if log_type == "all": - # Alle Log-Typen setzen - types = ["general", "moderation", "voice", "messages"] - for lt in types: - await self.db.set_log_channel(ctx.guild.id, channel.id, lt) - - embed = discord.Embed( - title="โœ… Alle Log-Channels gesetzt", - description=f"Alle Logs werden nun in {channel.mention} gesendet.\n\n" + - f"**Konfigurierte Typen:** {', '.join(types)}", - color=discord.Color.green() - ) - else: - await self.db.set_log_channel(ctx.guild.id, channel.id, log_type) - - embed = discord.Embed( - title="โœ… Log-Channel gesetzt", - description=f"**{log_type.title()}**-Logs werden nun in {channel.mention} gesendet.", - color=discord.Color.green() - ) - - embed.set_footer(text=f"Konfiguriert von {ctx.author}") - await ctx.respond(embed=embed, ephemeral=True) - - # Test-Nachricht senden - test_embed = discord.Embed( - title="๐Ÿงช Test-Nachricht", - description=f"Log-Channel fรผr **{log_type}** erfolgreich konfiguriert!", - color=discord.Color.blue(), - timestamp=datetime.utcnow() - ) - test_embed.set_footer(text="Dies ist eine Test-Nachricht") - await self.send_log(ctx.guild.id, test_embed, "general" if log_type == "all" else log_type) - - except Exception as e: - embed = discord.Embed( - title="โŒ Fehler", - description=f"Fehler beim Setzen des Log-Channels:\n```{str(e)}```", - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - logger.error(f"Error in set_log_channel: {e}") - - @logging.command(name="remove", description="Entfernt einen Log-Channel") - @discord.default_permissions(administrator=True) - async def remove_log_channel(self, ctx, - log_type: discord.Option(str, - choices=["general", "moderation", "voice", "messages", "all"], - description="Art der Logs", default="all")): - """Entfernt Log-Channel Konfiguration""" - try: - if log_type == "all": - deleted_count = await self.db.remove_all_log_channels(ctx.guild.id) - description = f"Alle Log-Channels wurden entfernt. ({deleted_count} Eintrรคge)" - else: - deleted_count = await self.db.remove_log_channel(ctx.guild.id, log_type) - if deleted_count > 0: - description = f"{log_type.title()}-Logging wurde deaktiviert." - else: - description = f"Kein {log_type.title()}-Logging war konfiguriert." - - embed = discord.Embed( - title="๐Ÿ—‘๏ธ Log-Channel entfernt", - description=description, - color=discord.Color.red(), - timestamp=datetime.utcnow() - ) - embed.set_footer(text=f"Entfernt von {ctx.author}") - await ctx.respond(embed=embed, ephemeral=True) - - except Exception as e: - embed = discord.Embed( - title="โŒ Fehler", - description=f"Fehler beim Entfernen des Log-Channels:\n```{str(e)}```", - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - logger.error(f"Error in remove_log_channel: {e}") - - @logging.command(name="status", description="Zeigt die aktuellen Log-Einstellungen") - @discord.default_permissions(administrator=True) - async def log_status(self, ctx): - """Verbesserter Log-Status mit mehr Details""" - try: - channels = await self.db.get_all_log_channels(ctx.guild.id) - stats = await self.db.get_statistics() - - embed = discord.Embed( - title="๐Ÿ“Š Logging Status", - color=discord.Color.blue(), - timestamp=datetime.utcnow() - ) - - if not channels: - embed.description = "โŒ Keine Log-Channels konfiguriert." - embed.add_field( - name="๐Ÿ’ก Tipp", - value="Nutze `/setlogchannel` um Logging zu aktivieren.", - inline=False - ) - else: - status_text = f"โœ… **{len(channels)}** Log-Typ(en) konfiguriert\n\n" - - for log_type, channel_id in channels.items(): - channel = self.bot.get_channel(channel_id) - if channel: - status_text += f"**{log_type.title()}:** {channel.mention}\n" - else: - status_text += f"**{log_type.title()}:** โŒ *Channel nicht gefunden* (`{channel_id}`)\n" - - embed.description = status_text - - # Bot Statistiken - uptime = datetime.utcnow() - self._stats['startup_time'] - uptime_str = f"{uptime.days}d {uptime.seconds//3600}h {(uptime.seconds%3600)//60}m" - - embed.add_field( - name="๐Ÿ“ˆ Cog Statistiken", - value=f"Events verarbeitet: **{self._stats['events_processed']:,}**\n" + - f"Logs gesendet: **{self._stats['logs_sent']:,}**\n" + - f"Fehler: **{self._stats['errors']}**\n" + - f"Uptime: **{uptime_str}**", - inline=True - ) - - # Cache Info - voice_cache_size = sum(len(vc) for vc in self._voice_cache.values()) - embed.add_field( - name="๐Ÿ—„๏ธ Cache Status", - value=f"Edit Tasks: **{len(self._edit_tasks)}**\n" + - f"Bulk Deletes: **{len(self._bulk_deletes)}**\n" + - f"Voice Cache: **{voice_cache_size}**", - inline=True - ) - - # Datenbank Statistiken - if stats: - embed.add_field( - name="๐Ÿ—ƒ๏ธ Datenbank", - value=f"Aktive Channels: **{stats.get('enabled_entries', 0)}**\n" + - f"Guilds mit Logging: **{stats.get('unique_guilds', 0)}**\n" + - f"Einzigartige Channels: **{stats.get('unique_channels', 0)}**", - inline=True - ) - - embed.set_footer(text=f"Guild ID: {ctx.guild.id}") - await ctx.respond(embed=embed, ephemeral=True) - - except Exception as e: - embed = discord.Embed( - title="โŒ Fehler", - description=f"Fehler beim Abrufen des Status:\n```{str(e)}```", - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - logger.error(f"Error in log_status: {e}") - - @logging.command(name="backup", description="Erstellt ein Backup der Log-Konfiguration") - @discord.default_permissions(administrator=True) - async def log_backup(self, ctx): - """Erstellt ein Datenbank-Backup""" - try: - backup_path = f"data/log_channels_backup_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}.db" - success = await self.db.backup_database(backup_path) - - if success: - embed = discord.Embed( - title="โœ… Backup erstellt", - description=f"Datenbank-Backup wurde erfolgreich erstellt:\n`{backup_path}`", - color=discord.Color.green() - ) - else: - embed = discord.Embed( - title="โŒ Backup fehlgeschlagen", - description="Backup konnte nicht erstellt werden. Prรผfe die Logs fรผr Details.", - color=discord.Color.red() - ) - - await ctx.respond(embed=embed, ephemeral=True) - - except Exception as e: - embed = discord.Embed( - title="โŒ Fehler", - description=f"Fehler beim Backup:\n```{str(e)}```", - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - logger.error(f"Error in log_backup: {e}") - - # ============================================================================= - # EVENT HANDLERS - Enhanced - # ============================================================================= - - @commands.Cog.listener() - async def on_member_join(self, member: discord.Member): - """Verbessertes Member Join Logging""" - try: - self._stats['events_processed'] += 1 - - account_age = datetime.utcnow() - member.created_at - age_days = account_age.days - - # Verdรคchtigkeits-Score - suspicious_factors = [] - if age_days < 1: - suspicious_factors.append("Sehr neues Konto (< 1 Tag)") - elif age_days < 7: - suspicious_factors.append("Neues Konto (< 7 Tage)") - - if member.display_avatar.is_default(): - suspicious_factors.append("Standard Avatar") - - # Default Username Pattern - if len(member.name) > 10 and member.discriminator != "0": - if member.name.lower().startswith(("discord", "user", "member")): - suspicious_factors.append("Verdรคchtiger Username") - - # Farbe basierend auf Verdรคchtigkeits-Level - if member.bot: - color = discord.Color.purple() - elif len(suspicious_factors) >= 2: - color = discord.Color.red() - elif suspicious_factors: - color = discord.Color.orange() - else: - color = discord.Color.green() - - extra_fields = { - "๐ŸŽ‚ Konto-Alter": f"{age_days} Tag{'e' if age_days != 1 else ''}", - "๐Ÿ‘ฅ Member #": f"{member.guild.member_count}", - } - - if suspicious_factors: - extra_fields["โš ๏ธ Verdรคchtig"] = "\n".join(suspicious_factors[:3]) - - if member.bot: - extra_fields["๐Ÿค– Bot"] = "โœ…" - - embed = self._create_user_embed( - "๐Ÿ“ฅ Member beigetreten", - member, - color, - extra_fields - ) - - await self.send_log(member.guild.id, embed, "general") - - except Exception as e: - logger.error(f"Error in on_member_join: {e}") - self._stats['errors'] += 1 - - @commands.Cog.listener() - async def on_member_remove(self, member: discord.Member): - """Verbessertes Member Leave Logging""" - try: - self._stats['events_processed'] += 1 - - extra_fields = { - "๐ŸŽญ Rollen": f"{len(member.roles) - 1}", # -1 fรผr @everyone - "๐Ÿ‘ฅ Member #": f"{member.guild.member_count}", - } - - if member.joined_at: - duration = datetime.utcnow() - member.joined_at - days = duration.days - hours = duration.seconds // 3600 - - if days > 0: - duration_str = f"{days} Tag{'e' if days != 1 else ''}" - elif hours > 0: - duration_str = f"{hours} Stunde{'n' if hours != 1 else ''}" - else: - minutes = duration.seconds // 60 - duration_str = f"{minutes} Minute{'n' if minutes != 1 else ''}" - - extra_fields["โฑ๏ธ Mitgliedschaftsdauer"] = duration_str - - # Top Rollen anzeigen (nicht @everyone) - top_roles = [role for role in member.roles if role.name != "@everyone"] - if top_roles: - top_roles = sorted(top_roles, key=lambda r: r.position, reverse=True)[:3] - extra_fields["๐Ÿ† Top Rollen"] = ", ".join([role.name for role in top_roles]) - - embed = self._create_user_embed( - "๐Ÿ“ค Member verlassen", - member, - discord.Color.red(), - extra_fields - ) - - await self.send_log(member.guild.id, embed, "general") - - except Exception as e: - logger.error(f"Error in on_member_remove: {e}") - self._stats['errors'] += 1 - - @commands.Cog.listener() - async def on_message_delete(self, message: discord.Message): - """Stark verbessertes Message Delete Logging mit Bulk-Detection""" - try: - if message.author.bot or not message.guild: - return - - self._stats['events_processed'] += 1 - guild_id = message.guild.id - - # Bulk Delete Detection - current_time = datetime.utcnow() - - if guild_id not in self._bulk_deletes: - self._bulk_deletes[guild_id] = { - 'messages': set(), - 'timestamp': current_time, - 'channels': set() - } - - bulk_data = self._bulk_deletes[guild_id] - - # Reset wenn zu alt - if (current_time - bulk_data['timestamp']).total_seconds() > self.config['bulk_delete_window']: - bulk_data['messages'].clear() - bulk_data['channels'].clear() - bulk_data['timestamp'] = current_time - - bulk_data['messages'].add(message.id) - bulk_data['channels'].add(message.channel.id) - - # Kurz warten um weitere Deletes zu erfassen - await asyncio.sleep(0.3) - - # Bulk Delete Check - if len(bulk_data['messages']) >= self.config['bulk_delete_threshold']: - embed = discord.Embed( - title="๐Ÿ—‘๏ธ Bulk-Lรถschung erkannt", - description=f"**{len(bulk_data['messages'])}** Nachrichten wurden in kurzer Zeit gelรถscht", - color=discord.Color.dark_red(), - timestamp=datetime.utcnow() - ) - - # Channel Info - affected_channels = [] - for ch_id in bulk_data['channels']: - channel = self.bot.get_channel(ch_id) - if channel: - affected_channels.append(channel.mention) - - if affected_channels: - embed.add_field( - name="๐Ÿ“ Betroffene Channels", - value="\n".join(affected_channels[:5]), - inline=False - ) - - embed.add_field(name="โฑ๏ธ Zeitfenster", value=f"< {self.config['bulk_delete_window']}s", inline=True) - embed.add_field(name="๐Ÿ” Hinweis", value="Mรถgliche Moderator-Aktion oder Bot-Cleanup", inline=True) - - await self.send_log(guild_id, embed, "messages") - - # Cache zurรผcksetzen - bulk_data['messages'].clear() - bulk_data['channels'].clear() - return - - # Normale Delete-Behandlung - if message.id not in bulk_data['messages']: - return # Bereits als Bulk verarbeitet - - embed = discord.Embed( - title="๐Ÿ—‘๏ธ Nachricht gelรถscht", - color=discord.Color.red(), - timestamp=datetime.utcnow() - ) - - # Author Info - embed.add_field( - name="๐Ÿ‘ค Author", - value=f"{message.author.mention}\n`{message.author}`", - inline=True - ) - embed.add_field( - name="๐Ÿ“ Channel", - value=message.channel.mention, - inline=True - ) - embed.add_field( - name="โฐ Erstellt", - value=f"", - inline=True - ) - - # Content - if message.content: - embed.add_field( - name="๐Ÿ’ฌ Inhalt", - value=self._format_content_for_embed(message.content), - inline=False - ) - - # Attachments - if message.attachments: - attachment_info = [] - for att in message.attachments[:self.config['max_attachment_display']]: - size_kb = att.size // 1024 - attachment_info.append(f"๐Ÿ“Ž `{att.filename}` ({size_kb} KB)") - - if len(message.attachments) > self.config['max_attachment_display']: - attachment_info.append(f"... und {len(message.attachments) - self.config['max_attachment_display']} weitere") - - embed.add_field( - name="๐Ÿ“Ž Anhรคnge", - value="\n".join(attachment_info), - inline=False - ) - - # Embeds - if message.embeds: - embed.add_field( - name="๐Ÿ“‹ Embeds", - value=f"{len(message.embeds)} Embed(s)", - inline=True - ) - - # Reactions - if message.reactions: - reaction_count = sum(r.count for r in message.reactions) - embed.add_field( - name="๐Ÿ‘ Reaktionen", - value=f"{reaction_count} Reaktionen", - inline=True - ) - - embed.set_author(name=message.author.display_name, icon_url=message.author.display_avatar.url) - embed.set_footer(text=f"Message ID: {message.id} | User ID: {message.author.id}") - - await self.send_log(guild_id, embed, "messages") - - # Message aus bulk cache entfernen - if message.id in bulk_data['messages']: - bulk_data['messages'].discard(message.id) - - except Exception as e: - logger.error(f"Error in on_message_delete: {e}") - self._stats['errors'] += 1 - - @commands.Cog.listener() - async def on_message_edit(self, before: discord.Message, after: discord.Message): - """Verbessertes Message Edit Logging mit intelligentem Debouncing""" - try: - if (before.author.bot or not before.guild or - before.content == after.content or not before.content): - return - - self._stats['events_processed'] += 1 - message_id = before.id - - # Bestehenden Task canceln - if message_id in self._edit_tasks: - self._edit_tasks[message_id].cancel() - - # Neuen debounced Task erstellen - self._edit_tasks[message_id] = asyncio.create_task( - self._delayed_edit_log(before, after) - ) - - except Exception as e: - logger.error(f"Error in on_message_edit: {e}") - self._stats['errors'] += 1 - - async def _delayed_edit_log(self, before: discord.Message, after: discord.Message): - """Verzรถgertes Edit-Logging mit verbesserter Logik""" - try: - await asyncio.sleep(self.config['edit_debounce_time']) - - # Aktuellste Version der Nachricht holen - try: - fresh_message = await before.channel.fetch_message(before.id) - after = fresh_message # Aktuellste Version verwenden - except (discord.NotFound, discord.Forbidden): - pass # Nachricht wurde gelรถscht oder keine Berechtigung - - await self._log_message_edit(before, after) - - except asyncio.CancelledError: - pass # Task wurde gecancelt - except Exception as e: - logger.error(f"Error in delayed edit log: {e}") - finally: - # Task aus Cache entfernen - if before.id in self._edit_tasks: - del self._edit_tasks[before.id] - - async def _log_message_edit(self, before: discord.Message, after: discord.Message): - """Internes Message Edit Logging mit Diff-Anzeige""" - try: - embed = discord.Embed( - title="โœ๏ธ Nachricht bearbeitet", - color=discord.Color.yellow(), - timestamp=datetime.utcnow() - ) - - embed.add_field( - name="๐Ÿ‘ค Author", - value=f"{before.author.mention}\n`{before.author}`", - inline=True - ) - embed.add_field( - name="๐Ÿ“ Channel", - value=before.channel.mention, - inline=True - ) - embed.add_field( - name="๐Ÿ”— Nachricht", - value=f"[Zur Nachricht]({after.jump_url})", - inline=True - ) - - # Content Comparison - intelligenter - before_content = self._truncate_content(before.content or "", 700) - after_content = self._truncate_content(after.content or "", 700) - - if len(before_content) + len(after_content) < 2000: - embed.add_field( - name="๐Ÿ“ Vorher", - value=self._format_content_for_embed(before_content, escape_markdown=True), - inline=False - ) - embed.add_field( - name="๐Ÿ“ Nachher", - value=self._format_content_for_embed(after_content, escape_markdown=True), - inline=False - ) - else: - # Zu lang - nur ร„nderungsinfo - char_diff = len(after.content) - len(before.content) - diff_text = f"**Zeichen-ร„nderung:** {char_diff:+d}\n" - diff_text += f"**Lรคnge:** {len(before.content)} โ†’ {len(after.content)}" - - embed.add_field( - name="๐Ÿ“Š ร„nderungsinfo", - value=diff_text, - inline=False - ) - - # Timestamp der ursprรผnglichen Nachricht - embed.add_field( - name="๐Ÿ• Original erstellt", - value=f"", - inline=True - ) - - embed.set_author(name=before.author.display_name, icon_url=before.author.display_avatar.url) - embed.set_footer(text=f"Message ID: {before.id} | User ID: {before.author.id}") - - await self.send_log(before.guild.id, embed, "messages") - - except Exception as e: - logger.error(f"Error in _log_message_edit: {e}") - -# ============================================================================= - # VOICE STATE EVENTS - # ============================================================================= - - @commands.Cog.listener() - async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState): - """Verbessertes Voice State Logging mit intelligenter Filterung""" - try: - if member.bot: - return - - self._stats['events_processed'] += 1 - guild_id = member.guild.id - - # Cache initialisieren - if guild_id not in self._voice_cache: - self._voice_cache[guild_id] = {} - - guild_cache = self._voice_cache[guild_id] - member_id = member.id - - # Vorherigen State aus Cache holen oder setzen - cached_before = guild_cache.get(member_id) - guild_cache[member_id] = after - - # Event-Typ bestimmen - event_type = None - color = discord.Color.blue() - title = "" - - if not before.channel and after.channel: - # Join - event_type = "join" - title = "๐Ÿ”Š Voice Channel beigetreten" - color = discord.Color.green() - elif before.channel and not after.channel: - # Leave - event_type = "leave" - title = "๐Ÿ”‡ Voice Channel verlassen" - color = discord.Color.red() - elif before.channel != after.channel and before.channel and after.channel: - # Move - event_type = "move" - title = "๐Ÿ”„ Voice Channel gewechselt" - color = discord.Color.orange() - elif before.channel == after.channel: - # State changes (mute, deafen, etc.) - changes = [] - if before.self_mute != after.self_mute: - changes.append(f"Self Mute: {'โœ…' if after.self_mute else 'โŒ'}") - if before.self_deaf != after.self_deaf: - changes.append(f"Self Deaf: {'โœ…' if after.self_deaf else 'โŒ'}") - if before.mute != after.mute: - changes.append(f"Server Mute: {'โœ…' if after.mute else 'โŒ'}") - if before.deaf != after.deaf: - changes.append(f"Server Deaf: {'โœ…' if after.deaf else 'โŒ'}") - if before.streaming != after.streaming: - changes.append(f"Streaming: {'โœ…' if after.streaming else 'โŒ'}") - if before.self_video != after.self_video: - changes.append(f"Camera: {'โœ…' if after.self_video else 'โŒ'}") - - if changes: - event_type = "state_change" - title = "๐ŸŽ›๏ธ Voice Status geรคndert" - color = discord.Color.blue() - - if not event_type: - return - - embed = discord.Embed( - title=title, - color=color, - timestamp=datetime.utcnow() - ) - - # User Info - embed.add_field( - name="๐Ÿ‘ค User", - value=f"{member.mention}\n`{member}`", - inline=True - ) - - # Channel Info - if event_type == "join": - embed.add_field( - name="๐Ÿ“ Channel", - value=after.channel.mention, - inline=True - ) - # Wer ist noch im Channel? - other_members = [m for m in after.channel.members if m != member and not m.bot] - if other_members: - embed.add_field( - name="๐Ÿ‘ฅ Andere Mitglieder", - value=f"{len(other_members)} Mitglied{'er' if len(other_members) != 1 else ''}", - inline=True - ) - - elif event_type == "leave": - embed.add_field( - name="๐Ÿ“ Channel", - value=before.channel.mention, - inline=True - ) - # Session-Dauer berechnen wenn im Cache - if cached_before and cached_before.channel: - # Schรคtze Join-Zeit (grober Wert) - embed.add_field( - name="โฑ๏ธ Ungefรคhre Dauer", - value="Session beendet", - inline=True - ) - - elif event_type == "move": - embed.add_field( - name="๐Ÿ“ Von", - value=before.channel.mention, - inline=True - ) - embed.add_field( - name="๐Ÿ“ Nach", - value=after.channel.mention, - inline=True - ) - - elif event_type == "state_change": - embed.add_field( - name="๐Ÿ“ Channel", - value=after.channel.mention, - inline=True - ) - embed.add_field( - name="๐Ÿ”ง ร„nderungen", - value="\n".join(changes), - inline=False - ) - - embed.set_author(name=member.display_name, icon_url=member.display_avatar.url) - embed.set_footer(text=f"User ID: {member.id}") - - await self.send_log(guild_id, embed, "voice") - - except Exception as e: - logger.error(f"Error in on_voice_state_update: {e}") - self._stats['errors'] += 1 - - # ============================================================================= - # MEMBER UPDATE EVENTS - # ============================================================================= - - @commands.Cog.listener() - async def on_member_update(self, before: discord.Member, after: discord.Member): - """Member Update Logging mit intelligenter Filterung""" - try: - if before.bot: - return - - self._stats['events_processed'] += 1 - changes = [] - important_change = False - - # Nickname ร„nderung - if before.display_name != after.display_name: - changes.append({ - 'field': '๐Ÿท๏ธ Nickname', - 'before': before.display_name or "*Kein Nickname*", - 'after': after.display_name or "*Kein Nickname*" - }) - important_change = True - - # Rollen ร„nderung - before_roles = set(before.roles) - after_roles = set(after.roles) - - added_roles = after_roles - before_roles - removed_roles = before_roles - after_roles - - if added_roles or removed_roles: - important_change = True - - if added_roles: - role_names = [role.name for role in added_roles if role.name != "@everyone"] - if role_names: - changes.append({ - 'field': 'โž• Rollen hinzugefรผgt', - 'value': ", ".join(role_names[:5]) # Max 5 anzeigen - }) - - if removed_roles: - role_names = [role.name for role in removed_roles if role.name != "@everyone"] - if role_names: - changes.append({ - 'field': 'โž– Rollen entfernt', - 'value': ", ".join(role_names[:5]) # Max 5 anzeigen - }) - - # Premium Status (Nitro Boost) - if hasattr(before, 'premium_since') and hasattr(after, 'premium_since'): - if before.premium_since != after.premium_since: - if after.premium_since and not before.premium_since: - changes.append({ - 'field': '๐Ÿ’Ž Server Boost', - 'value': 'Begonnen zu boosten' - }) - important_change = True - elif before.premium_since and not after.premium_since: - changes.append({ - 'field': '๐Ÿ’Ž Server Boost', - 'value': 'Boost beendet' - }) - important_change = True - - # Timeout Status - if hasattr(before, 'timed_out_until') and hasattr(after, 'timed_out_until'): - if before.timed_out_until != after.timed_out_until: - if after.timed_out_until: - changes.append({ - 'field': 'โธ๏ธ Timeout', - 'value': f"Bis " - }) - important_change = True - elif before.timed_out_until: - changes.append({ - 'field': 'โธ๏ธ Timeout', - 'value': 'Timeout aufgehoben' - }) - important_change = True - - # Nur loggen wenn wichtige ร„nderungen - if not important_change or not changes: - return - - embed = discord.Embed( - title="๐Ÿ‘ค Member geรคndert", - color=discord.Color.blue(), - timestamp=datetime.utcnow() - ) - - embed.add_field( - name="๐Ÿ‘ค Member", - value=f"{after.mention}\n`{after}`", - inline=True - ) - - # ร„nderungen hinzufรผgen - for change in changes[:self.config['max_embed_fields'] - 2]: # Platz fรผr User und ID - if 'before' in change and 'after' in change: - value = f"**Vorher:** {change['before']}\n**Nachher:** {change['after']}" - else: - value = change['value'] - - embed.add_field( - name=change['field'], - value=value[:1024], # Discord limit - inline=False - ) - - embed.set_author(name=after.display_name, icon_url=after.display_avatar.url) - embed.set_footer(text=f"User ID: {after.id}") - - await self.send_log(after.guild.id, embed, "general") - - except Exception as e: - logger.error(f"Error in on_member_update: {e}") - self._stats['errors'] += 1 - - # ============================================================================= - # CHANNEL EVENTS - # ============================================================================= - - @commands.Cog.listener() - async def on_guild_channel_create(self, channel): - """Channel Creation Logging""" - try: - self._stats['events_processed'] += 1 - - embed = discord.Embed( - title="โž• Channel erstellt", - color=discord.Color.green(), - timestamp=datetime.utcnow() - ) - - # Channel-Typ Icon - type_icons = { - discord.ChannelType.text: "๐Ÿ’ฌ", - discord.ChannelType.voice: "๐Ÿ”Š", - discord.ChannelType.category: "๐Ÿ“", - discord.ChannelType.news: "๐Ÿ“ข", - discord.ChannelType.stage_voice: "๐ŸŽญ", - discord.ChannelType.forum: "๐Ÿ’ญ", - discord.ChannelType.private_thread: "๐Ÿงต", - discord.ChannelType.public_thread: "๐Ÿงต" - } - - icon = type_icons.get(channel.type, "๐Ÿ“") - embed.add_field( - name="๐Ÿ“ Channel", - value=f"{icon} {channel.mention}\n`{channel.name}`", - inline=True - ) - - embed.add_field( - name="๐Ÿ“‹ Typ", - value=channel.type.name.replace('_', ' ').title(), - inline=True - ) - - embed.add_field( - name="๐Ÿ†” ID", - value=f"`{channel.id}`", - inline=True - ) - - # Kategorie info - if hasattr(channel, 'category') and channel.category: - embed.add_field( - name="๐Ÿ“ Kategorie", - value=channel.category.name, - inline=True - ) - - # Position - if hasattr(channel, 'position'): - embed.add_field( - name="๐Ÿ“Š Position", - value=str(channel.position), - inline=True - ) - - embed.set_footer(text=f"Channel ID: {channel.id}") - await self.send_log(channel.guild.id, embed, "general") - - except Exception as e: - logger.error(f"Error in on_guild_channel_create: {e}") - self._stats['errors'] += 1 - - @commands.Cog.listener() - async def on_guild_channel_delete(self, channel): - """Channel Deletion Logging""" - try: - self._stats['events_processed'] += 1 - - embed = discord.Embed( - title="โž– Channel gelรถscht", - color=discord.Color.red(), - timestamp=datetime.utcnow() - ) - - # Channel-Typ Icon - type_icons = { - discord.ChannelType.text: "๐Ÿ’ฌ", - discord.ChannelType.voice: "๐Ÿ”Š", - discord.ChannelType.category: "๐Ÿ“", - discord.ChannelType.news: "๐Ÿ“ข", - discord.ChannelType.stage_voice: "๐ŸŽญ", - discord.ChannelType.forum: "๐Ÿ’ญ" - } - - icon = type_icons.get(channel.type, "๐Ÿ“") - embed.add_field( - name="๐Ÿ“ Channel", - value=f"{icon} `#{channel.name}`", - inline=True - ) - - embed.add_field( - name="๐Ÿ“‹ Typ", - value=channel.type.name.replace('_', ' ').title(), - inline=True - ) - - embed.add_field( - name="๐Ÿ†” ID", - value=f"`{channel.id}`", - inline=True - ) - - # Kategorie info - if hasattr(channel, 'category') and channel.category: - embed.add_field( - name="๐Ÿ“ Kategorie", - value=channel.category.name, - inline=True - ) - - embed.set_footer(text=f"Channel ID: {channel.id}") - await self.send_log(channel.guild.id, embed, "general") - - except Exception as e: - logger.error(f"Error in on_guild_channel_delete: {e}") - self._stats['errors'] += 1 - - # ============================================================================= - # BAN/KICK EVENTS - # ============================================================================= - - @commands.Cog.listener() - async def on_member_ban(self, guild: discord.Guild, user: discord.User): - """Member Ban Logging""" - try: - self._stats['events_processed'] += 1 - - # Versuche Ban-Info mit Grund zu holen - ban_info = None - try: - ban_info = await guild.fetch_ban(user) - except: - pass - - embed = discord.Embed( - title="๐Ÿ”จ Member gebannt", - color=discord.Color.dark_red(), - timestamp=datetime.utcnow() - ) - - embed.add_field( - name="๐Ÿ‘ค User", - value=f"{user.mention}\n`{user}`", - inline=True - ) - - embed.add_field( - name="๐Ÿ†” ID", - value=f"`{user.id}`", - inline=True - ) - - embed.add_field( - name="๐Ÿ“… Account erstellt", - value=f"", - inline=True - ) - - if ban_info and ban_info.reason: - embed.add_field( - name="๐Ÿ“ Grund", - value=ban_info.reason[:1000], - inline=False - ) - - embed.set_author(name=user.display_name, icon_url=user.display_avatar.url) - embed.set_footer(text=f"User ID: {user.id}") - - await self.send_log(guild.id, embed, "moderation") - - except Exception as e: - logger.error(f"Error in on_member_ban: {e}") - self._stats['errors'] += 1 - - @commands.Cog.listener() - async def on_member_unban(self, guild: discord.Guild, user: discord.User): - """Member Unban Logging""" - try: - self._stats['events_processed'] += 1 - - embed = discord.Embed( - title="๐Ÿ”“ Member entbannt", - color=discord.Color.green(), - timestamp=datetime.utcnow() - ) - - embed.add_field( - name="๐Ÿ‘ค User", - value=f"{user.mention}\n`{user}`", - inline=True - ) - - embed.add_field( - name="๐Ÿ†” ID", - value=f"`{user.id}`", - inline=True - ) - - embed.add_field( - name="๐Ÿ“… Account erstellt", - value=f"", - inline=True - ) - - embed.set_author(name=user.display_name, icon_url=user.display_avatar.url) - embed.set_footer(text=f"User ID: {user.id}") - - await self.send_log(guild.id, embed, "moderation") - - except Exception as e: - logger.error(f"Error in on_member_unban: {e}") - self._stats['errors'] += 1 - - # ============================================================================= - # INVITE EVENTS - # ============================================================================= - - @commands.Cog.listener() - async def on_invite_create(self, invite: discord.Invite): - """Invite Creation Logging""" - try: - self._stats['events_processed'] += 1 - - embed = discord.Embed( - title="๐Ÿ”— Invite erstellt", - color=discord.Color.blue(), - timestamp=datetime.utcnow() - ) - - embed.add_field( - name="๐Ÿ”— Invite Code", - value=f"`{invite.code}`", - inline=True - ) - - embed.add_field( - name="๐Ÿ“ Channel", - value=invite.channel.mention if invite.channel else "Unbekannt", - inline=True - ) - - if invite.inviter: - embed.add_field( - name="๐Ÿ‘ค Ersteller", - value=f"{invite.inviter.mention}\n`{invite.inviter}`", - inline=True - ) - - # Invite Settings - settings = [] - if invite.max_uses: - settings.append(f"Max. Nutzungen: {invite.max_uses}") - else: - settings.append("Max. Nutzungen: โˆž") - - if invite.max_age: - settings.append(f"Ablauf: ") - else: - settings.append("Ablauf: Nie") - - if invite.temporary: - settings.append("Temporรคr: Ja") - - if settings: - embed.add_field( - name="โš™๏ธ Einstellungen", - value="\n".join(settings), - inline=False - ) - - if invite.inviter: - embed.set_author(name=invite.inviter.display_name, icon_url=invite.inviter.display_avatar.url) - - embed.set_footer(text=f"Invite Code: {invite.code}") - await self.send_log(invite.guild.id, embed, "general") - - except Exception as e: - logger.error(f"Error in on_invite_create: {e}") - self._stats['errors'] += 1 - - @commands.Cog.listener() - async def on_invite_delete(self, invite: discord.Invite): - """Invite Deletion Logging""" - try: - self._stats['events_processed'] += 1 - - embed = discord.Embed( - title="๐Ÿ—‘๏ธ Invite gelรถscht", - color=discord.Color.red(), - timestamp=datetime.utcnow() - ) - - embed.add_field( - name="๐Ÿ”— Invite Code", - value=f"`{invite.code}`", - inline=True - ) - - embed.add_field( - name="๐Ÿ“ Channel", - value=invite.channel.mention if invite.channel else "Unbekannt", - inline=True - ) - - if invite.uses is not None: - embed.add_field( - name="๐Ÿ“Š Verwendet", - value=f"{invite.uses} mal", - inline=True - ) - - embed.set_footer(text=f"Invite Code: {invite.code}") - await self.send_log(invite.guild.id, embed, "general") - - except Exception as e: - logger.error(f"Error in on_invite_delete: {e}") - self._stats['errors'] += 1 - -def setup(bot): - bot.add_cog(LoggingCog(bot)) \ No newline at end of file diff --git a/src/cogs/Servermanament/stats.py b/src/cogs/Servermanament/stats.py deleted file mode 100644 index 99c35a6..0000000 --- a/src/cogs/Servermanament/stats.py +++ /dev/null @@ -1,598 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import discord -from discord.ext import commands, tasks -from discord import SlashCommandGroup -import logging -from typing import Optional -from DevTools import StatsDB -import asyncio -from datetime import datetime, timedelta -import math - - -logger = logging.getLogger(__name__) - - -class EnhancedStatsCog(commands.Cog): - """ - Enhanced Discord Cog for tracking user statistics with global level system. - Provides comprehensive tracking of messages, voice activity, and user progression. - """ - - def __init__(self, bot: commands.Bot): - self.bot = bot - self.db = StatsDB() - self.cleanup_task.start() - logger.info("Enhanced StatsCog initialized") - - stats = SlashCommandGroup("stats", "Statistiken") - - def cog_unload(self): - """Called when the cog is unloaded.""" - self.cleanup_task.cancel() - self.db.close() - logger.info("Enhanced StatsCog unloaded") - - @tasks.loop(hours=24) - async def cleanup_task(self): - """Daily cleanup of old data.""" - await self.db.cleanup_old_data(days=90) - - @cleanup_task.before_loop - async def before_cleanup(self): - await self.bot.wait_until_ready() - - @commands.Cog.listener() - async def on_ready(self): - """Called when the bot is ready and connected to Discord.""" - logger.info(f"Enhanced StatsCog ready - Bot connected as {self.bot.user}") - - @commands.Cog.listener() - async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, - after: discord.VoiceState): - """Track voice channel activity with enhanced features.""" - if member.bot: - return - - try: - user_id = member.id - guild_id = member.guild.id - - # User left a voice channel - if before.channel and not after.channel: - await self.db.end_voice_session(user_id, before.channel.id) - logger.debug(f"User {member.display_name} left voice channel {before.channel.name}") - - # User joined a voice channel - elif not before.channel and after.channel: - await self.db.start_voice_session(user_id, guild_id, after.channel.id) - logger.debug(f"User {member.display_name} joined voice channel {after.channel.name}") - - # User switched voice channels - elif before.channel and after.channel and before.channel.id != after.channel.id: - await self.db.end_voice_session(user_id, before.channel.id) - await self.db.start_voice_session(user_id, guild_id, after.channel.id) - logger.debug(f"User {member.display_name} switched from {before.channel.name} to {after.channel.name}") - - except Exception as e: - logger.error(f"Error handling voice state update for {member.display_name}: {e}") - - @commands.Cog.listener() - async def on_message(self, message: discord.Message): - """Track messages with enhanced analysis.""" - if message.author.bot or not message.guild: - return - - try: - # Analyze message content - word_count = len(message.content.split()) if message.content else 0 - has_attachment = len(message.attachments) > 0 - message_type = 'text' - - if message.attachments: - message_type = 'attachment' - elif message.embeds: - message_type = 'embed' - elif message.stickers: - message_type = 'sticker' - - await self.db.log_message( - user_id=message.author.id, - guild_id=message.guild.id, - channel_id=message.channel.id, - message_id=message.id, - word_count=word_count, - has_attachment=has_attachment, - message_type=message_type - ) - - logger.debug(f"Logged enhanced message {message.id} from {message.author.display_name}") - - except Exception as e: - logger.error(f"Error logging enhanced message from {message.author.display_name}: {e}") - - @stats.command( - name="statsistics", - description="Zeige deine Aktivitรคtsstatistiken an" - ) - async def stats_command( - self, - ctx: discord.ApplicationContext, - zeitraum: discord.Option( - str, - description="Zeitraum fรผr die Statistiken", - choices=["24h", "7d", "30d"], - required=False, - default="24h" - ), - user: discord.Option( - discord.Member, - description="Statistiken eines anderen Users anzeigen (optional)", - required=False - ) - ): - """Enhanced stats command with more detailed information.""" - await ctx.defer() - - try: - target_user = user if user else ctx.author - time_periods = { - "24h": (24, "24 Stunden"), - "7d": (24 * 7, "7 Tagen"), - "30d": (24 * 30, "30 Tagen") - } - - hours, period_name = time_periods[zeitraum] - - # Get regular stats - message_count, voice_minutes = await self.db.get_user_stats( - target_user.id, hours, ctx.guild.id - ) - - # Get global user info - global_info = await self.db.get_global_user_info(target_user.id) - - # Format voice time - voice_hours = int(voice_minutes // 60) - voice_mins = int(voice_minutes % 60) - voice_time_str = f"{voice_hours}h {voice_mins}m" if voice_hours > 0 else f"{voice_mins}m" - - # Create main embed - embed = discord.Embed( - title=f"๐Ÿ“Š {'Deine' if target_user == ctx.author else f'{target_user.display_name}s'} Statistiken", - description=f"Aktivitรคt der letzten {period_name}", - color=discord.Color.blue() - ) - - # Local server stats - embed.add_field( - name="๐Ÿ“… Server Aktivitรคt", - value=f"๐Ÿ’ฌ **{message_count}** Nachrichten\n๐ŸŽค **{voice_time_str}** Voice-Zeit", - inline=True - ) - - # Global stats if available - if global_info: - level = global_info['level'] - xp_progress = global_info['xp_progress'] - xp_needed = global_info['xp_needed'] - progress_bar = self._create_progress_bar(xp_progress, xp_needed) - - embed.add_field( - name="๐ŸŒ Global Level", - value=f"**Level {level}** {self._get_level_emoji(level)}\n{progress_bar}\n`{int(xp_progress)}/{int(xp_needed)} XP`", - inline=True - ) - - # Global totals - total_voice_hours = int(global_info['total_voice_minutes'] // 60) - embed.add_field( - name="๐Ÿ† Global Totals", - value=f"๐Ÿ“จ **{global_info['total_messages']:,}** Nachrichten\n" - f"๐ŸŽค **{total_voice_hours:,}** Stunden Voice\n" - f"๐Ÿ”ฅ **{global_info['daily_streak']}** Tage Streak", - inline=True - ) - - embed.set_thumbnail(url=target_user.display_avatar.url) - embed.set_footer(text=f"Angefragt von {ctx.author.display_name}") - - await ctx.followup.send(embed=embed) - - except Exception as e: - logger.error(f"Error executing enhanced stats command: {e}") - error_embed = discord.Embed( - title="โŒ Fehler", - description="Es gab einen Fehler beim Abrufen der Statistiken.", - color=discord.Color.red() - ) - await ctx.followup.send(embed=error_embed, ephemeral=True) - - @stats.command( - name="globalstats", - description="Zeige deine globalen Level-Statistiken รผber alle Server an" - ) - async def global_stats_command( - self, - ctx: discord.ApplicationContext, - user: discord.Option( - discord.Member, - description="Global Stats eines anderen Users anzeigen", - required=False - ) - ): - """Show detailed global statistics and achievements.""" - await ctx.defer() - - try: - target_user = user if user else ctx.author - global_info = await self.db.get_global_user_info(target_user.id) - - if not global_info: - embed = discord.Embed( - title="๐Ÿ“Š Keine Daten", - description=f"{'Du hast' if target_user == ctx.author else f'{target_user.display_name} hat'} noch keine globalen Statistiken.", - color=discord.Color.orange() - ) - await ctx.followup.send(embed=embed) - return - - level = global_info['level'] - xp = global_info['xp'] - xp_progress = global_info['xp_progress'] - xp_needed = global_info['xp_needed'] - - # Create embed - embed = discord.Embed( - title=f"๐ŸŒ {'Deine' if target_user == ctx.author else f'{target_user.display_name}s'} Globalen Stats", - description=f"Level-System รผber alle Server", - color=self._get_level_color(level) - ) - - # Level info - progress_bar = self._create_progress_bar(xp_progress, xp_needed) - level_emoji = self._get_level_emoji(level) - - embed.add_field( - name=f"{level_emoji} Level & XP", - value=f"**Level {level}**\n{progress_bar}\n`{int(xp_progress):,} / {int(xp_needed):,} XP`\n`Total: {int(xp):,} XP`", - inline=False - ) - - # Activity stats - total_voice_hours = int(global_info['total_voice_minutes'] // 60) - days_since_joined = (datetime.now() - datetime.fromisoformat(global_info['first_seen'])).days + 1 - avg_messages_per_day = global_info['total_messages'] / days_since_joined - - embed.add_field( - name="๐Ÿ“ˆ Aktivitรคts-Statistiken", - value=f"๐Ÿ“จ **{global_info['total_messages']:,}** Nachrichten gesamt\n" - f"๐ŸŽค **{total_voice_hours:,}** Stunden in Voice\n" - f"๐Ÿข **{global_info['total_servers']}** Server aktiv\n" - f"๐Ÿ“Š **{avg_messages_per_day:.1f}** Nachrichten/Tag", - inline=True - ) - - # Streak info - embed.add_field( - name="๐Ÿ”ฅ Streak Statistiken", - value=f"๐Ÿ”ฅ **{global_info['daily_streak']}** Tage aktuell\n" - f"๐Ÿ† **{global_info['best_streak']}** Tage Rekord\n" - f"๐Ÿ“… Dabei seit **{days_since_joined}** Tagen", - inline=True - ) - - # Recent achievements - achievements = global_info['achievements'][-3:] # Last 3 achievements - if achievements: - achievement_text = "\n".join( - [f"{ach.get('icon', '๐Ÿ†')} {ach.get('name', 'Unknown')}" for ach in achievements]) - embed.add_field( - name="๐Ÿ† Neueste Erfolge", - value=achievement_text, - inline=True - ) - - embed.set_thumbnail(url=target_user.display_avatar.url) - embed.set_footer(text=f"Angefragt von {ctx.author.display_name} โ€ข Globales Level-System") - - await ctx.followup.send(embed=embed) - - except Exception as e: - logger.error(f"Error executing global stats command: {e}") - error_embed = discord.Embed( - title="โŒ Fehler", - description="Es gab einen Fehler beim Abrufen der globalen Statistiken.", - color=discord.Color.red() - ) - await ctx.followup.send(embed=error_embed, ephemeral=True) - - @stats.command( - name="leaderboard", - description="Zeige die Top-User Rangliste an" - ) - async def leaderboard_command( - self, - ctx: discord.ApplicationContext, - typ: discord.Option( - str, - description="Art der Rangliste", - choices=["global", "server"], - required=False, - default="server" - ), - limit: discord.Option( - int, - description="Anzahl der angezeigten User (max 20)", - min_value=5, - max_value=20, - required=False, - default=10 - ) - ): - """Show leaderboard for global or server stats.""" - await ctx.defer() - - try: - if typ == "global": - leaderboard_data = await self.db.get_leaderboard(limit) - title = "๐ŸŒ Globale Rangliste" - description = "Top User nach globalem Level & XP" - else: - leaderboard_data = await self.db.get_leaderboard(limit, ctx.guild.id) - title = f"๐Ÿข {ctx.guild.name} Rangliste" - description = "Top User der letzten 30 Tage" - - if not leaderboard_data: - embed = discord.Embed( - title="๐Ÿ“Š Keine Daten", - description="Keine Ranglisten-Daten verfรผgbar.", - color=discord.Color.orange() - ) - await ctx.followup.send(embed=embed) - return - - embed = discord.Embed( - title=title, - description=description, - color=discord.Color.gold() - ) - - leaderboard_text = "" - for i, data in enumerate(leaderboard_data, 1): - try: - user = self.bot.get_user(data[0]) - username = user.display_name if user else "Unbekannter User" - - # Position emoji - if i == 1: - pos_emoji = "๐Ÿฅ‡" - elif i == 2: - pos_emoji = "๐Ÿฅˆ" - elif i == 3: - pos_emoji = "๐Ÿฅ‰" - else: - pos_emoji = f"{i}." - - if typ == "global": - # Global leaderboard format: user_id, level, xp, messages, voice - level, xp, messages, voice = data[1], data[2], data[3], data[4] - level_emoji = self._get_level_emoji(level) - leaderboard_text += f"{pos_emoji} **{username}** {level_emoji}\n" - leaderboard_text += f" Level {level} โ€ข {int(xp):,} XP\n\n" - else: - # Server leaderboard format: user_id, messages, words - messages, words = data[1], data[2] - leaderboard_text += f"{pos_emoji} **{username}**\n" - leaderboard_text += f" {messages:,} Nachrichten โ€ข {words:,} Wรถrter\n\n" - - except Exception as e: - logger.error(f"Error processing leaderboard entry: {e}") - continue - - if leaderboard_text: - embed.description = leaderboard_text - else: - embed.description = "Fehler beim Laden der Rangliste." - - embed.set_footer(text=f"Angefragt von {ctx.author.display_name}") - await ctx.followup.send(embed=embed) - - except Exception as e: - logger.error(f"Error executing leaderboard command: {e}") - error_embed = discord.Embed( - title="โŒ Fehler", - description="Es gab einen Fehler beim Laden der Rangliste.", - color=discord.Color.red() - ) - await ctx.followup.send(embed=error_embed, ephemeral=True) - - @stats.command( - name="achievements", - description="Zeige deine freigeschalteten Erfolge an" - ) - async def achievements_command( - self, - ctx: discord.ApplicationContext, - user: discord.Option( - discord.Member, - description="Erfolge eines anderen Users anzeigen", - required=False - ) - ): - """Show user achievements.""" - await ctx.defer() - - try: - target_user = user if user else ctx.author - global_info = await self.db.get_global_user_info(target_user.id) - - if not global_info: - embed = discord.Embed( - title="๐Ÿ† Keine Erfolge", - description=f"{'Du hast' if target_user == ctx.author else f'{target_user.display_name} hat'} noch keine Erfolge freigeschaltet.", - color=discord.Color.orange() - ) - await ctx.followup.send(embed=embed) - return - - achievements = global_info.get('achievements', []) - - if not achievements: - embed = discord.Embed( - title="๐Ÿ† Noch keine Erfolge", - description=f"{'Du hast' if target_user == ctx.author else f'{target_user.display_name} hat'} noch keine Erfolge freigeschaltet.\nWerde aktiver um Erfolge zu sammeln!", - color=discord.Color.blue() - ) - await ctx.followup.send(embed=embed) - return - - embed = discord.Embed( - title=f"๐Ÿ† {'Deine' if target_user == ctx.author else f'{target_user.display_name}s'} Erfolge", - description=f"**{len(achievements)}** Erfolge freigeschaltet", - color=discord.Color.gold() - ) - - # Group achievements by category or show all - achievement_text = "" - for ach in achievements: - icon = ach.get('icon', '๐Ÿ†') - name = ach.get('name', 'Unbekannter Erfolg') - desc = ach.get('description', 'Keine Beschreibung') - unlocked = ach.get('unlocked_at', 'Unbekannt') - - achievement_text += f"{icon} **{name}**\n" - achievement_text += f" {desc}\n" - if unlocked != 'Unbekannt': - try: - unlock_date = datetime.fromisoformat(unlocked).strftime("%d.%m.%Y") - achievement_text += f" Freigeschaltet: {unlock_date}\n" - except: - pass - achievement_text += "\n" - - # Split into multiple fields if too long - if len(achievement_text) > 1024: - # Split achievements into chunks - chunks = [achievements[i:i + 5] for i in range(0, len(achievements), 5)] - for i, chunk in enumerate(chunks): - field_text = "" - for ach in chunk: - icon = ach.get('icon', '๐Ÿ†') - name = ach.get('name', 'Unbekannter Erfolg') - field_text += f"{icon} **{name}**\n" - - embed.add_field( - name=f"Erfolge {i * 5 + 1}-{min((i + 1) * 5, len(achievements))}", - value=field_text, - inline=True - ) - else: - embed.description = achievement_text - - embed.set_thumbnail(url=target_user.display_avatar.url) - embed.set_footer(text=f"Angefragt von {ctx.author.display_name}") - - await ctx.followup.send(embed=embed) - - except Exception as e: - logger.error(f"Error executing achievements command: {e}") - error_embed = discord.Embed( - title="โŒ Fehler", - description="Es gab einen Fehler beim Laden der Erfolge.", - color=discord.Color.red() - ) - await ctx.followup.send(embed=error_embed, ephemeral=True) - - @stats.command( - name="stats_info", - description="Informationen รผber das erweiterte Statistik-System" - ) - async def stats_info_command(self, ctx: discord.ApplicationContext): - """Provide information about the enhanced statistics system.""" - embed = discord.Embed( - title="โ„น๏ธ Erweitertes Statistik-System", - description="Informationen รผber das Activity-Tracking & Level-System", - color=discord.Color.green() - ) - - embed.add_field( - name="๐Ÿ“Š Was wird getrackt?", - value="โ€ข **Server-spezifisch:** Nachrichten & Voice-Zeit\n" - "โ€ข **Global:** Level, XP, Gesamtaktivitรคt\n" - "โ€ข **Erweitert:** Wortanzahl, Anhรคnge, Streaks", - inline=False - ) - - embed.add_field( - name="๐ŸŒ Globales Level-System", - value="โ€ข **XP-Quellen:** Nachrichten (+1-6 XP), Voice-Chat (+0.5 XP/min)\n" - "โ€ข **Level:** Basiert auf Gesamt-XP รผber alle Server\n" - "โ€ข **Erfolge:** Automatisch fรผr Meilensteine freigeschaltet", - inline=False - ) - - embed.add_field( - name="๐Ÿ† Verfรผgbare Kommandos", - value="โ€ข `/stats` - Server Aktivitรคts-Statistiken\n" - "โ€ข `/globalstats` - Globale Level & Erfolge\n" - "โ€ข `/leaderboard` - Ranglisten (global/server)\n" - "โ€ข `/achievements` - Freigeschaltete Erfolge", - inline=False - ) - - embed.add_field( - name="๐Ÿ”’ Datenschutz", - value="โ€ข Nur Metadaten werden gespeichert (keine Inhalte)\n" - "โ€ข Automatische Bereinigung alter Daten nach 90 Tagen\n" - "โ€ข [Vollstรคndige Datenschutzerklรคrung](https://medicopter117.github.io/ManagerX-Web/privacy.html)", - inline=False - ) - - embed.set_footer(text="Das globale Level-System funktioniert serverรผbergreifend!") - await ctx.respond(embed=embed, ephemeral=True) - - def _create_progress_bar(self, current: float, maximum: float, length: int = 10) -> str: - """Create a visual progress bar.""" - if maximum <= 0: - return "โ–“" * length - - filled = int((current / maximum) * length) - bar = "โ–“" * filled + "โ–‘" * (length - filled) - percentage = (current / maximum) * 100 - return f"{bar} {percentage:.1f}%" - - def _get_level_emoji(self, level: int) -> str: - """Get emoji based on user level.""" - if level >= 100: - return "๐Ÿ‘‘" - elif level >= 50: - return "๐Ÿ†" - elif level >= 25: - return "๐Ÿ…" - elif level >= 10: - return "โญ" - elif level >= 5: - return "๐ŸŒŸ" - else: - return "๐Ÿ”ฐ" - - def _get_level_color(self, level: int) -> discord.Color: - """Get embed color based on user level.""" - if level >= 100: - return discord.Color.gold() - elif level >= 50: - return discord.Color.purple() - elif level >= 25: - return discord.Color.red() - elif level >= 10: - return discord.Color.orange() - elif level >= 5: - return discord.Color.green() - else: - return discord.Color.blue() - - -def setup(bot: commands.Bot): - """Setup function to add the enhanced cog to the bot.""" - bot.add_cog(EnhancedStatsCog(bot)) \ No newline at end of file diff --git a/src/cogs/Servermanament/tempvc.py b/src/cogs/Servermanament/tempvc.py deleted file mode 100644 index 87fb7ec..0000000 --- a/src/cogs/Servermanament/tempvc.py +++ /dev/null @@ -1,612 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -from DevTools import TempVCDatabase -import discord -from discord import slash_command, option, SlashCommandGroup -from discord.ext import commands -from discord.ui import Container -import ezcord - -db = TempVCDatabase() - - -class TempChannelControlView(discord.ui.View): - def __init__(self, channel_owner_id: int, prefix: str = "๐Ÿ”ง"): - super().__init__(timeout=None) - self.channel_owner_id = channel_owner_id - self.prefix = prefix - - # Update button labels with custom prefix - self.rename_button.label = f"{prefix} Umbenennen" - self.limit_button.label = f"{prefix} Limit" - self.lock_button.label = f"{prefix} Sperren" - self.kick_button.label = f"{prefix} Kick" - - @discord.ui.button(label="๐Ÿ”ง Umbenennen", style=discord.ButtonStyle.primary, custom_id="tempvc_rename") - async def rename_button(self, button: discord.ui.Button, interaction: discord.Interaction): - if interaction.user.id != self.channel_owner_id: - container = Container() - container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") - return await interaction.response.send_message(view=container, ephemeral=True) - - modal = RenameChannelModal(interaction.channel) - await interaction.response.send_modal(modal) - - @discord.ui.button(label="๐Ÿ”ง Limit", style=discord.ButtonStyle.primary, custom_id="tempvc_limit") - async def limit_button(self, button: discord.ui.Button, interaction: discord.Interaction): - if interaction.user.id != self.channel_owner_id: - container = Container() - container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") - return await interaction.response.send_message(view=container, ephemeral=True) - - modal = UserLimitModal(interaction.channel) - await interaction.response.send_modal(modal) - - @discord.ui.button(label="๐Ÿ”ง Sperren", style=discord.ButtonStyle.secondary, custom_id="tempvc_lock") - async def lock_button(self, button: discord.ui.Button, interaction: discord.Interaction): - if interaction.user.id != self.channel_owner_id: - container = Container() - container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") - return await interaction.response.send_message(view=container, ephemeral=True) - - channel = interaction.channel - overwrites = channel.overwrites - - # Toggle lock status - is_locked = not overwrites.get(interaction.guild.default_role, discord.PermissionOverwrite()).connect - - if interaction.guild.default_role not in overwrites: - overwrites[interaction.guild.default_role] = discord.PermissionOverwrite() - - overwrites[interaction.guild.default_role].connect = not is_locked - - try: - await channel.edit(overwrites=overwrites) - status = "๐Ÿ”’ gesperrt" if is_locked else "๐Ÿ”“ entsperrt" - button.label = f"{self.prefix} {'Entsperren' if is_locked else 'Sperren'}" - button.style = discord.ButtonStyle.danger if is_locked else discord.ButtonStyle.secondary - - await interaction.response.edit_message(view=self) - - container = Container() - container.add_text(f"Channel wurde {status}!") - await interaction.followup.send(view=container, ephemeral=True) - except discord.Forbidden: - container = Container() - container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen!") - await interaction.response.send_message(view=container, ephemeral=True) - - @discord.ui.button(label="๐Ÿ”ง Kick", style=discord.ButtonStyle.danger, custom_id="tempvc_kick") - async def kick_button(self, button: discord.ui.Button, interaction: discord.Interaction): - if interaction.user.id != self.channel_owner_id: - container = Container() - container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") - return await interaction.response.send_message(view=container, ephemeral=True) - - modal = KickUserModal(interaction.channel) - await interaction.response.send_modal(modal) - - -class RenameChannelModal(discord.ui.Modal): - def __init__(self, channel): - super().__init__(title="Channel umbenennen") - self.channel = channel - - self.name_input = discord.ui.InputText( - label="Neuer Channel-Name", - placeholder="Gib einen neuen Namen ein...", - value=channel.name, - max_length=100, - required=True - ) - self.add_item(self.name_input) - - async def callback(self, interaction: discord.Interaction): - new_name = self.name_input.value.strip() - - # Validate name - if len(new_name) < 1: - container = Container() - container.add_text(f"{emoji_no} Ungรผltiger Name\nName darf nicht leer sein!") - return await interaction.response.send_message(view=container, ephemeral=True) - - # Check for forbidden characters - forbidden_chars = ['@', '#', ':', '`', '```'] - if any(char in new_name for char in forbidden_chars): - container = Container() - container.add_text(f"{emoji_no} Ungรผltige Zeichen\nName enthรคlt ungรผltige Zeichen!") - return await interaction.response.send_message(view=container, ephemeral=True) - - try: - old_name = self.channel.name - await self.channel.edit(name=new_name) - - container = Container() - container.add_text( - f"{emoji_yes} Channel umbenannt\n" - f"**{old_name}** โ†’ **{new_name}**" - ) - await interaction.response.send_message(view=container, ephemeral=True) - - except discord.Forbidden: - container = Container() - container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen zum Umbenennen!") - await interaction.response.send_message(view=container, ephemeral=True) - except discord.HTTPException as e: - container = Container() - container.add_text(f"{emoji_no} Fehler\nFehler beim Umbenennen: {str(e)}") - await interaction.response.send_message(view=container, ephemeral=True) - - -class UserLimitModal(discord.ui.Modal): - def __init__(self, channel): - super().__init__(title="User-Limit setzen") - self.channel = channel - - current_limit = channel.user_limit if channel.user_limit else "Kein Limit" - - self.limit_input = discord.ui.InputText( - label="Neues User-Limit (0 = Kein Limit)", - placeholder="Gib eine Zahl zwischen 0-99 ein...", - value=str(current_limit) if isinstance(current_limit, int) else "0", - max_length=2, - required=True - ) - self.add_item(self.limit_input) - - async def callback(self, interaction: discord.Interaction): - try: - limit = int(self.limit_input.value.strip()) - - if limit < 0 or limit > 99: - container = Container() - container.add_text(f"{emoji_no} Ungรผltiges Limit\nLimit muss zwischen 0 und 99 liegen!") - return await interaction.response.send_message(view=container, ephemeral=True) - - # 0 means no limit in Discord - limit = None if limit == 0 else limit - - await self.channel.edit(user_limit=limit) - - limit_text = "Kein Limit" if limit is None else f"{limit} User" - - container = Container() - container.add_text( - f"{emoji_yes} User-Limit geรคndert\n" - f"Neues Limit: **{limit_text}**" - ) - await interaction.response.send_message(view=container, ephemeral=True) - - except ValueError: - container = Container() - container.add_text(f"{emoji_no} Ungรผltige Eingabe\nBitte gib eine gรผltige Zahl ein!") - await interaction.response.send_message(view=container, ephemeral=True) - except discord.Forbidden: - container = Container() - container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen!") - await interaction.response.send_message(view=container, ephemeral=True) - except discord.HTTPException as e: - container = Container() - container.add_text(f"{emoji_no} Fehler\nFehler beim Setzen des Limits: {str(e)}") - await interaction.response.send_message(view=container, ephemeral=True) - - -class KickUserModal(discord.ui.Modal): - def __init__(self, channel): - super().__init__(title="User kicken") - self.channel = channel - - # Create list of current members (except bot and channel owner) - members_list = [] - for member in channel.members: - if not member.bot and db.get_temp_channel_owner(channel.id) != member.id: - members_list.append(f"{member.display_name} ({member.id})") - - members_text = "\n".join(members_list[:10]) # Limit to first 10 for display - if len(members_list) > 10: - members_text += f"\n... und {len(members_list) - 10} weitere" - - self.user_input = discord.ui.InputText( - label="User zum Kicken", - placeholder="@Username oder User-ID...", - style=discord.InputTextStyle.short, - required=True - ) - self.add_item(self.user_input) - - if members_text: - self.info_input = discord.ui.InputText( - label="Aktuelle Mitglieder:", - value=members_text if members_text else "Keine anderen Mitglieder im Channel", - style=discord.InputTextStyle.paragraph, - required=False - ) - self.add_item(self.info_input) - - async def callback(self, interaction: discord.Interaction): - user_input = self.user_input.value.strip() - - # Try to find user by mention, name or ID - target_user = None - - # Check if it's a mention - if user_input.startswith('<@') and user_input.endswith('>'): - user_id = int(user_input[2:-1].replace('!', '')) - target_user = interaction.guild.get_member(user_id) - else: - # Try by ID first - try: - user_id = int(user_input) - target_user = interaction.guild.get_member(user_id) - except ValueError: - # Try by username/display name - for member in self.channel.members: - if (member.display_name.lower() == user_input.lower() or - member.name.lower() == user_input.lower()): - target_user = member - break - - if not target_user: - container = Container() - container.add_text(f"{emoji_no} Fehler\nUser nicht gefunden!") - return await interaction.response.send_message(view=container, ephemeral=True) - - if target_user not in self.channel.members: - container = Container() - container.add_text(f"{emoji_no} Fehler\nUser ist nicht in diesem Channel!") - return await interaction.response.send_message(view=container, ephemeral=True) - - if target_user.id == db.get_temp_channel_owner(self.channel.id): - container = Container() - container.add_text(f"{emoji_no} Fehler\nDu kannst dich nicht selbst kicken!") - return await interaction.response.send_message(view=container, ephemeral=True) - - if target_user.bot: - container = Container() - container.add_text(f"{emoji_no} Fehler\nBots kรถnnen nicht gekickt werden!") - return await interaction.response.send_message(view=container, ephemeral=True) - - try: - await target_user.move_to(None) # Disconnect from voice - - container = Container() - container.add_text( - f"{emoji_yes} User gekickt\n" - f"**{target_user.display_name}** wurde aus dem Channel gekickt." - ) - await interaction.response.send_message(view=container, ephemeral=True) - - except discord.Forbidden: - container = Container() - container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen zum Kicken!") - await interaction.response.send_message(view=container, ephemeral=True) - except discord.HTTPException as e: - container = Container() - container.add_text(f"{emoji_no} Fehler\nFehler beim Kicken: {str(e)}") - await interaction.response.send_message(view=container, ephemeral=True) - - -class TempVC(ezcord.Cog): - def __init__(self, bot): - self.bot = bot - - tempvc = SlashCommandGroup("tempvc", "Verwalte temporรคre Voice-Channel Systeme") - - @tempvc.command(name="create", description="Erstelle ein VC-Erstellungssystem") - @option("creator_channel", description="Channel, den Mitglieder betreten, um ihren VC zu erstellen", - channel_types=[discord.ChannelType.voice]) - @option("category", description="Kategorie, in der die Temp-Channels erstellt werden", - channel_types=[discord.ChannelType.category]) - async def tempvc_create(self, ctx: discord.ApplicationContext, creator_channel: discord.VoiceChannel, - category: discord.CategoryChannel): - if not ctx.author.guild_permissions.administrator: - container = Container() - container.add_text( - f"{emoji_no} Keine Berechtigung\n" - "Du brauchst Administratorrechte." - ) - return await ctx.respond(view=container, ephemeral=True) - - try: - db.set_tempvc_settings(ctx.guild.id, creator_channel.id, category.id) - - container = Container() - container.add_text( - f"{emoji_yes} Temp-VC System aktiviert\n" - "Das temporรคre Voice-Channel System wurde erfolgreich eingerichtet!" - ) - container.add_separator() - container.add_text( - f"**๐ŸŽค Ersteller-Channel:** {creator_channel.mention}\n" - f"**๐Ÿ“ Kategorie:** {category.mention}\n" - "**โ„น๏ธ Information:** Mitglieder kรถnnen nun den Ersteller-Channel betreten, um automatisch einen eigenen temporรคren Voice-Channel zu erhalten." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - except Exception as e: - container = Container() - container.add_text( - f"{emoji_no} Fehler beim Erstellen\n" - f"```{str(e)}```" - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - - @tempvc.command(name="remove", description="Entferne das VC-Erstellungssystem") - async def tempvc_remove(self, ctx: discord.ApplicationContext): - if not ctx.author.guild_permissions.administrator: - container = Container() - container.add_text( - f"{emoji_no} Keine Berechtigung\n" - "Du brauchst Administratorrechte." - ) - view = discord.ui.View(container, timeout=None) - return await ctx.respond(view=view, ephemeral=True) - - try: - settings = db.get_tempvc_settings(ctx.guild.id) - if not settings: - container = Container() - container.add_text( - f"{emoji_no} Kein System aktiv\n" - "Es ist derzeit kein Temp-VC System auf diesem Server aktiv." - ) - view = discord.ui.View(container, timeout=None) - return await ctx.respond(view=view, ephemeral=True) - - db.remove_tempvc_settings(ctx.guild.id) - - container = Container() - container.add_text( - f"{emoji_yes} System deaktiviert\n" - "Das Temp-VC System wurde erfolgreich deaktiviert!" - ) - container.add_separator() - container.add_text( - "**โ„น๏ธ Information:** Bestehende temporรคre Channels bleiben bestehen, aber es werden keine neuen mehr erstellt." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - except Exception as e: - container = Container() - container.add_text( - f"{emoji_no} Fehler beim Entfernen\n" - f"```{str(e)}```" - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - - @tempvc.command(name="settings", description="Zeige die aktuellen Temp-VC Einstellungen") - async def tempvc_settings(self, ctx: discord.ApplicationContext): - if not ctx.author.guild_permissions.administrator: - container = Container() - container.add_text( - f"{emoji_no} Keine Berechtigung\n" - "Du brauchst Administratorrechte." - ) - view = discord.ui.View(container, timeout=None) - return await ctx.respond(view=view, ephemeral=True) - - settings = db.get_tempvc_settings(ctx.guild.id) - if not settings: - container = Container() - container.add_text( - f"{emoji_no} Kein System aktiv\n" - "Es ist derzeit kein Temp-VC System auf diesem Server aktiv." - ) - container.add_separator() - container.add_text( - "**๐Ÿ’ก Tipp:** Verwende `/tempvc create` um ein Temp-VC System einzurichten." - ) - view = discord.ui.View(container, timeout=None) - return await ctx.respond(view=view, ephemeral=True) - - creator_channel_id, category_id, auto_delete_time = settings - creator_channel = ctx.guild.get_channel(creator_channel_id) - category = ctx.guild.get_channel(category_id) - - container = Container() - container.add_text("๐ŸŽ›๏ธ **Temp-VC Einstellungen**\nAktuelle Konfiguration des temporรคren Voice-Channel Systems") - container.add_separator() - - container.add_text( - f"**๐ŸŽค Ersteller-Channel:**\n" - f"{creator_channel.mention if creator_channel else f'{emoji_no} Channel nicht gefunden (ID: {creator_channel_id})'}" - ) - container.add_separator() - - container.add_text( - f"**๐Ÿ“ Kategorie:**\n" - f"{category.mention if category else f'{emoji_no} Kategorie nicht gefunden (ID: {category_id})'}" - ) - container.add_separator() - - container.add_text(f"**โฐ Auto-Lรถschzeit:**\n{auto_delete_time} Minuten") - container.add_separator() - - # UI Settings - ui_settings = db.get_ui_settings(ctx.guild.id) - if ui_settings: - ui_enabled, ui_prefix = ui_settings - container.add_text( - f"**๐Ÿ–ฅ๏ธ Control-UI:**\n" - f"{'โœ… Aktiviert' if ui_enabled else 'โŒ Deaktiviert'}" - ) - if ui_enabled: - container.add_separator() - container.add_text(f"**๐Ÿท๏ธ UI-Prefix:**\n{ui_prefix}") - else: - container.add_text("**๐Ÿ–ฅ๏ธ Control-UI:**\nโŒ Deaktiviert") - - container.add_separator() - container.add_text( - f"**โ„น๏ธ Status:**\n" - f"{emoji_yes + ' System aktiv' if creator_channel and category else emoji_no + ' Fehlerhafte Konfiguration'}" - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - - @tempvc.command(name="ui", description="Konfiguriere das Control-UI fรผr Temp-Channels") - @option("enabled", description="Soll das UI aktiviert sein?", choices=[ - discord.OptionChoice(name="Aktiviert", value="true"), - discord.OptionChoice(name="Deaktiviert", value="false") - ]) - @option("prefix", description="Prefix fรผr UI-Buttons (Emoji oder Text)", required=False, default="๐Ÿ”ง") - async def tempvc_ui(self, ctx: discord.ApplicationContext, enabled: str, prefix: str = "๐Ÿ”ง"): - if not ctx.author.guild_permissions.administrator: - container = Container() - container.add_text( - f"{emoji_no} Keine Berechtigung\n" - "Du brauchst Administratorrechte." - ) - return await ctx.respond(view=container, ephemeral=True) - - # Check if TempVC system exists - settings = db.get_tempvc_settings(ctx.guild.id) - if not settings: - container = Container() - container.add_text( - f"{emoji_no} Kein System aktiv\n" - "Du musst zuerst ein Temp-VC System erstellen!" - ) - container.add_separator() - container.add_text( - "**๐Ÿ’ก Tipp:** Verwende `/tempvc create` um ein Temp-VC System einzurichten." - ) - view = discord.ui.View(container, timeout=None) - return await ctx.respond(view=view, ephemeral=True) - - ui_enabled = enabled == "true" - - # Validate prefix - if len(prefix) > 10: - container = Container() - container.add_text(f"{emoji_no} Ungรผltiger Prefix\nPrefix darf maximal 10 Zeichen lang sein!") - return await ctx.respond(view=container, ephemeral=True) - - try: - db.set_ui_settings(ctx.guild.id, ui_enabled, prefix) - - container = Container() - container.add_text(f"{emoji_yes} UI-Einstellungen gespeichert") - container.add_separator() - container.add_text( - f"**๐Ÿ–ฅ๏ธ Control-UI:** {'โœ… Aktiviert' if ui_enabled else 'โŒ Deaktiviert'}" - ) - if ui_enabled: - container.add_separator() - container.add_text(f"**๐Ÿท๏ธ Prefix:** {prefix}") - container.add_separator() - container.add_text( - "**โ„น๏ธ Information:** Das Control-UI wird nun in neu erstellten Temp-Channels angezeigt." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - - except Exception as e: - container = Container() - container.add_text( - f"{emoji_no} Fehler beim Speichern\n" - f"```{str(e)}```" - ) - await ctx.respond(view=container, ephemeral=True) - - @commands.Cog.listener() - async def on_voice_state_update(self, member, before, after): - try: - if after.channel: - await self.handle_creator_channel_join(member, after.channel) - if before.channel: - await self.handle_channel_leave(before.channel) - except Exception as e: - print(f"Error in voice state update: {e}") - - async def handle_creator_channel_join(self, member: discord.Member, channel: discord.VoiceChannel): - settings = db.get_tempvc_settings(member.guild.id) - if not settings: - return - - creator_channel_id, category_id, auto_delete_time = settings - - if channel.id != creator_channel_id: - return - - guild = member.guild - category = discord.utils.get(guild.categories, id=category_id) - if not category: - print(f"Category with ID {category_id} not found in guild {guild.id}") - return - - overwrites = { - guild.default_role: discord.PermissionOverwrite(view_channel=False), - member: discord.PermissionOverwrite( - view_channel=True, - connect=True, - manage_permissions=True, - move_members=True - ) - } - - try: - temp_channel = await guild.create_voice_channel( - name=f"๐Ÿ”Š {member.display_name}'s Raum", - category=category, - overwrites=overwrites - ) - db.add_temp_channel(temp_channel.id, guild.id, member.id) - await member.move_to(temp_channel) - - # Check if UI is enabled and send control panel - ui_settings = db.get_ui_settings(guild.id) - if ui_settings and ui_settings[0]: # UI enabled - ui_enabled, ui_prefix = ui_settings - - container = Container() - container.add_text( - f"## ๐ŸŽ›๏ธ **Channel-Kontrolle**\n" - f"**{member.display_name}**, du bist der Besitzer dieses Channels!\n" - "Verwende die Buttons unten, um deinen Channel zu verwalten." - ) - container.add_separator() - container.add_text( - "**๐Ÿ”ง Verfรผgbare Aktionen:**\n" - "โ€ข **Umbenennen** - ร„ndere den Channel-Namen\n" - "โ€ข **Limit** - Setze ein User-Limit\n" - "โ€ข **Sperren** - Sperre/Entsperre den Channel\n" - "โ€ข **Kick** - Kicke User aus dem Channel" - ) - container.add_separator() - container.add_text("Diese Buttons funktionieren nur fรผr den Channel-Besitzer.") - - control_view = TempChannelControlView(member.id, ui_prefix) - view = discord.ui.View(container, timeout=None) - await temp_channel.send(view=view) - await temp_channel.send(view=control_view) - - except discord.Forbidden: - print(f"Missing permissions to create voice channel in guild {guild.id}") - except discord.HTTPException as e: - print(f"HTTP error when creating voice channel: {e}") - except Exception as e: - print(f"Unexpected error when creating temp channel: {e}") - - async def handle_channel_leave(self, channel: discord.VoiceChannel): - if len(channel.members) > 0: - return - - if not db.is_temp_channel(channel.id): - return - - try: - db.remove_temp_channel(channel.id) - await channel.delete(reason="Temp channel cleanup - channel empty") - - except discord.Forbidden: - print(f"Missing permissions to delete channel {channel.id}") - except discord.NotFound: - db.remove_temp_channel(channel.id) - except Exception as e: - print(f"Error deleting temp channel {channel.id}: {e}") - - -def setup(bot): - bot.add_cog(TempVC(bot)) \ No newline at end of file diff --git a/src/cogs/Servermanament/welcome.py b/src/cogs/Servermanament/welcome.py deleted file mode 100644 index cc9fb69..0000000 --- a/src/cogs/Servermanament/welcome.py +++ /dev/null @@ -1,1467 +0,0 @@ -""" -Welcome System Cog -================== - -Umfassendes Welcome System mit Embed-Support, Auto-Roles, -DM-Nachrichten und Statistiken. -""" - -import discord -from discord.ext import commands -from DevTools import WelcomeDatabase -import asyncio -import json -import io -import logging -from typing import Optional, Dict, Any -import aiosqlite -from datetime import datetime -import ezcord -from discord.ui import Container - - -# Logger Setup -logger = logging.getLogger(__name__) - - -class WelcomeSystem(ezcord.Cog): - """ - Welcome System fรผr Discord Server. - - Bietet umfassende Willkommensnachrichten mit Embed-Support, - automatischen Rollen, privaten Nachrichten und Statistiken. - - Parameters - ---------- - bot : ezcord.Bot - Die Bot-Instanz - - Attributes - ---------- - bot : ezcord.Bot - Die Bot-Instanz - db : WelcomeDatabase - Datenbank-Handler fรผr Welcome-Einstellungen - _settings_cache : dict - Cache fรผr Server-Einstellungen - _cache_timeout : int - Cache-Timeout in Sekunden (Standard: 300) - _rate_limit_cache : dict - Rate-Limiting Cache fรผr Welcome-Messages - """ - - def __init__(self, bot): - """ - Initialisiert das Welcome System. - - Parameters - ---------- - bot : ezcord.Bot - Die Bot-Instanz - """ - self.bot = bot - self.db = WelcomeDatabase() - # Cache fรผr bessere Performance - self._settings_cache = {} - self._cache_timeout = 300 # 5 Minuten Cache - self._rate_limit_cache = {} # Rate Limiting - - async def get_cached_settings(self, guild_id: int): - """ - Holt Einstellungen mit Cache-Unterstรผtzung. - - Parameters - ---------- - guild_id : int - Discord Server ID - - Returns - ------- - dict or None - Server-Einstellungen aus Cache oder Datenbank - - Notes - ----- - Cache wird nach 5 Minuten automatisch invalidiert. - """ - now = asyncio.get_event_loop().time() - - if guild_id in self._settings_cache: - cached_data, timestamp = self._settings_cache[guild_id] - if now - timestamp < self._cache_timeout: - return cached_data - - # Aus Datenbank laden - settings = await self.db.get_welcome_settings(guild_id) - if settings: - self._settings_cache[guild_id] = (settings, now) - return settings - - def invalidate_cache(self, guild_id: int): - """ - Invalidiert Cache fรผr einen Server. - - Parameters - ---------- - guild_id : int - Discord Server ID - - Notes - ----- - Sollte nach jeder Einstellungsรคnderung aufgerufen werden. - """ - if guild_id in self._settings_cache: - del self._settings_cache[guild_id] - - def check_rate_limit(self, guild_id: int) -> bool: - """ - Prรผft Rate Limit fรผr Server. - - Parameters - ---------- - guild_id : int - Discord Server ID - - Returns - ------- - bool - True wenn Rate Limit nicht erreicht, False sonst - - Notes - ----- - Erlaubt maximal eine Welcome Message alle 5 Sekunden pro Server. - """ - now = asyncio.get_event_loop().time() - if guild_id not in self._rate_limit_cache: - self._rate_limit_cache[guild_id] = now - return True - - last_time = self._rate_limit_cache[guild_id] - if now - last_time >= 5: # 5 Sekunden zwischen Welcome Messages - self._rate_limit_cache[guild_id] = now - return True - - return False - - def replace_placeholders(self, text: str, member: discord.Member, guild: discord.Guild) -> str: - """ - Erweiterte Placeholder-Ersetzung mit Rรผckwรคrtskompatibilitรคt. - - Parameters - ---------- - text : str - Text mit Placeholders - member : discord.Member - Discord Member Objekt - guild : discord.Guild - Discord Guild Objekt - - Returns - ------- - str - Text mit ersetzten Placeholders - - Notes - ----- - Unterstรผtzte Placeholder-Kategorien: - - User: %user%, %username%, %mention%, %tag%, %userid% - - Server: %servername%, %server%, %guild%, %serverid%, %membercount% - - Zeit: %joindate%, %jointime%, %createddate%, %createdtime%, %accountage% - - Erweitert: %roles%, %rolecount%, %highestrole%, %avatar% - - Statistiken: %onlinemembers%, %textchannels%, %voicechannels% - - Examples - -------- - >>> text = "Willkommen %mention% auf %servername%!" - >>> replace_placeholders(text, member, guild) - "Willkommen @User auf Mein Server!" - """ - if not text: - return text - - try: - # Basis Placeholder (alte Version) - placeholders = { - '%user%': member.display_name, - '%username%': member.name, - '%mention%': member.mention, - '%tag%': str(member), - '%userid%': str(member.id), - '%servername%': guild.name, - '%serverid%': str(guild.id), - '%membercount%': str(guild.member_count), - '%joindate%': member.joined_at.strftime('%d.%m.%Y') if member.joined_at else 'Unbekannt', - '%createddate%': member.created_at.strftime('%d.%m.%Y'), - '%server%': guild.name, - '%guild%': guild.name, - } - - # Erweiterte Placeholder (neue Version) - try: - # Rolleninformationen - roles = [role.name for role in member.roles if role.name != "@everyone"] - highest_role = member.top_role.name if member.top_role.name != "@everyone" else "Keine" - - # Zeitberechnungen - account_age = (discord.utils.utcnow() - member.created_at).days - - # Online-Member zรคhlen (kann fehlschlagen bei groรŸen Servern) - try: - online_count = sum(1 for m in guild.members if m.status != discord.Status.offline) - except: - online_count = "Unbekannt" - - extended_placeholders = { - # Zeitinformationen - '%jointime%': member.joined_at.strftime('%H:%M') if member.joined_at else 'Unbekannt', - '%createdtime%': member.created_at.strftime('%H:%M'), - '%accountage%': f"{account_age} Tage", - - # Erweiterte Infos - '%discriminator%': member.discriminator if hasattr(member, 'discriminator') else "0000", - '%roles%': ', '.join(roles) if roles else 'Keine', - '%rolecount%': str(len(roles)), - '%highestrole%': highest_role, - '%avatar%': member.display_avatar.url, - '%defaultavatar%': member.default_avatar.url, - - # Server Statistiken - '%onlinemembers%': str(online_count), - '%textchannels%': str(len(guild.text_channels)), - '%voicechannels%': str(len(guild.voice_channels)), - '%categories%': str(len(guild.categories)), - '%emojis%': str(len(guild.emojis)), - } - - placeholders.update(extended_placeholders) - - except Exception as e: - logger.warning(f"Erweiterte Placeholder fehlgeschlagen: {e}") - - except Exception as e: - logger.error(f"Placeholder Fehler: {e}") - return text - - # Placeholder ersetzen - for placeholder, value in placeholders.items(): - text = text.replace(placeholder, str(value)) - - return text - - async def send_welcome_dm(self, member: discord.Member, settings: dict): - """ - Sendet private Willkommensnachricht. - - Parameters - ---------- - member : discord.Member - Neues Mitglied - settings : dict - Server-Einstellungen - - Notes - ----- - Fehler beim DM-Versand werden geloggt aber nicht als Fehler behandelt, - da viele User DMs deaktiviert haben. - """ - try: - if not settings.get('join_dm_enabled'): - return - - dm_message = settings.get('join_dm_message', - 'Willkommen auf **%servername%**! Schรถn, dass du da bist! ๐ŸŽ‰') - - processed_message = self.replace_placeholders(dm_message, member, member.guild) - - await member.send(processed_message) - logger.info(f"Welcome DM an {member} gesendet") - - except discord.Forbidden: - logger.warning(f"Konnte keine DM an {member} senden - DMs deaktiviert") - except Exception as e: - logger.error(f"Fehler beim Senden der Welcome DM: {e}") - - async def assign_auto_role(self, member: discord.Member, settings: dict): - """ - Vergibt automatische Rolle. - - Parameters - ---------- - member : discord.Member - Neues Mitglied - settings : dict - Server-Einstellungen mit auto_role_id - - Notes - ----- - Prรผft automatisch Berechtigungen und Rollen-Hierarchie. - """ - try: - auto_role_id = settings.get('auto_role_id') - if not auto_role_id: - return - - role = member.guild.get_role(auto_role_id) - if not role: - logger.warning(f"Auto-Role {auto_role_id} nicht gefunden in {member.guild.name}") - return - - if role >= member.guild.me.top_role: - logger.warning(f"Auto-Role {role.name} ist hรถher als Bot-Rolle") - return - - await member.add_roles(role, reason="Welcome Auto-Role") - logger.info(f"Auto-Role {role.name} an {member} vergeben") - - except discord.Forbidden: - logger.error(f"Keine Berechtigung fรผr Auto-Role") - except Exception as e: - logger.error(f"Auto-Role Fehler: {e}") - - @commands.Cog.listener() - async def on_member_join(self, member: discord.Member): - """ - Event wird ausgelรถst, wenn ein neuer User dem Server beitritt. - - Parameters - ---------- - member : discord.Member - Neues Mitglied - - Notes - ----- - Fรผhrt folgende Aktionen aus (wenn aktiviert): - 1. Rate Limiting Check - 2. Einstellungen aus Cache/DB laden - 3. Auto-Role vergeben - 4. Welcome Message senden (Channel) - 5. Welcome DM senden - 6. Statistiken aktualisieren - """ - try: - # Rate Limiting prรผfen - if not self.check_rate_limit(member.guild.id): - logger.info(f"Rate Limit aktiv fรผr {member.guild.name}") - return - - settings = await self.get_cached_settings(member.guild.id) - - if not settings or not settings.get('enabled', True): - return - - # Channel validieren - channel_id = settings.get('channel_id') - if not channel_id: - logger.warning(f"Kein Welcome Channel fรผr {member.guild.name} gesetzt") - return - - channel = self.bot.get_channel(channel_id) - if not channel: - logger.error(f"Welcome Channel {channel_id} nicht gefunden") - # Channel aus DB entfernen - await self.db.update_welcome_settings(member.guild.id, channel_id=None) - self.invalidate_cache(member.guild.id) - return - - # Permissions prรผfen - perms = channel.permissions_for(member.guild.me) - if not perms.send_messages: - logger.error(f"Keine Send-Berechtigung in {channel.name}") - return - - # Auto-Role vergeben - await self.assign_auto_role(member, settings) - - # Welcome Message - welcome_message = settings.get('welcome_message', 'Willkommen %mention% auf **%servername%**! ๐ŸŽ‰') - processed_message = self.replace_placeholders(welcome_message, member, member.guild) - - # Embed oder normale Nachricht - if settings.get('embed_enabled', False) and perms.embed_links: - await self.send_embed_welcome(channel, member, settings, processed_message) - else: - msg = await channel.send(processed_message) - await self.handle_auto_delete(msg, settings) - - # Private Nachricht senden - await self.send_welcome_dm(member, settings) - - # Statistiken aktualisieren - if settings.get('welcome_stats_enabled'): - await self.db.update_welcome_stats(member.guild.id, joins=1) - - except Exception as e: - logger.exception(f"Welcome System Fehler fรผr {member}: {e}") - - async def send_embed_welcome(self, channel, member, settings, processed_message): - """ - Sendet Embed Welcome Message. - - Parameters - ---------- - channel : discord.TextChannel - Ziel-Channel - member : discord.Member - Neues Mitglied - settings : dict - Server-Einstellungen - processed_message : str - Verarbeitete Welcome Message (Fallback) - - Notes - ----- - Fallback auf normale Nachricht bei Embed-Fehlern. - """ - try: - embed = discord.Embed() - - # Embed Farbe - color_hex = settings.get('embed_color', '#00ff00') - try: - color = int(color_hex.replace('#', ''), 16) - embed.color = discord.Color(color) - except: - embed.color = discord.Color.green() - - # Embed Titel - embed_title = settings.get('embed_title') - if embed_title: - embed.title = self.replace_placeholders(embed_title, member, member.guild) - - # Embed Beschreibung - embed_description = settings.get('embed_description') - if embed_description: - embed.description = self.replace_placeholders(embed_description, member, member.guild) - else: - embed.description = processed_message - - # Embed Thumbnail - if settings.get('embed_thumbnail', False): - embed.set_thumbnail(url=member.display_avatar.url) - - # Embed Footer - embed_footer = settings.get('embed_footer') - if embed_footer: - embed.set_footer(text=self.replace_placeholders(embed_footer, member, member.guild)) - - # Nachricht senden - content = member.mention if settings.get('ping_user', False) else None - msg = await channel.send(content=content, embed=embed) - - await self.handle_auto_delete(msg, settings) - - except Exception as e: - logger.error(f"Embed Welcome Fehler: {e}") - # Fallback auf normale Nachricht - msg = await channel.send(processed_message) - await self.handle_auto_delete(msg, settings) - - async def handle_auto_delete(self, message, settings): - """ - Behandelt automatisches Lรถschen von Nachrichten. - - Parameters - ---------- - message : discord.Message - Zu lรถschende Nachricht - settings : dict - Server-Einstellungen mit delete_after - - Notes - ----- - Wartet die angegebene Zeit und lรถscht dann die Nachricht. - Fehler beim Lรถschen werden geloggt aber nicht weitergegeben. - """ - try: - delete_after = settings.get('delete_after', 0) - if delete_after > 0: - await asyncio.sleep(delete_after) - try: - await message.delete() - except discord.NotFound: - pass # Message bereits gelรถscht - except discord.Forbidden: - logger.warning("Keine Berechtigung zum Lรถschen der Welcome Message") - except Exception as e: - logger.error(f"Auto-Delete Fehler: {e}") - - # Alle Commands bleiben gleich, aber mit Cache-Invalidierung - welcome = discord.SlashCommandGroup("welcome", "Welcome System Einstellungen") - - @welcome.command(name="channel", description="Setzt den Welcome Channel") - @commands.has_permissions(manage_guild=True) - async def set_welcome_channel(self, ctx, channel: discord.TextChannel): - """ - Setzt den Channel fรผr Welcome Messages. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - channel : discord.TextChannel - Ziel-Channel fรผr Welcome Messages - """ - success = await self.db.update_welcome_settings(ctx.guild.id, channel_id=channel.id) - self.invalidate_cache(ctx.guild.id) - - if success: - container = Container() - container.add_text( - f"{emoji_yes} Welcome Channel gesetzt" - ) - container.add_separator() - container.add_text( - f"Welcome Messages werden nun in {channel.mention} gesendet." - ) - view = discord.ui.View(container, timeout=None) - else: - container = Container() - container.add_text( - f"{emoji_no} Fehler" - ) - container.add_separator() - container.add_text( - "Der Welcome Channel konnte nicht gesetzt werden." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view) - - @welcome.command(name="message", description="Setzt die Welcome Message รผber ein Modal") - @commands.has_permissions(manage_guild=True) - async def set_welcome_message(self, ctx): - """ - ร–ffnet ein Modal zum Setzen der Welcome Message. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - - Notes - ----- - Zeigt ein Modal mit der aktuellen Message als Vorausfรผllung. - Bietet nach dem Speichern eine Vorschau der neuen Message. - """ - - # Aktuelle Einstellungen laden fรผr Vorausfรผllung - current_settings = await self.get_cached_settings(ctx.guild.id) - current_message = current_settings.get('welcome_message', '') if current_settings else '' - - class WelcomeMessageModal(discord.ui.Modal): - """ - Modal fรผr Welcome Message Konfiguration. - - Parameters - ---------- - cog : WelcomeSystem - Parent Cog Instanz - current_msg : str, optional - Aktuelle Message fรผr Vorausfรผllung - """ - - def __init__(self, cog, current_msg=""): - super().__init__(title="Welcome Message konfigurieren") - self.cog = cog - - self.message_input = discord.ui.InputText( - label="Welcome Message", - placeholder="z.B: Willkommen %mention% auf **%servername%**! ๐ŸŽ‰", - style=discord.InputTextStyle.long, - value=current_msg, - max_length=2000, - required=True - ) - self.add_item(self.message_input) - - async def callback(self, interaction: discord.Interaction): - """ - Callback nach Modal-Submit. - - Parameters - ---------- - interaction : discord.Interaction - Modal Interaction - """ - message = self.message_input.value.strip() - - if not message: - embed = discord.Embed( - title="โŒ Fehler", - description="Die Welcome Message darf nicht leer sein.", - color=discord.Color.red() - ) - await interaction.response.send_message(embed=embed, ephemeral=True) - return - - success = await self.cog.db.update_welcome_settings(interaction.guild.id, welcome_message=message) - self.cog.invalidate_cache(interaction.guild.id) - - if success: - # Vorschau erstellen - preview = self.cog.replace_placeholders(message, interaction.user, interaction.guild) - - container = Container() - container.add_text( - "# โœ… Welcome Message gesetzt" - ) - container.add_separator() - container.add_text( - "## ๐Ÿ’ฌ Neue Message\n\n" - f"```{message[:500]}{'...' if len(message) > 500 else ''}```" - ) - container.add_separator() - container.add_text( - "## ๐Ÿ‘€ Vorschau (mit deinen Daten)\n\n" - f"{preview[:500] + ("..." if len(preview) > 500 else "")}\n\n" - "-# ๐Ÿ’ก Tipp: Verwende `/welcome test` fรผr eine vollstรคndige Vorschau oder `/welcome placeholders` fรผr alle verfรผgbaren Optionen." - ) - view = discord.ui.View(container, timeout=None) - else: - container = Container() - container.add_text( - "# โŒ Fehler\nDie Welcome Message konnte nicht gesetzt werden." - ) - view = discord.ui.View(container, timeout=None) - await interaction.response.send_message(view=view) - - modal = WelcomeMessageModal(self, current_message) - await ctx.send_modal(modal) - - @welcome.command(name="toggle", description="Schaltet das Welcome System ein/aus") - @commands.has_permissions(manage_guild=True) - async def toggle_welcome(self, ctx): - """ - Schaltet das Welcome System ein oder aus. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - """ - new_state = await self.db.toggle_welcome(ctx.guild.id) - self.invalidate_cache(ctx.guild.id) - - if new_state is None: - container = Container() - container.add_text( - "# โŒ Fehler\nEs sind noch keine Welcome Einstellungen vorhanden. Setze zuerst einen Channel." - ) - view = discord.ui.View(container, timeout=None) - else: - status = "aktiviert" if new_state else "deaktiviert" - container = Container() - container.add_text( - f"# โœ… Welcome System {status}" - ) - container.add_separator() - container.add_text( - f"Das Welcome System wurde **{status}**." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view) - - @welcome.command(name="embed", description="Aktiviert/Deaktiviert Embed Modus") - @commands.has_permissions(manage_guild=True) - async def toggle_embed(self, ctx, enabled: bool): - """ - Aktiviert oder deaktiviert Embed Welcome Messages. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - enabled : bool - True fรผr Embed-Modus, False fรผr normale Nachrichten - """ - success = await self.db.update_welcome_settings(ctx.guild.id, embed_enabled=enabled) - self.invalidate_cache(ctx.guild.id) - - if success: - status = "aktiviert" if enabled else "deaktiviert" - container = Container( - f"# โœ… Embed Modus {status}" - ) - container.add_separator() - container.add_text( - f"Welcome Messages werden nun {'als Embed' if enabled else 'als normale Nachricht'} gesendet." - ) - view = discord.ui.View(container, timeout=None) - else: - container = Container() - container.add_text( - "# โŒ Fehler\nDer Embed Modus konnte nicht geรคndert werden." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view) - - @welcome.command(name="autorole", description="Setzt eine Rolle die automatisch vergeben wird") - @commands.has_permissions(manage_roles=True) - async def set_auto_role(self, ctx, role: discord.Role = None): - """ - Setzt eine Rolle die bei Join automatisch vergeben wird. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - role : discord.Role, optional - Rolle zum automatischen Vergeben (None zum Entfernen) - - Notes - ----- - Prรผft automatisch die Rollen-Hierarchie. - """ - if role is None: - # Auto-Role entfernen - success = await self.db.update_welcome_settings(ctx.guild.id, auto_role_id=None) - self.invalidate_cache(ctx.guild.id) - - container = Container() - container.add_text( - "# โœ… Auto-Role entfernt" - ) - container.add_separator() - container.add_text( - "Neue Mitglieder erhalten keine automatische Rolle mehr." - ) - view = discord.ui.View(container, timeout=None) - - else: - # Rolle validieren - if role >= ctx.guild.me.top_role: - container = Container() - container.add_text( - "# โŒ Fehler\nDiese Rolle ist hรถher als meine hรถchste Rolle. Ich kann sie nicht vergeben." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view) - return - - success = await self.db.update_welcome_settings(ctx.guild.id, auto_role_id=role.id) - self.invalidate_cache(ctx.guild.id) - - if success: - container = Container() - container.add_text( - "# โœ… Auto-Role gesetzt" - ) - container.add_separator() - container.add_text( - f"Neue Mitglieder erhalten automatisch die Rolle {role.mention}." - ) - view = discord.ui.View(container, timeout=None) - else: - container = Container() - container.add_text( - "# โŒ Fehler\nDie Auto-Role konnte nicht gesetzt werden." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view) - - @welcome.command(name="dm", description="Aktiviert/Konfiguriert private Willkommensnachrichten") - @commands.has_permissions(manage_guild=True) - async def setup_join_dm(self, ctx, enabled: bool, *, message: str = None): - """ - Konfiguriert private Willkommensnachrichten. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - enabled : bool - True zum Aktivieren, False zum Deaktivieren - message : str, optional - Custom DM Message (verwendet Standard wenn nicht angegeben) - """ - settings = {'join_dm_enabled': enabled} - if message and enabled: - settings['join_dm_message'] = message - - success = await self.db.update_welcome_settings(ctx.guild.id, **settings) - self.invalidate_cache(ctx.guild.id) - - if success: - if enabled: - if message: - description = f"Private Welcome Messages aktiviert!\n**Nachricht:** {message[:500]}{'...' if len(message) > 500 else ''}" - else: - description = "Private Welcome Messages aktiviert! (Standard-Nachricht wird verwendet)" - else: - description = "Private Welcome Messages deaktiviert." - - container = Container() - container.add_text( - "# โœ… DM Einstellungen aktualisiert" - ) - container.add_separator() - container.add_text( - f"{description}" - ) - view = discord.ui.View(container, timeout=None) - else: - container = Container() - container.add_text( - "# โŒ Fehler\nDie DM Einstellungen konnten nicht aktualisiert werden." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view) - - @welcome.command(name="template", description="Lรคdt eine Vorlage") - @commands.has_permissions(manage_guild=True) - async def load_template(self, ctx, template_name: str): - """ - Lรคdt eine vordefinierte Vorlage. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - template_name : str - Name der Vorlage (basic, fancy, minimal, detailed) - - Notes - ----- - Verfรผgbare Vorlagen: - - basic: Einfache Text-Nachricht - - fancy: Embed mit Thumbnail und Farbe - - minimal: Minimalistischer Text - - detailed: Detailliertes Embed mit vielen Infos - """ - templates = { - "basic": { - "welcome_message": "Willkommen %mention% auf **%servername%**! ๐ŸŽ‰", - "embed_enabled": False, - "template_name": "basic" - }, - "fancy": { - "welcome_message": None, - "embed_enabled": True, - "embed_title": "Willkommen auf %servername%! ๐ŸŽ‰", - "embed_description": "Hey %user%! Du bist unser **%membercount%.** Mitglied!\n\nViel SpaรŸ auf unserem Server! ๐Ÿš€", - "embed_color": "#ff6b6b", - "embed_thumbnail": True, - "embed_footer": "Beigetreten am %joindate%", - "template_name": "fancy" - }, - "minimal": { - "welcome_message": "%user% ist dem Server beigetreten.", - "embed_enabled": False, - "template_name": "minimal" - }, - "detailed": { - "welcome_message": None, - "embed_enabled": True, - "embed_title": "๐ŸŽŠ Neues Mitglied!", - "embed_description": "**%mention%** ist **%servername%** beigetreten!\n\n๐Ÿ‘ค **Username:** %username%\n๐Ÿ“… **Account erstellt:** %createddate%\n๐Ÿ“Š **Mitglied Nr.:** %membercount%\nโฐ **Beigetreten um:** %jointime%", - "embed_color": "#00d4ff", - "embed_thumbnail": True, - "embed_footer": "%servername% โ€ข %membercount% Mitglieder", - "template_name": "detailed" - } - } - - if template_name not in templates: - available = ", ".join(templates.keys()) - embed = discord.Embed( - title="โŒ Unbekannte Vorlage", - description=f"**Verfรผgbare Vorlagen:** {available}", - color=discord.Color.red() - ) - await ctx.respond(embed=embed) - return - - template = templates[template_name] - success = await self.db.update_welcome_settings(ctx.guild.id, **template) - self.invalidate_cache(ctx.guild.id) - - if success: - embed = discord.Embed( - title=f"โœ… Vorlage '{template_name}' geladen", - description="Die Welcome-Konfiguration wurde aktualisiert.", - color=discord.Color.green() - ) - - # Vorschau anzeigen - if template_name == "basic": - embed.add_field(name="Vorschau", value="Willkommen @User auf **Servername**! ๐ŸŽ‰", inline=False) - elif template_name == "minimal": - embed.add_field(name="Vorschau", value="Username ist dem Server beigetreten.", inline=False) - else: - embed.add_field(name="Typ", value="Embed-Nachricht", inline=False) - else: - embed = discord.Embed( - title="โŒ Fehler", - description="Die Vorlage konnte nicht geladen werden.", - color=discord.Color.red() - ) - - await ctx.respond(embed=embed) - - @welcome.command(name="config", description="Zeigt die aktuelle Konfiguration") - @commands.has_permissions(manage_messages=True) - async def show_config(self, ctx): - """ - Zeigt die aktuelle Welcome Konfiguration. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - - Notes - ----- - Zeigt alle konfigurierten Einstellungen รผbersichtlich an. - """ - settings = await self.get_cached_settings(ctx.guild.id) - - if not settings: - container = Container() - container.add_text( - "# โŒ Keine Konfiguration gefunden\nEs sind noch keine Welcome Einstellungen vorhanden." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view) - return - - channel = self.bot.get_channel(settings.get('channel_id')) if settings.get('channel_id') else None - auto_role = ctx.guild.get_role(settings.get('auto_role_id')) if settings.get('auto_role_id') else None - container = Container() - container.add_text( - "# โš™๏ธ Welcome System Konfiguration" - ) - container.add_separator() - container.add_text( - "## ๐Ÿ“Š Status\n" - f"{'โœ… Aktiviert' if settings.get('enabled') else 'โŒ Deaktiviert'}" - ) - - container.add_text( - "## ๐Ÿ“ข Channel\n" - f"{channel.mention if channel else 'โŒ Nicht gesetzt'}" - ) - - container.add_text( - "## ๐ŸŽจ Embed Modus\n" - f"{'โœ… Aktiviert' if settings.get('embed_enabled') else 'โŒ Deaktiviert'}" - ) - - container.add_text( - "## ๐Ÿท๏ธ Auto-Role\n" - f"{auto_role.mention if auto_role else 'โŒ Rolle nicht gefunden'}" - ) - - if settings.get('join_dm_enabled'): - container.add_text( - "## ๐Ÿ’Œ Private Nachricht\nโœ… Aktiviert" - ) - - if settings.get('template_name'): - container.add_text( - "## ๐Ÿ“‹ Vorlage\n" - f"{settings.get('template_name').title()}" - ) - - message = settings.get('welcome_message', 'Nicht gesetzt') - if len(message) > 100: - message = message[:100] + "..." - container.add_text( - "## ๐Ÿ’ฌ Welcome Message\n" - f"{message}" - ) - - if settings.get('delete_after', 0) > 0: - container.add_text( - "## ๐Ÿ—‘๏ธ Auto-Delete\n" - f"{settings.get('delete_after')} Sekunden" - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view) - - @welcome.command(name="test", description="Testet die Welcome Message") - @commands.has_permissions(manage_messages=True) - async def test_welcome(self, ctx): - """ - Testet die Welcome Message mit dem aktuellen User. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - - Notes - ----- - Simuliert einen Member Join mit den aktuellen Einstellungen. - Zeigt eine Vorschau ohne tatsรคchlich eine Welcome Message zu senden. - """ - settings = await self.get_cached_settings(ctx.guild.id) - - if not settings: - container = Container() - container.add_text( - "# โŒ Fehler\nEs sind noch keine Welcome Einstellungen vorhanden." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - return - - if not settings.get('channel_id'): - container = Container() - container.add_text( - "# โŒ Fehler\nEs ist kein Welcome Channel gesetzt." - ) - view = discord.ui.View(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - return - - # Simuliere Member Join Event - member = ctx.author - welcome_message = settings.get('welcome_message', 'Willkommen %mention% auf **%servername%**! ๐ŸŽ‰') - processed_message = self.replace_placeholders(welcome_message, member, ctx.guild) - - embed = discord.Embed( - title="๐Ÿงช Welcome Message Test", - color=discord.Color.blue() - ) - - if settings.get('embed_enabled'): - embed.add_field( - name="Typ", - value="Embed-Nachricht", - inline=True - ) - - test_embed_title = settings.get('embed_title', 'Kein Titel') - if test_embed_title: - test_embed_title = self.replace_placeholders(test_embed_title, member, ctx.guild) - embed.add_field(name="Embed Titel", value=test_embed_title, inline=False) - - test_embed_desc = settings.get('embed_description', processed_message) - if test_embed_desc: - test_embed_desc = self.replace_placeholders(test_embed_desc, member, ctx.guild) - embed.add_field(name="Embed Beschreibung", value=test_embed_desc[:500] + ("..." if len(test_embed_desc) > 500 else ""), inline=False) - else: - embed.add_field( - name="Typ", - value="Normale Nachricht", - inline=True - ) - embed.add_field( - name="Vorschau", - value=processed_message[:500] + ("..." if len(processed_message) > 500 else ""), - inline=False - ) - - # Zusรคtzliche Infos - if settings.get('auto_role_id'): - auto_role = ctx.guild.get_role(settings.get('auto_role_id')) - embed.add_field( - name="๐Ÿท๏ธ Auto-Role", - value=auto_role.mention if auto_role else "โŒ Rolle nicht gefunden", - inline=True - ) - - if settings.get('join_dm_enabled'): - embed.add_field( - name="๐Ÿ’Œ Private Nachricht", - value="โœ… Wรผrde gesendet werden", - inline=True - ) - - await ctx.respond(embed=embed, ephemeral=True) - - @welcome.command(name="placeholders", description="Zeigt alle verfรผgbaren Placeholder") - async def show_placeholders(self, ctx): - """ - Zeigt alle verfรผgbaren Placeholder. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - - Notes - ----- - Liste aller unterstรผtzten Placeholder mit Beschreibungen. - """ - embed = discord.Embed( - title="๐Ÿ“ Verfรผgbare Placeholder", - description="Diese Placeholder kรถnnen in Welcome Messages verwendet werden:", - color=discord.Color.blue() - ) - - embed.add_field( - name="๐Ÿ‘ค User Informationen", - value=( - "`%user%` - Username (Display Name)\n" - "`%username%` - Echter Username\n" - "`%mention%` - User erwรคhnen (@User)\n" - "`%tag%` - User#1234\n" - "`%userid%` - User ID\n" - "`%discriminator%` - User Discriminator" - ), - inline=False - ) - - embed.add_field( - name="๐Ÿ  Server Informationen", - value=( - "`%servername%` - Servername\n" - "`%server%` - Servername (Alternative)\n" - "`%guild%` - Servername (Alternative)\n" - "`%serverid%` - Server ID\n" - "`%membercount%` - Mitgliederanzahl\n" - "`%onlinemembers%` - Online Mitglieder" - ), - inline=False - ) - - embed.add_field( - name="โฐ Zeit & Datum", - value=( - "`%joindate%` - Beitrittsdatum (DD.MM.YYYY)\n" - "`%jointime%` - Beitrittszeit (HH:MM)\n" - "`%createddate%` - Account Erstellung (DD.MM.YYYY)\n" - "`%createdtime%` - Account Erstellung (HH:MM)\n" - "`%accountage%` - Account Alter in Tagen" - ), - inline=False - ) - - embed.add_field( - name="๐ŸŽญ Erweiterte Informationen", - value=( - "`%roles%` - Alle Rollen (auรŸer @everyone)\n" - "`%rolecount%` - Anzahl der Rollen\n" - "`%highestrole%` - Hรถchste Rolle\n" - "`%avatar%` - Avatar URL\n" - "`%defaultavatar%` - Standard Avatar URL" - ), - inline=False - ) - - embed.add_field( - name="๐Ÿ“Š Server Statistiken", - value=( - "`%textchannels%` - Anzahl Textchannels\n" - "`%voicechannels%` - Anzahl Voicechannels\n" - "`%categories%` - Anzahl Kategorien\n" - "`%emojis%` - Anzahl Emojis" - ), - inline=False - ) - - embed.set_footer(text="Beispiel: Willkommen %mention%! Du bist Mitglied #%membercount% auf %servername%") - - await ctx.respond(embed=embed, ephemeral=True) - - @welcome.command(name="export", description="Exportiert die Welcome Konfiguration") - @commands.has_permissions(administrator=True) - async def export_config(self, ctx): - """ - Exportiert die aktuelle Konfiguration als JSON-Datei. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - - Notes - ----- - Erstellt eine JSON-Datei mit allen Einstellungen. - Sensible Daten (IDs, Timestamps) werden entfernt. - """ - settings = await self.get_cached_settings(ctx.guild.id) - if not settings: - embed = discord.Embed( - title="โŒ Keine Konfiguration zum Exportieren", - description="Es sind noch keine Welcome Einstellungen vorhanden.", - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - return - - try: - # Sensible Daten entfernen - export_data = {k: v for k, v in settings.items() - if k not in ['guild_id', 'created_at', 'updated_at']} - - # JSON Export erstellen - config_json = json.dumps(export_data, indent=2, ensure_ascii=False) - - # Als Datei senden - file_content = f"# Welcome System Export fรผr {ctx.guild.name}\n# Exportiert am {datetime.now().strftime('%d.%m.%Y %H:%M')}\n\n{config_json}" - file = discord.File( - io.StringIO(file_content), - filename=f"welcome_config_{ctx.guild.name.replace(' ', '_')}.json" - ) - - embed = discord.Embed( - title="๐Ÿ“„ Konfiguration exportiert", - description="Die aktuelle Welcome-Konfiguration wurde als Datei exportiert.", - color=discord.Color.green() - ) - - await ctx.respond(embed=embed, file=file, ephemeral=True) - - except Exception as e: - logger.error(f"Export Fehler: {e}") - embed = discord.Embed( - title="โŒ Export fehlgeschlagen", - description="Es ist ein Fehler beim Exportieren aufgetreten.", - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - - @welcome.command(name="stats", description="Zeigt Welcome Statistiken") - @commands.has_permissions(manage_messages=True) - async def show_stats(self, ctx): - """ - Zeigt Welcome Statistiken fรผr den Server. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - - Notes - ----- - Zeigt Statistiken fรผr: - - Heute - - Diese Woche (letzte 7 Tage) - - Gesamt (seit Aktivierung) - """ - try: - await self.db.migrate_database() - - # Statistiken aktivieren falls noch nicht geschehen - settings = await self.get_cached_settings(ctx.guild.id) - if settings and not settings.get('welcome_stats_enabled'): - await self.db.update_welcome_settings(ctx.guild.id, welcome_stats_enabled=True) - self.invalidate_cache(ctx.guild.id) - - # Aktuelle Statistiken aus der DB holen - try: - async with aiosqlite.connect(self.db.db_path) as conn: - # Heute - today = datetime.now().strftime('%Y-%m-%d') - cursor = await conn.execute( - 'SELECT joins, leaves FROM welcome_stats WHERE guild_id = ? AND date = ?', - (ctx.guild.id, today) - ) - today_stats = await cursor.fetchone() - - # Letzte 7 Tage - cursor = await conn.execute(''' - SELECT SUM(joins) as total_joins, SUM(leaves) as total_leaves - FROM welcome_stats - WHERE guild_id = ? AND date >= date('now', '-7 days') - ''', (ctx.guild.id,)) - week_stats = await cursor.fetchone() - - # Gesamt - cursor = await conn.execute(''' - SELECT SUM(joins) as total_joins, SUM(leaves) as total_leaves - FROM welcome_stats - WHERE guild_id = ? - ''', (ctx.guild.id,)) - total_stats = await cursor.fetchone() - - embed = discord.Embed( - title="๐Ÿ“Š Welcome Statistiken", - description=f"Statistiken fรผr **{ctx.guild.name}**", - color=discord.Color.blue() - ) - - # Heute - today_joins = today_stats[0] if today_stats else 0 - today_leaves = today_stats[1] if today_stats else 0 - embed.add_field( - name="๐Ÿ“… Heute", - value=f"๐Ÿ‘‹ **Beigetreten:** {today_joins}\n๐Ÿšช **Verlassen:** {today_leaves}", - inline=True - ) - - # Diese Woche - week_joins = week_stats[0] if week_stats and week_stats[0] else 0 - week_leaves = week_stats[1] if week_stats and week_stats[1] else 0 - embed.add_field( - name="๐Ÿ“… Diese Woche", - value=f"๐Ÿ‘‹ **Beigetreten:** {week_joins}\n๐Ÿšช **Verlassen:** {week_leaves}", - inline=True - ) - - # Gesamt - total_joins = total_stats[0] if total_stats and total_stats[0] else 0 - total_leaves = total_stats[1] if total_stats and total_stats[1] else 0 - embed.add_field( - name="๐Ÿ“Š Gesamt", - value=f"๐Ÿ‘‹ **Beigetreten:** {total_joins}\n๐Ÿšช **Verlassen:** {total_leaves}", - inline=True - ) - - # Aktuelle Server Info - embed.add_field( - name="โ„น๏ธ Server Info", - value=f"๐Ÿ‘ฅ **Aktuelle Mitglieder:** {ctx.guild.member_count}\n๐Ÿ“ˆ **Netto Wachstum:** {total_joins - total_leaves}", - inline=False - ) - - embed.set_footer(text="Statistiken werden seit der Aktivierung des Systems gesammelt") - - except Exception as e: - logger.error(f"Stats DB Error: {e}") - embed = discord.Embed( - title="๐Ÿ“Š Welcome Statistiken", - description="Statistiken werden ab sofort gesammelt und beim nรคchsten Aufruf angezeigt.", - color=discord.Color.blue() - ) - embed.add_field( - name="โ„น๏ธ Server Info", - value=f"๐Ÿ‘ฅ **Aktuelle Mitglieder:** {ctx.guild.member_count}", - inline=False - ) - - await ctx.respond(embed=embed) - - except Exception as e: - logger.error(f"Stats Command Error: {e}") - embed = discord.Embed( - title="โŒ Fehler", - description="Statistiken konnten nicht geladen werden.", - color=discord.Color.red() - ) - await ctx.respond(embed=embed, ephemeral=True) - - @welcome.command(name="reset", description="Setzt alle Welcome Einstellungen zurรผck") - @commands.has_permissions(administrator=True) - async def reset_welcome(self, ctx): - """ - Setzt alle Welcome Einstellungen zurรผck. - - Parameters - ---------- - ctx : discord.ApplicationContext - Slash Command Context - - Notes - ----- - Zeigt eine Bestรคtigungsabfrage vor dem Lรถschen. - Diese Aktion kann nicht rรผckgรคngig gemacht werden. - """ - - # Bestรคtigungs-View - class ConfirmView(discord.ui.View): - """ - Bestรคtigungs-View fรผr Reset. - - Attributes - ---------- - confirmed : bool - Ob der Reset bestรคtigt wurde - """ - - def __init__(self): - super().__init__(timeout=30) - self.confirmed = False - - @discord.ui.button(label="โœ… Ja, zurรผcksetzen", style=discord.ButtonStyle.danger) - async def confirm_button(self, button: discord.ui.Button, interaction: discord.Interaction): - """ - Bestรคtigung des Resets. - - Parameters - ---------- - button : discord.ui.Button - Geklickter Button - interaction : discord.Interaction - Button Interaction - """ - self.confirmed = True - self.stop() - - success = await ctx.cog.db.delete_welcome_settings(ctx.guild.id) - ctx.cog.invalidate_cache(ctx.guild.id) - - if success: - embed = discord.Embed( - title="โœ… Einstellungen zurรผckgesetzt", - description="Alle Welcome Einstellungen wurden erfolgreich gelรถscht.", - color=discord.Color.green() - ) - else: - embed = discord.Embed( - title="โŒ Fehler", - description="Die Einstellungen konnten nicht zurรผckgesetzt werden.", - color=discord.Color.red() - ) - - await interaction.response.edit_message(embed=embed, view=None) - - @discord.ui.button(label="โŒ Abbrechen", style=discord.ButtonStyle.secondary) - async def cancel_button(self, button: discord.ui.Button, interaction: discord.Interaction): - """ - Abbruch des Resets. - - Parameters - ---------- - button : discord.ui.Button - Geklickter Button - interaction : discord.Interaction - Button Interaction - """ - self.stop() - - embed = discord.Embed( - title="โŒ Abgebrochen", - description="Die Einstellungen wurden nicht zurรผckgesetzt.", - color=discord.Color.orange() - ) - - await interaction.response.edit_message(embed=embed, view=None) - - embed = discord.Embed( - title="โš ๏ธ Einstellungen zurรผcksetzen", - description="Bist du sicher, dass du **alle** Welcome Einstellungen lรถschen mรถchtest?\n\n**Diese Aktion kann nicht rรผckgรคngig gemacht werden!**", - color=discord.Color.orange() - ) - - view = ConfirmView() - await ctx.respond(embed=embed, view=view, ephemeral=True) - - # Event Listeners fรผr Statistiken - @commands.Cog.listener() - async def on_member_remove(self, member: discord.Member): - """ - Tracking fรผr Member Leaves. - - Parameters - ---------- - member : discord.Member - Mitglied das den Server verlassen hat - - Notes - ----- - Aktualisiert die Statistiken wenn aktiviert. - """ - try: - settings = await self.get_cached_settings(member.guild.id) - if settings and settings.get('welcome_stats_enabled'): - await self.db.update_welcome_stats(member.guild.id, leaves=1) - except Exception as e: - logger.error(f"Leave Stats Error: {e}") - - -def setup(bot): - """ - Setup-Funktion fรผr das Cog. - - Parameters - ---------- - bot : ezcord.Bot - Bot-Instanz - - Notes - ----- - Wird automatisch von discord.py beim Laden des Cogs aufgerufen. - """ - bot.add_cog(WelcomeSystem(bot)) \ No newline at end of file diff --git a/src/cogs/fun/__init__.py b/src/cogs/fun/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/cogs/fun/gewinnt.py b/src/cogs/fun/gewinnt.py deleted file mode 100644 index 322723f..0000000 --- a/src/cogs/fun/gewinnt.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Import -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -from discord.ui import Button, View -import discord -from discord.ext import commands -import ezcord -import yaml -from pathlib import Path - -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Constants -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -ROWS = 6 -COLUMNS = 7 - -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Load messages from YAML -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -def load_messages(lang_code: str): - """ - Lรคdt Nachrichten fรผr den angegebenen Sprachcode. - Fรคllt auf 'en' und dann auf 'de' zurรผck, falls die Datei fehlt. - """ - base_path = Path("translation") / "messages" - - # 1. Versuch: Gewรผnschte Sprache - lang_file = base_path / f"{lang_code}.yaml" - - # 2. Versuch: Standard (Englisch) - if not lang_file.exists(): - lang_file = base_path / "en.yaml" - - # 3. Versuch: Fallback (Deutsch) - if not lang_file.exists(): - lang_file = base_path / "de.yaml" - - # Kritischer Fehler, wenn keine der drei Dateien existiert - if not lang_file.exists(): - raise FileNotFoundError(f"Missing language files: {lang_code}.yaml, en.yaml, and de.yaml") - - with open(lang_file, "r", encoding="utf-8") as f: - return yaml.safe_load(f) - -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Button & View -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -class Connect4Button(Button): - def __init__(self, column, view): - super().__init__(style=discord.ButtonStyle.secondary, label=str(column + 1)) - self.column = column - self.view_ref = view - - async def callback(self, interaction: discord.Interaction): - view = self.view_ref - msgs = view.messages - - if interaction.user != view.current_player: - await interaction.response.send_message( - msgs["cog_4gewinnt"]["error_types"]["not_your_turn"], - ephemeral=True - ) - return - - if not view.make_move(self.column): - await interaction.response.send_message( - msgs["cog_4gewinnt"]["error_types"]["this_column_full"], - ephemeral=True - ) - return - - winner = view.check_winner() - board_str = view.board_to_str() - - if winner or view.is_draw(): - for child in view.children: - child.disabled = True - - content = "" - if winner: - content = msgs["cog_4gewinnt"]["win_types"]["win"].format( - winner=view.current_player.mention, - board_str=board_str - ) - elif view.is_draw(): - content = msgs["cog_4gewinnt"]["win_types"]["draw"].format( - board_str=board_str - ) - - await interaction.response.edit_message( - content=content, - view=view - ) - view.stop() - return - - view.switch_player() - await interaction.response.edit_message( - content=msgs["cog_4gewinnt"]["message"]["player_turn"].format( - view=view, - board_str=board_str - ), - view=view - ) - -class Connect4View(View): - def __init__(self, player1, player2, messages): - super().__init__(timeout=180) - self.player1 = player1 - self.player2 = player2 - self.current_player = player1 - self.current_symbol = "๐Ÿ”ด" - self.board = [["โšช" for _ in range(COLUMNS)] for _ in range(ROWS)] - self.messages = messages - - for col in range(COLUMNS): - self.add_item(Connect4Button(col, self)) - - def make_move(self, column): - for row in reversed(range(ROWS)): - if self.board[row][column] == "โšช": - self.board[row][column] = self.current_symbol - return True - return False - - def switch_player(self): - if self.current_player == self.player1: - self.current_player = self.player2 - self.current_symbol = "๐ŸŸก" - else: - self.current_player = self.player1 - self.current_symbol = "๐Ÿ”ด" - - def check_winner(self): - b = self.board - # horizontal - for row in range(ROWS): - for col in range(COLUMNS - 3): - line = b[row][col:col+4] - if line.count(line[0]) == 4 and line[0] != "โšช": - return True - # vertikal - for col in range(COLUMNS): - for row in range(ROWS - 3): - line = [b[row+i][col] for i in range(4)] - if line.count(line[0]) == 4 and line[0] != "โšช": - return True - # diagonal rechts unten - for row in range(ROWS - 3): - for col in range(COLUMNS - 3): - line = [b[row+i][col+i] for i in range(4)] - if line.count(line[0]) == 4 and line[0] != "โšช": - return True - # diagonal rechts oben - for row in range(3, ROWS): - for col in range(COLUMNS - 3): - line = [b[row-i][col+i] for i in range(4)] - if line.count(line[0]) == 4 and line[0] != "โšช": - return True - return None - - def is_draw(self): - return all(cell != "โšช" for row in self.board for cell in row) - - def board_to_str(self): - return "\n".join("".join(row) for row in self.board) - - -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Cog -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -class Connect4Cog(ezcord.Cog, group="fun"): - @commands.slash_command(name="connect4", description="Starte ein 4 Gewinnt Spiel mit jemandem!") - async def connect4(self, ctx: discord.ApplicationContext, opponent: discord.Member): - - try: - lang_code = self.bot.get_user_language(ctx.author.id) - except AttributeError: - lang_code = "de" - - try: - messages = load_messages(lang_code) - except FileNotFoundError as e: - print(f"CRITICAL: {e}") - messages = {"cog_4gewinnt": {"error_types": {"is_opponent_bot": "Error: Missing language file."}, - "message": {"start_game": "Error: Missing language file."}}} - - if opponent.bot: - await ctx.respond( - messages["cog_4gewinnt"]["error_types"]["is_opponent_bot"], - ephemeral=True - ) - return - if opponent == ctx.author: - await ctx.respond( - messages["cog_4gewinnt"]["error_types"]["is_opponent_self"], - ephemeral=True - ) - return - - view = Connect4View(ctx.author, opponent, messages) - - # ๐ŸŸข KORREKTUR: Stabile Formatierung - await ctx.respond( - messages["cog_4gewinnt"]["message"]["start_game"].format( - author_mention=ctx.author.mention, - opponent_mention=opponent.mention - ) + view.board_to_str(), - view=view - ) - -def setup(bot): - bot.add_cog(Connect4Cog(bot)) \ No newline at end of file diff --git a/src/cogs/fun/tictactoe.py b/src/cogs/fun/tictactoe.py deleted file mode 100644 index 65ab4e7..0000000 --- a/src/cogs/fun/tictactoe.py +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Import -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -from discord.ui import Button, View -import discord -from discord.ext import commands -import ezcord -import yaml -from pathlib import Path -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Hilfsfunktionen -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -def load_messages(lang_code: str): - """ - Lรคdt Nachrichten fรผr den angegebenen Sprachcode. - Fรคllt auf 'en' und dann auf 'de' zurรผck, falls die Datei fehlt. - """ - base_path = Path("translation") / "messages" - - # 1. Versuch: Gewรผnschte Sprache - lang_file = base_path / f"{lang_code}.yaml" - - # 2. Versuch: Standard (Englisch) - if not lang_file.exists(): - lang_file = base_path / "en.yaml" - - # 3. Versuch: Fallback (Deutsch) - if not lang_file.exists(): - lang_file = base_path / "de.yaml" - - # Kritischer Fehler, wenn keine der drei Dateien existiert - if not lang_file.exists(): - # Da dies nur beim Laden eines Commands passiert, keine exit() nรถtig - print(f"WARNUNG: Keine Sprachdatei fรผr '{lang_code}' gefunden. Verwende leere Texte.") - return {} - - with open(lang_file, "r", encoding="utf-8") as f: - return yaml.safe_load(f) - -# ๐Ÿ”ด ENTFERNT: Die globale 'messages' Variable wird entfernt. -# Die Nachrichten werden jetzt in der Cog-Methode geladen. - - -class TicTacToeButton(Button): - def __init__(self, x, y): - super().__init__(style=discord.ButtonStyle.secondary, label="\u200b", row=x) - self.x = x - self.y = y - self.clicked = False - # Speichere die Nachrichten direkt im Button fรผr den Callback - # Siehe Callback: messages werden aus der View geholt - - async def callback(self, interaction: discord.Interaction): - view: TicTacToeView = self.view - messages = view.messages # ๐ŸŒŸ NEU: Nachrichten aus der View abrufen - - # ๐ŸŸข Korrigierte i18n-Nutzung: Nicht dein Zug - if interaction.user != view.current_player: - await interaction.response.send_message( - messages.get("cog_tictactoe", {}).get("error_types", {}).get("not_your_turn", "Not your turn!"), - ephemeral=True - ) - return - - # ๐ŸŸข Korrigierte i18n-Nutzung: Feld belegt - if self.clicked: - await interaction.response.send_message( - messages.get("cog_tictactoe", {}).get("error_types", {}).get("this_cell_taken", "This cell is already taken!"), - ephemeral=True - ) - return - - # ... (Spiellogik bleibt gleich) ... - self.clicked = True - if view.current_turn == 0: - self.style = discord.ButtonStyle.danger # rot = X - self.label = "X" - view.board[self.x][self.y] = "X" - view.current_turn = 1 - view.current_player = view.player2 - else: - self.style = discord.ButtonStyle.success # grรผn = O - self.label = "O" - view.board[self.x][self.y] = "O" - view.current_turn = 0 - view.current_player = view.player1 - - winner = view.check_winner() - - if winner: - for child in view.children: - child.disabled = True - - # ๐ŸŸข Korrigierte i18n-Nutzung: Gewinn - win_msg = messages.get("cog_tictactoe", {}).get("win_types", {}).get("win", "WINNER: {winner}").format(winner=winner) - await interaction.response.edit_message(content=win_msg, view=view) - view.stop() - - elif view.is_draw(): - for child in view.children: - child.disabled = True - - # ๐ŸŸข Korrigierte i18n-Nutzung: Unentschieden - draw_msg = messages.get("cog_tictactoe", {}).get("win_types", {}).get("draw", "It's a draw!") - await interaction.response.edit_message(content=draw_msg, view=view) - view.stop() - - else: - # ๐ŸŒŸ NEU: I18N fรผr den Zugwechsel - next_turn_msg = messages.get("cog_tictactoe", {}).get("message", {}).get("next_turn", "It is now {player}'s turn!").format( - player=view.current_player.mention - ) - await interaction.response.edit_message(content=next_turn_msg, view=view) - -class TicTacToeView(View): - def __init__(self, player1, player2, messages): # ๐ŸŒŸ NEU: Nachrichten werden รผbergeben - super().__init__(timeout=120) - self.player1 = player1 - self.player2 = player2 - self.current_player = player1 - self.current_turn = 0 # 0 = X (player1), 1 = O (player2) - self.board = [["" for _ in range(3)] for _ in range(3)] - self.messages = messages # ๐ŸŒŸ NEU: Nachrichten werden hier gespeichert - - for x in range(3): - for y in range(3): - self.add_item(TicTacToeButton(x, y)) - - # check_winner und is_draw bleiben unverรคndert - def check_winner(self): - # ... (Ihre bestehende Logik) ... - b = self.board - players_map = {"X": self.player1, "O": self.player2} - for i in range(3): - if b[i][0] == b[i][1] == b[i][2] != "": - winner_symbol = b[i][0] - return f"{winner_symbol} ({players_map[winner_symbol].display_name})" - for i in range(3): - if b[0][i] == b[1][i] == b[2][i] != "": - winner_symbol = b[0][i] - return f"{winner_symbol} ({players_map[winner_symbol].display_name})" - if b[0][0] == b[1][1] == b[2][2] != "": - winner_symbol = b[0][0] - return f"{winner_symbol} ({players_map[winner_symbol].display_name})" - if b[0][2] == b[1][1] == b[2][0] != "": - winner_symbol = b[0][2] - return f"{winner_symbol} ({players_map[winner_symbol].display_name})" - return None - - def is_draw(self): - return all(cell != "" for row in self.board for cell in row) - - -class fun(ezcord.Cog): - def __init__(self, bot): - self.bot = bot - - @commands.slash_command(name="tictactoe", description="Starte ein Tic Tac Toe Spiel mit jemandem!") - async def tictactoe(self, ctx: discord.ApplicationContext, opponent: discord.Member): - - # ๐ŸŒŸ NEU: Rufe den Sprachcode aus der Datenbank ab - # Annahme: Ihre db-Methode ist get_user_language - lang_code = self.bot.settings_db.get_user_language(ctx.author.id) - - # ๐ŸŒŸ NEU: Lade die korrekten Nachrichten fรผr den Benutzer - messages = load_messages(lang_code) - - # ๐ŸŸข Korrigierte i18n-Nutzung: Gegner ist Bot - if opponent.bot: - await ctx.respond( - messages.get("cog_tictactoe", {}).get("error_types", {}).get("is_opponent_bot", "You cannot challenge a bot."), - ephemeral=True - ) - return - - # ๐ŸŸข Korrigierte i18n-Nutzung: Gegner ist man selbst - if opponent == ctx.author: - await ctx.respond( - messages.get("cog_tictactoe", {}).get("error_types", {}).get("is_opponent_self", "You cannot challenge yourself."), - ephemeral=True - ) - return - - # ๐ŸŒŸ NEU: รœbergebe Nachrichten an die View - view = TicTacToeView(ctx.author, opponent, messages) - - # ๐ŸŸข KORREKTUR: Stabile Formatierung zur Behebung des Hรคngens wรคhrend der Synchronisierung. - start_msg = messages.get("cog_tictactoe", {}).get("message", {}).get("start_game", "Tic Tac Toe: {author_mention} vs {opponent_mention}").format( - author_mention=ctx.author.mention, - opponent_mention=opponent.mention - ) - await ctx.respond(start_msg, view=view) - -def setup(bot): - bot.add_cog(fun(bot)) \ No newline at end of file diff --git a/src/cogs/fun/weather.py b/src/cogs/fun/weather.py deleted file mode 100644 index 8f6bb6e..0000000 --- a/src/cogs/fun/weather.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -import requests -import discord -from discord import slash_command -from discord.ui import Container -import ezcord -import os -from pathlib import Path -import yaml - -WEATHER_API = os.getenv("WEATHER_API") - -# -------------------------- -# Hilfsfunktion fรผr Nachrichten -# -------------------------- -def load_messages(lang_code: str): - base_path = Path("translation") / "messages" - - lang_file = base_path / f"{lang_code}.yaml" - if not lang_file.exists(): - lang_file = base_path / "en.yaml" - if not lang_file.exists(): - lang_file = base_path / "de.yaml" - if not lang_file.exists(): - print(f"WARNUNG: Keine Sprachdatei fรผr '{lang_code}' gefunden. Verwende leere Texte.") - return {} - - with open(lang_file, "r", encoding="utf-8") as f: - return yaml.safe_load(f) - -# -------------------------- -# Weather Cog -# -------------------------- -class Weather(ezcord.Cog, group="fun"): - def __init__(self, bot: ezcord.Bot): - self.bot = bot - - @slash_command(name="weather", description="Erhalte das Wetter fรผr eine Stadt") - async def weather(self, ctx: discord.ApplicationContext, city: str): - """Get the weather for a city""" - - # ๐ŸŒŸ Benutzer-spezifische Sprache laden - lang_code = self.bot.settings_db.get_user_language(ctx.author.id) - messages = load_messages(lang_code) - - url = f"http://api.weatherapi.com/v1/current.json?key={WEATHER_API}&q={city}&lang={lang_code}" - - try: - response = requests.get(url, timeout=10) - response.raise_for_status() - data = response.json() - except requests.RequestException: - await ctx.respond( - messages.get("cog_weather", {}).get("error_types", {}).get( - "api_error", "Error with the weather API." - ) - ) - return - - if "error" in data: - await ctx.respond( - messages.get("cog_weather", {}).get("error_types", {}).get( - "city_not_found", f"โš ๏ธ Error: {data['error']['message']}" - ) - ) - return - - location = data['location'] - current = data['current'] - - container = Container() - - # รœbersetzbarer Header - container.add_text( - messages.get("cog_weather", {}).get("messages", {}).get( - "weather_report", "Weather report for {city}, {country}\n" - ).format(city=location['name'], country=location['country']) - ) - container.add_separator() - - # รœbersetzbare Details - details = ( - messages.get("cog_weather", {}).get("messages", {}).get( - "temperature", "Temperature: {temperature}ยฐC\n" - ).format(temperature=current['temp_c']) + - messages.get("cog_weather", {}).get("messages", {}).get( - "humidity", "Humidity: {humidity}%\n" - ).format(humidity=current['humidity']) + - messages.get("cog_weather", {}).get("messages", {}).get( - "wind_speed", "Wind speed: {wind_speed} km/h ({wind_dir})\n" - ).format(wind_speed=current['wind_kph'], wind_dir=current['wind_dir']) + - messages.get("cog_weather", {}).get("messages", {}).get( - "condition", "Condition: {condition}\n" - ).format(condition=current['condition']['text']) + - messages.get("cog_weather", {}).get("messages", {}).get( - "visibility", "Visibility: {visibility} km\n" - ).format(visibility=current['vis_km']) + - messages.get("cog_weather", {}).get("messages", {}).get( - "pressure", "Pressure: {pressure} hPa\n" - ).format(pressure=current['pressure_mb']) - ) - - container.add_text(details) - - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - -def setup(bot: ezcord.Bot): - bot.add_cog(Weather(bot)) diff --git a/src/cogs/fun/wikipedia/__init__.py b/src/cogs/fun/wikipedia/__init__.py deleted file mode 100644 index d708692..0000000 --- a/src/cogs/fun/wikipedia/__init__.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Wikipedia Bot Package -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -""" -Wikipedia Bot fรผr Discord - -Ein umfassender Wikipedia-Bot mit Unterstรผtzung fรผr mehrere Sprachen, -Caching, interaktive UI-Komponenten und erweiterte Suchfunktionen. -""" - -__version__ = "2.0.0" -__author__ = "OPPRO.NET Network" - -from .cog import WikipediaCog, setup -from .config import WIKI_CONFIG, LANGUAGE_CHOICES -from .cache import WikiCache, wiki_cache -from .utils import clean_text, format_page_info -from .containers import ( - create_article_container, - create_error_container, - create_disambiguation_container, - create_loading_container, - create_random_article_container -) -from .components import ( - LanguageSelectContainer, - ArticleButtonContainer, - RandomArticleButton, - ArticleInfoButton, - RefreshArticleButton -) -from .autocomplete import enhanced_wiki_autocomplete - -__all__ = [ - # Main - 'WikipediaCog', - 'setup', - - # Config - 'WIKI_CONFIG', - 'LANGUAGE_CHOICES', - - # Cache - 'WikiCache', - 'wiki_cache', - - # Utils - 'clean_text', - 'format_page_info', - - # Containers - 'create_article_container', - 'create_error_container', - 'create_disambiguation_container', - 'create_loading_container', - 'create_random_article_container', - - # Components - 'LanguageSelectContainer', - 'ArticleButtonContainer', - 'RandomArticleButton', - 'ArticleInfoButton', - 'RefreshArticleButton', - - # Autocomplete - 'enhanced_wiki_autocomplete', -] \ No newline at end of file diff --git a/src/cogs/fun/wikipedia/autocomplete.py b/src/cogs/fun/wikipedia/autocomplete.py deleted file mode 100644 index 9c25512..0000000 --- a/src/cogs/fun/wikipedia/autocomplete.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Autocomplete Functions -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -import discord -import wikipedia -from .cache import wiki_cache - - -async def enhanced_wiki_autocomplete(ctx: discord.AutocompleteContext): - """ - Erweiterte Autocomplete mit Caching - - Args: - ctx: Autocomplete Context - - Returns: - Liste von Vorschlรคgen - """ - suchwert = ctx.value or "" - - # Standard-Vorschlรคge fรผr kurze Eingaben - if len(suchwert) < 2: - return [ - "Kรผnstliche Intelligenz", "Python (Programmiersprache)", "Discord", - "Deutschland", "Wikipedia", "Klimawandel", "Quantenphysik", "Internet" - ] - - try: - cache_key = f"autocomplete_{suchwert}_de" - cached_results = wiki_cache.get(cache_key) - - if cached_results: - return cached_results.get('suggestions', []) - - # Wikipedia-Suche - vorschlaege = wikipedia.search(suchwert, results=15) - - def relevance_score(suggestion): - """Berechnet die Relevanz eines Vorschlags""" - suggestion_lower = suggestion.lower() - suchwert_lower = suchwert.lower() - - if suchwert_lower == suggestion_lower: - return 0 - elif suggestion_lower.startswith(suchwert_lower): - return 1 - elif suchwert_lower in suggestion_lower: - return 2 - else: - return 3 + len(suggestion) - - # Nach Relevanz sortieren - vorschlaege.sort(key=relevance_score) - final_suggestions = vorschlaege[:25] - - # Im Cache speichern - wiki_cache.set(cache_key, {'suggestions': final_suggestions}) - - return final_suggestions - - except Exception: - return ["Fehler bei der Suche - bitte erneut versuchen"] \ No newline at end of file diff --git a/src/cogs/fun/wikipedia/cache.py b/src/cogs/fun/wikipedia/cache.py deleted file mode 100644 index e9a311f..0000000 --- a/src/cogs/fun/wikipedia/cache.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Cache System -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -from datetime import datetime, timedelta -from typing import Optional, Dict, Any - - -class WikiCache: - """Cache-System fรผr Wikipedia-Anfragen""" - - def __init__(self): - self.cache: Dict[str, Dict[str, Any]] = {} - self.timestamps: Dict[str, datetime] = {} - - def get(self, key: str) -> Optional[Dict[str, Any]]: - """Ruft einen Wert aus dem Cache ab""" - if key in self.cache: - cache_duration = 300 # 5 Minuten - if datetime.now() - self.timestamps[key] < timedelta(seconds=cache_duration): - return self.cache[key] - else: - del self.cache[key] - del self.timestamps[key] - return None - - def set(self, key: str, value: Dict[str, Any]): - """Speichert einen Wert im Cache""" - self.cache[key] = value - self.timestamps[key] = datetime.now() - - def clear_expired(self): - """Entfernt abgelaufene Cache-Eintrรคge""" - now = datetime.now() - cache_duration = 300 # 5 Minuten - expired_keys = [ - key for key, timestamp in self.timestamps.items() - if now - timestamp >= timedelta(seconds=cache_duration) - ] - for key in expired_keys: - self.cache.pop(key, None) - self.timestamps.pop(key, None) - - def clear(self): - """Leert den gesamten Cache""" - self.cache.clear() - self.timestamps.clear() - - @property - def size(self) -> int: - """Gibt die Anzahl der Cache-Eintrรคge zurรผck""" - return len(self.cache) - - def get_expired_count(self) -> int: - """Zรคhlt die abgelaufenen Eintrรคge""" - now = datetime.now() - cache_duration = 300 # 5 Minuten - return sum( - 1 for timestamp in self.timestamps.values() - if now - timestamp >= timedelta(seconds=cache_duration) - ) - - -# Globale Cache-Instanz -wiki_cache = WikiCache() \ No newline at end of file diff --git a/src/cogs/fun/wikipedia/cog.py b/src/cogs/fun/wikipedia/cog.py deleted file mode 100644 index 97f428f..0000000 --- a/src/cogs/fun/wikipedia/cog.py +++ /dev/null @@ -1,461 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Main Cog Class -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -import discord -import ezcord -import wikipedia -import asyncio -from discord import slash_command -from discord.ui import Container -from datetime import datetime -from .config import WIKI_CONFIG, LANGUAGE_CHOICES -from .cache import wiki_cache -from .utils import format_page_info, clean_text -from .containers import ( - create_article_container, create_error_container, - create_disambiguation_container, create_random_article_container -) -from .components import ArticleButtonContainer -from .autocomplete import enhanced_wiki_autocomplete - - -class WikipediaCog(ezcord.Cog): - """Hauptklasse fรผr Wikipedia-Bot Funktionen""" - - def __init__(self, bot): - self.bot = bot - self.current_language = 'de' - self.cleanup_task = None - self.stats = { - 'searches': 0, - 'articles_viewed': 0, - 'languages_used': set(), - 'start_time': datetime.now() - } - wikipedia.set_lang("de") - wikipedia.set_rate_limiting(True) - - @ezcord.Cog.listener() - async def on_ready(self): - """Startet den Cache-Cleanup Task""" - if self.cleanup_task is None: - self.cleanup_task = self.bot.loop.create_task(self._cleanup_cache()) - - async def _cleanup_cache(self): - """RegelmรครŸige Cache-Bereinigung""" - while True: - try: - await asyncio.sleep(300) - wiki_cache.clear_expired() - except: - pass - - def cog_unload(self): - """Cleanup beim Entladen des Cogs""" - if hasattr(self, 'cleanup_task') and self.cleanup_task: - self.cleanup_task.cancel() - - @slash_command(name="wiki_search", description="๐Ÿ” Durchsuche Wikipedia nach Artikeln und Informationen") - async def wikipedia_search( - self, - ctx: discord.ApplicationContext, - suchbegriff: discord.Option( - str, - "Was mรถchtest du auf Wikipedia nachschlagen?", - autocomplete=enhanced_wiki_autocomplete, - max_length=100 - ), - sprache: discord.Option( - str, - "Sprache fรผr die Suche", - choices=LANGUAGE_CHOICES, - default="de", - required=False - ) - ): - await ctx.defer() - - self.stats['searches'] += 1 - self.stats['languages_used'].add(sprache) - - original_lang = self.current_language - if sprache != original_lang: - wikipedia.set_lang(sprache) - self.current_language = sprache - - try: - cache_key = f"{suchbegriff}_{sprache}" - cached_info = wiki_cache.get(cache_key) - - if cached_info: - info = cached_info - else: - page = wikipedia.page(suchbegriff) - info = format_page_info(page, sprache) - wiki_cache.set(cache_key, info) - - self.stats['articles_viewed'] += 1 - - similar_articles = wikipedia.search(suchbegriff, results=8) - similar_articles = [a for a in similar_articles if a.lower() != info['title'].lower()] - - container = create_article_container(info, ctx.author, similar_articles[:6], - suchbegriff, sprache, cog_instance=self) - view = discord.ui.DesignerView(container, timeout=WIKI_CONFIG['timeout']) - - await ctx.respond(view=view) - - except wikipedia.DisambiguationError as e: - container = create_disambiguation_container(suchbegriff, e.options[:12], sprache) - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - - except wikipedia.PageError: - error_text = f"Kein Wikipedia-Artikel fรผr **'{suchbegriff}'** in {WIKI_CONFIG['languages'][sprache]['name']} gefunden." - - try: - suggestions = wikipedia.search(suchbegriff, results=5) - if suggestions: - error_text += "\n\n๐Ÿ’ก **Meintest du vielleicht:**\n" - error_text += "\n".join([f"โ€ข {s}" for s in suggestions]) - except: - pass - - container = create_error_container("Artikel nicht gefunden", error_text) - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - - except Exception as e: - container = create_error_container("Unerwarteter Fehler", f"```py\n{str(e)[:800]}\n```") - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - - finally: - if sprache != original_lang: - wikipedia.set_lang(original_lang) - self.current_language = original_lang - - @slash_command(name="wiki_random", description="๐ŸŽฒ Zeige einen zufรคlligen Wikipedia-Artikel") - async def wiki_random( - self, - ctx: discord.ApplicationContext, - sprache: discord.Option( - str, - "Sprache fรผr den zufรคlligen Artikel", - choices=LANGUAGE_CHOICES, - default="de", - required=False - ), - anzahl: discord.Option(int, "Anzahl zufรคlliger Artikel (1-5)", min_value=1, max_value=5, default=1) - ): - await ctx.defer() - - original_lang = self.current_language - if sprache != original_lang: - wikipedia.set_lang(sprache) - self.current_language = sprache - - try: - if anzahl == 1: - random_title = wikipedia.random() - page = wikipedia.page(random_title) - info = format_page_info(page, sprache) - - similar_articles = wikipedia.search(random_title, results=6) - similar_articles = [a for a in similar_articles if a.lower() != info['title'].lower()] - - container = create_random_article_container( - info, ctx.author, similar_articles[:4], - random_title, sprache, cog_instance=self - ) - - view = discord.ui.DesignerView(container, timeout=WIKI_CONFIG['timeout']) - await ctx.respond(view=view) - - else: - lang_info = WIKI_CONFIG['languages'][sprache] - container = Container() - container.add_text(f"๐ŸŽฒ **{anzahl} Zufรคllige Artikel**") - container.add_text(f"Entdecke neue Themen in {lang_info['flag']} {lang_info['name']}:") - container.add_separator() - - random_articles = [] - for i in range(anzahl): - try: - random_title = wikipedia.random() - summary = clean_text(wikipedia.summary(random_title, sentences=1), 200) - random_articles.append(random_title) - - container.add_text(f"**{i + 1}. {random_title}**") - container.add_text(summary) - container.add_separator() - except: - container.add_text(f"**{i + 1}. Artikel nicht verfรผgbar**") - container.add_text("Dieser Artikel konnte nicht geladen werden.") - container.add_separator() - - if random_articles: - container.add_text("๐Ÿ“š **Artikel รถffnen:**") - for article in random_articles[:4]: - article_btn = ArticleButtonContainer(article, "similar", self) - container.add_item(article_btn) - - container.add_separator() - container.add_text(f"Wikipedia โ€ข {anzahl} zufรคllige Artikel") - - view = discord.ui.DesignerView(container, timeout=WIKI_CONFIG['timeout']) - await ctx.respond(view=view) - - except Exception as e: - container = create_error_container("Fehler beim Laden", - f"Zufรคllige Artikel konnten nicht geladen werden: {str(e)[:500]}") - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - finally: - if sprache != original_lang: - wikipedia.set_lang(original_lang) - self.current_language = original_lang - - @slash_command(name="wiki_multisearch", description="๐Ÿ”Ž Erweiterte Wikipedia-Suche mit mehreren Ergebnissen") - async def wiki_multi_search( - self, - ctx: discord.ApplicationContext, - suchbegriff: discord.Option(str, "Suchbegriff fรผr erweiterte Suche", max_length=100), - anzahl: discord.Option(int, "Anzahl der Ergebnisse (1-15)", min_value=1, max_value=15, default=8), - sprache: discord.Option(str, "Sprache fรผr die Suche", choices=LANGUAGE_CHOICES, default="de", required=False) - ): - await ctx.defer() - - original_lang = self.current_language - if sprache != original_lang: - wikipedia.set_lang(sprache) - self.current_language = sprache - - try: - results = wikipedia.search(suchbegriff, results=anzahl) - - if not results: - container = create_error_container( - "Keine Ergebnisse", - f"Keine Artikel fรผr **'{suchbegriff}'** in {WIKI_CONFIG['languages'][sprache]['name']} gefunden." - ) - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - return - - lang_info = WIKI_CONFIG['languages'][sprache] - container = Container() - container.add_text(f"๐Ÿ” **Suchergebnisse fรผr '{suchbegriff}'**") - container.add_text(f"**{len(results)} Ergebnisse** in {lang_info['flag']} {lang_info['name']}:") - container.add_separator() - - for i, result in enumerate(results, 1): - try: - summary = wikipedia.summary(result, sentences=1) - summary = clean_text(summary, 150) - except: - summary = "Keine Vorschau verfรผgbar." - - container.add_text(f"**{i}. {result}**") - container.add_text(summary) - container.add_separator() - - container.add_text("๐Ÿ“š **Artikel รถffnen:**") - for result in results[:4]: - article_btn = ArticleButtonContainer(result, "similar", self) - container.add_item(article_btn) - - container.add_separator() - container.add_text(f"Wikipedia โ€ข {len(results)} Ergebnisse โ€ข Sprache: {lang_info['name']}") - - view = discord.ui.DesignerView(container, timeout=WIKI_CONFIG['timeout']) - await ctx.respond(view=view) - - except Exception as e: - container = create_error_container("Suchfehler", f"Fehler bei der Suche: {str(e)[:500]}") - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - finally: - if sprache != original_lang: - wikipedia.set_lang(original_lang) - self.current_language = original_lang - - @slash_command(name="wiki_stats", description="๐Ÿ“Š Zeige Bot-Statistiken und Wikipedia-Informationen") - async def wiki_statistics(self, ctx: discord.ApplicationContext): - uptime = datetime.now() - self.stats['start_time'] - uptime_str = f"{uptime.days}d {uptime.seconds // 3600}h {(uptime.seconds // 60) % 60}m" - - container = Container() - container.add_text("๐Ÿ“Š **Wikipedia Bot Statistiken**") - container.add_separator() - - stats_text = f"๐Ÿ” **Suchanfragen:** {self.stats['searches']:,}\n" - stats_text += f"๐Ÿ“– **Artikel angezeigt:** {self.stats['articles_viewed']:,}\n" - stats_text += f"โฑ๏ธ **Laufzeit:** {uptime_str}" - container.add_text(stats_text) - - container.add_separator() - - lang_names = [WIKI_CONFIG['languages'][lang]['name'] for lang in self.stats['languages_used']] - if lang_names: - container.add_text(f"๐ŸŒ **Verwendete Sprachen:** {', '.join(lang_names)}") - else: - container.add_text("๐ŸŒ **Verwendete Sprachen:** Keine") - - container.add_separator() - - all_langs = [f"{info['flag']} {info['name']}" for info in WIKI_CONFIG['languages'].values()] - container.add_text("๐Ÿ“š **Verfรผgbare Sprachen:**") - container.add_text(", ".join(all_langs)) - - container.add_separator() - - tech_text = f"๐Ÿ’พ **Cache-Eintrรคge:** {len(wiki_cache.cache)}\n" - tech_text += f"โšก **Rate Limiting:** Aktiviert\n" - tech_text += f"๐Ÿ”ง **Features:** Suche, Zufรคllig, Multi-Sprache, Cache" - container.add_text(tech_text) - - container.add_separator() - container.add_text("Wikipedia Bot โ€ข Erweiterte Funktionen verfรผgbar") - - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - - @slash_command(name="wiki_category", description="๐Ÿ“‚ Durchsuche Wikipedia-Kategorien") - async def wiki_category( - self, - ctx: discord.ApplicationContext, - kategorie: discord.Option(str, "Name der Kategorie", max_length=100), - sprache: discord.Option(str, "Sprache fรผr die Kategorie-Suche", choices=LANGUAGE_CHOICES, default="de", required=False) - ): - await ctx.defer() - - original_lang = self.current_language - if sprache != original_lang: - wikipedia.set_lang(sprache) - self.current_language = sprache - - try: - search_results = wikipedia.search(f"Kategorie:{kategorie}", results=10) - if not search_results: - search_results = wikipedia.search(kategorie, results=10) - - if not search_results: - container = create_error_container( - "Kategorie nicht gefunden", - f"Keine Artikel in der Kategorie **'{kategorie}'** gefunden." - ) - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - return - - lang_info = WIKI_CONFIG['languages'][sprache] - container = Container() - container.add_text(f"๐Ÿ“‚ **Kategorie: {kategorie}**") - container.add_text(f"Artikel in dieser Kategorie ({lang_info['flag']} {lang_info['name']}):") - container.add_separator() - - for i, result in enumerate(search_results[:8], 1): - try: - summary = wikipedia.summary(result, sentences=1) - summary = clean_text(summary, 150) - except: - summary = "Keine Beschreibung verfรผgbar." - - container.add_text(f"**{i}. {result}**") - container.add_text(summary) - container.add_separator() - - container.add_text("๐Ÿ“š **Artikel รถffnen:**") - for result in search_results[:4]: - article_btn = ArticleButtonContainer(result, "category", self) - container.add_item(article_btn) - - container.add_separator() - container.add_text(f"Wikipedia โ€ข Kategorie-Suche โ€ข {len(search_results)} Ergebnisse") - - view = discord.ui.DesignerView(container, timeout=WIKI_CONFIG['timeout']) - await ctx.respond(view=view) - - except Exception as e: - container = create_error_container("Kategorie-Fehler", - f"Fehler beim Laden der Kategorie: {str(e)[:500]}") - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view) - finally: - if sprache != original_lang: - wikipedia.set_lang(original_lang) - self.current_language = original_lang - - @slash_command(name="wiki_cache", description="๐Ÿ—‘๏ธ Cache-Management (nur fรผr Administratoren)") - @discord.default_permissions(administrator=True) - async def wiki_cache_management( - self, - ctx: discord.ApplicationContext, - aktion: discord.Option( - str, - "Cache-Aktion", - choices=[ - discord.OptionChoice(name="๐Ÿ“Š Status anzeigen", value="status"), - discord.OptionChoice(name="๐Ÿ—‘๏ธ Cache leeren", value="clear"), - discord.OptionChoice(name="โฐ Abgelaufene entfernen", value="cleanup") - ] - ) - ): - if not ctx.author.guild_permissions.administrator: - container = create_error_container("Berechtigung verweigert", - "Nur Administratoren kรถnnen Cache-Befehle verwenden.") - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - return - - await ctx.defer(ephemeral=True) - - if aktion == "status": - total_entries = wiki_cache.size - expired_count = wiki_cache.get_expired_count() - - container = Container() - container.add_text("๐Ÿ’พ **Cache-Status**") - container.add_separator() - - status_text = f"๐Ÿ“Š **Gesamt-Eintrรคge:** {total_entries}\n" - status_text += f"โฐ **Abgelaufene Eintrรคge:** {expired_count}\n" - status_text += f"โœ… **Aktive Eintrรคge:** {total_entries - expired_count}\n" - status_text += f"โš™๏ธ **Cache-Dauer:** {WIKI_CONFIG['cache_duration']} Sekunden" - container.add_text(status_text) - - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - - elif aktion == "clear": - old_count = wiki_cache.size - wiki_cache.clear() - - container = Container() - container.add_text("๐Ÿ—‘๏ธ **Cache geleert**") - container.add_separator() - container.add_text(f"**{old_count}** Eintrรคge wurden entfernt.") - - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - - elif aktion == "cleanup": - old_count = wiki_cache.size - wiki_cache.clear_expired() - new_count = wiki_cache.size - removed = old_count - new_count - - container = Container() - container.add_text("โฐ **Cache bereinigt**") - container.add_separator() - container.add_text(f"**{removed}** abgelaufene Eintrรคge entfernt.\n**{new_count}** Eintrรคge verbleiben.") - - view = discord.ui.DesignerView(container, timeout=None) - await ctx.respond(view=view, ephemeral=True) - - -def setup(bot): - """Setup-Funktion fรผr den Cog""" - bot.add_cog(WikipediaCog(bot)) \ No newline at end of file diff --git a/src/cogs/fun/wikipedia/components.py b/src/cogs/fun/wikipedia/components.py deleted file mode 100644 index 58cad61..0000000 --- a/src/cogs/fun/wikipedia/components.py +++ /dev/null @@ -1,306 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> UI Button Components -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -import discord -import wikipedia -from discord import SelectOption -from discord.ui import Button, Select, Container -from typing import Dict, Any -from .config import WIKI_CONFIG -from .cache import wiki_cache -from .utils import format_page_info - - -class LanguageSelectContainer(Select): - """Dropdown fรผr Sprachauswahl""" - - def __init__(self, current_term: str, current_lang: str = 'de', cog_instance=None): - self.current_term = current_term - self.current_lang = current_lang - self.cog = cog_instance - - options = [] - for code, info in WIKI_CONFIG['languages'].items(): - options.append(SelectOption( - label=info['name'], - value=code, - emoji=info['flag'], - default=(code == current_lang), - description=f"Suche auf {info['domain']}" - )) - - super().__init__( - placeholder="๐ŸŒ Sprache wรคhlen...", - options=options, - min_values=1, - max_values=1 - ) - - async def callback(self, interaction: discord.Interaction): - from .containers import ( - create_article_container, - create_disambiguation_container, - create_error_container, - create_loading_container - ) - - await interaction.response.defer() - - selected_lang = self.values[0] - if selected_lang == self.current_lang: - error_container = Container() - error_container.add_text("Diese Sprache ist bereits ausgewรคhlt.") - view = discord.ui.DesignerView(error_container, timeout=60) - await interaction.followup.send(view=view, ephemeral=True) - return - - original_lang = self.cog.current_language if self.cog else 'de' - if selected_lang != original_lang: - wikipedia.set_lang(selected_lang) - if self.cog: - self.cog.current_language = selected_lang - - try: - loading_container = create_loading_container( - f"Lade Artikel in {WIKI_CONFIG['languages'][selected_lang]['name']}...") - view = discord.ui.DesignerView(loading_container, timeout=None) - await interaction.edit_original_response(view=view) - - page = wikipedia.page(self.current_term) - info = format_page_info(page, selected_lang) - - similar_articles = wikipedia.search(self.current_term, results=6) - similar_articles = [a for a in similar_articles if a.lower() != info['title'].lower()] - - container = create_article_container(info, interaction.user, similar_articles[:4], - self.current_term, selected_lang, cog_instance=self.cog) - view = discord.ui.DesignerView(container, timeout=WIKI_CONFIG['timeout']) - await interaction.edit_original_response(view=view) - - except wikipedia.DisambiguationError as e: - container = create_disambiguation_container(self.current_term, e.options[:10], selected_lang) - view = discord.ui.DesignerView(container, timeout=None) - await interaction.edit_original_response(view=view) - except wikipedia.PageError: - container = create_error_container( - "Artikel nicht gefunden", - f"'{self.current_term}' existiert nicht in {WIKI_CONFIG['languages'][selected_lang]['name']}." - ) - view = discord.ui.DesignerView(container, timeout=None) - await interaction.edit_original_response(view=view) - except Exception as e: - container = create_error_container("Unerwarteter Fehler", str(e)[:500]) - view = discord.ui.DesignerView(container, timeout=None) - await interaction.edit_original_response(view=view) - finally: - if selected_lang != original_lang: - wikipedia.set_lang(original_lang) - if self.cog: - self.cog.current_language = original_lang - - -class ArticleButtonContainer(Button): - """Button zum ร–ffnen eines Artikels""" - - def __init__(self, article_title: str, button_type: str = "similar", cog_instance=None): - self.article_title = article_title - self.button_type = button_type - self.cog = cog_instance - - if button_type == "similar": - emoji = "๐Ÿ“–" - style = discord.ButtonStyle.secondary - elif button_type == "category": - emoji = "๐Ÿ“‚" - style = discord.ButtonStyle.primary - else: - emoji = "๐Ÿ“„" - style = discord.ButtonStyle.secondary - - super().__init__( - label=article_title[:80], - style=style, - emoji=emoji - ) - - async def callback(self, interaction: discord.Interaction): - from .containers import ( - create_article_container, - create_disambiguation_container, - create_error_container - ) - - await interaction.response.defer(ephemeral=True) - - try: - current_lang = self.cog.current_language if self.cog else 'de' - cache_key = f"{self.article_title}_{current_lang}" - cached_info = wiki_cache.get(cache_key) - - if cached_info: - info = cached_info - else: - page = wikipedia.page(self.article_title) - info = format_page_info(page, current_lang) - wiki_cache.set(cache_key, info) - - similar_articles = wikipedia.search(self.article_title, results=6) - similar_articles = [a for a in similar_articles if a.lower() != info['title'].lower()] - - container = create_article_container(info, interaction.user, similar_articles[:4], - self.article_title, current_lang, cog_instance=self.cog) - view = discord.ui.DesignerView(container, timeout=WIKI_CONFIG['timeout']) - await interaction.followup.send(view=view, ephemeral=True) - - except wikipedia.DisambiguationError as e: - container = create_disambiguation_container(self.article_title, e.options[:8]) - view = discord.ui.DesignerView(container, timeout=None) - await interaction.followup.send(view=view, ephemeral=True) - except wikipedia.PageError: - container = create_error_container("Artikel nicht gefunden", - f"'{self.article_title}' existiert nicht.") - view = discord.ui.DesignerView(container, timeout=None) - await interaction.followup.send(view=view, ephemeral=True) - except Exception as e: - container = create_error_container("Fehler beim Laden", str(e)[:500]) - view = discord.ui.DesignerView(container, timeout=None) - await interaction.followup.send(view=view, ephemeral=True) - - -class RandomArticleButton(Button): - """Button fรผr zufรคllige Artikel""" - - def __init__(self, language: str, cog_instance=None): - self.language = language - self.cog = cog_instance - super().__init__( - label="๐ŸŽฒ Zufรคlliger Artikel", - style=discord.ButtonStyle.success - ) - - async def callback(self, interaction: discord.Interaction): - from .containers import ( - create_random_article_container, - create_loading_container, - create_error_container - ) - - await interaction.response.defer() - - try: - loading_container = create_loading_container("Lade zufรคlligen Artikel...") - view = discord.ui.DesignerView(loading_container, timeout=None) - await interaction.edit_original_response(view=view) - - random_title = wikipedia.random() - page = wikipedia.page(random_title) - info = format_page_info(page, self.language) - - similar_articles = wikipedia.search(random_title, results=6) - similar_articles = [a for a in similar_articles if a.lower() != info['title'].lower()] - - container = create_random_article_container( - info, interaction.user, similar_articles[:4], - random_title, self.language, cog_instance=self.cog - ) - - view = discord.ui.DesignerView(container, timeout=WIKI_CONFIG['timeout']) - await interaction.edit_original_response(view=view) - - except Exception as e: - container = create_error_container("Fehler beim Laden", - f"Zufรคlliger Artikel konnte nicht geladen werden: {str(e)[:300]}") - view = discord.ui.DesignerView(container, timeout=None) - await interaction.edit_original_response(view=view) - - -class ArticleInfoButton(Button): - """Button fรผr Artikel-Informationen""" - - def __init__(self, info: Dict[str, Any], language: str): - self.info = info - self.language = language - super().__init__( - label="๐Ÿ“Š Artikel-Info", - style=discord.ButtonStyle.primary - ) - - async def callback(self, interaction: discord.Interaction): - await interaction.response.defer(ephemeral=True) - - container = Container() - container.add_text(f"๐Ÿ“Š **Informationen zu '{self.info['title']}'**") - container.add_separator() - - stats_text = f"๐ŸŒ **Sprache:** {WIKI_CONFIG['languages'][self.language]['name']}\n" - stats_text += f"๐Ÿ“‚ **Kategorien:** {len(self.info.get('categories', []))}\n" - stats_text += f"๐Ÿ”— **Verweise:** {len(self.info.get('links', []))}" - container.add_text(stats_text) - - if self.info.get('coordinates'): - lat, lon = self.info['coordinates'] - container.add_text(f"๐Ÿ—บ๏ธ **Koordinaten:** {lat:.2f}ยฐN, {lon:.2f}ยฐE") - - if self.info.get('images'): - container.add_text(f"๐Ÿ–ผ๏ธ **Bilder:** {len(self.info['images'])}") - - if self.info.get('categories'): - container.add_separator() - container.add_text("๐Ÿ“š **Hauptkategorien:**") - categories_text = "\n".join([f"โ€ข {cat}" for cat in self.info['categories'][:5]]) - container.add_text(categories_text) - - container.add_separator() - container.add_text("Wikipedia โ€ข Artikel-Statistiken") - - view = discord.ui.DesignerView(container, timeout=300) - await interaction.followup.send(view=view, ephemeral=True) - - -class RefreshArticleButton(Button): - """Button zum Aktualisieren eines Artikels""" - - def __init__(self, search_term: str, language: str, cog_instance=None): - self.search_term = search_term - self.language = language - self.cog = cog_instance - super().__init__( - label="๐Ÿ”„ Aktualisieren", - style=discord.ButtonStyle.secondary - ) - - async def callback(self, interaction: discord.Interaction): - from .containers import ( - create_article_container, - create_loading_container, - create_error_container - ) - - await interaction.response.defer() - - try: - cache_key = f"{self.search_term}_{self.language}" - if cache_key in wiki_cache.cache: - del wiki_cache.cache[cache_key] - del wiki_cache.timestamps[cache_key] - - loading_container = create_loading_container("Aktualisiere Artikel...") - view = discord.ui.DesignerView(loading_container, timeout=None) - await interaction.edit_original_response(view=view) - - page = wikipedia.page(self.search_term) - info = format_page_info(page, self.language) - - similar_articles = wikipedia.search(self.search_term, results=6) - similar_articles = [a for a in similar_articles if a.lower() != info['title'].lower()] - - container = create_article_container(info, interaction.user, similar_articles[:4], - self.search_term, self.language, cog_instance=self.cog) - view = discord.ui.DesignerView(container, timeout=WIKI_CONFIG['timeout']) - await interaction.edit_original_response(view=view) - - except Exception as e: - container = create_error_container("Aktualisierung fehlgeschlagen", str(e)[:500]) - view = discord.ui.DesignerView(container, timeout=None) - await interaction.edit_original_response(view=view) \ No newline at end of file diff --git a/src/cogs/fun/wikipedia/config.py b/src/cogs/fun/wikipedia/config.py deleted file mode 100644 index 1002102..0000000 --- a/src/cogs/fun/wikipedia/config.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Wikipedia Bot Configuration -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -import discord - -# Fallback fรผr Farben -try: - from DevTools import INFO_COLOR, ERROR_COLOR, SUCCESS_COLOR, WARNING_COLOR -except ImportError: - INFO_COLOR = discord.Color.blue() - ERROR_COLOR = discord.Color.red() - SUCCESS_COLOR = discord.Color.green() - WARNING_COLOR = discord.Color.orange() - -# Wikipedia Konfiguration -WIKI_CONFIG = { - 'languages': { - 'de': {'name': 'Deutsch', 'flag': '\U0001F1E9\U0001F1EA', 'domain': 'de.wikipedia.org'}, - 'en': {'name': 'English', 'flag': '\U0001F1FA\U0001F1F8', 'domain': 'en.wikipedia.org'}, - 'fr': {'name': 'Franรงais', 'flag': '\U0001F1EB\U0001F1F7', 'domain': 'fr.wikipedia.org'}, - 'es': {'name': 'Espaรฑol', 'flag': '\U0001F1EA\U0001F1F8', 'domain': 'es.wikipedia.org'}, - 'it': {'name': 'Italiano', 'flag': '\U0001F1EE\U0001F1F9', 'domain': 'it.wikipedia.org'}, - 'ja': {'name': 'ๆ—ฅๆœฌ่ชž', 'flag': '\U0001F1EF\U0001F1F5', 'domain': 'ja.wikipedia.org'}, - 'ru': {'name': 'ะ ัƒััะบะธะน', 'flag': '\U0001F1F7\U0001F1FA', 'domain': 'ru.wikipedia.org'}, - }, - 'max_summary_length': 1500, - 'max_categories': 3, - 'max_similar_articles': 6, - 'timeout': 600, - 'cache_duration': 300 -} - -# Discord Option Choices fรผr Sprachauswahl -LANGUAGE_CHOICES = [ - discord.OptionChoice(name="DE Deutsch", value="de"), - discord.OptionChoice(name="US English", value="en"), - discord.OptionChoice(name="FR Franรงais", value="fr"), - discord.OptionChoice(name="ES Espaรฑol", value="es"), - discord.OptionChoice(name="IT Italiano", value="it"), - discord.OptionChoice(name="JP ๆ—ฅๆœฌ่ชž", value="ja"), - discord.OptionChoice(name="RU ะ ัƒััะบะธะน", value="ru"), -] \ No newline at end of file diff --git a/src/cogs/fun/wikipedia/containers.py b/src/cogs/fun/wikipedia/containers.py deleted file mode 100644 index 870a87d..0000000 --- a/src/cogs/fun/wikipedia/containers.py +++ /dev/null @@ -1,228 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Container Creation Functions (py-cord Designer) -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -import discord -from discord.ui import Container -from typing import Dict, Any, List - - -def create_article_container( - info: Dict[str, Any], - user: discord.User, - similar_articles: List[str] = None, - search_term: str = "", - language: str = 'de', - cog_instance=None -) -> Container: - """Erstellt einen Container fรผr einen Wikipedia-Artikel""" - from .components import ( - LanguageSelectContainer, ArticleButtonContainer, - RandomArticleButton, ArticleInfoButton, RefreshArticleButton - ) - - container = Container() - - # Header mit Titel - lang_info = { - 'de': {'name': 'Deutsch', 'flag': 'DE'}, - 'en': {'name': 'English', 'flag': 'EN'}, - 'fr': {'name': 'Franรงais', 'flag': 'FR'}, - 'es': {'name': 'Espaรฑol', 'flag': 'ES'}, - 'it': {'name': 'Italiano', 'flag': 'IT'}, - 'ja': {'name': 'ๆ—ฅๆœฌ่ชž', 'flag': 'JP'}, - 'ru': {'name': 'ะ ัƒััะบะธะน', 'flag': 'RU'}, - } - lang_data = lang_info.get(language, {'name': 'Deutsch', 'flag': 'DE'}) - header_text = f"๐Ÿ“– **{info['title']}**\n[{lang_data['flag']}] {lang_data['name']} โ€ข Wikipedia" - container.add_text(header_text) - - container.add_separator() - - # Zusammenfassung - summary_text = info['summary'][:800] + ("..." if len(info['summary']) > 800 else "") - container.add_text(summary_text) - - # Kategorien falls vorhanden - if info.get('categories'): - container.add_separator() - categories_text = "๐Ÿ“‚ **Kategorien:** " + ", ".join(info['categories'][:3]) - if len(info['categories']) > 3: - categories_text += f" (+{len(info['categories']) - 3} weitere)" - container.add_text(categories_text) - - # Koordinaten falls vorhanden - if info.get('coordinates'): - lat, lon = info['coordinates'] - container.add_text(f"๐Ÿ—บ๏ธ **Standort:** {lat:.2f}ยฐN, {lon:.2f}ยฐE") - - container.add_separator() - - # Link zum vollstรคndigen Artikel - if info.get('url'): - container.add_text(f"๐Ÿ”— [Vollstรคndigen Artikel lesen]({info['url']})") - - # Sprachauswahl - if cog_instance and search_term: - lang_select = LanguageSelectContainer(search_term, language, cog_instance) - container.add_item(lang_select) - - # ร„hnliche Artikel als Buttons - if similar_articles and cog_instance: - container.add_separator() - container.add_text("๐Ÿ“š **ร„hnliche Artikel:**") - for article in similar_articles[:4]: - article_btn = ArticleButtonContainer(article, "similar", cog_instance) - container.add_item(article_btn) - - container.add_separator() - - # Action Buttons - if cog_instance: - random_btn = RandomArticleButton(language, cog_instance) - container.add_item(random_btn) - - info_btn = ArticleInfoButton(info, language) - container.add_item(info_btn) - - if search_term: - refresh_btn = RefreshArticleButton(search_term, language, cog_instance) - container.add_item(refresh_btn) - - # Footer - container.add_separator() - footer_text = f"๐Ÿ‘ค Angefragt von {user.display_name}" - container.add_text(footer_text) - - return container - - -def create_error_container(title: str, description: str) -> Container: - """Erstellt einen Fehler-Container""" - container = Container() - container.add_text(f"โŒ **{title}**") - container.add_separator() - container.add_text(description) - container.add_separator() - container.add_text("Wikipedia Bot โ€ข Fehler aufgetreten") - return container - - -def create_disambiguation_container(term: str, options: List[str], language: str = 'de') -> Container: - """Erstellt einen Mehrdeutigkeits-Container""" - lang_info = { - 'de': 'Deutsch', - 'en': 'English', - 'fr': 'Franรงais', - 'es': 'Espaรฑol', - 'it': 'Italiano', - 'ja': 'ๆ—ฅๆœฌ่ชž', - 'ru': 'ะ ัƒััะบะธะน' - } - - container = Container() - - lang_name = lang_info.get(language, 'Deutsch') - container.add_text(f"๐Ÿ”€ **Mehrdeutige Suche**") - container.add_separator() - container.add_text(f"**'{term}'** kann mehrere Bedeutungen haben in {lang_name}:") - - container.add_separator() - container.add_text("๐Ÿ“‹ **Mรถgliche Optionen:**") - - options_text = "\n".join([f"โ€ข {opt}" for opt in options[:10]]) - container.add_text(options_text) - - container.add_separator() - container.add_text("๐Ÿ’ก Versuche eine spezifischere Suche oder wรคhle eine der Optionen.") - - return container - - -def create_loading_container(title: str = "Lade Wikipedia-Artikel...") -> Container: - """Erstellt einen Lade-Container""" - container = Container() - container.add_text(f"โณ **{title}**") - container.add_separator() - container.add_text("Dies kann einen Moment dauern...") - return container - - -def create_random_article_container( - info: Dict[str, Any], - user: discord.User, - similar_articles: List[str], - random_title: str, - language: str, - cog_instance=None -) -> Container: - """Erstellt einen Container fรผr zufรคllige Artikel""" - from .components import ( - LanguageSelectContainer, ArticleButtonContainer, - RandomArticleButton, ArticleInfoButton, RefreshArticleButton - ) - - container = Container() - - lang_info = { - 'de': {'name': 'Deutsch', 'flag': 'DE'}, - 'en': {'name': 'English', 'flag': 'EN'}, - 'fr': {'name': 'Franรงais', 'flag': 'FR'}, - 'es': {'name': 'Espaรฑol', 'flag': 'ES'}, - 'it': {'name': 'Italiano', 'flag': 'IT'}, - 'ja': {'name': 'ๆ—ฅๆœฌ่ชž', 'flag': 'JP'}, - 'ru': {'name': 'ะ ัƒััะบะธะน', 'flag': 'RU'}, - } - lang_data = lang_info.get(language, {'name': 'Deutsch', 'flag': 'DE'}) - - container.add_text(f"๐ŸŽฒ **Zufรคlliger Artikel: {info['title']}**") - container.add_text(f"[{lang_data['flag']}] {lang_data['name']} โ€ข Wikipedia") - container.add_separator() - - summary_text = info['summary'][:800] + ("..." if len(info['summary']) > 800 else "") - container.add_text(summary_text) - - if info.get('categories'): - container.add_separator() - categories_text = "๐Ÿ“‚ **Kategorien:** " + ", ".join(info['categories'][:3]) - if len(info['categories']) > 3: - categories_text += f" (+{len(info['categories']) - 3} weitere)" - container.add_text(categories_text) - - if info.get('coordinates'): - lat, lon = info['coordinates'] - container.add_text(f"๐Ÿ—บ๏ธ **Standort:** {lat:.2f}ยฐN, {lon:.2f}ยฐE") - - container.add_separator() - - if info.get('url'): - container.add_text(f"๐Ÿ”— [Vollstรคndigen Artikel lesen]({info['url']})") - - if cog_instance: - lang_select = LanguageSelectContainer(random_title, language, cog_instance) - container.add_item(lang_select) - - if similar_articles and cog_instance: - container.add_separator() - container.add_text("๐Ÿ“š **ร„hnliche Artikel:**") - for article in similar_articles[:4]: - article_btn = ArticleButtonContainer(article, "similar", cog_instance) - container.add_item(article_btn) - - container.add_separator() - - if cog_instance: - random_btn = RandomArticleButton(language, cog_instance) - container.add_item(random_btn) - - info_btn = ArticleInfoButton(info, language) - container.add_item(info_btn) - - refresh_btn = RefreshArticleButton(random_title, language, cog_instance) - container.add_item(refresh_btn) - - container.add_separator() - container.add_text(f"๐Ÿ‘ค Angefragt von {user.display_name}") - - return container \ No newline at end of file diff --git a/src/cogs/fun/wikipedia/utils.py b/src/cogs/fun/wikipedia/utils.py deleted file mode 100644 index aedf754..0000000 --- a/src/cogs/fun/wikipedia/utils.py +++ /dev/null @@ -1,114 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Utility Functions -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -import re -import wikipedia -from typing import Dict, Any - - -def clean_text(text: str, max_length: int = None) -> str: - """ - Erweiterte Textbereinigung - - Args: - text: Der zu bereinigende Text - max_length: Maximale Lรคnge des Textes - - Returns: - Bereinigter Text - """ - if not text: - return "Keine Beschreibung verfรผgbar." - - # HTML-Tags entfernen - text = re.sub(r'<[^>]+>', '', text) - # Referenzen in eckigen Klammern entfernen - text = re.sub(r'\[.*?\]', '', text) - # Mehrfache Leerzeichen normalisieren - text = re.sub(r'\s+', ' ', text).strip() - - max_length = max_length or 1500 - if len(text) > max_length: - truncated = text[:max_length - 3] - last_sentence = truncated.rfind('.') - if last_sentence > max_length // 2: - text = truncated[:last_sentence + 1] - else: - text = truncated + "..." - - return text - - -def format_page_info(page, language: str = 'de') -> Dict[str, Any]: - """ - Erweiterte Seiteninformationen mit Fehlerbehandlung - - Args: - page: Wikipedia-Seitenobjekt - language: Sprachcode - - Returns: - Dictionary mit formatierten Seiteninformationen - """ - try: - info = { - 'title': getattr(page, 'title', 'Unbekannt'), - 'url': getattr(page, 'url', ''), - 'summary': '', - 'categories': [], - 'links': [], - 'images': [], - 'language': language, - 'coordinates': None, - 'references': [] - } - - # Zusammenfassung laden - try: - info['summary'] = clean_text(wikipedia.summary(page.title, sentences=4)) - except: - info['summary'] = "Zusammenfassung nicht verfรผgbar." - - # Kategorien laden - try: - info['categories'] = getattr(page, 'categories', [])[:3] - except: - pass - - # Links laden - try: - info['links'] = getattr(page, 'links', [])[:15] - except: - pass - - # Bilder laden - try: - info['images'] = getattr(page, 'images', []) - except: - pass - - # Koordinaten extrahieren - try: - content = getattr(page, 'content', '') - coord_match = re.search(r'(\d+\.?\d*)ยฐ\s*N.*?(\d+\.?\d*)ยฐ\s*[EW]', content) - if coord_match: - info['coordinates'] = (float(coord_match.group(1)), float(coord_match.group(2))) - except: - pass - - return info - - except Exception as e: - return { - 'title': 'Fehler beim Laden', - 'url': '', - 'summary': f'Informationen konnten nicht geladen werden: {str(e)}', - 'categories': [], - 'links': [], - 'images': [], - 'language': language, - 'coordinates': None, - 'references': [] - } \ No newline at end of file diff --git a/src/cogs/informationen/botstatus.py b/src/cogs/informationen/botstatus.py deleted file mode 100644 index 24f00a6..0000000 --- a/src/cogs/informationen/botstatus.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Imports -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -import discord -from discord.ext import commands, tasks -import ezcord -import math -import yaml -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Cogs -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -class StatusCog(ezcord.Cog): - def __init__(self, bot): - self.bot = bot - self.update_status.start() # Starte den Loop direkt, er pausiert automatisch, falls der Bot nicht bereit ist - - @tasks.loop(seconds=30) - async def update_status(self): - if not self.bot.is_ready(): - return - - guild_count = len(self.bot.guilds) - member_count = sum(g.member_count for g in self.bot.guilds) - - latency = self.bot.latency * 1000 - latency = 0 if math.isnan(latency) else round(latency) - - statuses = [ - f"๐ŸŒ {guild_count} | ๐Ÿ‘ฅ {member_count} | ๐Ÿ“ {latency}ms" - ] - status_text = statuses[self.update_status.current_loop % len(statuses)] - - await self.bot.change_presence(activity=discord.CustomActivity(name=status_text)) - - @commands.Cog.listener() - async def on_ready(self): - if not self.update_status.is_running(): # Falls er aus irgendeinem Grund gestoppt wurde - self.update_status.start() - -def setup(bot): - bot.add_cog(StatusCog(bot)) \ No newline at end of file diff --git a/src/cogs/informationen/serverinfo.py b/src/cogs/informationen/serverinfo.py deleted file mode 100644 index 00a1562..0000000 --- a/src/cogs/informationen/serverinfo.py +++ /dev/null @@ -1,535 +0,0 @@ -import discord -from discord.ext import commands -from discord import SlashCommandGroup, Option -import datetime -import asyncio -from typing import Optional -import logging - - -class ServerInfoCog(commands.Cog): - def __init__(self, bot): - self.bot = bot - - server = SlashCommandGroup("server", "Server-Informationen und -Statistiken") - - @server.command(description="Zeigt umfassende Discord-Server Informationen an") - async def info(self, ctx): - """Hauptbefehl fรผr Server-Informationen mit detaillierter รœbersicht""" - guild = ctx.guild - - try: - await ctx.defer() # Mehr Zeit fรผr komplexe Berechnungen - - # Erweiterte Mitglieder-Statistiken - members = guild.members - total_members = len(members) - - # Status-Statistiken - status_counts = { - 'online': len([m for m in members if m.status == discord.Status.online]), - 'idle': len([m for m in members if m.status == discord.Status.idle]), - 'dnd': len([m for m in members if m.status == discord.Status.dnd]), - 'offline': len([m for m in members if m.status == discord.Status.offline]) - } - - bots = len([m for m in members if m.bot]) - humans = total_members - bots - - # Kanal-Statistiken - text_channels = len(guild.text_channels) - voice_channels = len(guild.voice_channels) - stage_channels = len(guild.stage_channels) - forum_channels = len([c for c in guild.channels if isinstance(c, discord.ForumChannel)]) - categories = len(guild.categories) - total_channels = len(guild.channels) - - # Rollen und Features - roles = len(guild.roles) - 1 # Exclude @everyone - emojis = len(guild.emojis) - stickers = len(guild.stickers) - - # Boost-Informationen - boost_count = guild.premium_subscription_count or 0 - boost_tier = guild.premium_tier - boosters = len(guild.premium_subscribers) if guild.premium_subscribers else 0 - - # Haupt-Embed erstellen - embed = discord.Embed( - title=f"๐Ÿ“Š {guild.name}", - description=guild.description or "*Keine Beschreibung verfรผgbar*", - color=discord.Color.blue(), - timestamp=datetime.datetime.now(datetime.timezone.utc) - ) - - # Server-Icon und Banner - if guild.icon: - embed.set_thumbnail(url=guild.icon.url) - - if guild.banner: - embed.set_image(url=guild.banner.url) - - # Grundlegende Informationen - created_timestamp = int(guild.created_at.timestamp()) - embed.add_field( - name="โ„น๏ธ Allgemeine Informationen", - value=f"๐Ÿ‘‘ **Besitzer:** {guild.owner.mention}\n" - f"๐Ÿ†” **ID:** `{guild.id}`\n" - f"๐Ÿ“… **Erstellt:** ()\n" - f"๐ŸŒ **Region:** {self._get_region_flag()} Automatisch", - inline=False - ) - - # Mitglieder-Statistiken - online_total = status_counts['online'] + status_counts['idle'] + status_counts['dnd'] - embed.add_field( - name="๐Ÿ‘ฅ Mitglieder", - value=f"**Gesamt:** {total_members:,}\n" - f"๐Ÿ‘ค **Menschen:** {humans:,}\n" - f"๐Ÿค– **Bots:** {bots:,}\n" - f"๐ŸŸข **Online:** {online_total:,}\n" - f"โ”œ ๐ŸŸข Aktiv: {status_counts['online']:,}\n" - f"โ”œ ๐ŸŸก Abwesend: {status_counts['idle']:,}\n" - f"โ”œ ๐Ÿ”ด Beschรคftigt: {status_counts['dnd']:,}\n" - f"โ”” โšซ Offline: {status_counts['offline']:,}", - inline=True - ) - - # Kanal-Informationen - embed.add_field( - name="๐Ÿ“บ Kanรคle", - value=f"**Gesamt:** {total_channels}\n" - f"๐Ÿ’ฌ **Text:** {text_channels}\n" - f"๐Ÿ”Š **Voice:** {voice_channels}\n" - f"๐ŸŽญ **Stage:** {stage_channels}\n" - f"๐Ÿ“‹ **Forum:** {forum_channels}\n" - f"๐Ÿ“ **Kategorien:** {categories}", - inline=True - ) - - # Server-Features und Anpassungen - embed.add_field( - name="๐ŸŽจ Anpassungen", - value=f"๐Ÿท๏ธ **Rollen:** {roles}\n" - f"๐Ÿ˜€ **Emojis:** {emojis}/{guild.emoji_limit}\n" - f"๐ŸŽƒ **Sticker:** {stickers}\n" - f"๐Ÿ“ **DateigrรถรŸe:** {guild.filesize_limit // 1024 // 1024} MB", - inline=True - ) - - # Boost-Informationen - boost_benefits = self._get_boost_benefits(boost_tier) - embed.add_field( - name="๐Ÿ’Ž Nitro Boosts", - value=f"๐Ÿš€ **Level:** {boost_tier}/3\n" - f"โญ **Boosts:** {boost_count}\n" - f"๐Ÿ‘‘ **Booster:** {boosters}\n" - f"๐ŸŽ **Benefits:** {boost_benefits}", - inline=True - ) - - # Sicherheit und Moderation - verification_emoji = { - discord.VerificationLevel.none: "๐ŸŸข", - discord.VerificationLevel.low: "๐ŸŸก", - discord.VerificationLevel.medium: "๐ŸŸ ", - discord.VerificationLevel.high: "๐Ÿ”ด", - discord.VerificationLevel.highest: "๐Ÿ”ด" - } - - nsfw_level_names = { - discord.NSFWLevel.default: "Standard", - discord.NSFWLevel.explicit: "Explizit", - discord.NSFWLevel.safe: "Sicher", - discord.NSFWLevel.age_restricted: "Altersbeschrรคnkt" - } - - embed.add_field( - name="๐Ÿ›ก๏ธ Sicherheit & Moderation", - value=f"{verification_emoji.get(guild.verification_level, 'โ“')} **Verifikation:** {guild.verification_level.name.title()}\n" - f"๐Ÿ”’ **2FA:** {'โœ… Aktiviert' if guild.mfa_level else 'โŒ Deaktiviert'}\n" - f"๐Ÿ”ž **NSFW Level:** {nsfw_level_names.get(guild.nsfw_level, 'Unbekannt')}\n" - f"๐Ÿ“ข **System Channel:** {guild.system_channel.mention if guild.system_channel else 'Nicht gesetzt'}", - inline=True - ) - - # Server-Features - features = self._format_guild_features(guild.features) - if features: - embed.add_field(name="โœจ Premium Features", value=features, inline=False) - - # Zusรคtzliche Informationen falls vorhanden - if guild.vanity_url: - embed.add_field(name="๐Ÿ”— Vanity URL", value=f"discord.gg/{guild.vanity_url}", inline=True) - - if guild.rules_channel: - embed.add_field(name="๐Ÿ“œ Regeln", value=guild.rules_channel.mention, inline=True) - - if guild.public_updates_channel: - embed.add_field(name="๐Ÿ“ข Updates", value=guild.public_updates_channel.mention, inline=True) - - embed.set_footer( - text=f"Angefragt von {ctx.author.display_name}", - icon_url=ctx.author.display_avatar.url - ) - - await ctx.followup.send(embed=embed) - - except Exception as e: - logging.error(f"Fehler in server info command: {e}") - await ctx.followup.send("โŒ Ein Fehler ist aufgetreten beim Laden der Server-Informationen.", ephemeral=True) - - @server.command(description="Zeigt Top-Rollen des Servers an") - async def roles(self, ctx, limit: Option(int, "Anzahl der anzuzeigenden Rollen (max 25)", min_value=1, max_value=25, default=15)): - """Zeigt die hรถchsten Rollen des Servers mit Details""" - try: - guild = ctx.guild - roles = sorted([role for role in guild.roles if role.name != "@everyone"], - key=lambda x: x.position, reverse=True) - - if not roles: - await ctx.respond("โŒ Keine besonderen Rollen auf diesem Server gefunden.", ephemeral=True) - return - - embed = discord.Embed( - title=f"๐Ÿท๏ธ Top Rollen in {guild.name}", - color=discord.Color.gold(), - timestamp=datetime.datetime.now(datetime.timezone.utc) - ) - - role_list = [] - for i, role in enumerate(roles[:limit], 1): - member_count = len(role.members) - permissions_count = sum(1 for perm, value in role.permissions if value) - - # Spezielle Rollen-Indikatoren - indicators = [] - if role.permissions.administrator: - indicators.append("๐Ÿ‘‘") - if role.permissions.manage_guild: - indicators.append("โš™๏ธ") - if role.permissions.ban_members or role.permissions.kick_members: - indicators.append("๐Ÿ”จ") - if role.managed: - indicators.append("๐Ÿค–") - if role.hoist: - indicators.append("๐Ÿ“Œ") - - indicator_str = "".join(indicators) - - role_list.append( - f"`#{i:2d}` {role.mention} {indicator_str}\n" - f" ๐Ÿ‘ฅ {member_count} | ๐Ÿ” {permissions_count} Perms | Pos: {role.position}" - ) - - # Aufteilen in mehrere Fields falls nรถtig - chunk_size = 8 - for i in range(0, len(role_list), chunk_size): - chunk = role_list[i:i+chunk_size] - field_name = f"Rollen {i+1}-{min(i+chunk_size, len(role_list))}" if len(role_list) > chunk_size else "Rollen" - embed.add_field(name=field_name, value="\n".join(chunk), inline=False) - - embed.add_field( - name="๐Ÿ“Š Statistiken", - value=f"**Gesamt:** {len(guild.roles)-1} Rollen\n" - f"**Angezeigt:** {min(limit, len(roles))}\n" - f"**Legende:** ๐Ÿ‘‘ Admin | โš™๏ธ Management | ๐Ÿ”จ Moderation | ๐Ÿค– Bot | ๐Ÿ“Œ Angeheftet", - inline=False - ) - - await ctx.respond(embed=embed) - - except Exception as e: - logging.error(f"Fehler in server roles command: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Laden der Rollen.", ephemeral=True) - - @server.command(description="Zeigt Kanal-รœbersicht des Servers") - async def channels(self, ctx): - """Zeigt eine strukturierte รœbersicht aller Kanรคle""" - try: - guild = ctx.guild - - embed = discord.Embed( - title=f"๐Ÿ“บ Kanรคle in {guild.name}", - color=discord.Color.blue(), - timestamp=datetime.datetime.now(datetime.timezone.utc) - ) - - # Kategorien und ihre Kanรคle - categories_processed = set() - - # Kanรคle ohne Kategorie - no_category = [ch for ch in guild.channels if ch.category is None and not isinstance(ch, discord.CategoryChannel)] - if no_category: - channel_list = [] - for ch in no_category: - channel_list.append(f"{self._get_channel_emoji(ch)} {ch.name}") - - if len("\n".join(channel_list)) <= 1024: - embed.add_field( - name="๐Ÿ“ Ohne Kategorie", - value="\n".join(channel_list) or "Keine", - inline=False - ) - - # Kategorien mit ihren Kanรคlen - for category in guild.categories[:10]: # Limit fรผr Embed-GrรถรŸe - if category in categories_processed: - continue - - channel_list = [] - for ch in category.channels: - channel_list.append(f"{self._get_channel_emoji(ch)} {ch.name}") - - if channel_list and len("\n".join(channel_list)) <= 1024: - embed.add_field( - name=f"๐Ÿ“ {category.name} ({len(category.channels)})", - value="\n".join(channel_list), - inline=True - ) - categories_processed.add(category) - - # Statistiken - stats = ( - f"๐Ÿ“Š **Gesamt:** {len(guild.channels)}\n" - f"๐Ÿ’ฌ **Text:** {len(guild.text_channels)}\n" - f"๐Ÿ”Š **Voice:** {len(guild.voice_channels)}\n" - f"๐ŸŽญ **Stage:** {len(guild.stage_channels)}\n" - f"๐Ÿ“‹ **Forum:** {len([c for c in guild.channels if isinstance(c, discord.ForumChannel)])}\n" - f"๐Ÿ“ **Kategorien:** {len(guild.categories)}" - ) - - embed.add_field(name="๐Ÿ“ˆ Statistiken", value=stats, inline=True) - - if len(guild.categories) > 10: - embed.set_footer(text=f"... und {len(guild.categories) - 10} weitere Kategorien") - - await ctx.respond(embed=embed) - - except Exception as e: - logging.error(f"Fehler in server channels command: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Laden der Kanal-รœbersicht.", ephemeral=True) - - @server.command(description="Zeigt Emoji-รœbersicht des Servers") - async def emojis(self, ctx): - """Zeigt alle Custom Emojis des Servers""" - try: - guild = ctx.guild - emojis = guild.emojis - - if not emojis: - embed = discord.Embed( - title="๐Ÿ˜” Keine Custom Emojis", - description="Dieser Server hat keine benutzerdefinierten Emojis.", - color=discord.Color.orange() - ) - await ctx.respond(embed=embed) - return - - # Emojis nach Typ sortieren - static_emojis = [e for e in emojis if not e.animated] - animated_emojis = [e for e in emojis if e.animated] - - embed = discord.Embed( - title=f"๐Ÿ˜€ Emojis in {guild.name}", - description=f"**{len(static_emojis)}** statische โ€ข **{len(animated_emojis)}** animierte โ€ข **{len(emojis)}/{guild.emoji_limit}** gesamt", - color=discord.Color.yellow(), - timestamp=datetime.datetime.now(datetime.timezone.utc) - ) - - # Statische Emojis (max 25 pro Field) - if static_emojis: - emoji_chunks = [static_emojis[i:i+25] for i in range(0, len(static_emojis), 25)] - for i, chunk in enumerate(emoji_chunks[:3]): # Max 3 Chunks - emoji_display = "".join([str(emoji) for emoji in chunk]) - field_name = f"๐Ÿ“ท Statische Emojis" if i == 0 else f"๐Ÿ“ท Statische Emojis (Teil {i+1})" - embed.add_field(name=field_name, value=emoji_display or "Keine", inline=False) - - # Animierte Emojis - if animated_emojis: - emoji_chunks = [animated_emojis[i:i+25] for i in range(0, len(animated_emojis), 25)] - for i, chunk in enumerate(emoji_chunks[:2]): # Max 2 Chunks fรผr animierte - emoji_display = "".join([str(emoji) for emoji in chunk]) - field_name = f"๐ŸŽฌ Animierte Emojis" if i == 0 else f"๐ŸŽฌ Animierte Emojis (Teil {i+1})" - embed.add_field(name=field_name, value=emoji_display or "Keine", inline=False) - - await ctx.respond(embed=embed) - - except Exception as e: - logging.error(f"Fehler in server emojis command: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Laden der Emojis.", ephemeral=True) - - @server.command(description="Zeigt Server-Boosts und Premium-Features") - async def boosts(self, ctx): - """Detaillierte Boost-Informationen""" - try: - guild = ctx.guild - - embed = discord.Embed( - title=f"๐Ÿ’Ž Server Boosts - {guild.name}", - color=discord.Color.purple(), - timestamp=datetime.datetime.now(datetime.timezone.utc) - ) - - boost_count = guild.premium_subscription_count or 0 - boost_tier = guild.premium_tier - boosters = guild.premium_subscribers or [] - - # Aktuelle Boost-Situation - embed.add_field( - name="๐Ÿ“Š Aktuelle Situation", - value=f"๐Ÿš€ **Level:** {boost_tier}/3\n" - f"โญ **Boosts:** {boost_count}\n" - f"๐Ÿ‘‘ **Booster:** {len(boosters)}\n" - f"๐Ÿ“ˆ **Progress:** {self._get_boost_progress(boost_count, boost_tier)}", - inline=False - ) - - # Nรคchstes Level - next_level_info = self._get_next_level_info(boost_count, boost_tier) - if next_level_info: - embed.add_field(name="๐ŸŽฏ Nรคchstes Level", value=next_level_info, inline=False) - - # Aktuelle Benefits - benefits = self._get_detailed_boost_benefits(guild) - embed.add_field(name="๐ŸŽ Aktuelle Benefits", value=benefits, inline=False) - - # Top Booster (falls vorhanden) - if boosters: - booster_list = [booster.mention for booster in boosters[:10]] - embed.add_field( - name=f"๐Ÿ‘‘ Booster ({len(boosters)})", - value=", ".join(booster_list) + ("..." if len(boosters) > 10 else ""), - inline=False - ) - - await ctx.respond(embed=embed) - - except Exception as e: - logging.error(f"Fehler in server boosts command: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Laden der Boost-Informationen.", ephemeral=True) - - def _get_channel_emoji(self, channel): - """Gibt das passende Emoji fรผr einen Kanal-Typ zurรผck""" - if isinstance(channel, discord.TextChannel): - return "๐Ÿ’ฌ" - elif isinstance(channel, discord.VoiceChannel): - return "๐Ÿ”Š" - elif isinstance(channel, discord.StageChannel): - return "๐ŸŽญ" - elif isinstance(channel, discord.ForumChannel): - return "๐Ÿ“‹" - elif isinstance(channel, discord.CategoryChannel): - return "๐Ÿ“" - else: - return "๐Ÿ“บ" - - def _get_region_flag(self): - """Gibt eine Flagge fรผr die Region zurรผck (falls erwรผnscht)""" - return "๐ŸŒ" # Globus fรผr automatische Region - - def _get_boost_benefits(self, tier): - """Gibt die Benefits fรผr ein Boost-Level zurรผck""" - benefits = { - 0: "Keine", - 1: "50 Emoji Slots, 128kb Audio", - 2: "150 Emoji Slots, 256kb Audio, Banner", - 3: "250 Emoji Slots, 384kb Audio, Vanity URL" - } - return benefits.get(tier, "Unbekannt") - - def _get_detailed_boost_benefits(self, guild): - """Detaillierte Boost-Benefits fรผr den aktuellen Server""" - tier = guild.premium_tier - - benefits = [ - f"๐Ÿ˜€ **Emoji Slots:** {guild.emoji_limit}", - f"๐Ÿ“ **DateigrรถรŸe:** {guild.filesize_limit // 1024 // 1024} MB", - f"๐ŸŽต **Audio Qualitรคt:** {64 * (2 ** tier)} kbps" - ] - - if tier >= 2: - benefits.extend([ - "๐Ÿ–ผ๏ธ **Server Banner:** โœ…", - "๐ŸŽจ **Server Icon Animation:** โœ…" - ]) - - if tier >= 3: - benefits.extend([ - "๐Ÿ”— **Vanity URL:** โœ…", - "๐Ÿ“บ **Go Live 1080p:** โœ…" - ]) - - return "\n".join(benefits) - - def _get_boost_progress(self, current_boosts, current_tier): - """Zeigt den Progress zum nรคchsten Level""" - requirements = {1: 2, 2: 7, 3: 14} - - if current_tier >= 3: - return "โœ… Max Level erreicht!" - - next_tier = current_tier + 1 - needed = requirements[next_tier] - progress = min(current_boosts, needed) - - bar_length = 10 - filled = int((progress / needed) * bar_length) - bar = "โ–ˆ" * filled + "โ–‘" * (bar_length - filled) - - return f"{bar} {progress}/{needed}" - - def _get_next_level_info(self, current_boosts, current_tier): - """Informationen รผber das nรคchste Boost-Level""" - if current_tier >= 3: - return None - - requirements = {1: 2, 2: 7, 3: 14} - next_tier = current_tier + 1 - needed = requirements[next_tier] - current_boosts - - if needed <= 0: - return f"๐ŸŽ‰ Level {next_tier} bereits erreicht!" - - benefits = { - 1: "50 Emoji Slots, bessere Audio-Qualitรคt (128 kbps)", - 2: "150 Emoji Slots, Server Banner, noch bessere Audio (256 kbps)", - 3: "250 Emoji Slots, Vanity URL, beste Audio-Qualitรคt (384 kbps)" - } - - return f"**Level {next_tier}**\nNoch {needed} Boost{'s' if needed != 1 else ''} benรถtigt\n{benefits[next_tier]}" - - def _format_guild_features(self, features): - """Formatiert Guild-Features fรผr die Anzeige""" - if not features: - return None - - feature_names = { - 'ANIMATED_ICON': '๐ŸŽญ Animiertes Icon', - 'BANNER': '๐Ÿ–ผ๏ธ Server Banner', - 'COMMERCE': '๐Ÿ›’ Commerce', - 'COMMUNITY': '๐Ÿ˜๏ธ Community Server', - 'DISCOVERABLE': '๐Ÿ” Auffindbar', - 'FEATURABLE': 'โญ Auszeichnungsfรคhig', - 'INVITE_SPLASH': '๐ŸŒŠ Invite Splash', - 'MEMBER_VERIFICATION_GATE_ENABLED': '๐Ÿšช Mitglieder-Verifizierung', - 'NEWS': '๐Ÿ“ฐ News Channel', - 'PARTNERED': '๐Ÿค Partner', - 'PREVIEW_ENABLED': '๐Ÿ‘€ Preview aktiviert', - 'PUBLIC_DISABLED': '๐Ÿ”’ Nicht รถffentlich', - 'VANITY_URL': '๐Ÿ”— Vanity URL', - 'VERIFIED': 'โœ… Verifiziert', - 'VIP_REGIONS': '๐ŸŒŸ VIP Regionen', - 'WELCOME_SCREEN_ENABLED': '๐Ÿ‘‹ Willkommensbildschirm' - } - - formatted_features = [] - for feature in features: - display_name = feature_names.get(feature, feature.replace('_', ' ').title()) - formatted_features.append(display_name) - - return "\n".join(formatted_features) if formatted_features else None - - -def setup(bot): - bot.add_cog(ServerInfoCog(bot)) \ No newline at end of file diff --git a/src/cogs/informationen/usermanagemt.py b/src/cogs/informationen/usermanagemt.py deleted file mode 100644 index b535872..0000000 --- a/src/cogs/informationen/usermanagemt.py +++ /dev/null @@ -1,403 +0,0 @@ -import discord -from discord import slash_command, Option, SlashCommandGroup -from discord.ext import commands -import ezcord -from datetime import datetime, timezone -import logging - -class UserManagement(ezcord.Cog): - def __init__(self, bot): - self.bot = bot - - user = SlashCommandGroup("user", "Erweiterte Benutzerverwaltung") - - @user.command(description="Zeigt detaillierte Informationen รผber einen Benutzer an") - async def info(self, ctx, user: Option(discord.User, "Der Benutzer, รผber den du Informationen erhalten mรถchtest", default=None)): - # Wenn kein Benutzer angegeben wurde, zeige Informationen รผber den Autor - target_user = user or ctx.author - - try: - # Versuche den Benutzer als Member zu bekommen fรผr erweiterte Informationen - if isinstance(target_user, discord.User): - member = ctx.guild.get_member(target_user.id) if ctx.guild else None - else: - member = target_user - - embed = discord.Embed( - title=f"๐Ÿ“‹ Informationen รผber {target_user.display_name}", - color=discord.Color.blue(), - timestamp=datetime.now(timezone.utc) - ) - - # Grundlegende Informationen - embed.add_field(name="๐Ÿ‘ค Benutzername", value=f"{target_user.name}#{target_user.discriminator}", inline=True) - embed.add_field(name="๐Ÿ†” ID", value=target_user.id, inline=True) - embed.add_field(name="๐Ÿค– Bot", value="Ja" if target_user.bot else "Nein", inline=True) - - # Account-Erstellung - created_at = target_user.created_at - embed.add_field( - name="๐Ÿ“… Account erstellt", - value=f"{created_at.strftime('%d.%m.%Y')}\n()", - inline=True - ) - - # Server-spezifische Informationen (nur wenn Member) - if member: - embed.add_field(name="๐Ÿ“ฑ Status", value=str(member.status).capitalize(), inline=True) - - if member.joined_at: - joined_at = member.joined_at - embed.add_field( - name="๐Ÿ“ฅ Server beigetreten", - value=f"{joined_at.strftime('%d.%m.%Y')}\n()", - inline=True - ) - - # Rollen (nur die wichtigsten anzeigen) - roles = [role for role in member.roles[1:] if role.name != "@everyone"][:5] - if roles: - embed.add_field( - name=f"๐Ÿท๏ธ Rollen ({len(member.roles)-1} gesamt)", - value=", ".join(role.mention for role in roles) + ("..." if len(member.roles) > 6 else ""), - inline=False - ) - - # Hรถchste Rolle - if member.top_role.name != "@everyone": - embed.add_field(name="โญ Hรถchste Rolle", value=member.top_role.mention, inline=True) - - # Nickname - if member.nick: - embed.add_field(name="๐Ÿ“ Nickname", value=member.nick, inline=True) - - # Gemeinsame Server - mutual_guilds = len(target_user.mutual_guilds) if hasattr(target_user, 'mutual_guilds') else "Unbekannt" - embed.add_field(name="๐ŸŒ Gemeinsame Server", value=str(mutual_guilds), inline=True) - - # Avatar - if target_user.avatar: - embed.set_thumbnail(url=target_user.avatar.url) - embed.add_field(name="๐Ÿ–ผ๏ธ Avatar", value=f"[Link]({target_user.avatar.url})", inline=True) - else: - embed.set_thumbnail(url=target_user.default_avatar.url) - embed.add_field(name="๐Ÿ–ผ๏ธ Avatar", value="Standard Avatar", inline=True) - - embed.set_footer( - text=f"Angefordert von {ctx.author.display_name}", - icon_url=ctx.author.display_avatar.url - ) - - await ctx.respond(embed=embed) - - except Exception as e: - logging.error(f"Fehler in user info command: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Abrufen der Benutzerinformationen.", ephemeral=True) - - @user.command(description="Zeigt alle Rollen eines Benutzers an") - async def roles(self, ctx, user: Option(discord.Member, "Der Benutzer, dessen Rollen du sehen mรถchtest", default=None)): - target_user = user or ctx.author - - try: - roles = [role for role in target_user.roles[1:] if role.name != "@everyone"] - - if not roles: - embed = discord.Embed( - title="๐Ÿท๏ธ Rollen", - description=f"{target_user.display_name} hat keine besonderen Rollen.", - color=discord.Color.orange() - ) - await ctx.respond(embed=embed) - return - - embed = discord.Embed( - title=f"๐Ÿท๏ธ Rollen von {target_user.display_name}", - color=target_user.top_role.color or discord.Color.blue(), - timestamp=datetime.now(timezone.utc) - ) - - # Rollen nach Hierarchie sortieren - roles.sort(key=lambda x: x.position, reverse=True) - - role_list = [] - for i, role in enumerate(roles, 1): - permissions_count = sum(1 for perm, value in role.permissions if value) - role_list.append(f"{i}. {role.mention} (Pos: {role.position}, Perms: {permissions_count})") - - # Aufteilen in Chunks falls zu viele Rollen - chunk_size = 10 - for i in range(0, len(role_list), chunk_size): - chunk = role_list[i:i+chunk_size] - field_name = "Rollen" if i == 0 else f"Rollen (Fortsetzung)" - embed.add_field(name=field_name, value="\n".join(chunk), inline=False) - - embed.set_footer(text=f"Gesamt: {len(roles)} Rollen") - await ctx.respond(embed=embed) - - except Exception as e: - logging.error(f"Fehler in user roles command: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Abrufen der Rollen.", ephemeral=True) - - @user.command(description="Setzt den Nicknamen eines Benutzers") - @discord.default_permissions(manage_nicknames=True) - async def set_nickname(self, ctx, user: Option(discord.Member, "Der Benutzer, dessen Nicknamen du รคndern mรถchtest"), nickname: Option(str, "Der neue Nickname (leer lassen zum Entfernen)", required=False)): - try: - # Berechtigungsprรผfungen - if not ctx.author.guild_permissions.manage_nicknames: - await ctx.respond("โŒ Du hast keine Berechtigung, Nicknames zu verwalten.", ephemeral=True) - return - - if user.top_role >= ctx.author.top_role and ctx.author != ctx.guild.owner: - await ctx.respond("โŒ Du kannst den Nickname dieses Benutzers nicht รคndern (hรถhere Rolle).", ephemeral=True) - return - - if user == ctx.guild.owner: - await ctx.respond("โŒ Der Nickname des Server-Besitzers kann nicht geรคndert werden.", ephemeral=True) - return - - # Nickname validieren - if nickname and len(nickname) > 32: - await ctx.respond("โŒ Der Nickname ist zu lang (maximal 32 Zeichen).", ephemeral=True) - return - - old_nick = user.display_name - await user.edit(nick=nickname, reason=f"Nickname geรคndert von {ctx.author}") - - embed = discord.Embed( - title="โœ… Nickname geรคndert", - color=discord.Color.green(), - timestamp=datetime.now(timezone.utc) - ) - embed.add_field(name="Benutzer", value=user.mention, inline=True) - embed.add_field(name="Vorher", value=old_nick, inline=True) - embed.add_field(name="Nachher", value=nickname or user.name, inline=True) - embed.set_footer(text=f"Geรคndert von {ctx.author.display_name}") - - await ctx.respond(embed=embed) - - except discord.Forbidden: - await ctx.respond("โŒ Ich habe keine Berechtigung, den Nickname zu รคndern.", ephemeral=True) - except Exception as e: - logging.error(f"Fehler beim Setzen des Nicknames: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim ร„ndern des Nicknames.", ephemeral=True) - - @user.command(description="Entfernt alle Rollen eines Benutzers") - @discord.default_permissions(manage_roles=True) - async def remove_roles(self, ctx, user: Option(discord.Member, "Der Benutzer, dessen Rollen du entfernen mรถchtest"), reason: Option(str, "Grund fรผr die Aktion", required=False)): - try: - # Berechtigungsprรผfungen - if not ctx.author.guild_permissions.manage_roles: - await ctx.respond("โŒ Du hast keine Berechtigung, Rollen zu verwalten.", ephemeral=True) - return - - if user.top_role >= ctx.author.top_role and ctx.author != ctx.guild.owner: - await ctx.respond("โŒ Du kannst die Rollen dieses Benutzers nicht verwalten (hรถhere Rolle).", ephemeral=True) - return - - if user == ctx.guild.owner: - await ctx.respond("โŒ Die Rollen des Server-Besitzers kรถnnen nicht entfernt werden.", ephemeral=True) - return - - removable_roles = [role for role in user.roles[1:] if role < ctx.me.top_role] - - if not removable_roles: - await ctx.respond("โŒ Keine Rollen zum Entfernen gefunden oder Bot hat unzureichende Berechtigungen.", ephemeral=True) - return - - # Bestรคtigung anfordern - embed = discord.Embed( - title="โš ๏ธ Rollen entfernen bestรคtigen", - description=f"Mรถchtest du wirklich **{len(removable_roles)} Rollen** von {user.mention} entfernen?\n\n**Rollen:** {', '.join(role.name for role in removable_roles[:5])}{'...' if len(removable_roles) > 5 else ''}", - color=discord.Color.orange() - ) - - view = ConfirmationView() - await ctx.respond(embed=embed, view=view, ephemeral=True) - await view.wait() - - if view.value: - audit_reason = f"Alle Rollen entfernt von {ctx.author}" + (f" | Grund: {reason}" if reason else "") - await user.remove_roles(*removable_roles, reason=audit_reason) - - embed = discord.Embed( - title="โœ… Rollen entfernt", - description=f"**{len(removable_roles)} Rollen** wurden von {user.mention} entfernt.", - color=discord.Color.green(), - timestamp=datetime.now(timezone.utc) - ) - embed.set_footer(text=f"Entfernt von {ctx.author.display_name}") - await ctx.edit(embed=embed, view=None) - else: - embed = discord.Embed( - title="โŒ Abgebrochen", - description="Die Aktion wurde abgebrochen.", - color=discord.Color.red() - ) - await ctx.edit(embed=embed, view=None) - - except discord.Forbidden: - await ctx.respond("โŒ Ich habe keine Berechtigung, diese Rollen zu entfernen.", ephemeral=True) - except Exception as e: - logging.error(f"Fehler beim Entfernen der Rollen: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Entfernen der Rollen.", ephemeral=True) - - @user.command(description="Gibt einem Benutzer eine Rolle") - @discord.default_permissions(manage_roles=True) - async def give_role(self, ctx, user: Option(discord.Member, "Der Benutzer, dem du eine Rolle geben mรถchtest"), role: Option(discord.Role, "Die Rolle, die du vergeben mรถchtest"), reason: Option(str, "Grund fรผr die Rollenvergabe", required=False)): - try: - # Berechtigungsprรผfungen - if not ctx.author.guild_permissions.manage_roles: - await ctx.respond("โŒ Du hast keine Berechtigung, Rollen zu verwalten.", ephemeral=True) - return - - if role >= ctx.author.top_role and ctx.author != ctx.guild.owner: - await ctx.respond("โŒ Du kannst diese Rolle nicht vergeben (Rolle ist hรถher als deine).", ephemeral=True) - return - - if role >= ctx.me.top_role: - await ctx.respond("โŒ Ich kann diese Rolle nicht vergeben (Rolle ist hรถher als meine).", ephemeral=True) - return - - if role in user.roles: - await ctx.respond(f"โŒ {user.display_name} hat bereits die Rolle {role.mention}.", ephemeral=True) - return - - audit_reason = f"Rolle vergeben von {ctx.author}" + (f" | Grund: {reason}" if reason else "") - await user.add_roles(role, reason=audit_reason) - - embed = discord.Embed( - title="โœ… Rolle vergeben", - color=discord.Color.green(), - timestamp=datetime.now(timezone.utc) - ) - embed.add_field(name="Benutzer", value=user.mention, inline=True) - embed.add_field(name="Rolle", value=role.mention, inline=True) - if reason: - embed.add_field(name="Grund", value=reason, inline=False) - embed.set_footer(text=f"Vergeben von {ctx.author.display_name}") - - await ctx.respond(embed=embed) - - except discord.Forbidden: - await ctx.respond("โŒ Ich habe keine Berechtigung, diese Rolle zu vergeben.", ephemeral=True) - except Exception as e: - logging.error(f"Fehler beim Vergeben der Rolle: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Vergeben der Rolle.", ephemeral=True) - - @user.command(description="Entfernt eine Rolle von einem Benutzer") - @discord.default_permissions(manage_roles=True) - async def remove_role(self, ctx, user: Option(discord.Member, "Der Benutzer, von dem du eine Rolle entfernen mรถchtest"), role: Option(discord.Role, "Die Rolle, die du entfernen mรถchtest"), reason: Option(str, "Grund fรผr die Entfernung", required=False)): - try: - # Berechtigungsprรผfungen - if not ctx.author.guild_permissions.manage_roles: - await ctx.respond("โŒ Du hast keine Berechtigung, Rollen zu verwalten.", ephemeral=True) - return - - if role >= ctx.author.top_role and ctx.author != ctx.guild.owner: - await ctx.respond("โŒ Du kannst diese Rolle nicht entfernen (Rolle ist hรถher als deine).", ephemeral=True) - return - - if role >= ctx.me.top_role: - await ctx.respond("โŒ Ich kann diese Rolle nicht entfernen (Rolle ist hรถher als meine).", ephemeral=True) - return - - if role not in user.roles: - await ctx.respond(f"โŒ {user.display_name} hat die Rolle {role.mention} nicht.", ephemeral=True) - return - - audit_reason = f"Rolle entfernt von {ctx.author}" + (f" | Grund: {reason}" if reason else "") - await user.remove_roles(role, reason=audit_reason) - - embed = discord.Embed( - title="โœ… Rolle entfernt", - color=discord.Color.green(), - timestamp=datetime.now(timezone.utc) - ) - embed.add_field(name="Benutzer", value=user.mention, inline=True) - embed.add_field(name="Rolle", value=role.mention, inline=True) - if reason: - embed.add_field(name="Grund", value=reason, inline=False) - embed.set_footer(text=f"Entfernt von {ctx.author.display_name}") - - await ctx.respond(embed=embed) - - except discord.Forbidden: - await ctx.respond("โŒ Ich habe keine Berechtigung, diese Rolle zu entfernen.", ephemeral=True) - except Exception as e: - logging.error(f"Fehler beim Entfernen der Rolle: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Entfernen der Rolle.", ephemeral=True) - - @user.command(description="Zeigt die Berechtigungen eines Benutzers an") - async def permissions(self, ctx, user: Option(discord.Member, "Der Benutzer, dessen Berechtigungen du sehen mรถchtest", default=None)): - target_user = user or ctx.author - - try: - permissions = target_user.guild_permissions - - embed = discord.Embed( - title=f"๐Ÿ” Berechtigungen von {target_user.display_name}", - color=discord.Color.blue(), - timestamp=datetime.now(timezone.utc) - ) - - # Wichtige Berechtigungen hervorheben - admin_perms = [] - mod_perms = [] - basic_perms = [] - - for perm, value in permissions: - if not value: - continue - - perm_name = perm.replace('_', ' ').title() - - if perm in ['administrator']: - admin_perms.append(perm_name) - elif perm in ['manage_guild', 'manage_roles', 'manage_channels', 'ban_members', 'kick_members', 'manage_messages']: - mod_perms.append(perm_name) - else: - basic_perms.append(perm_name) - - if admin_perms: - embed.add_field(name="๐Ÿ‘‘ Administrator", value="\n".join(admin_perms), inline=False) - - if mod_perms: - embed.add_field(name="๐Ÿ›ก๏ธ Moderation", value="\n".join(mod_perms), inline=False) - - if basic_perms: - # Nur die ersten 10 anzeigen - basic_display = basic_perms[:10] - if len(basic_perms) > 10: - basic_display.append(f"... und {len(basic_perms) - 10} weitere") - embed.add_field(name="๐Ÿ“ Allgemein", value="\n".join(basic_display), inline=False) - - embed.set_footer(text=f"Gesamt: {sum(1 for _, value in permissions if value)} Berechtigungen") - await ctx.respond(embed=embed) - - except Exception as e: - logging.error(f"Fehler beim Abrufen der Berechtigungen: {e}") - await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Abrufen der Berechtigungen.", ephemeral=True) - - -class ConfirmationView(discord.ui.View): - def __init__(self): - super().__init__(timeout=30) - self.value = None - - @discord.ui.button(label="Bestรคtigen", style=discord.ButtonStyle.danger, emoji="โœ…") - async def confirm(self, button: discord.ui.Button, interaction: discord.Interaction): - self.value = True - self.stop() - - @discord.ui.button(label="Abbrechen", style=discord.ButtonStyle.secondary, emoji="โŒ") - async def cancel(self, button: discord.ui.Button, interaction: discord.Interaction): - self.value = False - self.stop() - - async def on_timeout(self): - self.value = False - self.stop() - - -def setup(bot): - bot.add_cog(UserManagement(bot)) \ No newline at end of file diff --git a/src/cogs/moderation/antispam.py b/src/cogs/moderation/antispam.py deleted file mode 100644 index 6664a44..0000000 --- a/src/cogs/moderation/antispam.py +++ /dev/null @@ -1,439 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -from collections import defaultdict -import asyncio -import discord -from discord import SlashCommandGroup -import ezcord -import datetime -from datetime import timedelta - - -from DevTools import AntiSpamDatabase as SpamDB - - -class AntiSpam(ezcord.Cog): - antispam = SlashCommandGroup( - "antispam", - "Verwalte Anti-Spam-Einstellungen und Protokolle.", - ) - - def __init__(self, bot: ezcord.Bot): - self.bot = bot - self.db = SpamDB() - # Track user message timestamps per guild - self.user_messages = defaultdict(lambda: defaultdict(list)) - # Track users currently in timeout to prevent duplicate actions - self.users_in_timeout = set() - - @ezcord.Cog.listener() - async def on_message(self, message): - """Monitor messages for spam detection.""" - # Ignore bot messages and DMs - if message.author.bot or not message.guild: - return - - # Check if user is whitelisted - if self.is_whitelisted(message.guild.id, message.author.id): - return - - # Get spam settings for this guild - settings = self.db.get_spam_settings(message.guild.id) - if not settings: - # If no settings are configured, don't process spam detection - return - - # Check if log channel is set - if not settings.get('log_channel_id'): - return - - # Record this message timestamp - user_id = message.author.id - guild_id = message.guild.id - current_time = datetime.now() - - # Add current message to tracking - self.user_messages[guild_id][user_id].append(current_time) - - # Clean old messages outside the time frame - time_threshold = current_time - timedelta(seconds=settings['time_frame']) - self.user_messages[guild_id][user_id] = [ - timestamp for timestamp in self.user_messages[guild_id][user_id] - if timestamp > time_threshold - ] - - # Check if user exceeded message limit - message_count = len(self.user_messages[guild_id][user_id]) - if message_count > settings['max_messages']: - await self.handle_spam_violation(message, settings) - - async def handle_spam_violation(self, message, settings): - """Handle a user who violated spam limits.""" - user = message.author - guild = message.guild - - # Prevent duplicate actions for the same user - user_timeout_key = f"{guild.id}_{user.id}" - if user_timeout_key in self.users_in_timeout: - return - - self.users_in_timeout.add(user_timeout_key) - - try: - # Log the spam incident - self.db.log_spam(guild.id, user.id, message.content[:100]) # Limit message length - - # Delete recent messages from this user - await self.delete_recent_messages(message.channel, user, limit=settings['max_messages']) - - # Apply timeout (5 minutes) - timeout_duration = timedelta(minutes=5) - timeout_applied = False - - try: - await user.timeout_for(timeout_duration, reason="Anti-Spam: Zu viele Nachrichten") - timeout_applied = True - except discord.Forbidden: - pass # Continue to log even if timeout fails - - # Send log to designated channel - await self.send_spam_log(guild, user, message, settings, timeout_applied) - - # Send warning message in channel - embed = discord.Embed( - title=f"{emoji_forbidden} ร— Anti-Spam Warnung", - description=f"{user.mention} wurde wegen zu vieler Nachrichten {'stumm geschaltet' if timeout_applied else 'verwarnt'}.", - color=ERROR_COLOR - ) - embed.add_field( - name="Limit รผberschritten", - value=f"Maximal {settings['max_messages']} Nachrichten in {settings['time_frame']} Sekunden erlaubt", - inline=False - ) - await message.channel.send(embed=embed, delete_after=10) - - # Clear user's message tracking after violation - if guild.id in self.user_messages and user.id in self.user_messages[guild.id]: - self.user_messages[guild_id][user.id].clear() - - # Remove from timeout tracking after delay - await asyncio.sleep(300) # 5 minutes - self.users_in_timeout.discard(user_timeout_key) - - except Exception as e: - print(f"Error handling spam violation: {e}") - self.users_in_timeout.discard(user_timeout_key) - - async def send_spam_log(self, guild, user, message, settings, timeout_applied): - """Send spam log to designated log channel.""" - log_channel_id = settings.get('log_channel_id') - if not log_channel_id: - return - - log_channel = guild.get_channel(log_channel_id) - if not log_channel: - return - - try: - embed = discord.Embed( - title=f"{emoji_warn} ร— Anti-Spam VerstoรŸ", - color=discord.Color.red(), - timestamp=datetime.now() - ) - embed.add_field( - name=f"{emoji_member} ร— Benutzer", - value=f"{user.mention} ({user.id})", - inline=True - ) - embed.add_field( - name=f"{emoji_channel} ร— Kanal", - value=message.channel.mention, - inline=True - ) - embed.add_field( - name=f"{emoji_moderator} ร— Aktion", - value="Timeout (5 Min)" if timeout_applied else "Warnung", - inline=True - ) - embed.add_field( - name=f"{emoji_statistics} ร— Limit", - value=f"{settings['max_messages']} Nachrichten in {settings['time_frame']}s", - inline=True - ) - embed.add_field( - name=f"{emoji_annoattention} ร— Nachricht (Vorschau)", - value=f"```{message.content[:100]}{'...' if len(message.content) > 100 else ''}```", - inline=False - ) - embed.set_footer(text=f"User ID: {user.id}") - embed.set_thumbnail(url=user.display_avatar.url) - - await log_channel.send(embed=embed) - except Exception as e: - print(f"Error sending spam log: {e}") - - async def delete_recent_messages(self, channel, user, limit=5): - """Delete recent messages from a user.""" - try: - messages_to_delete = [] - async for msg in channel.history(limit=50): # Check last 50 messages - if msg.author == user and len(messages_to_delete) < limit: - messages_to_delete.append(msg) - if len(messages_to_delete) >= limit: - break - - for msg in messages_to_delete: - try: - await msg.delete() - except discord.NotFound: - pass # Message already deleted - except discord.Forbidden: - break # No permission to delete - - except Exception as e: - print(f"Error deleting messages: {e}") - - @antispam.command(name="setup", description="Richte das Anti-Spam-System ein.") - async def setup_antispam(self, ctx, log_channel: discord.TextChannel, max_messages: int = 5, time_frame: int = 10): - """Richte das Anti-Spam-System mit einem Log-Channel ein.""" - if not ctx.author.guild_permissions.manage_guild: - await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) - return - - if max_messages < 1 or max_messages > 50: - await ctx.respond(f"{emoji_no} ร— Maximale Nachrichten mรผssen zwischen 1 und 50 liegen.", ephemeral=True) - return - - if time_frame < 1 or time_frame > 300: - await ctx.respond(f"{emoji_no} ร— Zeitrahmen muss zwischen 1 und 300 Sekunden liegen.", ephemeral=True) - return - - # Check if bot can send messages to log channel - if not log_channel.permissions_for(ctx.guild.me).send_messages: - await ctx.respond(f"{emoji_no} ร— Ich habe keine Berechtigung, Nachrichten in den angegebenen Log-Channel zu senden.", - ephemeral=True) - return - - self.db.set_spam_settings(ctx.guild.id, max_messages, time_frame, log_channel.id) - - embed = discord.Embed( - title=f"{emoji_yes} ร— Anti-Spam-System eingerichtet", - color=discord.Color.green() - ) - embed.add_field( - name=f"{emoji_channel} ร— Log-Channel", - value=log_channel.mention, - inline=True - ) - embed.add_field( - name=f"{emoji_annoattention} ร— Nachrichtenlimit", - value=f"{max_messages} Nachrichten", - inline=True - ) - embed.add_field( - name=f"{emoji_statistics} ร— Zeitrahmen", - value=f"{time_frame} Sekunden", - inline=True - ) - embed.add_field( - name=f"{emoji_owner} ร— Status", - value="๐ŸŸข Aktiv", - inline=False - ) - await ctx.respond(embed=embed, ephemeral=True) - - @antispam.command(name="set", description="ร„ndere Anti-Spam-Parameter.") - async def set_parameters(self, ctx, max_messages: int = None, time_frame: int = None): - """ร„ndere die Anti-Spam-Parameter (Log-Channel bleibt unverรคndert).""" - if not ctx.author.guild_permissions.manage_guild: - await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) - return - - # Get current settings - current_settings = self.db.get_spam_settings(ctx.guild.id) - if not current_settings: - await ctx.respond(f"{emoji_no} ร— Anti-Spam-System wurde noch nicht eingerichtet. Verwende `/antispam setup` zuerst.", - ephemeral=True) - return - - # Use current values if not provided - new_max_messages = max_messages if max_messages is not None else current_settings['max_messages'] - new_time_frame = time_frame if time_frame is not None else current_settings['time_frame'] - - if new_max_messages < 5 or new_max_messages > 50: - await ctx.respond(f"{emoji_no} ร— Maximale Nachrichten mรผssen zwischen 5 und 50 liegen.", ephemeral=True) - return - - if new_time_frame < 5 or new_time_frame > 300: - await ctx.respond(f"{emoji_no} ร— Zeitrahmen muss zwischen 5 und 300 Sekunden liegen.", ephemeral=True) - return - - self.db.set_spam_settings(ctx.guild.id, new_max_messages, new_time_frame, current_settings['log_channel_id']) - - embed = discord.Embed( - title=f"{emoji_owner} ร— Anti-Spam Einstellungen aktualisiert", - description=f"Maximal **{new_max_messages}** Nachrichten in **{new_time_frame}** Sekunden erlaubt.", - color=discord.Color.green() - ) - await ctx.respond(embed=embed, ephemeral=True) - - @antispam.command(name="log-channel", description="ร„ndere den Log-Channel.") - async def set_log_channel(self, ctx, log_channel: discord.TextChannel): - """ร„ndere den Log-Channel fรผr Anti-Spam.""" - if not ctx.author.guild_permissions.manage_guild: - await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) - return - - # Check if bot can send messages to log channel - if not log_channel.permissions_for(ctx.guild.me).send_messages: - await ctx.respond(f"{emoji_no} ร— Ich habe keine Berechtigung, Nachrichten in den angegebenen Log-Channel zu senden.", - ephemeral=True) - return - - self.db.set_log_channel(ctx.guild.id, log_channel.id) - - embed = discord.Embed( - title=f"{emoji_owner} ร— Log-Channel aktualisiert", - description=f"Anti-Spam-Logs werden nun in {log_channel.mention} gesendet.", - color=discord.Color.green() - ) - await ctx.respond(embed=embed, ephemeral=True) - - @antispam.command(name="view", description="Zeige aktuelle Anti-Spam-Einstellungen an.") - async def view_settings(self, ctx): - """Zeigt die aktuellen Anti-Spam-Einstellungen an.""" - settings = self.db.get_spam_settings(ctx.guild.id) - - if settings and settings.get('log_channel_id'): - log_channel = ctx.guild.get_channel(settings['log_channel_id']) - log_channel_display = log_channel.mention if log_channel else f"{emoji_warn} ร— Channel nicht gefunden" - - embed = discord.Embed( - title=f"{emoji_owner} ร— Anti-Spam Einstellungen", - color=discord.Color.blue() - ) - embed.add_field( - name=f"{emoji_channel} ร— Log-Channel", - value=log_channel_display, - inline=True - ) - embed.add_field( - name=f"{emoji_annoattention} ร— Nachrichtenlimit", - value=f"{settings['max_messages']} Nachrichten", - inline=True - ) - embed.add_field( - name=f"{emoji_statistics} ร— Zeitrahmen", - value=f"{settings['time_frame']} Sekunden", - inline=True - ) - embed.add_field( - name=f"{emoji_owner} ร— Status", - value="๐ŸŸข Aktiv", - inline=False - ) - else: - embed = discord.Embed( - title=f"{emoji_owner} ร— Anti-Spam Einstellungen", - description=f"{emoji_no} ร— **Anti-Spam-System nicht eingerichtet**\n\nVerwende `/antispam setup` um das System zu konfigurieren.", - color=discord.Color.red() - ) - - await ctx.respond(embed=embed, ephemeral=True) - - @antispam.command(name="logs", description="Zeige Anti-Spam-Logs an.") - async def view_logs(self, ctx, limit: int = 10): - """Zeigt die Anti-Spam-Protokolle an.""" - if not ctx.author.guild_permissions.manage_guild: - await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) - return - - logs = self.db.get_spam_logs(ctx.guild.id, limit) - - if logs: - embed = discord.Embed( - title=f"{emoji_statistics} ร— Anti-Spam Protokolle", - color=discord.Color.red() - ) - - log_text = "" - for i, log in enumerate(logs, 1): - user_id, message_preview, timestamp = log - # Try to get user mention, fallback to ID - try: - user = self.bot.get_user(user_id) - user_display = user.mention if user else f"<@{user_id}>" - except: - user_display = f"User ID: {user_id}" - - log_text += f"**{i}.** {user_display}\n" - log_text += f"๐Ÿ“ `{message_preview[:50]}{'...' if len(message_preview) > 50 else ''}`\n" - log_text += f"๐Ÿ•’ {timestamp}\n\n" - - embed.description = log_text - embed.set_footer(text=f"Zeige die letzten {len(logs)} Eintrรคge") - else: - embed = discord.Embed( - title=f"{emoji_statistics} ร— Anti-Spam Protokolle", - description="Fรผr diesen Server wurden keine Anti-Spam-Logs gefunden.", - color=discord.Color.green() - ) - - await ctx.respond(embed=embed, ephemeral=True) - - @antispam.command(name="clear", description="Lรถsche alle Anti-Spam-Logs fรผr diesen Server.") - async def clear_logs(self, ctx): - """Lรถscht alle Anti-Spam-Protokolle fรผr den Server.""" - if not ctx.author.guild_permissions.administrator: - await ctx.respond(f"{emoji_no} ร— Du benรถtigst Administrator-Rechte fรผr diesen Befehl.", ephemeral=True) - return - - self.db.clear_spam_logs(ctx.guild.id) - - embed = discord.Embed( - title=f"{emoji_yes} ร— Protokolle gelรถscht", - description="Alle Anti-Spam-Protokolle fรผr diesen Server wurden gelรถscht.", - color=discord.Color.green() - ) - await ctx.respond(embed=embed, ephemeral=True) - - @antispam.command(name="whitelist", description="Fรผge einen Benutzer zur Whitelist hinzu.") - async def add_whitelist(self, ctx, user: discord.Member): - """Fรผgt einen Benutzer zur Anti-Spam Whitelist hinzu.""" - if not ctx.author.guild_permissions.manage_guild: - await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) - return - - self.db.add_to_whitelist(ctx.guild.id, user.id) - - embed = discord.Embed( - title=f"{emoji_yes} ร— Zur Whitelist hinzugefรผgt", - description=f"{user.mention} wurde zur Anti-Spam Whitelist hinzugefรผgt.", - color=discord.Color.green() - ) - await ctx.respond(embed=embed, ephemeral=True) - - @antispam.command(name="disable", description="Deaktiviere das Anti-Spam-System.") - async def disable_antispam(self, ctx): - """Deaktiviert das Anti-Spam-System fรผr diesen Server.""" - if not ctx.author.guild_permissions.administrator: - await ctx.respond(f"{emoji_no} ร— Du benรถtigst Administrator-Rechte fรผr diesen Befehl.", ephemeral=True) - return - - # Remove settings to disable the system - with self.db.conn: - self.db.conn.execute('DELETE FROM spam_settings WHERE guild_id = ?', (ctx.guild.id,)) - - embed = discord.Embed( - title=f"{emoji_delete} ร— Anti-Spam-System deaktiviert", - description="Das Anti-Spam-System wurde fรผr diesen Server deaktiviert.\nVerwende `/antispam setup` um es wieder zu aktivieren.", - color=discord.Color.orange() - ) - await ctx.respond(embed=embed, ephemeral=True) - - def is_whitelisted(self, guild_id, user_id): - """Check if user is whitelisted.""" - return self.db.is_whitelisted(guild_id, user_id) - - -def setup(bot: ezcord.Bot): - bot.add_cog(AntiSpam(bot)) \ No newline at end of file diff --git a/src/cogs/moderation/moderation.py b/src/cogs/moderation/moderation.py deleted file mode 100644 index 4956073..0000000 --- a/src/cogs/moderation/moderation.py +++ /dev/null @@ -1,549 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Imports -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -import asyncio -import re -from datetime import datetime, timezone -from typing import Optional, Dict, List -import logging - -import discord -import ezcord -from discord import slash_command, option, SlashCommandGroup -import timedelta -from discord.ui import Container -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Cogs -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -class moderation(ezcord.Cog): - """Erweiterte Moderations-Cog mit verbesserter Sicherheit und Fehlerbehandlung""" - - def __init__(self, bot): - self.bot = bot - self.max_timeout_days = 28 - self._active_votes: Dict[int, Dict] = {} - self.logger = logging.getLogger(__name__) - - moderation = SlashCommandGroup("mod", "Erweiterte Moderationsbefehle") - - def _has_permission(self, member: discord.Member, permission: str) -> bool: - """รœberprรผft ob ein Member eine bestimmte Berechtigung hat""" - return getattr(member.guild_permissions, permission, False) - - def _can_moderate_member(self, moderator: discord.Member, target: discord.Member) -> tuple[bool, str]: - """Erweiterte รœberprรผfung ob ein Moderator ein Ziel-Mitglied moderieren kann""" - if target.id == target.guild.owner_id: - return False, "Der Server-Owner kann nicht moderiert werden." - if moderator.id == target.id: - return False, "Du kannst dich nicht selbst moderieren." - if target.id == self.bot.user.id: - return False, "Ich kann mich nicht selbst moderieren." - if target.bot and not moderator.guild_permissions.administrator: - return False, "Nur Administratoren kรถnnen Bots moderieren." - if moderator.id != target.guild.owner_id: - if moderator.top_role <= target.top_role: - return False, "Du kannst keine Mitglieder mit gleicher oder hรถherer Rolle moderieren." - bot_member = target.guild.get_member(self.bot.user.id) - if bot_member and bot_member.top_role <= target.top_role: - return False, "Meine Rolle ist nicht hoch genug, um dieses Mitglied zu moderieren." - return True, "" - - def _parse_duration(self, duration_str: str) -> Optional[timedelta]: - """Erweiterte Dauer-Parsing mit mehr Formaten und besserer Validierung""" - duration_str = duration_str.lower().strip() - pattern = r'(\d+)([smhdw])' - matches = re.findall(pattern, duration_str) - if not matches: - return None - total_seconds = 0 - for amount_str, unit in matches: - try: - amount = int(amount_str) - except ValueError: - return None - if amount < 0: - return None - if unit == 's': - total_seconds += amount - elif unit == 'm': - total_seconds += amount * 60 - elif unit == 'h': - total_seconds += amount * 3600 - elif unit == 'd': - total_seconds += amount * 86400 - elif unit == 'w': - total_seconds += amount * 604800 - else: - return None - if total_seconds < 1: - return None - max_seconds = self.max_timeout_days * 86400 - if total_seconds > max_seconds: - return None - return timedelta(seconds=total_seconds) - - def _format_duration(self, duration: timedelta) -> str: - """Formatiert eine timedelta in einen lesbaren String""" - total_seconds = int(duration.total_seconds()) - weeks = total_seconds // 604800 - days = (total_seconds % 604800) // 86400 - hours = (total_seconds % 86400) // 3600 - minutes = (total_seconds % 3600) // 60 - seconds = total_seconds % 60 - parts = [] - if weeks: parts.append(f"{weeks}w") - if days: parts.append(f"{days}d") - if hours: parts.append(f"{hours}h") - if minutes: parts.append(f"{minutes}m") - if seconds: parts.append(f"{seconds}s") - return " ".join(parts) if parts else "0s" - - def _create_moderation_embed(self, action: str, moderator: discord.Member, target: discord.Member, - reason: str, duration: str = None, additional_info: str = None) -> discord.Embed: - """Erstellt ein einheitliches Moderations-Embed""" - color_map = { - "Bann": discord.Color.dark_red(), - "Kick": discord.Color.red(), - "Timeout": discord.Color.orange(), - "Timeout aufgehoben": discord.Color.green(), - "Slowmode aktiviert": discord.Color.blue(), - "Slowmode deaktiviert": discord.Color.green(), - } - embed = discord.Embed( - title=f"{emoji_yes} ร— {action} erfolgreich", - color=color_map.get(action, SUCCESS_COLOR), - timestamp=datetime.now(timezone.utc) - ) - embed.set_author(name=AUTHOR) - if target: - embed.add_field(name=f"{emoji_member} ร— Ziel", value=f"{target.mention} ({target})", inline=True) - embed.add_field(name=f"{emoji_staff} ร— Moderator", value=moderator.mention, inline=True) - if duration: - embed.add_field(name=f"{emoji_slowmode} ร— Dauer", value=duration, inline=True) - embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) - if additional_info: - embed.add_field(name=f"{emoji_summary} ร— Zusรคtzlich", value=additional_info, inline=False) - if target: - embed.set_footer(text=f"User ID: {target.id}") - else: - embed.set_footer(text=FLOOTER) - return embed - - def _create_error_embed(self, title: str, description: str, additional_info: str = None) -> discord.Embed: - """Erstellt ein einheitliches Error-Embed""" - embed = discord.Embed( - title=f"{emoji_no} {title}", - description=description, - color=ERROR_COLOR, - timestamp=datetime.now(timezone.utc) - ) - embed.set_author(name=AUTHOR) - if additional_info: - embed.add_field(name=f"{emoji_summary} ร— Details", value=additional_info, inline=False) - embed.set_footer(text=FLOOTER) - return embed - - @moderation.command(name="ban", description="Bannt ein Mitglied vom Server") - @option("member", discord.Member, description="Das zu bannende Mitglied") - @option("reason", str, description="Grund fรผr den Bann", max_length=500, required=False) - @option("notify_user", bool, description="User per DM benachrichtigen?", required=False, default=True) - async def ban(self, ctx: discord.ApplicationContext, member: discord.Member, - reason: str = "Kein Grund angegeben", notify_user: bool = True): - await ctx.defer(ephemeral=True) - try: - if not self._has_permission(ctx.author, BAN): - embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder bannen` Berechtigung.") - return await ctx.followup.send(embed=embed) - if not self._has_permission(ctx.guild.me, BAN): - embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder bannen` Berechtigung.") - return await ctx.followup.send(embed=embed) - can_moderate, error_msg = self._can_moderate_member(ctx.author, member) - if not can_moderate: - embed = self._create_error_embed("Moderation nicht mรถglich", error_msg) - return await ctx.followup.send(embed=embed) - notification_sent = False - if notify_user: - try: - dm_embed = discord.Embed( - title=f"{emoji_warn} ร— Du wurdest gebannt", - color=ERROR_COLOR, - description=f"Du wurdest von **{ctx.guild.name}** gebannt." - ) - dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) - dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) - dm_embed.set_footer(text="Bei Fragen wende dich an die Serverleitung.") - await member.send(embed=dm_embed) - notification_sent = True - except discord.Forbidden: - pass - ban_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" - await member.ban(reason=ban_reason) - additional_info = [] - if notification_sent: - additional_info.append(f"{emoji_yes} ร— User per DM benachrichtigt") - elif notify_user: - additional_info.append(f"{emoji_no} ร— DM-Benachrichtigung fehlgeschlagen") - embed = self._create_moderation_embed("Bann", ctx.author, member, reason, additional_info="\n".join(additional_info) if additional_info else None) - await ctx.followup.send(embed=embed) - self.logger.info(f"User {member} ({member.id}) banned by {ctx.author} ({ctx.author.id}): {reason}") - except discord.Forbidden: - embed = self._create_error_embed("Berechtigung verweigert", f"Mir fehlen die Berechtigungen, um {member.mention} zu bannen.", "Stelle sicher, dass meine Rolle hรถher als die des Ziels ist.") - await ctx.followup.send(embed=embed) - except discord.HTTPException as e: - embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Bannen: {str(e)}") - await ctx.followup.send(embed=embed) - except Exception as e: - embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") - await ctx.followup.send(embed=embed) - self.logger.error(f"Unexpected error in ban command: {e}", exc_info=True) - - @moderation.command(name="kick", description="Kickt ein Mitglied vom Server") - @option("member", discord.Member, description="Das zu kickende Mitglied") - @option("reason", str, description="Grund fรผr den Kick", max_length=500, required=False) - @option("notify_user", bool, description="User per DM benachrichtigen?", required=False, default=True) - async def kick(self, ctx: discord.ApplicationContext, member: discord.Member, - reason: str = "Kein Grund angegeben", notify_user: bool = True): - await ctx.defer(ephemeral=True) - try: - if not self._has_permission(ctx.author, KICK): - embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder kicken` Berechtigung.") - return await ctx.followup.send(embed=embed) - if not self._has_permission(ctx.guild.me, KICK): - embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder kicken` Berechtigung.") - return await ctx.followup.send(embed=embed) - can_moderate, error_msg = self._can_moderate_member(ctx.author, member) - if not can_moderate: - embed = self._create_error_embed("Moderation nicht mรถglich", error_msg) - return await ctx.followup.send(embed=embed) - notification_sent = False - if notify_user: - try: - dm_embed = discord.Embed( - title=f"{emoji_warn} ร— Du wurdest gekickt", - color=ERROR_COLOR, - description=f"Du wurdest von **{ctx.guild.name}** gekickt." - ) - dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) - dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) - dm_embed.set_footer(text="Du kannst dem Server erneut beitreten.") - await member.send(embed=dm_embed) - notification_sent = True - except discord.Forbidden: - pass - kick_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" - await member.kick(reason=kick_reason) - additional_info = None - if notification_sent: - additional_info = f"{emoji_yes} ร— User per DM benachrichtigt" - elif notify_user: - additional_info = f"{emoji_no} ร— DM-Benachrichtigung fehlgeschlagen" - embed = self._create_moderation_embed("Kick", ctx.author, member, reason, additional_info=additional_info) - await ctx.followup.send(embed=embed) - self.logger.info(f"User {member} ({member.id}) kicked by {ctx.author} ({ctx.author.id}): {reason}") - except discord.Forbidden: - embed = self._create_error_embed("Berechtigung verweigert", f"Mir fehlen die Berechtigungen, um {member.mention} zu kicken.", "Stelle sicher, dass meine Rolle hรถher als die des Ziels ist.") - await ctx.followup.send(embed=embed) - except discord.HTTPException as e: - embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Kicken: {str(e)}") - await ctx.followup.send(embed=embed) - except Exception as e: - embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") - await ctx.followup.send(embed=embed) - self.logger.error(f"Unexpected error in kick command: {e}", exc_info=True) - - @moderation.command(name="timeout", description="Versetzt ein Mitglied in Timeout") - @option("member", discord.Member, description="Das zu mutende Mitglied") - @option("duration", str, description="Dauer (z.B. 10m, 1h30m, 2d, 1w)") - @option("reason", str, description="Grund fรผr den Timeout", max_length=500, required=False) - @option("notify_user", bool, description="User per DM benachrichtigen?", required=False, default=True) - async def timeout(self, ctx: discord.ApplicationContext, member: discord.Member, - duration: str, reason: str = "Kein Grund angegeben", notify_user: bool = True): - await ctx.defer(ephemeral=True) - try: - if not self._has_permission(ctx.author, MODERATE): - embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder moderieren` Berechtigung.") - return await ctx.followup.send(embed=embed) - if not self._has_permission(ctx.guild.me, MODERATE): - embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder moderieren` Berechtigung.") - return await ctx.followup.send(embed=embed) - can_moderate, error_msg = self._can_moderate_member(ctx.author, member) - if not can_moderate: - embed = self._create_error_embed("Moderation nicht mรถglich", error_msg) - return await ctx.followup.send(embed=embed) - parsed_duration = self._parse_duration(duration) - if parsed_duration is None: - embed = self._create_error_embed("Ungรผltige Dauer", f"Konnte '{duration}' nicht als gรผltige Dauer erkennen.", f"Beispiele: `10m`, `1h30m`, `2d`, `1w`\nMaximum: {self.max_timeout_days} Tage") - return await ctx.followup.send(embed=embed) - if member.communication_disabled_until and member.communication_disabled_until > datetime.now(timezone.utc): - current_timeout = member.communication_disabled_until - embed = self._create_error_embed("User bereits in Timeout", f"{member.mention} ist bereits bis {discord.utils.format_dt(current_timeout, 'F')} in Timeout.", "Verwende `/moderation untimeout` um den aktuellen Timeout zu beenden.") - return await ctx.followup.send(embed=embed) - notification_sent = False - if notify_user: - try: - dm_embed = discord.Embed( - title=f"{emoji_warn} ร— Du wurdest in Timeout versetzt", - color=ERROR_COLOR, - description=f"Du wurdest auf **{ctx.guild.name}** in Timeout versetzt." - ) - dm_embed.add_field(name=f"{emoji_slowmode} ร— Dauer", value=self._format_duration(parsed_duration), inline=True) - dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) - dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) - end_time = datetime.now(timezone.utc) + parsed_duration - dm_embed.add_field(name="๐Ÿ• Ende", value=discord.utils.format_dt(end_time, 'F'), inline=True) - dm_embed.set_footer(text="Bitte beachte die Serverregeln.") - await member.send(embed=dm_embed) - notification_sent = True - except discord.Forbidden: - pass - timeout_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" - await member.timeout_for(parsed_duration, reason=timeout_reason) - additional_info = None - if notification_sent: - additional_info = f"{emoji_yes} ร— User per DM benachrichtigt" - elif notify_user: - additional_info = f"{emoji_no} ร— DM-Benachrichtigung fehlgeschlagen" - embed = self._create_moderation_embed("Timeout", ctx.author, member, reason, duration=self._format_duration(parsed_duration), additional_info=additional_info) - end_time = datetime.now(timezone.utc) + parsed_duration - embed.add_field(name="๐Ÿ• Ende", value=discord.utils.format_dt(end_time, 'F'), inline=False) - await ctx.followup.send(embed=embed) - self.logger.info(f"User {member} ({member.id}) timed out by {ctx.author} ({ctx.author.id}) for {duration}: {reason}") - except discord.Forbidden: - embed = self._create_error_embed("Berechtigung verweigert", f"Mir fehlen die Berechtigungen, um {member.mention} zu timeouten.", "Stelle sicher, dass meine Rolle hรถher als die des Ziels ist.") - await ctx.followup.send(embed=embed) - except discord.HTTPException as e: - embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Timeout: {str(e)}") - await ctx.followup.send(embed=embed) - except Exception as e: - embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") - await ctx.followup.send(embed=embed) - self.logger.error(f"Unexpected error in timeout command: {e}", exc_info=True) - - @moderation.command(name="untimeout", description="Hebt einen Timeout auf") - @option("member", discord.Member, description="Das Mitglied, dessen Timeout aufgehoben werden soll") - @option("reason", str, description="Grund fรผr die Aufhebung", max_length=500, required=False) - @option("notify_user", bool, description="User per DM benachrichtigen?", required=False, default=True) - async def untimeout(self, ctx: discord.ApplicationContext, member: discord.Member, - reason: str = "Kein Grund angegeben", notify_user: bool = True): - await ctx.defer(ephemeral=True) - try: - if not self._has_permission(ctx.author, MODERATE): - embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder moderieren` Berechtigung.") - return await ctx.followup.send(embed=embed) - if not self._has_permission(ctx.guild.me, MODERATE): - embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder moderieren` Berechtigung.") - return await ctx.followup.send(embed=embed) - if (member.communication_disabled_until is None or member.communication_disabled_until <= datetime.now(timezone.utc)): - embed = self._create_error_embed("Kein aktiver Timeout", f"{member.mention} ist derzeit nicht in Timeout.") - return await ctx.followup.send(embed=embed) - notification_sent = False - if notify_user: - try: - dm_embed = discord.Embed( - title=f"{emoji_yes} ร— Dein Timeout wurde aufgehoben", - color=SUCCESS_COLOR, - description=f"Dein Timeout auf **{ctx.guild.name}** wurde vorzeitig aufgehoben." - ) - dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) - dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) - dm_embed.set_footer(text="Bitte beachte weiterhin die Serverregeln.") - await member.send(embed=dm_embed) - notification_sent = True - except discord.Forbidden: - pass - untimeout_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" - await member.remove_timeout(reason=untimeout_reason) - additional_info = None - if notification_sent: - additional_info = f"{emoji_yes} ร— User per DM benachrichtigt" - elif notify_user: - additional_info = f"{emoji_no} ร— DM-Benachrichtigung fehlgeschlagen" - embed = self._create_moderation_embed("Timeout aufgehoben", ctx.author, member, reason, additional_info=additional_info) - await ctx.followup.send(embed=embed) - self.logger.info(f"Timeout removed from {member} ({member.id}) by {ctx.author} ({ctx.author.id}): {reason}") - except discord.Forbidden: - embed = self._create_error_embed("Berechtigung verweigert", f"Mir fehlen die Berechtigungen, um den Timeout von {member.mention} aufzuheben.") - await ctx.followup.send(embed=embed) - except discord.HTTPException as e: - embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Aufheben des Timeouts: {str(e)}") - await ctx.followup.send(embed=embed) - except Exception as e: - embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") - await ctx.followup.send(embed=embed) - self.logger.error(f"Unexpected error in untimeout command: {e}", exc_info=True) - - @moderation.command(name="slowmode", description="Setzt den Slowmode fรผr den aktuellen Channel") - @option("duration", str, description="Dauer (z.B. 10s, 5m, 1h) oder '0' zum Deaktivieren", default="0") - @option("reason", str, description="Grund fรผr den Slowmode", max_length=500, required=False) - async def slowmode(self, ctx: discord.ApplicationContext, duration: str = "0", reason: str = "Kein Grund angegeben"): - await ctx.defer(ephemeral=True) - try: - if not ctx.author.guild_permissions.manage_channels: - embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Kanรคle verwalten` Berechtigung.") - return await ctx.followup.send(embed=embed) - if not ctx.guild.me.guild_permissions.manage_channels: - embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Kanรคle verwalten` Berechtigung.") - return await ctx.followup.send(embed=embed) - if duration == "0": - seconds = 0 - else: - parsed_duration = self._parse_duration(duration) - if parsed_duration is None: - embed = self._create_error_embed("Ungรผltige Dauer", f"Konnte '{duration}' nicht als gรผltige Dauer erkennen.", "Beispiele: `10s`, `5m`, `1h` oder `0` zum Deaktivieren") - return await ctx.followup.send(embed=embed) - seconds = int(parsed_duration.total_seconds()) - if seconds < 0 or seconds > 21600: - embed = self._create_error_embed("Ungรผltiger Zeitraum", f"Slowmode muss zwischen 0 Sekunden und 6 Stunden liegen.", f"Eingabe: {seconds} Sekunden") - return await ctx.followup.send(embed=embed) - old_slowmode = ctx.channel.slowmode_delay - slowmode_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" - await ctx.channel.edit(slowmode_delay=seconds, reason=slowmode_reason) - if seconds == 0: - action = "Slowmode deaktiviert" - additional_info = f"Vorheriger Slowmode: {old_slowmode}s" if old_slowmode > 0 else None - else: - action = "Slowmode aktiviert" - additional_info = f"{emoji_slowmode} Slowmode auf {seconds} Sekunden gesetzt" - embed = self._create_moderation_embed(action, ctx.author, None, reason, duration=f"{seconds} Sekunden" if seconds > 0 else "Deaktiviert", additional_info=additional_info) - embed.add_field(name="๐Ÿ“ข ร— Kanal", value=ctx.channel.mention, inline=True) - await ctx.followup.send(embed=embed) - self.logger.info(f"Slowmode set to {seconds}s in {ctx.channel} by {ctx.author} ({ctx.author.id}): {reason}") - except discord.Forbidden: - embed = self._create_error_embed("Berechtigung verweigert", "Mir fehlen die Berechtigungen, um den Slowmode zu setzen.") - await ctx.followup.send(embed=embed) - except discord.HTTPException as e: - embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Setzen des Slowmodes: {str(e)}") - await ctx.followup.send(embed=embed) - except Exception as e: - embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") - await ctx.followup.send(embed=embed) - self.logger.error(f"Unexpected error in slowmode command: {e}", exc_info=True) - - @moderation.command(name="votekick", description="Startet eine Votekick-Abstimmung fรผr ein Mitglied") - @option("member", discord.Member, description="Das zu kickende Mitglied") - @option("reason", str, description="Grund fรผr den Kick", max_length=500, required=False) - @option("duration", int, description="Abstimmungsdauer in Minuten (Standard: 5)", min_value=1, max_value=30, required=False) - async def votekick(self, ctx: discord.ApplicationContext, member: discord.Member, reason: str = "Kein Grund angegeben", duration: int = 5): - await ctx.defer() - try: - if not self._has_permission(ctx.author, KICK): - embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder kicken` Berechtigung.") - return await ctx.followup.send(embed=embed, ephemeral=True) - if not self._has_permission(ctx.guild.me, KICK): - embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder kicken` Berechtigung.") - return await ctx.followup.send(embed=embed, ephemeral=True) - can_moderate, error_msg = self._can_moderate_member(ctx.author, member) - if not can_moderate: - embed = self._create_error_embed("Moderation nicht mรถglich", error_msg) - return await ctx.followup.send(embed=embed, ephemeral=True) - if member.id in self._active_votes: - embed = self._create_error_embed("Abstimmung bereits aktiv", f"Es lรคuft bereits eine Abstimmung fรผr {member.mention}.") - return await ctx.followup.send(embed=embed, ephemeral=True) - end_time = datetime.now(timezone.utc) + timedelta(minutes=duration) - embed = discord.Embed( - title=f"๐Ÿ—ณ๏ธ ร— Votekick fรผr {member.display_name}", - description=f"{ctx.author.mention} mรถchte {member.mention} kicken.\n\n" - f"**{emoji_summary} Grund:** {reason}\n\n" - f"Reagiere mit {emoji_yes} zum Kicken oder {emoji_no} zum Ablehnen.\n" - f"**๐Ÿ• Ende:** {discord.utils.format_dt(end_time, 'R')}", - color=discord.Color.orange(), - timestamp=datetime.now(timezone.utc) - ) - embed.set_author(name=f"Gestartet von {ctx.author}", icon_url=ctx.author.display_avatar.url) - embed.add_field(name=f"{emoji_member} ร— Ziel", value=f"{member.mention}", inline=True) - embed.add_field(name=f"{emoji_slowmode} ร— Dauer", value=f"{duration} Minuten", inline=True) - embed.set_footer(text=f"Votekick ID: {member.id}") - message = await ctx.followup.send(embed=embed) - await message.add_reaction(emoji_yes) - await message.add_reaction(emoji_no) - self._active_votes[member.id] = { - 'message': message, - 'initiator': ctx.author, - 'target': member, - 'reason': reason, - 'end_time': end_time, - 'guild': ctx.guild - } - asyncio.create_task(self._handle_votekick(member.id, duration * 60)) - except Exception as e: - embed = self._create_error_embed("Unerwarteter Fehler", f"Fehler bei der Votekick-Abstimmung: {str(e)}") - try: - await ctx.followup.send(embed=embed, ephemeral=True) - except: - await ctx.respond(embed=embed, ephemeral=True) - self.logger.error(f"Unexpected error in votekick command: {e}", exc_info=True) - - async def _handle_votekick(self, member_id: int, duration_seconds: int): - """Verwaltet eine Votekick-Abstimmung""" - await asyncio.sleep(duration_seconds) - if member_id not in self._active_votes: - return - vote_data = self._active_votes[member_id] - message = vote_data['message'] - target = vote_data['target'] - initiator = vote_data['initiator'] - reason = vote_data['reason'] - guild = vote_data['guild'] - try: - message = await message.channel.fetch_message(message.id) - yes_count = 0 - no_count = 0 - voters = set() - for reaction in message.reactions: - if str(reaction.emoji) == emoji_yes: - async for user in reaction.users(): - if not user.bot and user.id not in voters: - yes_count += 1 - voters.add(user.id) - elif str(reaction.emoji) == emoji_no: - async for user in reaction.users(): - if not user.bot and user.id not in voters: - no_count += 1 - voters.add(user.id) - total_members = len([m for m in guild.members if not m.bot]) - required_votes = max(3, total_members // 4) - if yes_count >= required_votes and yes_count > no_count: - try: - kick_reason = f"Votekick | Grund: {reason} | Initiator: {initiator} | Ja: {yes_count}, Nein: {no_count}" - await target.kick(reason=kick_reason) - result_embed = discord.Embed( - title=f"{emoji_yes} Votekick erfolgreich", - description=f"{emoji_member} {target.mention} wurde gekickt.", - color=discord.Color.green(), - timestamp=datetime.now(timezone.utc) - ) - result_embed.add_field(name="๐Ÿ“Š ร— Ergebnis", value=f"{emoji_yes} Ja: {yes_count} | {emoji_no} Nein: {no_count}\n{emoji_summary} Benรถtigt: {required_votes}", inline=False) - self.logger.info(f"Votekick successful: {target} ({target.id}) kicked with {yes_count} votes") - except discord.Forbidden: - result_embed = discord.Embed( - title=f"{emoji_no} ร— Votekick fehlgeschlagen", - description=f"Berechtigung fehlt, um {target.mention} zu kicken.", - color=discord.Color.red(), - timestamp=datetime.now(timezone.utc) - ) - except discord.HTTPException as e: - result_embed = discord.Embed( - title=f"{emoji_no} ร— Votekick fehlgeschlagen", - description=f"Fehler beim Kicken: {str(e)}", - color=discord.Color.red(), - timestamp=datetime.now(timezone.utc) - ) - else: - result_embed = discord.Embed( - title=f"{emoji_no} ร— Votekick abgelehnt", - description=f"{emoji_member} {target.mention} wurde nicht gekickt.", - color=discord.Color.red(), - timestamp=datetime.now(timezone.utc) - ) - result_embed.add_field(name="๐Ÿ“Š ร— Ergebnis", value=f"{emoji_yes} Ja: {yes_count} | {emoji_no} Nein: {no_count}\n{emoji_summary} Benรถtigt: {required_votes}", inline=False) - await message.edit(embed=result_embed, view=None) - except Exception as e: - self.logger.error(f"Error handling votekick result: {e}", exc_info=True) - finally: - if member_id in self._active_votes: - del self._active_votes[member_id] - - -def setup(bot): - bot.add_cog(moderation(bot)) \ No newline at end of file diff --git a/src/cogs/moderation/notes.py b/src/cogs/moderation/notes.py deleted file mode 100644 index 7475c7d..0000000 --- a/src/cogs/moderation/notes.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Imports -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -import discord -from discord import SlashCommandGroup -import datetime -import ezcord -from DevTools import NotesDatabase -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Cog -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -class NotesCog(ezcord.Cog, group="moderation"): - notes = SlashCommandGroup("notes", "๐Ÿ“ Verwaltung von Notizen fรผr User") - - def __init__(self, bot): - self.bot = bot - self.db = NotesDatabase("data") - - @notes.command(name="add", description="๐Ÿ“ Speichere eine Notiz fรผr einen User") - async def add( - self, - ctx: discord.ApplicationContext, - user: discord.Member, - *, - content: str - ): - if not content: - return await ctx.respond("Bitte gib den Inhalt der Notiz an.", ephemeral=True) - - timestamp = datetime.datetime.now().strftime("%d.%m.%Y %H:%M") - self.db.add_note(ctx.guild.id, user.id, ctx.author.id, ctx.author.name, content, timestamp) - await ctx.respond(f"Notiz fรผr {user.mention} gespeichert.", ephemeral=True) - - @notes.command(name="list", description="๐Ÿ“œ Zeige alle Notizen eines Users an") - async def list(self, ctx: discord.ApplicationContext, user: discord.Member): - notes = self.db.get_notes(ctx.guild.id, user.id) - - if not notes: - return await ctx.respond(f"{emoji_no} {emoji_user}{user.mention} hat keine Notizen.", ephemeral=True) - - embed = discord.Embed(title=f"Notizen fรผr {user.name}", color=discord.Color.blurple()) - for note in notes: - embed.add_field( - name=f"ID: {note['id']} โ€“ von {note['author_name']} am {note['timestamp']}", - value=note['content'], - inline=False - ) - - await ctx.respond(embed=embed, ephemeral=True) - - @notes.command(name="delete", description="๐Ÿ—‘๏ธ Lรถsche eine Notiz eines Users") - async def delete(self, ctx: discord.ApplicationContext, user: discord.Member, note_id: int): - notes = self.db.get_notes(ctx.guild.id, user.id) - if not notes: - return await ctx.respond(f"User {user} (ID: {user.id}) hat keine Notizen.", ephemeral=True) - - note_ids = [note['id'] for note in notes] - if note_id not in note_ids: - return await ctx.respond(f"{emoji_no} Notiz mit ID {note_id} existiert nicht fรผr User {user}.", ephemeral=True) - - if self.db.delete_note(note_id): - await ctx.respond(f"{emoji_yes} Notiz mit ID {note_id} von User {user} wurde gelรถscht.", ephemeral=True) - else: - await ctx.respond(f"{emoji_no} Fehler beim Lรถschen der Notiz mit ID {note_id}.", ephemeral=True) - - -def setup(bot): - bot.add_cog(NotesCog(bot)) diff --git a/src/cogs/moderation/warningsystem.py b/src/cogs/moderation/warningsystem.py deleted file mode 100644 index c56dd7f..0000000 --- a/src/cogs/moderation/warningsystem.py +++ /dev/null @@ -1,557 +0,0 @@ -# Copyright (c) 2025 OPPRO.NET Network -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Imports -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -from DevTools import WarnDatabase -import discord -from discord import slash_command, Option -import os -import datetime -import ezcord -import asyncio -from typing import Optional - - -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# >> Cogs -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -class WarnSystem(ezcord.Cog, group="moderation"): - """Erweiterte Warn-System Cog mit verbesserter Funktionalitรคt""" - - def __init__(self, bot): - self.bot = bot - base_path = os.path.dirname(__file__) - self.db = WarnDatabase(base_path) - # Cache fรผr bessere Performance - self._warn_cache = {} - - def _has_moderate_permissions(self, member: discord.Member) -> bool: - """รœberprรผft ob ein Member Moderationsrechte hat""" - return ( - member.guild_permissions.kick_members or - member.guild_permissions.ban_members or - member.guild_permissions.manage_messages or - member.guild_permissions.moderate_members - ) - - def _can_warn_member(self, moderator: discord.Member, target: discord.Member) -> tuple[bool, str]: - """รœberprรผft ob ein Moderator ein Ziel-Mitglied verwarnen kann""" - - # Server-Owner kann nicht verwarnt werden - if target.id == target.guild.owner_id: - return False, "Der Server Owner kann nicht verwarnt werden." - - # Selbst-Verwarnung verhindern - if moderator.id == target.id: - return False, "Du kannst dich nicht selbst verwarnen." - - # Bot kann nicht verwarnt werden - if target.bot: - return False, "Du kannst keine Bots verwarnen." - - # Rollen-Hierarchie prรผfen (auรŸer bei Owner) - if (moderator.top_role <= target.top_role and - moderator.id != target.guild.owner_id): - return False, "Du kannst keine Mitglieder mit gleicher oder hรถherer Rolle verwarnen." - - return True, "" - - def _create_warn_embed(self, action: str, moderator: discord.Member, - target: discord.Member, reason: str, - timestamp: str, warn_id: int = None) -> discord.Embed: - """Erstellt ein einheitliches Warn-Embed""" - - if action == "warn": - embed = discord.Embed( - title=f"{emoji_warn} Warnung erteilt", - color=SUCCESS_COLOR, - description=f"{target.mention} wurde erfolgreich verwarnt." - ) - elif action == "unwarn": - embed = discord.Embed( - title=f"{emoji_yes} Warnung entfernt", - color=SUCCESS_COLOR, - description=f"Warnung wurde erfolgreich entfernt." - ) - else: - embed = discord.Embed( - title=f" {action}", - color=SUCCESS_COLOR - ) - - embed.set_author(name=AUTHOR) - - if action == "warn": - embed.add_field(name=f"{emoji_member} ร— Verwarnter User", value=target.mention, inline=True) - embed.add_field(name=f"{emoji_staff} ร— Verwarnt von", value=moderator.mention, inline=True) - embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) - embed.add_field(name=f"{emoji_slowmode} ร— Zeitstempel", value=timestamp, inline=False) - embed.set_footer(text="Powered by ManagerX") - - elif action == "unwarn": - embed.add_field(name=f" Entfernt von", value=moderator.mention, inline=True) - if warn_id: - embed.add_field(name=f" Warnung ID", value=f"`{warn_id}`", inline=True) - embed.set_footer(text=FLOOTER) - - return embed - - def _create_error_embed(self, title: str, message: str) -> discord.Embed: - """Erstellt ein einheitliches Error-Embed""" - embed = discord.Embed(title=title, color=ERROR_COLOR) - embed.set_author(name=AUTHOR) - embed.add_field(name=f"{emoji_no} {title}", value=message, inline=False) - embed.set_footer(text=FLOOTER) - return embed - - @slash_command(name="warn", description="Warnen Sie einen Benutzer") - async def warn( - self, - ctx, - user: Option(discord.Member, "User to warn"), - reason: Option(str, "Reason for the warning", max_length=500) - ): - try: - # Berechtigung prรผfen - if not self._has_moderate_permissions(ctx.author): - embed = self._create_error_embed( - "Keine Berechtigung", - "Du benรถtigst Moderationsrechte, um Mitglieder zu verwarnen." - ) - return await ctx.respond(embed=embed, ephemeral=True) - - # Kann Mitglied verwarnt werden? - can_warn, error_msg = self._can_warn_member(ctx.author, user) - if not can_warn: - embed = self._create_error_embed("Verwarnung nicht mรถglich", error_msg) - return await ctx.respond(embed=embed, ephemeral=True) - - # Warn-Daten erstellen - timestamp = datetime.datetime.utcnow().strftime("%d.%m.%Y %H:%M") - - # In Datenbank speichern - try: - self.db.add_warning(ctx.guild.id, user.id, ctx.author.id, reason, timestamp) - - # Cache invalidieren - cache_key = f"{ctx.guild.id}_{user.id}" - if cache_key in self._warn_cache: - del self._warn_cache[cache_key] - - except Exception as e: - embed = self._create_error_embed( - "Datenbankfehler", - f"Fehler beim Speichern der Warnung: {str(e)}" - ) - return await ctx.respond(embed=embed, ephemeral=True) - - # Erfolgs-Embed - success_embed = self._create_warn_embed("warn", ctx.author, user, reason, timestamp) - await ctx.respond(embed=success_embed, ephemeral=True) - - # Optional: DM an verwarnten User senden - try: - dm_embed = discord.Embed( - title=f"{emoji_warn} Du wurdest verwarnt", - color=ERROR_COLOR, - description=f"Du wurdest auf **{ctx.guild.name}** verwarnt." - ) - dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) - dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) - dm_embed.add_field(name=f"{emoji_slowmode} ร— Zeitpunkt", value=timestamp, inline=True) - dm_embed.set_footer(text="Powered by ManagerX") - - await user.send(embed=dm_embed) - except discord.Forbidden: - # User hat DMs deaktiviert - ignorieren - pass - - except Exception as e: - embed = self._create_error_embed( - "Unerwarteter Fehler", - f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}" - ) - await ctx.respond(embed=embed, ephemeral=True) - - @slash_command(name="warnings", description="Zeigt die Verwarnungen eines Users an") - async def warnings( - self, - ctx, - user: Option(discord.Member, "User whose warnings to show", required=False) - ): - try: - # Wenn kein User angegeben, eigene Warnungen zeigen - target_user = user if user else ctx.author - - # Cache prรผfen - cache_key = f"{ctx.guild.id}_{target_user.id}" - - if cache_key in self._warn_cache: - results = self._warn_cache[cache_key] - else: - # Warnungen aus Datenbank laden - results = self.db.get_warnings(ctx.guild.id, target_user.id) - self._warn_cache[cache_key] = results - - # รœberprรผfung ob User Warnungen einsehen darf - if target_user != ctx.author and not self._has_moderate_permissions(ctx.author): - embed = self._create_error_embed( - "Keine Berechtigung", - "Du kannst nur deine eigenen Warnungen einsehen." - ) - return await ctx.respond(embed=embed, ephemeral=True) - - if not results: - # Keine Warnungen vorhanden - no_warnings_embed = discord.Embed( - title=f"{emoji_circleinfo} Keine Verwarnungen", - color=SUCCESS_COLOR, - description=f"{target_user.mention} hat keine Verwarnungen." - ) - no_warnings_embed.set_author(name=AUTHOR) - no_warnings_embed.set_footer(text=FLOOTER) - return await ctx.respond(embed=no_warnings_embed, ephemeral=True) - - # Warnungen-Liste aufteilen falls zu viele (max 10 pro Seite) - warnings_per_page = 10 - total_warnings = len(results) - total_pages = (total_warnings + warnings_per_page - 1) // warnings_per_page - - if total_pages == 1: - # Alle Warnungen auf einer Seite - warn_list = "\n".join([ - f"**ID `{warn_id}`** | {timestamp}\nโ”” **Grund:** {reason[:100]}{'...' if len(reason) > 100 else ''}" - for warn_id, reason, timestamp in results[:warnings_per_page] - ]) - - warnings_embed = discord.Embed( - title=f"{emoji_warn} Verwarnungen fรผr {target_user.display_name}", - color=ERROR_COLOR, - description=warn_list - ) - warnings_embed.set_author(name=AUTHOR) - warnings_embed.add_field(name=f"{emoji_member} User", value=target_user.mention, inline=True) - warnings_embed.add_field(name=f"{emoji_summary} Anzahl Verwarnungen", value=str(total_warnings), inline=True) - warnings_embed.set_footer(text=FLOOTER) - - await ctx.respond(embed=warnings_embed, ephemeral=True) - else: - # Mehrere Seiten - ersten 10 zeigen mit Navigation - await self._send_paginated_warnings(ctx, target_user, results, 0) - - except Exception as e: - embed = self._create_error_embed( - "Unerwarteter Fehler", - f"Fehler beim Laden der Warnungen: {str(e)}" - ) - await ctx.respond(embed=embed, ephemeral=True) - - async def _send_paginated_warnings(self, ctx, target_user: discord.Member, - warnings: list, page: int = 0): - """Sendet paginierte Warnungen mit Navigation""" - warnings_per_page = 10 - total_pages = (len(warnings) + warnings_per_page - 1) // warnings_per_page - - start_idx = page * warnings_per_page - end_idx = min(start_idx + warnings_per_page, len(warnings)) - page_warnings = warnings[start_idx:end_idx] - - warn_list = "\n".join([ - f"**ID `{warn_id}`** | {timestamp}\nโ”” **Grund:** {reason[:100]}{'...' if len(reason) > 100 else ''}" - for warn_id, reason, timestamp in page_warnings - ]) - - embed = discord.Embed( - title=f"{emoji_warn} Verwarnungen fรผr {target_user.display_name}", - color=ERROR_COLOR, - description=warn_list - ) - embed.set_author(name=AUTHOR) - embed.add_field(name=f"{emoji_member} User", value=target_user.mention, inline=True) - embed.add_field(name=f"{emoji_summary} Anzahl Verwarnungen", value=str(len(warnings)), inline=True) - embed.set_footer(text=f"Seite {page + 1}/{total_pages} โ€ข {FLOOTER}") - - # View fรผr Navigation erstellen - view = WarningsView(self, target_user, warnings, page, total_pages) - - if ctx.response.is_done(): - await ctx.followup.send(embed=embed, view=view, ephemeral=True) - else: - await ctx.respond(embed=embed, view=view, ephemeral=True) - - @slash_command(name="unwarn", description="Lรถscht eine Verwarnung mit ID") - async def unwarn( - self, - ctx, - warn_id: Option(int, "Die ID der Verwarnung", min_value=1) - ): - try: - # Berechtigung prรผfen - if not self._has_moderate_permissions(ctx.author): - embed = self._create_error_embed( - "Keine Berechtigung", - "Du benรถtigst Moderationsrechte, um Verwarnungen zu lรถschen." - ) - return await ctx.respond(embed=embed, ephemeral=True) - - # Warnung suchen - result = self.db.get_warning_by_id(warn_id) - if not result: - embed = self._create_error_embed( - "Verwarnung nicht gefunden", - f"Keine Verwarnung mit der ID `{warn_id}` gefunden." - ) - return await ctx.respond(embed=embed, ephemeral=True) - - # รœberprรผfen ob Warnung zu diesem Server gehรถrt - warn_guild_id = result[1] # guild_id ist der zweite Wert - if warn_guild_id != ctx.guild.id: - embed = self._create_error_embed( - "Verwarnung nicht gefunden", - f"Keine Verwarnung mit der ID `{warn_id}` in diesem Server gefunden." - ) - return await ctx.respond(embed=embed, ephemeral=True) - - # Warnung lรถschen - success = self.db.delete_warning(warn_id) - if not success: - embed = self._create_error_embed( - "Lรถschfehler", - f"Fehler beim Lรถschen der Verwarnung `{warn_id}`." - ) - return await ctx.respond(embed=embed, ephemeral=True) - - # Cache invalidieren - user_id = result[2] # user_id ist der dritte Wert - cache_key = f"{ctx.guild.id}_{user_id}" - if cache_key in self._warn_cache: - del self._warn_cache[cache_key] - - # Erfolgs-Embed - removal_embed = self._create_warn_embed("unwarn", ctx.author, None, None, None, warn_id) - await ctx.respond(embed=removal_embed, ephemeral=True) - - except Exception as e: - embed = self._create_error_embed( - "Unerwarteter Fehler", - f"Fehler beim Lรถschen der Verwarnung: {str(e)}" - ) - await ctx.respond(embed=embed, ephemeral=True) - - @slash_command(name="clearwarns", description="Lรถscht alle Verwarnungen eines Users") - async def clearwarns( - self, - ctx, - user: Option(discord.Member, "User dessen Warnungen gelรถscht werden sollen"), - reason: Option(str, "Grund fรผr das Lรถschen", required=False, default="Kein Grund angegeben") - ): - try: - # Nur Administratoren kรถnnen alle Warnungen lรถschen - if not ctx.author.guild_permissions.administrator: - embed = self._create_error_embed( - "Keine Berechtigung", - "Du benรถtigst Administrator-Rechte, um alle Warnungen zu lรถschen." - ) - return await ctx.respond(embed=embed, ephemeral=True) - - # Aktuelle Warnungen zรคhlen - warn_count = self.db.get_warning_count(ctx.guild.id, user.id) - - if warn_count == 0: - embed = discord.Embed( - title=f"{emoji_summary} Keine Verwarnungen", - color=SUCCESS_COLOR, - description=f"{user.mention} hat keine Verwarnungen zum Lรถschen." - ) - embed.set_author(name=AUTHOR) - return await ctx.respond(embed=embed, ephemeral=True) - - # Bestรคtigung anfordern - confirm_embed = discord.Embed( - title=f"{emoji_warn} Bestรคtigung erforderlich", - color=ERROR_COLOR, - description=f"Mรถchtest du wirklich **{warn_count}** Warnungen von {user.mention} lรถschen?\n\n**Grund:** {reason}" - ) - confirm_embed.set_footer(text="Diese Aktion kann nicht rรผckgรคngig gemacht werden! ร— Powered by ManagerX") - - view = ClearWarningsConfirmView(self, user, ctx.author, reason, warn_count) - await ctx.respond(embed=confirm_embed, view=view, ephemeral=True) - - except Exception as e: - embed = self._create_error_embed( - "Unerwarteter Fehler", - f"Fehler beim Vorbereiten der Lรถschung: {str(e)}" - ) - await ctx.respond(embed=embed, ephemeral=True) - - async def clear_all_user_warnings(self, guild_id: int, user_id: int) -> int: - """Lรถscht alle Warnungen eines Users und gibt die Anzahl zurรผck""" - try: - # Alle Warn-IDs fรผr den User holen - warnings = self.db.get_warnings(guild_id, user_id) - deleted_count = 0 - - for warn_id, _, _ in warnings: - if self.db.delete_warning(warn_id): - deleted_count += 1 - - # Cache invalidieren - cache_key = f"{guild_id}_{user_id}" - if cache_key in self._warn_cache: - del self._warn_cache[cache_key] - - return deleted_count - - except Exception as e: - print(f"Fehler beim Lรถschen aller Warnungen: {e}") - return 0 - - -class WarningsView(discord.ui.View): - """View fรผr die Navigation durch paginierte Warnungen""" - - def __init__(self, cog, target_user: discord.Member, warnings: list, current_page: int, total_pages: int): - super().__init__(timeout=300) # 5 Minuten Timeout - self.cog = cog - self.target_user = target_user - self.warnings = warnings - self.current_page = current_page - self.total_pages = total_pages - - # Buttons aktivieren/deaktivieren - self.previous_button.disabled = current_page == 0 - self.next_button.disabled = current_page >= total_pages - 1 - - @discord.ui.button(label="โ—€ Vorherige", style=discord.ButtonStyle.secondary, disabled=True) - async def previous_button(self, button: discord.ui.Button, interaction: discord.Interaction): - if self.current_page > 0: - self.current_page -= 1 - await self._update_page(interaction) - - @discord.ui.button(label="Nรคchste โ–ถ", style=discord.ButtonStyle.secondary) - async def next_button(self, button: discord.ui.Button, interaction: discord.Interaction): - if self.current_page < self.total_pages - 1: - self.current_page += 1 - await self._update_page(interaction) - - async def _update_page(self, interaction: discord.Interaction): - """Aktualisiert die angezeigte Seite""" - warnings_per_page = 10 - start_idx = self.current_page * warnings_per_page - end_idx = min(start_idx + warnings_per_page, len(self.warnings)) - page_warnings = self.warnings[start_idx:end_idx] - - warn_list = "\n".join([ - f"**ID `{warn_id}`** | {timestamp}\nโ”” **Grund:** {reason[:100]}{'...' if len(reason) > 100 else ''}" - for warn_id, reason, timestamp in page_warnings - ]) - - embed = discord.Embed( - title=f"{emoji_warn} Verwarnungen fรผr {self.target_user.display_name}", - color=ERROR_COLOR, - description=warn_list - ) - embed.set_author(name=AUTHOR) - embed.add_field(name=f"{emoji_member} User", value=self.target_user.mention, inline=True) - embed.add_field(name=f"{emoji_summary} Anzahl Verwarnungen", value=str(len(self.warnings)), inline=True) - embed.set_footer(text=f"Seite {self.current_page + 1}/{self.total_pages} โ€ข {FLOOTER}") - - # Buttons aktualisieren - self.previous_button.disabled = self.current_page == 0 - self.next_button.disabled = self.current_page >= self.total_pages - 1 - - await interaction.response.edit_message(embed=embed, view=self) - - async def on_timeout(self): - """Deaktiviert alle Buttons nach Timeout""" - for item in self.children: - item.disabled = True - - -class ClearWarningsConfirmView(discord.ui.View): - """View fรผr die Bestรคtigung beim Lรถschen aller Warnungen""" - - def __init__(self, cog, target_user: discord.Member, moderator: discord.Member, reason: str, warn_count: int): - super().__init__(timeout=60) # 1 Minute Timeout - self.cog = cog - self.target_user = target_user - self.moderator = moderator - self.reason = reason - self.warn_count = warn_count - - @discord.ui.button(label="โœ… Bestรคtigen", style=discord.ButtonStyle.danger) - async def confirm_button(self, button: discord.ui.Button, interaction: discord.Interaction): - # รœberprรผfen ob der richtige User geantwortet hat - if interaction.user.id != self.moderator.id: - await interaction.response.send_message( - "โŒ Nur der ursprรผngliche Moderator kann diese Aktion bestรคtigen.", - ephemeral=True - ) - return - - try: - # Alle Warnungen lรถschen - deleted_count = await self.cog.clear_all_user_warnings( - interaction.guild.id, self.target_user.id - ) - - if deleted_count > 0: - success_embed = discord.Embed( - title=f"{emoji_yes} Warnungen gelรถscht", - color=SUCCESS_COLOR, - description=f"**{deleted_count}** Warnungen von {self.target_user.mention} wurden gelรถscht." - ) - success_embed.add_field(name="Grund", value=self.reason, inline=False) - success_embed.add_field(name="Moderator", value=self.moderator.mention, inline=True) - success_embed.set_footer(text=FLOOTER) - else: - success_embed = discord.Embed( - title=f"{emoji_no} Keine Warnungen gelรถscht", - color=ERROR_COLOR, - description="Es konnten keine Warnungen gelรถscht werden." - ) - - # View deaktivieren - for item in self.children: - item.disabled = True - - await interaction.response.edit_message(embed=success_embed, view=self) - - except Exception as e: - error_embed = discord.Embed( - title=ERROR_TITLE, - color=ERROR_COLOR, - description=f"Fehler beim Lรถschen: {str(e)}" - ) - await interaction.response.edit_message(embed=error_embed, view=None) - - @discord.ui.button(label="โŒ Abbrechen", style=discord.ButtonStyle.secondary) - async def cancel_button(self, button: discord.ui.Button, interaction: discord.Interaction): - # รœberprรผfen ob der richtige User geantwortet hat - if interaction.user.id != self.moderator.id: - await interaction.response.send_message( - "โŒ Nur der ursprรผngliche Moderator kann diese Aktion abbrechen.", - ephemeral=True - ) - return - - cancel_embed = discord.Embed( - title=f"{emoji_yes} Abgebrochen", - color=SUCCESS_COLOR, - description="Das Lรถschen der Warnungen wurde abgebrochen." - ) - - # View deaktivieren - for item in self.children: - item.disabled = True - - await interaction.response.edit_message(embed=cancel_embed, view=self) - - async def on_timeout(self): - """Deaktiviert alle Buttons nach Timeout""" - for item in self.children: - item.disabled = True - - -def setup(bot): - bot.add_cog(WarnSystem(bot)) \ No newline at end of file diff --git a/src/cogs/setlang.py b/src/cogs/setlang.py deleted file mode 100644 index 37bf622..0000000 --- a/src/cogs/setlang.py +++ /dev/null @@ -1,56 +0,0 @@ -import discord -from discord.ext import commands -import ezcord - -from handler import TranslationHandler - - -class SetLangCog(ezcord.Cog): - """Cog for setting user language preferences.""" - - AVAILABLE_LANGUAGES = { - "de": "Deutsch ๐Ÿ‡ฉ๐Ÿ‡ช", - "en": "English ๐Ÿ‡ฌ๐Ÿ‡ง" - } - - @commands.slash_command( - name="set-lang", - description="Set your preferred language for bot messages." - ) - @discord.option( - "language", - description="Choose a language", - choices=[ - discord.OptionChoice(name=name, value=code) - for code, name in AVAILABLE_LANGUAGES.items() - ], - required=True - ) - async def set_language(self, ctx: discord.ApplicationContext, language: str): - """ - Set the user's preferred language. - - Args: - ctx: Discord application context - language: Selected language code - """ - # Save language preference - self.bot.settings_db.set_user_language(ctx.author.id, language) - - # Get display name for the selected language - lang_name = self.AVAILABLE_LANGUAGES.get(language, language) - - # Load response message using TranslationHandler - response_text = await TranslationHandler.get_async( - language, - "cog_setlang.message.language_set", - default="Language has been set to {language}.", - language=lang_name - ) - - await ctx.respond(response_text, ephemeral=True) - - -def setup(bot): - """Setup function to add the cog to the bot.""" - bot.add_cog(SetLangCog(bot)) \ No newline at end of file diff --git a/src/managerx/cli.py b/src/managerx/cli.py deleted file mode 100644 index 5cd9696..0000000 --- a/src/managerx/cli.py +++ /dev/null @@ -1,45 +0,0 @@ -# src/managerx/cli.py -import click -import os - -FOLDER_STRUCTURE = [ - "src/handler", - "src/DevTools/backend/utils", - "src/DevTools/backend/database", - "src/DevTools/backend/config", - "src/cogs/fun/wikipedia", - "src/cogs/information", - "src/cogs/moderation", - "src/cogs/servermanagement", - "src/managerx", -] - -@click.group() -def managerx(): - """ManagerX CLI Tool""" - pass - -@managerx.command() -def create(): - """Erstellt automatisch die komplette ManagerX-Ordnerstruktur""" - root_folder = "ManagerX" - root_path = os.path.join(os.getcwd(), root_folder) - - if os.path.exists(root_path): - click.echo(f"Ordner '{root_folder}' existiert bereits. Bitte lรถschen oder umbenennen!") - return - - for path in FOLDER_STRUCTURE: - full_path = os.path.join(root_path, path) - os.makedirs(full_path, exist_ok=True) - - # Automatisch __init__.py erstellen, damit Python-Pakete erkannt werden - if path.endswith("managerx") or "DevTools" in path or "cogs" in path: - init_file = os.path.join(full_path, "__init__.py") - with open(init_file, "w") as f: - f.write("# Init for package\n") - - click.echo(f"ManagerX-Ordnerstruktur wurde erfolgreich in '{root_folder}' erstellt!") - -if __name__ == "__main__": - managerx() diff --git a/translation/ez_de.json b/translation/ez_de.json deleted file mode 100644 index b4f48bb..0000000 --- a/translation/ez_de.json +++ /dev/null @@ -1,32 +0,0 @@ - -{ - "times": { - "min": "Minute", - "sec": "Sekunde", - "hour": "Stunde", - "day": "Tag" - }, - "bot": { - "error_title": "โ›” โจฏ Error", - "error": "Ein **unbekannter Fehler** ist aufgetreten. {}\nIch habe meinen Entwickler รผber dieses Problem informiert.", - "cooldown_title": "โŒ› โจฏ Cooldown", - "cooldown": "Versuche es {} erneut.", - "no_perms_title": "\uD83D\uDEA8 โจฏ Fehlende Rechte", - "no_perms": "Mir fehlen die folgenden Berechtigungen, um diesen Befehl auszufรผhren.", - "no_user_perms": "Du hast keine Rechte, um diesen Befehl auszufรผhren." - }, - "help": { - "cmd_name": "help", - "cmd_description": "\uD83D\uDD25 Zeigt eine Liste aller Befehle an.", - "wrong_user": "Dieser Help Command gehรถrt dir nicht!", - "placeholder": "\uD83D\uDD30 โ€บ Wรคhle eine Kategorie", - "embed_title": "Meine Befehle", - "default_description": "Alle Befehle der Kategorie **{}**.", - "no_commands": "Ups, ich konnte keine Befehle finden, auf die du Zugriff hast." - }, - "blacklist": { - "admin_group": "admin", - "no_perms": "Du wurdest von der Nutzung dieses Bots ausgeschlossen. Wenn du denkst, dass dies ein Fehler ist, kontaktiere meinen Owner.", - "guild_error": "Ich habe deinen Server **{}** verlassen, da du keine Rechte hast, um mich zu nutzen. Wenn du denkst, dass dies ein Fehler ist, kontaktiere meinen Owner." - } -} \ No newline at end of file diff --git a/translation/ez_en.json b/translation/ez_en.json deleted file mode 100644 index f62542d..0000000 --- a/translation/ez_en.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "times": { - "min": "minute", - "sec": "second", - "hour": "hour", - "day": "day" - }, - "bot": { - "error_title": "โ›” โจฏ Error", - "error": "An **unexpected error** has occurred. {}\nI have informed my developer about this issue.", - "cooldown_title": "โŒ› โจฏ Cooldown", - "cooldown": "Try again {}.", - "no_perms_title": "\uD83D\uDEA8 โจฏ Missing permissions", - "no_perms": "I'm missing the following permissions to execute this command.", - "no_user_perms": "You do not have permission to run this command." - }, - "help": { - "cmd_name": "help", - "cmd_description": "\uD83D\uDD25 Displays a list of all commands.", - "wrong_user": "This help command does not belong to you!", - "placeholder": "\uD83D\uDD30 โ€บ Choose a category", - "embed_title": "My commands", - "default_description": "All commands of category **{}**.", - "no_commands": "Oops, I couldn't find any commands that you have access to." - }, - "blacklist": { - "admin_group": "admin", - "no_perms": "You have been banned from using this bot. If you think this is a mistake, please contact my owner.", - "guild_error": "I left your server **{}** because you don't have permissions to use me. If you think this is a mistake, please contact my owner." - } -} \ No newline at end of file diff --git a/translation/messages/de.yaml b/translation/messages/de.yaml deleted file mode 100644 index f598cf1..0000000 --- a/translation/messages/de.yaml +++ /dev/null @@ -1,116 +0,0 @@ -general: - - error_types: - no_permission: "Du hast keine Berechtigung, diesen Befehl auszufรผhren." - user_not_found: "Benutzer nicht gefunden." - bot_error: "Ein Fehler ist im Bot aufgetreten. Bitte versuche es spรคter erneut." - option_missing: "Eine erforderliche Option fehlt." - bot_has_no_permission: "Der Bot hat nicht die erforderlichen Berechtigungen, um diesen Befehl auszufรผhren." - - -cog_setlang: - error_types: - unsupported_language: "Die angegebene Sprache wird nicht unterstรผtzt." - same_language: "Die angegebene Sprache ist bereits eingestellt." - - message: - language_set: "Die Sprache wurde auf {language} gesetzt." -######################################################### -# Fun Cogs -######################################################### - -cog_4gewinnt: - error_types: - not_your_turn: "Es ist nicht dein Zug." - this_column_full: "Diese Spalte ist voll!" - is_opponent_bot: "Du kannst nicht gegen einen Bot spielen!" - is_opponent_self: "Du kannst nicht gegen dich selbst spielen!" - - - - win_types: - win: "Spiel vorbei! {winner} hat gewonnen!\n\n{board_str}" - draw: "Unentschieden!\n\n{board_str}" - - message: - start_game: "4 Gewinnt: {author_mention} (๐Ÿ”ด) vs {opponent_mention} (๐ŸŸก)\n{author_mention} fรคngt an!\n\n" - player_turn: "{view.current_player.mention} ist jetzt dran!\n\n{board_str}" - - - -cog_tictactoe: - error_types: - not_your_turn: "Es ist nicht dein Zug." - this_cell_taken: "Dieses Feld ist bereits belegt!" - is_opponent_bot: "Du kannst nicht gegen einen Bot spielen!" - is_opponent_self: "Du kannst nicht gegen dich selbst spielen!" - - - - win_types: - win: "Spiel vorbei! {winner} hat gewonnen!" - draw: "Unentschieden!" - - message: - start_game: "Tic Tac Toe: {author_mention} (X) gegen {opponent_mention} (O)\n{author_mention} fรคngt an!" - -cog_weather: - error_types: - city_not_found: "โš ๏ธ Stadt nicht gefunden." - api_error: "โŒ Fehler bei der Wetter-API." - - messages: - weather_report: "# ๐ŸŒค๏ธ Wetterbericht fรผr {city}, {country}:\n\n" - temperature: "**๐ŸŒก๏ธ Temperatur:** {temperature}ยฐC\n" - humidity: "**๐Ÿ’ง Luftfeuchtigkeit:** {humidity}%\n" - wind_speed: "**๐Ÿ’จ Windgeschwindigkeit:** {wind_speed} km/h ({wind_dir})\n" - condition: "**โ˜๏ธ Wetterbedingungen:** {condition}\n" - visibility: "**๐ŸŒซ๏ธ Sichtweite:** {visibility} km\n" - pressure: "**๐Ÿงญ Luftdruck:** {pressure} hPa\n" - -cog_autorole: - error_types: - role_to_high: - title: "โŒ Fehler" - desc: "Ich kann diese Rolle nicht vergeben, da sie hรถher oder gleich meiner hรถchsten Rolle ist!" - role_managed: - title: "โŒ Fehler" - desc: "Diese Rolle wird von einer Integration verwaltet und kann nicht als Autorole hinzugefรผgt werden!" - not_found: - title: "โŒ Autorole nicht gefunden" - desc: "Es existiert keine Autorole mit der ID `{autorole_id}`!" - wrong_guild: - title: "โŒ Fehler" - desc: "Diese Autorole gehรถrt nicht zu diesem Server!" - no_roles: - title: "โŒ Keine Autoroles" - desc: "Es sind keine Autoroles fรผr diesen Server eingerichtet!" - role_deleted: - title: "โš ๏ธ Rolle nicht gefunden" - desc: "Die konfigurierte Rolle fรผr `{autorole_id}` existiert nicht mehr!" - - messages: - add_success: - title: "โœ… Autorole hinzugefรผgt" - desc: "Neue Mitglieder erhalten automatisch die Rolle {role}\n\n**Autorole-ID:** `{autorole_id}`" - remove_success: - title: "โœ… Autorole entfernt" - desc: "Die Autorole `{autorole_id}` wurde erfolgreich entfernt!" - toggle_success: - enabled_title: "โœ… Autorole aktiviert" - enabled_desc: "Die Autorole `{autorole_id}` wurde aktiviert!" - disabled_title: "โœ… Autorole deaktiviert" - disabled_desc: "Die Autorole `{autorole_id}` wurde deaktiviert!" - list: - title: "๐Ÿ“‹ Autoroles Liste" - desc: "Alle Autoroles fรผr **{guild_name}**" - role_deleted: "โš ๏ธ **Rolle gelรถscht**" - info: - title: "โ„น๏ธ Autorole Information" - desc: "Details zur Autorole `{autorole_id}`" - - system: - audit_reason: "Autorole System" - console_log: "โœ… Autoroles [{role_names}] wurden {member_name} zugewiesen" - error_forbidden: "โŒ Keine Berechtigung, um Rollen zu vergeben" - error_http: "โŒ Fehler beim Zuweisen der Rollen: {error}" \ No newline at end of file diff --git a/translation/messages/en.yaml b/translation/messages/en.yaml deleted file mode 100644 index 391ff35..0000000 --- a/translation/messages/en.yaml +++ /dev/null @@ -1,114 +0,0 @@ -general: - error_types: - no_permission: "You do not have permission to execute this command." - user_not_found: "User not found." - bot_error: "An error occurred within the bot. Please try again later." - option_missing: "A required option is missing." - bot_has_no_permission: "The bot does not have the necessary permissions to execute this command." - -cog_setlang: - error_types: - unsupported_language: "The specified language is not supported." - same_language: "The specified language is already set." - - message: - language_set: "Language has been set to {language}." -################################################################### -# -# Cog Folder: cogs/fun -# -#################################################################### -cog_4gewinnt: - error_types: - not_your_turn: "It's not your turn." - this_column_full: "This column is full!" - is_opponent_bot: "You cannot play against a bot!" - is_opponent_self: "You cannot play against yourself!" - - win_types: - win: "Game over! {winner} won!\n\n{board_str}" - draw: "It's a draw!\n\n{board_str}" - - message: - start_game: "Connect Four: {author_mention} (๐Ÿ”ด) vs {opponent_mention} (๐ŸŸก)\n{author_mention} starts!\n\n" - player_turn: "{view.current_player.mention}'s turn now!\n\n{board_str}" - -cog_tictactoe: - error_types: - not_your_turn: "It's not your turn." - this_cell_taken: "This cell is already taken!" - is_opponent_bot: "You cannot play against a bot!" - is_opponent_self: "You cannot play against yourself!" - - win_types: - win: "Game over! {winner} won!" - draw: "It's a draw!" - - message: - # NEU: Nur einfache Schlรผssel verwenden - start_game: "Tic Tac Toe: {author_mention} (X) vs {opponent_mention} (O)\n{author_mention} starts!" - -cog_weather: - error_types: - city_not_found: "โš ๏ธ City not found." - api_error: "โŒ Error with the weather API." - - messages: - weather_report: "# ๐ŸŒค๏ธ Weather report for {city}, {country}:\n\n" - temperature: "**๐ŸŒก๏ธ Temperature:** {temperature}ยฐC\n" - humidity: "**๐Ÿ’ง Humidity:** {humidity}%\n" - wind_speed: "**๐Ÿ’จ Wind:** {wind_speed} km/h ({wind_dir})\n" - condition: "**โ˜๏ธ Condition:** {condition}\n" - visibility: "**๐ŸŒซ๏ธ Visibility:** {visibility} km\n" - pressure: "**๐Ÿงญ Pressure:** {pressure} hPa\n" - -######################################################### -# Server Management -######################################################### - -cog_autorole: - error_types: - role_to_high: - title: "โŒ Error" - desc: "I cannot assign this role because it is higher than or equal to my highest role!" - role_managed: - title: "โŒ Error" - desc: "This role is managed by an integration and cannot be added as an autorole!" - not_found: - title: "โŒ Autorole Not Found" - desc: "There is no autorole with the ID `{autorole_id}`!" - wrong_guild: - title: "โŒ Error" - desc: "This autorole does not belong to this server!" - no_roles: - title: "โŒ No Autoroles" - desc: "No autoroles have been set up for this server!" - role_deleted: - title: "โš ๏ธ Role Not Found" - desc: "The configured role for `{autorole_id}` no longer exists!" - - messages: - add_success: - title: "โœ… Autorole Added" - desc: "New members will now automatically receive the role {role}\n\n**Autorole-ID:** `{autorole_id}`" - remove_success: - title: "โœ… Autorole Removed" - desc: "The autorole `{autorole_id}` was successfully removed!" - toggle_success: - enabled_title: "โœ… Autorole Enabled" - enabled_desc: "The autorole `{autorole_id}` has been enabled!" - disabled_title: "โœ… Autorole Disabled" - disabled_desc: "The autorole `{autorole_id}` has been disabled!" - list: - title: "๐Ÿ“‹ Autoroles List" - desc: "All autoroles for **{guild_name}**" - role_deleted: "โš ๏ธ **Role deleted**" - info: - title: "โ„น๏ธ Autorole Information" - desc: "Details for autorole `{autorole_id}`" - - system: - audit_reason: "Autorole System" - console_log: "โœ… Autoroles [{role_names}] were assigned to {member_name}" - error_forbidden: "โŒ Missing permissions to assign roles" - error_http: "โŒ Error while assigning roles: {error}" \ No newline at end of file From 6dc6509509156b13cc7953ce16fb3545610bde90 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Sat, 17 Jan 2026 16:37:49 +0100 Subject: [PATCH 5/8] Updated --- .gitignore | 6 +- docs/source/changelog/index.rst | 0 src/bot/cogs/fun/4gewinnt.py | 802 ++++++++++++++++++++++++++++++++ src/bot/cogs/fun/tictactoe.py | 602 ++++++++++++++++++++++++ 4 files changed, 1407 insertions(+), 3 deletions(-) create mode 100644 docs/source/changelog/index.rst create mode 100644 src/bot/cogs/fun/4gewinnt.py create mode 100644 src/bot/cogs/fun/tictactoe.py diff --git a/.gitignore b/.gitignore index 38bdde6..5758c0f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,16 +30,16 @@ checker.py bot_stats.json # Build-Ordner: alles ignorieren... -_build/* +build/* .pickle .doctree .buildinfo .nojekyll .inv -docs/_build/html/_sources/ +docs/build/ furo.js.LICENSE.txt fontawesome.js.LICENSE.txt .map -docs/_build/* +docs/build/* ManagerX.egg-info/ dist/ \ No newline at end of file diff --git a/docs/source/changelog/index.rst b/docs/source/changelog/index.rst new file mode 100644 index 0000000..e69de29 diff --git a/src/bot/cogs/fun/4gewinnt.py b/src/bot/cogs/fun/4gewinnt.py new file mode 100644 index 0000000..9af9f1c --- /dev/null +++ b/src/bot/cogs/fun/4gewinnt.py @@ -0,0 +1,802 @@ +# Copyright (c) 2026 ManagerX Development +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Import +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +from discord.ui import Button, View, Select +import discord +from discord.ext import commands +import ezcord +import yaml +from pathlib import Path +from datetime import datetime, timedelta +from typing import Optional, Dict, List, Tuple +import asyncio +import random + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Constants +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +ROWS = 6 +COLUMNS = 7 +DEFAULT_TIMEOUT = 300 # 5 Minuten + +# Improved difficulty levels with better depth and strategy +DIFFICULTY_CONFIG = { + "easy": { + "depth": 2, + "randomness": 0.3, # 30% zufรคllige Zรผge + "name": "Anfรคnger" + }, + "medium": { + "depth": 4, + "randomness": 0.1, # 10% zufรคllige Zรผge + "name": "Fortgeschritten" + }, + "hard": { + "depth": 6, + "randomness": 0.0, # Keine zufรคlligen Zรผge + "name": "Experte" + } +} + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Statistics Manager +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class GameStats: + """Verwaltet Spielstatistiken fรผr Connect4""" + + def __init__(self): + self.stats: Dict[int, Dict] = {} + + def get_user_stats(self, user_id: int) -> Dict: + """Gibt Statistiken fรผr einen Benutzer zurรผck""" + if user_id not in self.stats: + self.stats[user_id] = { + "wins": 0, + "losses": 0, + "draws": 0, + "total_games": 0, + "win_streak": 0, + "best_streak": 0, + "ai_wins": 0, + "ai_losses": 0 + } + return self.stats[user_id] + + def record_win(self, user_id: int, vs_ai: bool = False): + """Zeichnet einen Sieg auf""" + stats = self.get_user_stats(user_id) + stats["wins"] += 1 + stats["total_games"] += 1 + stats["win_streak"] += 1 + stats["best_streak"] = max(stats["best_streak"], stats["win_streak"]) + if vs_ai: + stats["ai_wins"] += 1 + + def record_loss(self, user_id: int, vs_ai: bool = False): + """Zeichnet eine Niederlage auf""" + stats = self.get_user_stats(user_id) + stats["losses"] += 1 + stats["total_games"] += 1 + stats["win_streak"] = 0 + if vs_ai: + stats["ai_losses"] += 1 + + def record_draw(self, user_id: int): + """Zeichnet ein Unentschieden auf""" + stats = self.get_user_stats(user_id) + stats["draws"] += 1 + stats["total_games"] += 1 + stats["win_streak"] = 0 + + def get_winrate(self, user_id: int) -> float: + """Berechnet die Gewinnrate""" + stats = self.get_user_stats(user_id) + if stats["total_games"] == 0: + return 0.0 + return (stats["wins"] / stats["total_games"]) * 100 + +# Global stats instance +game_stats = GameStats() + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Load messages from YAML +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +def load_messages(lang_code: str): + """ + Lรคdt Nachrichten fรผr den angegebenen Sprachcode. + Fรคllt auf 'en' und dann auf 'de' zurรผck, falls die Datei fehlt. + """ + base_path = Path("translation") / "messages" + + lang_file = base_path / f"{lang_code}.yaml" + if not lang_file.exists(): + lang_file = base_path / "en.yaml" + if not lang_file.exists(): + lang_file = base_path / "de.yaml" + + if not lang_file.exists(): + raise FileNotFoundError(f"Missing language files: {lang_code}.yaml, en.yaml, and de.yaml") + + with open(lang_file, "r", encoding="utf-8") as f: + return yaml.safe_load(f) + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Enhanced AI Engine (Improved Minimax) +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class Connect4AI: + """Verbesserte KI mit optimiertem Minimax-Algorithmus""" + + def __init__(self, difficulty: str = "medium"): + config = DIFFICULTY_CONFIG.get(difficulty, DIFFICULTY_CONFIG["medium"]) + self.max_depth = config["depth"] + self.randomness = config["randomness"] + self.difficulty_name = config["name"] + + def evaluate_window(self, window: List[str], ai_symbol: str, player_symbol: str) -> int: + """Verbesserte Fensterbewertung mit genaueren Heuristiken""" + score = 0 + ai_count = window.count(ai_symbol) + player_count = window.count(player_symbol) + empty_count = window.count("โšช") + + # AI-Bewertung + if ai_count == 4: + score += 10000 # Gewinn + elif ai_count == 3 and empty_count == 1: + score += 100 # Fast gewonnen + elif ai_count == 2 and empty_count == 2: + score += 10 # Gute Position + elif ai_count == 1 and empty_count == 3: + score += 1 # Basis-Position + + # Gegner-Bewertung (Verteidigung) + if player_count == 4: + score -= 10000 # Verloren (sollte nicht passieren) + elif player_count == 3 and empty_count == 1: + score -= 500 # Muss blocken! + elif player_count == 2 and empty_count == 2: + score -= 50 # Gefรคhrliche Position + + return score + + def score_position(self, board: List[List[str]], ai_symbol: str, player_symbol: str) -> int: + """Verbesserte Positionsbewertung mit strategischen Prรคferenzen""" + score = 0 + + # Zentrum bevorzugen (stรคrkere Gewichtung) + center_array = [board[i][COLUMNS // 2] for i in range(ROWS)] + center_count = center_array.count(ai_symbol) + score += center_count * 6 + + # Mittlere Spalten bevorzugen + for row in range(ROWS): + for col in [2, 3, 4]: # Mittlere Spalten + if board[row][col] == ai_symbol: + score += 2 + + # Horizontal scannen + for row in range(ROWS): + for col in range(COLUMNS - 3): + window = board[row][col:col + 4] + score += self.evaluate_window(window, ai_symbol, player_symbol) + + # Vertikal scannen + for col in range(COLUMNS): + for row in range(ROWS - 3): + window = [board[row + i][col] for i in range(4)] + score += self.evaluate_window(window, ai_symbol, player_symbol) + + # Diagonal (rechts-unten) + for row in range(ROWS - 3): + for col in range(COLUMNS - 3): + window = [board[row + i][col + i] for i in range(4)] + score += self.evaluate_window(window, ai_symbol, player_symbol) + + # Diagonal (rechts-oben) + for row in range(3, ROWS): + for col in range(COLUMNS - 3): + window = [board[row - i][col + i] for i in range(4)] + score += self.evaluate_window(window, ai_symbol, player_symbol) + + return score + + def get_valid_columns(self, board: List[List[str]]) -> List[int]: + """Gibt alle gรผltigen Spalten zurรผck""" + return [col for col in range(COLUMNS) if board[0][col] == "โšช"] + + def is_terminal_node(self, board: List[List[str]], ai_symbol: str, player_symbol: str) -> Tuple[bool, Optional[str]]: + """Prรผft ob das Spiel beendet ist und wer gewonnen hat""" + # Check fรผr Gewinn + for symbol in [ai_symbol, player_symbol]: + # Horizontal + for row in range(ROWS): + for col in range(COLUMNS - 3): + if all(board[row][col + i] == symbol for i in range(4)): + return True, symbol + + # Vertikal + for col in range(COLUMNS): + for row in range(ROWS - 3): + if all(board[row + i][col] == symbol for i in range(4)): + return True, symbol + + # Diagonal (rechts-unten) + for row in range(ROWS - 3): + for col in range(COLUMNS - 3): + if all(board[row + i][col + i] == symbol for i in range(4)): + return True, symbol + + # Diagonal (rechts-oben) + for row in range(3, ROWS): + for col in range(COLUMNS - 3): + if all(board[row - i][col + i] == symbol for i in range(4)): + return True, symbol + + # Check fรผr Unentschieden + if len(self.get_valid_columns(board)) == 0: + return True, None + + return False, None + + def minimax(self, board: List[List[str]], depth: int, alpha: float, beta: float, + maximizing: bool, ai_symbol: str, player_symbol: str) -> Tuple[Optional[int], float]: + """Optimierter Minimax mit Alpha-Beta-Pruning und Move-Ordering""" + valid_cols = self.get_valid_columns(board) + is_terminal, winner = self.is_terminal_node(board, ai_symbol, player_symbol) + + # Terminal-Zustรคnde + if depth == 0 or is_terminal: + if is_terminal: + if winner == ai_symbol: + return None, 100000000 + elif winner == player_symbol: + return None, -100000000 + else: + return None, 0 + else: + return None, self.score_position(board, ai_symbol, player_symbol) + + # Move ordering: Zentrum zuerst prรผfen + valid_cols.sort(key=lambda x: abs(x - COLUMNS // 2)) + + if maximizing: + value = float('-inf') + column = random.choice(valid_cols) if valid_cols else None + + for col in valid_cols: + temp_board = [row[:] for row in board] + self._drop_piece(temp_board, col, ai_symbol) + new_score = self.minimax(temp_board, depth - 1, alpha, beta, False, ai_symbol, player_symbol)[1] + + if new_score > value: + value = new_score + column = col + + alpha = max(alpha, value) + if alpha >= beta: + break # Beta cutoff + + return column, value + else: + value = float('inf') + column = random.choice(valid_cols) if valid_cols else None + + for col in valid_cols: + temp_board = [row[:] for row in board] + self._drop_piece(temp_board, col, player_symbol) + new_score = self.minimax(temp_board, depth - 1, alpha, beta, True, ai_symbol, player_symbol)[1] + + if new_score < value: + value = new_score + column = col + + beta = min(beta, value) + if alpha >= beta: + break # Alpha cutoff + + return column, value + + def _drop_piece(self, board: List[List[str]], column: int, symbol: str) -> Optional[int]: + """Lรคsst einen Spielstein in die Spalte fallen und gibt die Zeile zurรผck""" + for row in reversed(range(ROWS)): + if board[row][column] == "โšช": + board[row][column] = symbol + return row + return None + + def get_best_move(self, board: List[List[str]], ai_symbol: str, player_symbol: str) -> int: + """Gibt den besten Zug zurรผck mit optionaler Zufรคlligkeit""" + valid_cols = self.get_valid_columns(board) + + if not valid_cols: + return 0 + + # Zufรคlligkeit fรผr niedrigere Schwierigkeitsgrade + if random.random() < self.randomness: + return random.choice(valid_cols) + + # Prรผfe auf sofortigen Gewinnzug + for col in valid_cols: + temp_board = [row[:] for row in board] + self._drop_piece(temp_board, col, ai_symbol) + is_terminal, winner = self.is_terminal_node(temp_board, ai_symbol, player_symbol) + if is_terminal and winner == ai_symbol: + return col + + # Prรผfe ob Gegner blockiert werden muss + for col in valid_cols: + temp_board = [row[:] for row in board] + self._drop_piece(temp_board, col, player_symbol) + is_terminal, winner = self.is_terminal_node(temp_board, ai_symbol, player_symbol) + if is_terminal and winner == player_symbol: + return col + + # Verwende Minimax fรผr den besten Zug + column, _ = self.minimax(board, self.max_depth, float('-inf'), float('inf'), + True, ai_symbol, player_symbol) + + return column if column is not None else random.choice(valid_cols) + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Game Timer +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class GameTimer: + """Verwaltet Zugzeiten und Gesamtspielzeit""" + + def __init__(self): + self.start_time = datetime.now() + self.move_times: List[timedelta] = [] + self.current_move_start: Optional[datetime] = None + + def start_move(self): + """Startet den Timer fรผr einen Zug""" + self.current_move_start = datetime.now() + + def end_move(self): + """Beendet den Timer fรผr einen Zug""" + if self.current_move_start: + duration = datetime.now() - self.current_move_start + self.move_times.append(duration) + self.current_move_start = None + + def get_game_duration(self) -> timedelta: + """Gibt die Gesamtspielzeit zurรผck""" + return datetime.now() - self.start_time + + def get_average_move_time(self) -> Optional[timedelta]: + """Gibt die durchschnittliche Zugzeit zurรผck""" + if not self.move_times: + return None + return sum(self.move_times, timedelta()) / len(self.move_times) + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Enhanced Button & View +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class Connect4Button(Button): + def __init__(self, column, view): + # Dynamische Farben basierend auf Spalte + styles = [ + discord.ButtonStyle.primary, + discord.ButtonStyle.secondary, + discord.ButtonStyle.success, + ] + style = styles[column % 3] + + # Verteile Buttons auf 2 Reihen (4 + 3) + row = 0 if column < 4 else 1 + + super().__init__(style=style, label=str(column + 1), row=row) + self.column = column + self.view_ref = view + + async def callback(self, interaction: discord.Interaction): + view = self.view_ref + msgs = view.messages + + # Prรผfe ob Spiel bereits beendet + if view.game_ended: + await interaction.response.send_message( + "Das Spiel ist bereits beendet!", + ephemeral=True + ) + return + + # PvP mode checks + if not view.is_ai_mode and interaction.user != view.current_player: + await interaction.response.send_message( + msgs["cog_4gewinnt"]["error_types"]["not_your_turn"], + ephemeral=True + ) + return + + # AI mode checks + if view.is_ai_mode and interaction.user != view.player1: + await interaction.response.send_message( + msgs["cog_4gewinnt"]["error_types"]["not_your_turn"], + ephemeral=True + ) + return + + # End move timer + view.timer.end_move() + + if not view.make_move(self.column): + await interaction.response.send_message( + msgs["cog_4gewinnt"]["error_types"]["this_column_full"], + ephemeral=True + ) + view.timer.start_move() + return + + winner = view.check_winner() + board_str = view.board_to_str() + + if winner or view.is_draw(): + await view.end_game(interaction, winner, board_str) + return + + view.switch_player() + + # AI turn + if view.is_ai_mode and view.current_player == view.player2: + await interaction.response.edit_message( + content=f"๐Ÿค– **{view.ai.difficulty_name} KI denkt nach...**\n{board_str}", + view=view + ) + + # Simuliere Denkzeit (abhรคngig von Schwierigkeit) + think_time = { + "easy": 0.5, + "medium": 1.0, + "hard": 1.5 + } + await asyncio.sleep(think_time.get(view.difficulty, 1.0)) + + view.timer.start_move() + ai_col = view.ai.get_best_move(view.board, view.current_symbol, "๐Ÿ”ด") + view.timer.end_move() + + view.make_move(ai_col) + + winner = view.check_winner() + board_str = view.board_to_str() + + if winner or view.is_draw(): + await view.end_game(interaction, winner, board_str, is_followup=True) + return + + view.switch_player() + view.timer.start_move() + + # Automatisches Update nach KI-Zug + await interaction.edit_original_response( + content=f"โœ… KI hat Spalte **{ai_col + 1}** gewรคhlt!\n\n" + f"{view.current_player.mention}, du bist dran! ๐Ÿ”ด\n\n" + f"{board_str}\n" + f"Zug: {view.move_count}", + view=view + ) + else: + view.timer.start_move() + await interaction.response.edit_message( + content=msgs["cog_4gewinnt"]["message"]["player_turn"].format( + current_player=view.current_player.mention, + board_str=board_str, + move_count=view.move_count + ), + view=view + ) + +class Connect4View(View): + def __init__(self, player1, player2, messages, is_ai_mode=False, difficulty="medium"): + super().__init__(timeout=DEFAULT_TIMEOUT) + self.player1 = player1 + self.player2 = player2 + self.current_player = player1 + self.current_symbol = "๐Ÿ”ด" + self.board = [["โšช" for _ in range(COLUMNS)] for _ in range(ROWS)] + self.messages = messages + self.is_ai_mode = is_ai_mode + self.difficulty = difficulty + self.ai = Connect4AI(difficulty) if is_ai_mode else None + self.timer = GameTimer() + self.move_count = 0 + self.move_history: List[tuple] = [] + self.game_ended = False + + for col in range(COLUMNS): + self.add_item(Connect4Button(col, self)) + + # Start timer for first move + self.timer.start_move() + + def make_move(self, column: int) -> bool: + """Fรผhrt einen Zug aus""" + if column < 0 or column >= COLUMNS: + return False + + for row in reversed(range(ROWS)): + if self.board[row][column] == "โšช": + self.board[row][column] = self.current_symbol + self.move_history.append((row, column, self.current_symbol)) + self.move_count += 1 + return True + return False + + def switch_player(self): + """Wechselt den aktuellen Spieler""" + if self.current_player == self.player1: + self.current_player = self.player2 + self.current_symbol = "๐ŸŸก" + else: + self.current_player = self.player1 + self.current_symbol = "๐Ÿ”ด" + + def check_winner(self) -> bool: + """รœberprรผft, ob es einen Gewinner gibt""" + b = self.board + + # horizontal + for row in range(ROWS): + for col in range(COLUMNS - 3): + if (b[row][col] == b[row][col+1] == b[row][col+2] == b[row][col+3] + and b[row][col] != "โšช"): + return True + + # vertikal + for col in range(COLUMNS): + for row in range(ROWS - 3): + if (b[row][col] == b[row+1][col] == b[row+2][col] == b[row+3][col] + and b[row][col] != "โšช"): + return True + + # diagonal rechts unten + for row in range(ROWS - 3): + for col in range(COLUMNS - 3): + if (b[row][col] == b[row+1][col+1] == b[row+2][col+2] == b[row+3][col+3] + and b[row][col] != "โšช"): + return True + + # diagonal rechts oben + for row in range(3, ROWS): + for col in range(COLUMNS - 3): + if (b[row][col] == b[row-1][col+1] == b[row-2][col+2] == b[row-3][col+3] + and b[row][col] != "โšช"): + return True + + return False + + def is_draw(self) -> bool: + """รœberprรผft, ob das Spiel unentschieden ist""" + return all(cell != "โšช" for row in self.board for cell in row) + + def board_to_str(self) -> str: + """Konvertiert das Board zu einem String""" + numbers = ["1๏ธโƒฃ", "2๏ธโƒฃ", "3๏ธโƒฃ", "4๏ธโƒฃ", "5๏ธโƒฃ", "6๏ธโƒฃ", "7๏ธโƒฃ"] + header = "".join(numbers) + board_rows = "\n".join("".join(row) for row in self.board) + return f"{header}\n{board_rows}" + + async def end_game(self, interaction: discord.Interaction, winner: bool, board_str: str, is_followup: bool = False): + """Beendet das Spiel und zeigt Statistiken""" + self.game_ended = True + + for child in self.children: + child.disabled = True + + msgs = self.messages + game_duration = self.timer.get_game_duration() + avg_move_time = self.timer.get_average_move_time() + + # Update statistics + if winner: + if self.is_ai_mode: + if self.current_player == self.player1: + game_stats.record_win(self.player1.id, vs_ai=True) + else: + game_stats.record_loss(self.player1.id, vs_ai=True) + else: + game_stats.record_win(self.current_player.id) + other_player = self.player2 if self.current_player == self.player1 else self.player1 + game_stats.record_loss(other_player.id) + else: + game_stats.record_draw(self.player1.id) + if not self.is_ai_mode: + game_stats.record_draw(self.player2.id) + + # Build result message + embed = discord.Embed( + title="๐ŸŽฎ 4 Gewinnt - Spiel beendet!", + color=discord.Color.gold() if winner else discord.Color.greyple() + ) + + # Ergebnis + if winner: + if self.is_ai_mode and self.current_player == self.player2: + result_text = f"๐Ÿค– **Die {self.ai.difficulty_name} KI hat gewonnen!**" + embed.color = discord.Color.red() + else: + result_text = msgs["cog_4gewinnt"]["win_types"]["win"].format( + winner=self.current_player.mention + ) + embed.color = discord.Color.green() + else: + result_text = msgs["cog_4gewinnt"]["win_types"]["draw"] + + embed.add_field( + name="๐ŸŽฏ Ergebnis", + value=result_text, + inline=False + ) + + # Spielstatistiken + avg_time_str = f"{avg_move_time.seconds}s" if avg_move_time else "0s" + embed.add_field( + name="๐Ÿ“Š Spielstatistiken", + value=f"โฑ๏ธ Spielzeit: {game_duration.seconds // 60}m {game_duration.seconds % 60}s\n" + f"๐Ÿ”ข Zรผge: {self.move_count}\n" + f"โšก ร˜ Zugzeit: {avg_time_str}", + inline=True + ) + + # Sieger-Stats + if winner: + winner_stats = game_stats.get_user_stats(self.current_player.id if not self.is_ai_mode or self.current_player == self.player1 else self.player1.id) + + if self.is_ai_mode: + if self.current_player == self.player1: + stats_text = f"๐Ÿ† Siege vs KI: {winner_stats['ai_wins']}\n๐Ÿ’” Niederlagen vs KI: {winner_stats['ai_losses']}\n๐Ÿ”ฅ Aktuelle Serie: {winner_stats['win_streak']}" + else: + stats_text = f"Die KI bleibt ungeschlagen! ๐Ÿค–" + else: + stats_text = f"๐Ÿ† Siege: {winner_stats['wins']}\n๐Ÿ’” Niederlagen: {winner_stats['losses']}\n๐Ÿ”ฅ Serie: {winner_stats['win_streak']}" + + embed.add_field( + name="๐Ÿ“ˆ Spieler-Stats", + value=stats_text, + inline=True + ) + + # Spielfeld + embed.add_field( + name="๐ŸŽฒ Endposition", + value=f"```\n{board_str}\n```", + inline=False + ) + + embed.set_footer(text=f"Spiel-ID: {interaction.id} โ€ข Schwierigkeit: {self.ai.difficulty_name if self.is_ai_mode else 'PvP'}") + embed.timestamp = datetime.now() + + if is_followup: + await interaction.edit_original_response(embed=embed, view=self) + else: + await interaction.response.edit_message(embed=embed, view=self) + + self.stop() + + async def on_timeout(self): + """Wird aufgerufen wenn das Timeout erreicht wird""" + self.game_ended = True + for child in self.children: + child.disabled = True + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Cog +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class Connect4Cog(ezcord.Cog, group="fun"): + + @commands.slash_command(name="connect4", description="Starte ein 4 Gewinnt Spiel!") + async def connect4( + self, + ctx: discord.ApplicationContext, + opponent: Optional[discord.Member] = None, + difficulty: discord.Option( + str, + description="KI-Schwierigkeit (nur wenn kein Gegner gewรคhlt)", + choices=["easy", "medium", "hard"], + default="medium", + required=False + ) = "medium" + ): + try: + lang_code = self.bot.get_user_language(ctx.author.id) + except AttributeError: + lang_code = "de" + + try: + messages = load_messages(lang_code) + except FileNotFoundError as e: + print(f"CRITICAL: {e}") + messages = {"cog_4gewinnt": {"error_types": {}, "message": {}, "win_types": {}}} + + # AI mode + if opponent is None: + ai_user = ctx.guild.me + view = Connect4View(ctx.author, ai_user, messages, is_ai_mode=True, difficulty=difficulty) + + difficulty_info = DIFFICULTY_CONFIG.get(difficulty, DIFFICULTY_CONFIG["medium"]) + difficulty_emoji = {"easy": "๐Ÿ˜Š", "medium": "๐Ÿค”", "hard": "๐Ÿ˜ˆ"} + + await ctx.respond( + f"๐Ÿค– **4 Gewinnt vs KI** {difficulty_emoji.get(difficulty, '๐Ÿค–')}\n" + f"**Schwierigkeit:** {difficulty_info['name']}\n" + f"{ctx.author.mention} ๐Ÿ”ด spielt gegen die KI! ๐ŸŸก\n\n" + f"{view.board_to_str()}", + view=view + ) + return + + # PvP mode validations + if opponent.bot: + await ctx.respond( + messages["cog_4gewinnt"]["error_types"]["is_opponent_bot"], + ephemeral=True + ) + return + + if opponent == ctx.author: + await ctx.respond( + messages["cog_4gewinnt"]["error_types"]["is_opponent_self"], + ephemeral=True + ) + return + + view = Connect4View(ctx.author, opponent, messages) + + await ctx.respond( + f"๐ŸŽฎ **4 Gewinnt - PvP Match**\n" + f"{ctx.author.mention} ๐Ÿ”ด vs ๐ŸŸก {opponent.mention}\n\n" + f"{view.board_to_str()}", + view=view + ) + + @commands.slash_command(name="connect4stats", description="Zeige deine 4 Gewinnt Statistiken!") + async def stats(self, ctx: discord.ApplicationContext, user: Optional[discord.Member] = None): + target_user = user or ctx.author + stats = game_stats.get_user_stats(target_user.id) + winrate = game_stats.get_winrate(target_user.id) + + embed = discord.Embed( + title=f"๐Ÿ“Š 4 Gewinnt Statistiken - {target_user.display_name}", + color=discord.Color.blue() + ) + + embed.set_thumbnail(url=target_user.display_avatar.url) + + embed.add_field( + name="๐ŸŽฏ รœbersicht", + value=f"**Gesamt:** {stats['total_games']}\n" + f"๐Ÿ† Siege: {stats['wins']}\n" + f"๐Ÿ’” Niederlagen: {stats['losses']}\n" + f"๐Ÿค Unentschieden: {stats['draws']}", + inline=True + ) + + embed.add_field( + name="๐Ÿ“ˆ Performance", + value=f"**Siegrate:** {winrate:.1f}%\n" + f"๐Ÿ”ฅ Aktuelle Serie: {stats['win_streak']}\n" + f"โญ Beste Serie: {stats['best_streak']}", + inline=True + ) + + # KI-Stats + if stats['ai_wins'] > 0 or stats['ai_losses'] > 0: + ai_total = stats['ai_wins'] + stats['ai_losses'] + ai_winrate = (stats['ai_wins'] / ai_total * 100) if ai_total > 0 else 0 + embed.add_field( + name="๐Ÿค– KI-Statistiken", + value=f"๐Ÿ† Siege: {stats['ai_wins']}\n" + f"๐Ÿ’” Niederlagen: {stats['ai_losses']}\n" + f"๐Ÿ“Š Siegrate: {ai_winrate:.1f}%", + inline=True + ) + + embed.set_footer(text=f"Abgefragt von {ctx.author.display_name}") + embed.timestamp = datetime.now() + + await ctx.respond(embed=embed) + +def setup(bot): + bot.add_cog(Connect4Cog(bot)) \ No newline at end of file diff --git a/src/bot/cogs/fun/tictactoe.py b/src/bot/cogs/fun/tictactoe.py new file mode 100644 index 0000000..8d77f7f --- /dev/null +++ b/src/bot/cogs/fun/tictactoe.py @@ -0,0 +1,602 @@ +# Copyright (c) 2025 OPPRO.NET Network +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Import +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +from discord.ui import Button, View +import discord +from discord.ext import commands +import ezcord +import yaml +from pathlib import Path +from typing import Optional, List, Tuple +import asyncio +import random + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Constants +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +DEFAULT_TIMEOUT = 120 + +DIFFICULTY_CONFIG = { + "easy": { + "name": "Anfรคnger", + "randomness": 0.5 # 50% zufรคllige Zรผge + }, + "medium": { + "name": "Fortgeschritten", + "randomness": 0.2 # 20% zufรคllige Zรผge + }, + "hard": { + "name": "Experte", + "randomness": 0.0 # Perfektes Spiel + } +} + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Statistics Manager +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class GameStats: + """Verwaltet Spielstatistiken fรผr TicTacToe""" + + def __init__(self): + self.stats = {} + + def get_user_stats(self, user_id: int) -> dict: + if user_id not in self.stats: + self.stats[user_id] = { + "wins": 0, + "losses": 0, + "draws": 0, + "total_games": 0, + "win_streak": 0, + "best_streak": 0, + "ai_wins": 0, + "ai_losses": 0 + } + return self.stats[user_id] + + def record_win(self, user_id: int, vs_ai: bool = False): + stats = self.get_user_stats(user_id) + stats["wins"] += 1 + stats["total_games"] += 1 + stats["win_streak"] += 1 + stats["best_streak"] = max(stats["best_streak"], stats["win_streak"]) + if vs_ai: + stats["ai_wins"] += 1 + + def record_loss(self, user_id: int, vs_ai: bool = False): + stats = self.get_user_stats(user_id) + stats["losses"] += 1 + stats["total_games"] += 1 + stats["win_streak"] = 0 + if vs_ai: + stats["ai_losses"] += 1 + + def record_draw(self, user_id: int): + stats = self.get_user_stats(user_id) + stats["draws"] += 1 + stats["total_games"] += 1 + stats["win_streak"] = 0 + + def get_winrate(self, user_id: int) -> float: + stats = self.get_user_stats(user_id) + if stats["total_games"] == 0: + return 0.0 + return (stats["wins"] / stats["total_games"]) * 100 + +# Global stats instance +game_stats = GameStats() + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Load messages from YAML +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +def load_messages(lang_code: str): + """ + Lรคdt Nachrichten fรผr den angegebenen Sprachcode. + Fรคllt auf 'en' und dann auf 'de' zurรผck, falls die Datei fehlt. + """ + base_path = Path("translation") / "messages" + + lang_file = base_path / f"{lang_code}.yaml" + if not lang_file.exists(): + lang_file = base_path / "en.yaml" + if not lang_file.exists(): + lang_file = base_path / "de.yaml" + + if not lang_file.exists(): + print(f"WARNUNG: Keine Sprachdatei fรผr '{lang_code}' gefunden. Verwende leere Texte.") + return {} + + with open(lang_file, "r", encoding="utf-8") as f: + return yaml.safe_load(f) + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> AI Engine (Minimax Algorithm) +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class TicTacToeAI: + """KI-Gegner mit Minimax-Algorithmus fรผr TicTacToe""" + + def __init__(self, difficulty: str = "medium"): + config = DIFFICULTY_CONFIG.get(difficulty, DIFFICULTY_CONFIG["medium"]) + self.randomness = config["randomness"] + self.difficulty_name = config["name"] + + def get_available_moves(self, board: List[List[str]]) -> List[Tuple[int, int]]: + """Gibt alle verfรผgbaren Zรผge zurรผck""" + moves = [] + for i in range(3): + for j in range(3): + if board[i][j] == "": + moves.append((i, j)) + return moves + + def check_winner(self, board: List[List[str]]) -> Optional[str]: + """Prรผft ob es einen Gewinner gibt""" + # Horizontal + for i in range(3): + if board[i][0] == board[i][1] == board[i][2] != "": + return board[i][0] + + # Vertikal + for i in range(3): + if board[0][i] == board[1][i] == board[2][i] != "": + return board[0][i] + + # Diagonal + if board[0][0] == board[1][1] == board[2][2] != "": + return board[0][0] + if board[0][2] == board[1][1] == board[2][0] != "": + return board[0][2] + + return None + + def is_board_full(self, board: List[List[str]]) -> bool: + """Prรผft ob das Board voll ist""" + return all(cell != "" for row in board for cell in row) + + def minimax(self, board: List[List[str]], depth: int, is_maximizing: bool, + ai_symbol: str, player_symbol: str) -> int: + """Minimax-Algorithmus fรผr optimale Zรผge""" + winner = self.check_winner(board) + + # Terminal-Zustรคnde + if winner == ai_symbol: + return 10 - depth # Schnellerer Gewinn ist besser + elif winner == player_symbol: + return depth - 10 # Schnellerer Verlust ist schlechter + elif self.is_board_full(board): + return 0 # Unentschieden + + if is_maximizing: + best_score = float('-inf') + for i, j in self.get_available_moves(board): + board[i][j] = ai_symbol + score = self.minimax(board, depth + 1, False, ai_symbol, player_symbol) + board[i][j] = "" + best_score = max(score, best_score) + return best_score + else: + best_score = float('inf') + for i, j in self.get_available_moves(board): + board[i][j] = player_symbol + score = self.minimax(board, depth + 1, True, ai_symbol, player_symbol) + board[i][j] = "" + best_score = min(score, best_score) + return best_score + + def get_best_move(self, board: List[List[str]], ai_symbol: str, player_symbol: str) -> Tuple[int, int]: + """Gibt den besten Zug zurรผck""" + available_moves = self.get_available_moves(board) + + if not available_moves: + return (0, 0) + + # Zufรคlligkeit fรผr niedrigere Schwierigkeitsgrade + if random.random() < self.randomness: + return random.choice(available_moves) + + # Prรผfe auf Gewinnzug + for i, j in available_moves: + board[i][j] = ai_symbol + if self.check_winner(board) == ai_symbol: + board[i][j] = "" + return (i, j) + board[i][j] = "" + + # Prรผfe ob Gegner blockiert werden muss + for i, j in available_moves: + board[i][j] = player_symbol + if self.check_winner(board) == player_symbol: + board[i][j] = "" + return (i, j) + board[i][j] = "" + + # Verwende Minimax fรผr optimalen Zug + best_score = float('-inf') + best_move = available_moves[0] + + for i, j in available_moves: + board[i][j] = ai_symbol + score = self.minimax(board, 0, False, ai_symbol, player_symbol) + board[i][j] = "" + + if score > best_score: + best_score = score + best_move = (i, j) + + return best_move + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Enhanced Button & View +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class TicTacToeButton(Button): + def __init__(self, x, y): + super().__init__(style=discord.ButtonStyle.secondary, label="\u200b", row=x) + self.x = x + self.y = y + self.clicked = False + + async def callback(self, interaction: discord.Interaction): + view: TicTacToeView = self.view + messages = view.messages + + # Prรผfe ob Spiel bereits beendet + if view.game_ended: + await interaction.response.send_message( + "Das Spiel ist bereits beendet!", + ephemeral=True + ) + return + + # PvP mode checks + if not view.is_ai_mode and interaction.user != view.current_player: + await interaction.response.send_message( + messages.get("cog_tictactoe", {}).get("error_types", {}).get("not_your_turn", "Not your turn!"), + ephemeral=True + ) + return + + # AI mode checks + if view.is_ai_mode and interaction.user != view.player1: + await interaction.response.send_message( + messages.get("cog_tictactoe", {}).get("error_types", {}).get("not_your_turn", "Not your turn!"), + ephemeral=True + ) + return + + if self.clicked: + await interaction.response.send_message( + messages.get("cog_tictactoe", {}).get("error_types", {}).get("this_cell_taken", "This cell is already taken!"), + ephemeral=True + ) + return + + # Spieler-Zug + self.clicked = True + if view.current_turn == 0: + self.style = discord.ButtonStyle.danger # rot = X + self.label = "X" + view.board[self.x][self.y] = "X" + view.current_turn = 1 + view.current_player = view.player2 + else: + self.style = discord.ButtonStyle.success # grรผn = O + self.label = "O" + view.board[self.x][self.y] = "O" + view.current_turn = 0 + view.current_player = view.player1 + + winner = view.check_winner() + + if winner: + await view.end_game(interaction, winner) + return + + elif view.is_draw(): + await view.end_game(interaction, None) + return + + # AI-Zug + if view.is_ai_mode and view.current_player == view.player2: + next_turn_msg = messages.get("cog_tictactoe", {}).get("message", {}).get("ai_thinking", "๐Ÿค– KI denkt nach...").format( + player=view.current_player.mention + ) + await interaction.response.edit_message(content=next_turn_msg, view=view) + + # Simuliere Denkzeit + await asyncio.sleep(0.8) + + # KI macht Zug + ai_move = view.ai.get_best_move(view.board, "O", "X") + if ai_move: + ai_x, ai_y = ai_move + for child in view.children: + if isinstance(child, TicTacToeButton) and child.x == ai_x and child.y == ai_y: + child.clicked = True + child.style = discord.ButtonStyle.success + child.label = "O" + view.board[ai_x][ai_y] = "O" + view.current_turn = 0 + view.current_player = view.player1 + break + + winner = view.check_winner() + + if winner: + await view.end_game(interaction, winner, is_followup=True) + return + + elif view.is_draw(): + await view.end_game(interaction, None, is_followup=True) + return + + # Zeige KI-Zug an + next_turn_msg = messages.get("cog_tictactoe", {}).get("message", {}).get("ai_moved", "โœ… KI hat Feld ({x}, {y}) gewรคhlt!\n\n{player}, du bist dran!").format( + x=ai_x + 1, + y=ai_y + 1, + player=view.current_player.mention + ) + await interaction.edit_original_response(content=next_turn_msg, view=view) + else: + next_turn_msg = messages.get("cog_tictactoe", {}).get("message", {}).get("next_turn", "It is now {player}'s turn!").format( + player=view.current_player.mention + ) + await interaction.response.edit_message(content=next_turn_msg, view=view) + +class TicTacToeView(View): + def __init__(self, player1, player2, messages, is_ai_mode=False, difficulty="medium"): + super().__init__(timeout=DEFAULT_TIMEOUT) + self.player1 = player1 + self.player2 = player2 + self.current_player = player1 + self.current_turn = 0 # 0 = X (player1), 1 = O (player2) + self.board = [["" for _ in range(3)] for _ in range(3)] + self.messages = messages + self.is_ai_mode = is_ai_mode + self.difficulty = difficulty + self.ai = TicTacToeAI(difficulty) if is_ai_mode else None + self.game_ended = False + + for x in range(3): + for y in range(3): + self.add_item(TicTacToeButton(x, y)) + + def check_winner(self): + """Prรผft auf Gewinner""" + b = self.board + players_map = {"X": self.player1, "O": self.player2} + + # Horizontal + for i in range(3): + if b[i][0] == b[i][1] == b[i][2] != "": + winner_symbol = b[i][0] + return f"{winner_symbol} ({players_map[winner_symbol].display_name})" + + # Vertikal + for i in range(3): + if b[0][i] == b[1][i] == b[2][i] != "": + winner_symbol = b[0][i] + return f"{winner_symbol} ({players_map[winner_symbol].display_name})" + + # Diagonal + if b[0][0] == b[1][1] == b[2][2] != "": + winner_symbol = b[0][0] + return f"{winner_symbol} ({players_map[winner_symbol].display_name})" + if b[0][2] == b[1][1] == b[2][0] != "": + winner_symbol = b[0][2] + return f"{winner_symbol} ({players_map[winner_symbol].display_name})" + + return None + + def is_draw(self): + """Prรผft auf Unentschieden""" + return all(cell != "" for row in self.board for cell in row) + + async def end_game(self, interaction: discord.Interaction, winner: Optional[str], is_followup: bool = False): + """Beendet das Spiel und zeigt Statistiken""" + self.game_ended = True + + for child in self.children: + child.disabled = True + + messages = self.messages + + # Update Statistiken + if winner: + winner_symbol = winner[0] # "X" oder "O" + winner_player = self.player1 if winner_symbol == "X" else self.player2 + loser_player = self.player2 if winner_symbol == "X" else self.player1 + + if self.is_ai_mode: + if winner_player == self.player1: + game_stats.record_win(self.player1.id, vs_ai=True) + else: + game_stats.record_loss(self.player1.id, vs_ai=True) + else: + game_stats.record_win(winner_player.id) + game_stats.record_loss(loser_player.id) + else: + game_stats.record_draw(self.player1.id) + if not self.is_ai_mode: + game_stats.record_draw(self.player2.id) + + # Erstelle Embed + embed = discord.Embed( + title="๐ŸŽฎ Tic Tac Toe - Spiel beendet!", + color=discord.Color.green() if winner else discord.Color.gold() + ) + + # Ergebnis + if winner: + if self.is_ai_mode and winner[0] == "O": + result_text = f"๐Ÿค– **Die {self.ai.difficulty_name} KI hat gewonnen!**" + embed.color = discord.Color.red() + else: + result_text = messages.get("cog_tictactoe", {}).get("win_types", {}).get("win", "WINNER: {winner}").format(winner=winner) + else: + result_text = messages.get("cog_tictactoe", {}).get("win_types", {}).get("draw", "It's a draw!") + + embed.add_field( + name="๐ŸŽฏ Ergebnis", + value=result_text, + inline=False + ) + + # Statistiken + if winner: + winner_player = self.player1 if winner[0] == "X" else self.player2 + if not self.is_ai_mode or winner_player == self.player1: + stats = game_stats.get_user_stats(winner_player.id) + + if self.is_ai_mode: + stats_text = f"๐Ÿ† Siege vs KI: {stats['ai_wins']}\n๐Ÿ’” Niederlagen vs KI: {stats['ai_losses']}\n๐Ÿ”ฅ Serie: {stats['win_streak']}" + else: + stats_text = f"๐Ÿ† Siege: {stats['wins']}\n๐Ÿ’” Niederlagen: {stats['losses']}\n๐Ÿ”ฅ Serie: {stats['win_streak']}" + + embed.add_field( + name="๐Ÿ“ˆ Spieler-Stats", + value=stats_text, + inline=True + ) + + # Spielfeld anzeigen + board_display = "" + for row in self.board: + board_display += " | ".join([cell if cell else "ยท" for cell in row]) + "\n" + + embed.add_field( + name="๐ŸŽฒ Endposition", + value=f"```\n{board_display}```", + inline=False + ) + + embed.set_footer(text=f"Schwierigkeit: {self.ai.difficulty_name if self.is_ai_mode else 'PvP'}") + + if is_followup: + await interaction.edit_original_response(embed=embed, view=self) + else: + await interaction.response.edit_message(embed=embed, view=self) + + self.stop() + + async def on_timeout(self): + """Wird aufgerufen wenn das Timeout erreicht wird""" + self.game_ended = True + for child in self.children: + child.disabled = True + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Cog +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class fun(ezcord.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.slash_command(name="tictactoe", description="Starte ein Tic Tac Toe Spiel!") + async def tictactoe( + self, + ctx: discord.ApplicationContext, + opponent: Optional[discord.Member] = None, + difficulty: discord.Option( + str, + description="KI-Schwierigkeit (nur wenn kein Gegner gewรคhlt)", + choices=["easy", "medium", "hard"], + default="medium", + required=False + ) = "medium" + ): + try: + lang_code = self.bot.settings_db.get_user_language(ctx.author.id) + except: + lang_code = "de" + + messages = load_messages(lang_code) + + # AI mode + if opponent is None: + ai_user = ctx.guild.me + view = TicTacToeView(ctx.author, ai_user, messages, is_ai_mode=True, difficulty=difficulty) + + difficulty_info = DIFFICULTY_CONFIG.get(difficulty, DIFFICULTY_CONFIG["medium"]) + difficulty_emoji = {"easy": "๐Ÿ˜Š", "medium": "๐Ÿค”", "hard": "๐Ÿ˜ˆ"} + + await ctx.respond( + f"๐Ÿค– **Tic Tac Toe vs KI** {difficulty_emoji.get(difficulty, '๐Ÿค–')}\n" + f"**Schwierigkeit:** {difficulty_info['name']}\n" + f"{ctx.author.mention} (X) spielt gegen die KI! (O)\n\n" + f"Du bist dran!", + view=view + ) + return + + # PvP mode validations + if opponent.bot: + await ctx.respond( + messages.get("cog_tictactoe", {}).get("error_types", {}).get("is_opponent_bot", "You cannot challenge a bot."), + ephemeral=True + ) + return + + if opponent == ctx.author: + await ctx.respond( + messages.get("cog_tictactoe", {}).get("error_types", {}).get("is_opponent_self", "You cannot challenge yourself."), + ephemeral=True + ) + return + + view = TicTacToeView(ctx.author, opponent, messages) + + start_msg = messages.get("cog_tictactoe", {}).get("message", {}).get("start_game", "Tic Tac Toe: {author_mention} vs {opponent_mention}").format( + author_mention=ctx.author.mention, + opponent_mention=opponent.mention + ) + await ctx.respond(start_msg, view=view) + + @commands.slash_command(name="tictactoestats", description="Zeige deine Tic Tac Toe Statistiken!") + async def stats(self, ctx: discord.ApplicationContext, user: Optional[discord.Member] = None): + target_user = user or ctx.author + stats = game_stats.get_user_stats(target_user.id) + winrate = game_stats.get_winrate(target_user.id) + + embed = discord.Embed( + title=f"๐Ÿ“Š Tic Tac Toe Statistiken - {target_user.display_name}", + color=discord.Color.blue() + ) + + embed.set_thumbnail(url=target_user.display_avatar.url) + + embed.add_field( + name="๐ŸŽฏ รœbersicht", + value=f"**Gesamt:** {stats['total_games']}\n" + f"๐Ÿ† Siege: {stats['wins']}\n" + f"๐Ÿ’” Niederlagen: {stats['losses']}\n" + f"๐Ÿค Unentschieden: {stats['draws']}", + inline=True + ) + + embed.add_field( + name="๐Ÿ“ˆ Performance", + value=f"**Siegrate:** {winrate:.1f}%\n" + f"๐Ÿ”ฅ Aktuelle Serie: {stats['win_streak']}\n" + f"โญ Beste Serie: {stats['best_streak']}", + inline=True + ) + + # KI-Stats + if stats['ai_wins'] > 0 or stats['ai_losses'] > 0: + ai_total = stats['ai_wins'] + stats['ai_losses'] + ai_winrate = (stats['ai_wins'] / ai_total * 100) if ai_total > 0 else 0 + embed.add_field( + name="๐Ÿค– KI-Statistiken", + value=f"๐Ÿ† Siege: {stats['ai_wins']}\n" + f"๐Ÿ’” Niederlagen: {stats['ai_losses']}\n" + f"๐Ÿ“Š Siegrate: {ai_winrate:.1f}%", + inline=True + ) + + embed.set_footer(text=f"Abgefragt von {ctx.author.display_name}") + + await ctx.respond(embed=embed) + +def setup(bot): + bot.add_cog(fun(bot)) \ No newline at end of file From 1577c1e2f3b3d0d27e9c9f21ee36c0564f99b8da Mon Sep 17 00:00:00 2001 From: LennyPegauOfficial Date: Sat, 17 Jan 2026 16:46:02 +0100 Subject: [PATCH 6/8] Potential fix for pull request finding 'Unused import' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> --- src/bot/core/database.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bot/core/database.py b/src/bot/core/database.py index 6d1e695..397739a 100644 --- a/src/bot/core/database.py +++ b/src/bot/core/database.py @@ -6,7 +6,6 @@ Pfad: src/bot/core/database.py """ -import sys from logger import logger, Category try: From c0dab116cb66f1efc57942919417665ce5c5f217 Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Sun, 18 Jan 2026 09:21:25 +0100 Subject: [PATCH 7/8] UPDATED --- docs/source/changelog/index.rst | 3 + main.py | 3 +- src/bot/cogs/guild/globalchat.py | 1518 +++++++++++++++++++++++++ src/bot/cogs/guild/levelsystem.py | 974 ++++++++++++++++ src/bot/cogs/guild/loggingsystem.py | 1465 ++++++++++++++++++++++++ src/bot/cogs/guild/tempvc.py | 612 ++++++++++ src/bot/cogs/guild/welcome.py | 1467 ++++++++++++++++++++++++ src/bot/cogs/management/autodelete.py | 309 +++++ src/bot/cogs/management/autorole.py | 273 +++++ src/bot/cogs/moderation/antispam.py | 435 +++++++ src/bot/cogs/moderation/moderation.py | 550 +++++++++ src/bot/cogs/moderation/notes.py | 70 ++ src/bot/cogs/moderation/warn.py | 557 +++++++++ src/bot/cogs/user/settings.py | 108 ++ src/bot/cogs/user/stats.py | 598 ++++++++++ src/bot/core/__init__.py | 1 - translation/en_en.json | 31 + translation/ez_de.json | 32 + translation/messages/de.yaml | 122 ++ translation/messages/en.yaml | 119 ++ 20 files changed, 9244 insertions(+), 3 deletions(-) create mode 100644 src/bot/cogs/guild/globalchat.py create mode 100644 src/bot/cogs/guild/levelsystem.py create mode 100644 src/bot/cogs/guild/loggingsystem.py create mode 100644 src/bot/cogs/guild/tempvc.py create mode 100644 src/bot/cogs/guild/welcome.py create mode 100644 src/bot/cogs/management/autodelete.py create mode 100644 src/bot/cogs/management/autorole.py create mode 100644 src/bot/cogs/moderation/antispam.py create mode 100644 src/bot/cogs/moderation/moderation.py create mode 100644 src/bot/cogs/moderation/notes.py create mode 100644 src/bot/cogs/moderation/warn.py create mode 100644 src/bot/cogs/user/settings.py create mode 100644 src/bot/cogs/user/stats.py create mode 100644 translation/en_en.json create mode 100644 translation/ez_de.json create mode 100644 translation/messages/de.yaml create mode 100644 translation/messages/en.yaml diff --git a/docs/source/changelog/index.rst b/docs/source/changelog/index.rst index e69de29..cfbea3d 100644 --- a/docs/source/changelog/index.rst +++ b/docs/source/changelog/index.rst @@ -0,0 +1,3 @@ +All Versions of ManagerX. +========================================= + diff --git a/main.py b/main.py index 6dc07c8..30b27d9 100644 --- a/main.py +++ b/main.py @@ -27,7 +27,6 @@ from src.bot.core.database import DatabaseManager from src.bot.core.dashboard import DashboardTask from src.bot.core.utils import print_logo - # ============================================================================= # SETUP # ============================================================================= @@ -38,7 +37,6 @@ # Sys-Path if str(BASEDIR) not in sys.path: sys.path.append(str(BASEDIR)) - # ============================================================================= # MAIN EXECUTION # ============================================================================= @@ -88,6 +86,7 @@ async def on_ready(): # Commands sync await bot.sync_commands() logger.success("COMMANDS", "Application Commands synchronisiert") + # Minimaler KeepAlive Cog - damit Bot immer online bleibt class KeepAlive(discord.ext.commands.Cog): diff --git a/src/bot/cogs/guild/globalchat.py b/src/bot/cogs/guild/globalchat.py new file mode 100644 index 0000000..daa4686 --- /dev/null +++ b/src/bot/cogs/guild/globalchat.py @@ -0,0 +1,1518 @@ +# Copyright (c) 2025 OPPRO.NET Network +import discord +from discord.ext import commands, tasks +from discord import slash_command, Option, SlashCommandGroup +from DevTools.backend.database.globalchat_db import GlobalChatDatabase, db +import asyncio +import logging +import re +import time +from typing import List, Optional, Dict, Tuple +import aiohttp +import io +import json +from datetime import datetime, timedelta +import ezcord +from collections import defaultdict +from discord.ui import Container + +# Logger konfigurieren +logger = logging.getLogger(__name__) + + +class GlobalChatConfig: + """Zentrale Konfiguration fรผr GlobalChat""" + RATE_LIMIT_MESSAGES = 15 + RATE_LIMIT_SECONDS = 60 + CACHE_DURATION = 180 # 3 Minuten + CLEANUP_DAYS = 30 + MIN_MESSAGE_LENGTH = 0 # Erlaube Nachrichten ohne Text (nur Medien) + DEFAULT_MAX_MESSAGE_LENGTH = 1900 + DEFAULT_EMBED_COLOR = '#5865F2' + + # Medien-Limits + MAX_FILE_SIZE_MB = 25 # Discord-Standard + MAX_ATTACHMENTS = 10 + ALLOWED_IMAGE_FORMATS = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp'] + ALLOWED_VIDEO_FORMATS = ['mp4', 'mov', 'webm', 'avi', 'mkv'] + ALLOWED_AUDIO_FORMATS = ['mp3', 'wav', 'ogg', 'm4a', 'flac'] + ALLOWED_DOCUMENT_FORMATS = ['pdf', 'txt', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', '7z'] + + # Bot Owner IDs + BOT_OWNERS = [1093555256689959005, 1427994077332373554] + + # Content Filter Patterns + DISCORD_INVITE_PATTERN = r'(?i)\b(discord\.gg|discord\.com/invite|discordapp\.com/invite)/[a-zA-Z0-9]+\b' + URL_PATTERN = r'(?i)\bhttps?://(?:[a-zA-Z0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F]{2}))+\b' + + # NSFW Keywords + NSFW_KEYWORDS = [ + 'nsfw', 'porn', 'sex', 'xxx', 'nude', 'hentai', + 'dick', 'pussy', 'cock', 'tits', 'ass', 'fuck' + ] + + +class MediaHandler: + """Verarbeitet alle Arten von Medien und Anhรคngen""" + + def __init__(self, config: GlobalChatConfig): + self.config = config + + def validate_attachments(self, attachments: List[discord.Attachment]) -> Tuple[bool, str, List[discord.Attachment]]: + """Validiert Attachments und gibt valide zurรผck""" + if not attachments: + return True, "", [] + + if len(attachments) > self.config.MAX_ATTACHMENTS: + return False, f"Zu viele Anhรคnge (max. {self.config.MAX_ATTACHMENTS})", [] + + valid_attachments = [] + max_size_bytes = self.config.MAX_FILE_SIZE_MB * 1024 * 1024 + + for attachment in attachments: + # GrรถรŸe prรผfen + if attachment.size > max_size_bytes: + return False, f"Datei '{attachment.filename}' ist zu groรŸ (max. {self.config.MAX_FILE_SIZE_MB}MB)", [] + + # Dateiformat prรผfen + file_ext = attachment.filename.split('.')[-1].lower() if '.' in attachment.filename else '' + + all_allowed = ( + self.config.ALLOWED_IMAGE_FORMATS + + self.config.ALLOWED_VIDEO_FORMATS + + self.config.ALLOWED_AUDIO_FORMATS + + self.config.ALLOWED_DOCUMENT_FORMATS + ) + + if file_ext and file_ext not in all_allowed: + return False, f"Dateiformat '.{file_ext}' nicht erlaubt", [] + + valid_attachments.append(attachment) + + return True, "", valid_attachments + + def categorize_attachment(self, attachment: discord.Attachment) -> str: + """Kategorisiert einen Anhang nach Typ""" + if not attachment.filename or '.' not in attachment.filename: + return 'other' + + file_ext = attachment.filename.split('.')[-1].lower() + + if file_ext in self.config.ALLOWED_IMAGE_FORMATS: + return 'image' + elif file_ext in self.config.ALLOWED_VIDEO_FORMATS: + return 'video' + elif file_ext in self.config.ALLOWED_AUDIO_FORMATS: + return 'audio' + elif file_ext in self.config.ALLOWED_DOCUMENT_FORMATS: + return 'document' + else: + return 'other' + + def get_attachment_icon(self, attachment: discord.Attachment) -> str: + """Gibt passendes Icon fรผr Attachment-Typ zurรผck""" + category = self.categorize_attachment(attachment) + + icons = { + 'image': '๐Ÿ–ผ๏ธ', + 'video': '๐ŸŽฅ', + 'audio': '๐ŸŽต', + 'document': '๐Ÿ“„', + 'other': '๐Ÿ“Ž' + } + + return icons.get(category, '๐Ÿ“Ž') + + def format_file_size(self, size_bytes: int) -> str: + """Formatiert DateigrรถรŸe leserlich""" + for unit in ['B', 'KB', 'MB']: + if size_bytes < 1024.0: + return f"{size_bytes:.1f} {unit}" + size_bytes /= 1024.0 + return f"{size_bytes:.1f} GB" + + +class MessageValidator: + """Validiert und filtert Nachrichten""" + + def __init__(self, config: GlobalChatConfig): + self.config = config + self.media_handler = MediaHandler(config) + self._compile_patterns() + + def _compile_patterns(self): + """Kompiliert Regex-Patterns fรผr bessere Performance""" + self.invite_pattern = re.compile(self.config.DISCORD_INVITE_PATTERN) + self.url_pattern = re.compile(self.config.URL_PATTERN) + + def validate_message(self, message: discord.Message, settings: Dict) -> Tuple[bool, str]: + """Hauptvalidierung fรผr Nachrichten""" + # Bot-Nachrichten ignorieren + if message.author.bot: + return False, "Bot-Nachricht" + + # Blacklist prรผfen + if db.is_blacklisted('user', message.author.id): + return False, "User auf Blacklist" + + if db.is_blacklisted('guild', message.guild.id): + return False, "Guild auf Blacklist" + + # Leere Nachrichten (ohne Text UND ohne Anhรคnge/Sticker) + if not message.content and not message.attachments and not message.stickers: + return False, "Leere Nachricht" + + # Nachrichtenlรคnge (nur wenn Text vorhanden) + if message.content: + content_length = len(message.content.strip()) + + # Mindestlรคnge nur bei reinen Text-Nachrichten + if content_length < self.config.MIN_MESSAGE_LENGTH and not message.attachments and not message.stickers: + return False, "Zu kurze Nachricht" + + max_length = settings.get('max_message_length', self.config.DEFAULT_MAX_MESSAGE_LENGTH) + if content_length > max_length: + return False, f"Nachricht zu lang (max. {max_length} Zeichen)" + + # Attachments validieren + if message.attachments: + valid, reason, _ = self.media_handler.validate_attachments(message.attachments) + if not valid: + return False, f"Ungรผltige Anhรคnge: {reason}" + + # Content Filter + if settings.get('filter_enabled', True): + is_filtered, filter_reason = self.check_filtered_content(message.content) + if is_filtered: + return False, f"Gefilterte Inhalte: {filter_reason}" + + # NSFW Filter + if settings.get('nsfw_filter', True): + if self.check_nsfw_content(message.content): + return False, "NSFW Inhalt erkannt" + + return True, "OK" + + def check_filtered_content(self, content: str) -> Tuple[bool, str]: + """Prรผft auf gefilterte Inhalte mit detailliertem Grund""" + if not content: + return False, "" + + # Discord Invites + if self.invite_pattern.search(content): + return True, "Discord Invite" + + return False, "" + + def check_nsfw_content(self, content: str) -> bool: + """Erweiterte NSFW-Erkennung""" + if not content: + return False + + content_lower = content.lower() + + # Keyword-Check mit Wortgrenzen + for keyword in self.config.NSFW_KEYWORDS: + pattern = r'\b' + re.escape(keyword) + r'\b' + if re.search(pattern, content_lower): + return True + + return False + + def clean_content(self, content: str) -> str: + """Bereinigt Nachrichteninhalt""" + if not content: + return "" + + # @everyone und @here neutralisieren + content = content.replace('@everyone', '๏ผ everyone') + content = content.replace('@here', '๏ผ here') + + # Rolle-Mentions neutralisieren + content = re.sub(r'<@&(\d+)>', r'๏ผ role', content) + + return content + + +class EmbedBuilder: + """Erstellt formatierte Embeds fรผr GlobalChat mit vollstรคndigem Medien-Support""" + + def __init__(self, config: GlobalChatConfig, bot=None): + self.config = config + self.media_handler = MediaHandler(config) + self.bot = bot # Bot fรผr Message-Fetching + + async def create_message_embed(self, message: discord.Message, settings: Dict, attachment_data: List[Tuple[str, bytes, str]] = None) -> Tuple[discord.Embed, List[Tuple[str, bytes]]]: + """Erstellt ein verbessertes Embed mit vollstรคndigem Medien-Support + + attachment_data: Liste von (filename, bytes, content_type) - schon heruntergeladene Dateien + Gibt (embed, [(filename, bytes), ...]) zurรผck - Bytes statt discord.File! + """ + if attachment_data is None: + attachment_data = [] + + content = self._clean_content(message.content) + + # Embed-Farbe + embed_color = self._parse_color(settings.get('embed_color', self.config.DEFAULT_EMBED_COLOR)) + + # Beschreibung + if content: + description = content + elif message.attachments or message.stickers or attachment_data: + description = "*Medien-Nachricht*" + else: + description = "*Keine Beschreibung*" + + # Embed erstellen + embed = discord.Embed( + description=description, + color=embed_color, + timestamp=message.created_at + ) + + # Author mit Badges + author_text, badges = self._build_author_info(message.author) + embed.set_author( + name=author_text, + icon_url=message.author.display_avatar.url + ) + + # Footer mit Server-Info UND Original-Message-ID (fรผr Reply-Tracking) + footer_text = f"๐Ÿ“ {message.guild.name} โ€ข #{message.channel.name} โ€ข ID:{message.id}" + embed.set_footer( + text=footer_text, + icon_url=message.guild.icon.url if message.guild.icon else None + ) + + # Reply-Kontext hinzufรผgen (robust, ohne invasive ร„nderungen) + if message.reference: + try: + # Versuche zuerst die gecachte referenzierte Nachricht + replied_msg = message.reference.resolved + + # Falls nicht im Cache, versuche die referenzierte Nachricht aus dem referenzierten Kanal zu holen + if not replied_msg and getattr(message.reference, 'message_id', None): + ref_channel = None + ref_chan_id = getattr(message.reference, 'channel_id', None) + if ref_chan_id: + # Versuche zuerst den Kanal vom Bot-Cache + ref_channel = self.bot.get_channel(ref_chan_id) + # Fallback auf Guild-Kanal + if not ref_channel and message.guild: + try: + ref_channel = message.guild.get_channel(ref_chan_id) + except Exception: + ref_channel = None + if not ref_channel: + ref_channel = message.channel + + if ref_channel: + try: + replied_msg = await ref_channel.fetch_message(message.reference.message_id) + except Exception: + replied_msg = None + + # Wenn wir eine referenzierte Nachricht haben, bereite Vorschau vor + if isinstance(replied_msg, discord.Message): + # Text-Vorschau (bevorzuge echten content) + preview = replied_msg.content or "" + + # Wenn die referenzierte Nachricht das Relay-Bot-Embed ist, versuche Text aus dem Embed + if not preview and replied_msg.embeds: + try: + preview = replied_msg.embeds[0].description or "" + except Exception: + preview = "" + + # Fallback auf Anhรคnge/Sticker + if not preview: + if replied_msg.attachments: + preview = f"๐Ÿ“Ž {len(replied_msg.attachments)} Datei(en)" + elif replied_msg.stickers: + preview = "๐ŸŽจ Sticker" + else: + preview = "*(Leere Nachricht)*" + + preview = self._clean_content(preview) + preview_short = (preview[:200] + "...") if len(preview) > 200 else preview + + # Author bestimmen: falls die referenzierte Nachricht vom Bot ist, versuche embed.author + author_display = None + try: + if replied_msg.author and replied_msg.author.id == getattr(self.bot, 'user', None).id and replied_msg.embeds: + emb = replied_msg.embeds[0] + if emb.author and emb.author.name: + author_display = emb.author.name + except Exception: + author_display = None + + if not author_display: + try: + author_display = replied_msg.author.display_name + except Exception: + author_display = "Unbekannter User" + + # Herkunft (Server โ€ข #channel) + origin = None + try: + if getattr(replied_msg, 'guild', None) and getattr(replied_msg, 'channel', None): + origin = f"{replied_msg.guild.name} โ€ข #{replied_msg.channel.name}" + except Exception: + origin = None + + reply_field = f"**{author_display}:** {preview_short}" + if origin: + reply_field += f"\n_{origin}_" + + embed.add_field(name="โ†ฉ๏ธ Antwort (Vorschau)", value=reply_field, inline=False) + except Exception: + # Never fail building the embed just because reply resolution failed + pass + + # Medien verarbeiten mit heruntergeladenen Dateien + files_to_upload = await self._process_media(embed, message, attachment_data) + + # Rรผckgabe: Embed + Liste von discord.File Objekten + return embed, files_to_upload + + async def _process_media(self, embed: discord.Embed, message: discord.Message, attachment_data: List[Tuple[str, bytes, str]] = None) -> List[Tuple[str, bytes]]: + """Verarbeitet alle Medien-Typen mit heruntergeladenen Anhรคngen + + attachment_data: Liste von (filename, bytes, content_type) - bereits heruntergeladen + Gibt Liste von (filename, bytes) zurรผck - NOT discord.File! + """ + if attachment_data is None: + attachment_data = [] + + attachment_bytes: List[Tuple[str, bytes]] = [] + + # === HERUNTERGELADENE ATTACHMENTS === + if attachment_data: + attachment_bytes.extend(self._process_downloaded_attachments(embed, attachment_data)) + + # === STICKERS === + if message.stickers: + self._process_stickers(embed, message.stickers) + + # === ORIGINAL EMBEDS (z.B. von Links) === + if message.embeds: + self._process_embeds(embed, message.embeds) + + return attachment_bytes + + def _process_downloaded_attachments(self, embed: discord.Embed, attachment_data: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes]]: + """Verarbeitet heruntergeladene Anhรคnge und gibt (filename, bytes) zurรผck + + attachment_data: [(filename, bytes_data, content_type), ...] + Gibt [(filename, bytes), ...] zurรผck - NICHT discord.File! + """ + attachment_bytes: List[Tuple[str, bytes]] = [] + + # Kategorisiere nach Typ + images = [] + videos = [] + audios = [] + documents = [] + others = [] + + for filename, data, content_type in attachment_data: + # Bestimme Dateityp anhand von content_type und Dateiendung + category = self._get_attachment_category(filename, content_type) + + if category == 'image': + images.append((filename, data)) + elif category == 'video': # HIER wurde der Code vervollstรคndigt + videos.append((filename, data)) + elif category == 'audio': + audios.append((filename, data)) + elif category == 'document': + documents.append((filename, data)) + else: + others.append((filename, data)) # Vervollstรคndigt + + # === IMAGE (NUR das erste Bild als embed.image) === + if images: + # Das erste Bild als Embed-Bild setzen + embed.set_image(url=f"attachment://{images[0][0]}") + # Alle Bilder fรผr den Upload vorbereiten + for filename, data in images: + attachment_bytes.append((filename, data)) + + if len(images) > 1: + # Fรผge einen Hinweis hinzu, dass weitere Bilder angehรคngt sind + embed.add_field( + name="๐Ÿ–ผ๏ธ Weitere Bilder", + value=f"_{len(images)-1} zusรคtzliche Bilder angehรคngt._", + inline=False + ) + + # === VIDEOS === + if videos: + video_links = [] + for video_name, video_data in videos: + size = len(video_data) + size_str = self.media_handler.format_file_size(size) + video_links.append(f"๐ŸŽฅ {video_name} ({size_str})") + attachment_bytes.append((video_name, video_data)) + + if video_links: + embed.add_field( + name="๐ŸŽฌ Videos", + value="\n".join(video_links[:3]), # Max 3 + inline=False + ) + + # === AUDIO === + if audios: + audio_links = [] + for audio_name, audio_data in audios: + size = len(audio_data) + size_str = self.media_handler.format_file_size(size) + audio_links.append(f"๐ŸŽต {audio_name} ({size_str})") + attachment_bytes.append((audio_name, audio_data)) + + if audio_links: + embed.add_field( + name="๐ŸŽง Audio-Dateien", + value="\n".join(audio_links[:3]), # Max 3 + inline=False + ) + + # === DOKUMENTE === + if documents: + doc_links = [] + for doc_name, doc_data in documents: + size = len(doc_data) + size_str = self.media_handler.format_file_size(size) + doc_links.append(f"๐Ÿ“„ {doc_name} ({size_str})") + attachment_bytes.append((doc_name, doc_data)) + + if doc_links: + embed.add_field( + name="๐Ÿ“„ Dokumente", + value="\n".join(doc_links[:3]), # Max 3 + inline=False + ) + + # === SONSTIGE === + if others: + other_links = [] + for other_name, other_data in others: + size = len(other_data) + size_str = self.media_handler.format_file_size(size) + other_links.append(f"๐Ÿ“Ž {other_name} ({size_str})") + attachment_bytes.append((other_name, other_data)) + + if other_links: + embed.add_field( + name="๐Ÿ“Ž Sonstige", + value="\n".join(other_links[:3]), # Max 3 + inline=False + ) + + return attachment_bytes # Wichtig: bytes zurรผckgeben + + def _process_stickers(self, embed: discord.Embed, stickers: List[discord.StickerItem]): + """Verarbeitet Discord Sticker""" + if not stickers: + return + + sticker_info = [] + for sticker in stickers: + sticker_type = "Standard" if sticker.url.endswith('.png') else "Animiert" + sticker_info.append(f"๐ŸŽจ **{sticker.name}** ({sticker_type})") + + embed.add_field( + name="๐ŸŽจ Sticker", + value="\n".join(sticker_info[:3]), + inline=False + ) + + # Versuche, das erste Bild (falls vorhanden) als Thumbnail zu setzen + if stickers[0].format.name in ['PNG', 'LOTTIE']: + embed.set_thumbnail(url=stickers[0].url) + + def _process_embeds(self, main_embed: discord.Embed, embeds: List[discord.Embed]): + """Verarbeitet Original-Embeds (z.B. Link-Vorschauen)""" + if not embeds: + return + + link_embeds = [] + for embed in embeds: + # Nur Embeds mit Titeln oder Beschreibungen, die keine eigenen Attachments sind, verarbeiten + if embed.type not in ['image', 'video', 'gifv'] and (embed.title or embed.description or embed.url): + + title = embed.title or "Unbekannter Link" + description = (embed.description[:100] + "...") if embed.description else "" + url = embed.url or "" + + link_embeds.append(f"**[{title}]({url})**\n_{description}_") + + if link_embeds: + main_embed.add_field( + name="๐Ÿ”— Verlinkte Inhalte", + value="\n\n".join(link_embeds), + inline=False + ) + + def _get_attachment_category(self, filename: str, content_type: str) -> str: + """Hilfsfunktion zur Kategorisierung basierend auf Name und Content-Type""" + if content_type.startswith('image/'): + return 'image' + elif content_type.startswith('video/'): + return 'video' + elif content_type.startswith('audio/'): + return 'audio' + + # Fallback auf Dateiendung + if not filename or '.' not in filename: + return 'other' + + file_ext = filename.split('.')[-1].lower() + if file_ext in self.config.ALLOWED_IMAGE_FORMATS: + return 'image' + elif file_ext in self.config.ALLOWED_VIDEO_FORMATS: + return 'video' + elif file_ext in self.config.ALLOWED_AUDIO_FORMATS: + return 'audio' + elif file_ext in self.config.ALLOWED_DOCUMENT_FORMATS: + return 'document' + else: + return 'other' + + def _clean_content(self, content: str) -> str: + """Bereinigt Nachrichteninhalt""" + if not content: + return "" + content = content.replace('@everyone', '๏ผ everyone') + content = content.replace('@here', '๏ผ here') + content = re.sub(r'<@&(\d+)>', r'๏ผ role', content) + return content.strip() + + def _parse_color(self, color_hex: str) -> discord.Color: + """Parst Hex-Farbe zu discord.Color""" + try: + color_hex = color_hex.lstrip('#') + return discord.Color(int(color_hex, 16)) + except (ValueError, TypeError): + return discord.Color.blurple() + + def _build_author_info(self, author: discord.Member) -> Tuple[str, List[str]]: + """Baut Author-Text mit Badges""" + badges = [] + roles = [] + # Bot Owner + if author.id in self.config.BOT_OWNERS: + badges.append("๐Ÿ‘‘") + roles.append("Bot Owner") + # Server Admin/Mod + if author.guild_permissions.administrator: + badges.append("โšก") + roles.append("Admin") + elif author.guild_permissions.manage_guild: + badges.append("๐Ÿ”ง") + roles.append("Mod") + + badge_text = " ".join(badges) + author_text = f"{badge_text} {author.display_name}".strip() + + # Hinzufรผgen von Discord System Badges (z.B. Bot, Verified Bot) + if author.bot: + author_text += " [BOT]" + + return author_text, roles + + +class GlobalChatSender: + """Verantwortlich fรผr das Senden der Nachricht an alle verbundenen Kanรคle""" + def __init__(self, bot, config: GlobalChatConfig, embed_builder: EmbedBuilder, cache_ref: List[int]): + self.bot = bot + self.config = config + self.embed_builder = embed_builder + self._cached_channels = cache_ref # Referenz zum Cache in der Cog + + async def _get_all_active_channels(self) -> List[int]: + """Ruft alle aktiven Channel-IDs ab, nutzt den Cache""" + if self._cached_channels is None: + # Cache initial fรผllen + self._cached_channels = await self._fetch_all_channels() + return self._cached_channels + + async def _fetch_all_channels(self) -> List[int]: + """Holt Channel IDs direkt aus der Datenbank""" + try: + channel_ids = db.get_all_channels() + return channel_ids + except Exception as e: + logger.error(f"โŒ Fehler beim Abrufen aller Channel-IDs: {e}", exc_info=True) + return [] + + async def _send_to_channel(self, channel_id: int, embed: discord.Embed, attachment_bytes: List[Tuple[str, bytes]]) -> bool: + """Sendet die Embed-Nachricht an einen spezifischen Channel mit Error-Handling + attachment_bytes: Liste von (filename, bytes) - wird zu discord.File konvertiert + Wichtig: Raw bytes, nicht discord.File, da File-Streams verbraucht sind! + """ + try: + channel = self.bot.get_channel(channel_id) + if not channel: + logger.warning(f"โš ๏ธ Channel {channel_id} nicht gefunden") + return False + + # Permissions prรผfen + perms = channel.permissions_for(channel.guild.me) + if not perms.send_messages or not perms.embed_links: + logger.warning(f"โš ๏ธ Keine Permissions in {channel_id}") + return False + + # Erstelle NEUE discord.File Objekte fรผr diesen Channel (wichtig!) + # Jeder Channel bekommt seine eigenen frischen Files! + files = [] + if attachment_bytes: + for filename, data in attachment_bytes: + try: + files.append(discord.File(io.BytesIO(data), filename=filename)) + except Exception as e: + logger.warning(f"โš ๏ธ Error creating file {filename}: {e}") + + # Sende mit Retry-Logik + max_retries = 3 + for attempt in range(max_retries): + try: + if files: + await channel.send(embed=embed, files=files) + else: + await channel.send(embed=embed) + return True + except (ConnectionResetError, aiohttp.ClientConnectorError, asyncio.TimeoutError) as e: + logger.warning(f"โŒ Sendefehler (Retry {attempt+1}/{max_retries}) in {channel_id}: {e}") + await asyncio.sleep(1 + attempt * 2) + except discord.Forbidden: + logger.warning(f"โŒ Bot hat Senderechte in {channel_id} verloren. Enferne aus Cache.") + if channel_id in self._cached_channels: + self._cached_channels.remove(channel_id) + return False + except Exception as e: + logger.error(f"โŒ Unerwarteter Sendefehler in {channel_id}: {e}") + return False + + # Wenn alle Retries fehlschlagen + logger.error(f"โŒ Senden nach {max_retries} Retries in {channel_id} fehlgeschlagen.") + return False + + except Exception as e: + logger.error(f"โŒ Generischer Fehler im _send_to_channel: {e}", exc_info=True) + return False + + async def send_global_message(self, message: discord.Message, attachment_data: List[Tuple[str, bytes, str]] = None) -> Tuple[int, int]: + """Sendet eine Nachricht global an alle verbundenen Channels""" + settings = db.get_guild_settings(message.guild.id) + + embed, files_to_upload = await self.embed_builder.create_message_embed(message, settings, attachment_data) + + active_channels = await self._get_all_active_channels() + successful_sends = 0 + failed_sends = 0 + + # Berechne, wie viele Tasks gleichzeitig laufen sollen (z.B. 10) + tasks = [] + for channel_id in active_channels: + # Sende nicht an den Ursprungskanal zurรผck + if channel_id == message.channel.id: + continue + + tasks.append(self._send_to_channel(channel_id, embed, files_to_upload)) + + results = await asyncio.gather(*tasks, return_exceptions=True) + + for result in results: + if result is True: + successful_sends += 1 + else: + failed_sends += 1 + if isinstance(result, Exception): + logger.error(f"โŒ Task-Fehler beim Senden: {result}") + + return successful_sends, failed_sends + + +class GlobalChatCog(ezcord.Cog): + """Haupt-Cog fรผr das GlobalChat-System""" + + globalchat = SlashCommandGroup("globalchat", "GlobalChat Verwaltung") + + + def __init__(self, bot): + self.bot = bot + self.config = GlobalChatConfig() + self.validator = MessageValidator(self.config) + self.embed_builder = EmbedBuilder(self.config, bot) + self.message_cooldown = commands.CooldownMapping.from_cooldown( + self.config.RATE_LIMIT_MESSAGES, + self.config.RATE_LIMIT_SECONDS, + commands.BucketType.user + ) + self._cached_channels: Optional[List[int]] = None + self.sender = GlobalChatSender(self.bot, self.config, self.embed_builder, self._cached_channels) + self.cleanup_task.start() + + @tasks.loop(hours=12) + async def cleanup_task(self): + """Task zur Bereinigung abgelaufener Blacklist-Eintrรคge und Cache-Aktualisierung""" + # db.delete_expired_blacklist_entries() <--- DIESE ZEILE AUSKOMMENTIEREN + # logger.info("๐Ÿ—‘๏ธ GlobalChat: Abgelaufene Blacklist-Eintrรคge bereinigt.") + + # Cache neu laden, um ร„nderungen in der DB zu sehen + self._cached_channels = await self.sender._fetch_all_channels() + logger.info("๐Ÿง  GlobalChat: Channel-Cache neu geladen.") + + @ezcord.Cog.listener() + async def on_message(self, message: discord.Message): + """Haupt-Listener fรผr eingehende GlobalChat-Nachrichten""" + if not message.guild or message.author.bot: + return + + # Prรผfen ob Channel ein GlobalChat-Channel ist + global_chat_channel_id = db.get_globalchat_channel(message.guild.id) + if message.channel.id != global_chat_channel_id: + return + + # Guild-Settings laden + settings = db.get_guild_settings(message.guild.id) + + # Message validieren + is_valid, reason = self.validator.validate_message(message, settings) + if not is_valid: + logger.debug(f"โŒ Nachricht abgelehnt: {reason} (User: {message.author.id})") + + # User benachrichtigen bei bestimmten Grรผnden + if any(keyword in reason for keyword in ["Blacklist", "NSFW", "Gefilterte", "Ungรผltige Anhรคnge", "zu groรŸ"]): + try: + await message.add_reaction("โŒ") + # Info-Nachricht fรผr spezifische Fehler + if "Ungรผltige Anhรคnge" in reason or "zu groรŸ" in reason: + info_msg = await message.reply( + f"โŒ **Fehler:** {reason}\n" + f"**Max. GrรถรŸe:** {self.config.MAX_FILE_SIZE_MB}MB pro Datei\n" + f"**Max. Anhรคnge:** {self.config.MAX_ATTACHMENTS}", + delete_after=7 + ) + await asyncio.sleep(2) + await message.delete() + except (discord.Forbidden, discord.NotFound): + pass # Kann Nachricht nicht lรถschen/reagieren + return + + # Rate Limiting prรผfen + bucket = self.message_cooldown.get_bucket(message) + retry_after = bucket.update_rate_limit() + if retry_after: + try: + await message.add_reaction("โฐ") + await asyncio.sleep(2) + await message.delete() + logger.debug(f"โฐ Nachricht von {message.author.id} wegen Rate Limit entfernt.") + except (discord.Forbidden, discord.NotFound): + pass + return + + # === Medien herunterladen (wenn vorhanden) === + attachment_data: List[Tuple[str, bytes, str]] = [] + if message.attachments: + try: + await message.channel.trigger_typing() + for attachment in message.attachments: + # Maximal 25MB (Discord-Limit) + if attachment.size <= self.config.MAX_FILE_SIZE_MB * 1024 * 1024: + data = await attachment.read() + attachment_data.append((attachment.filename, data, attachment.content_type)) + except Exception as e: + logger.error(f"โŒ Fehler beim Herunterladen von Attachments: {e}") + # Wenn Download fehlschlรคgt, Nachricht trotzdem ohne Medien senden + attachment_data = [] + + # Nachricht senden + successful, failed = await self.sender.send_global_message(message, attachment_data) + + # Ursprรผngliche Nachricht lรถschen, wenn Relaying erfolgreich war + if settings.get('delete_original', False): + try: + await message.delete() + except discord.Forbidden: + logger.warning(f"โš ๏ธ Keine Permissions zum Lรถschen der Original-Nachricht in {message.channel.id}") + except discord.NotFound: + pass + + logger.info(f"๐ŸŒ GlobalChat: Nachricht von {message.guild.name} | User: {message.author.name} | โœ… {successful} | โŒ {failed}") + + + # ==================== Slash Commands ==================== + + @globalchat.command( + name="setup", + description="Richtet einen GlobalChat-Channel ein" + ) + async def setup_globalchat( + self, + ctx: discord.ApplicationContext, + channel: discord.TextChannel = Option(discord.TextChannel, "Der GlobalChat-Channel", required=True) + ): + """Setup-Command fรผr GlobalChat""" + if not ctx.author.guild_permissions.manage_guild: + await ctx.respond("โŒ Du benรถtigst die **Server verwalten** Berechtigung!", ephemeral=True) + return + + # Bot Permissions prรผfen + bot_perms = channel.permissions_for(ctx.guild.me) + missing_perms = [] + if not bot_perms.send_messages: missing_perms.append("Nachrichten senden") + if not bot_perms.manage_messages: missing_perms.append("Nachrichten verwalten") + if not bot_perms.embed_links: missing_perms.append("Links einbetten") + if not bot_perms.read_message_history: missing_perms.append("Nachrichten-Historie lesen") + if not bot_perms.attach_files: missing_perms.append("Dateien anhรคngen") # Wichtig fรผr Medien + + if missing_perms: + perms_list = "\n".join([f"โ€ข {p}" for p in missing_perms]) + await ctx.respond( + f"โŒ Mir fehlen wichtige Berechtigungen in {channel.mention}:\n{perms_list}", + ephemeral=True + ) + return + + try: + db.set_globalchat_channel(ctx.guild.id, channel.id) + + # Cache aktualisieren + self._cached_channels = await self.sender._fetch_all_channels() + + # UI Container fรผr eine schรถnere Antwort (falls vorhanden) + container = Container() + + status_text = f"โœ… **GlobalChat eingerichtet!**\n\n" + status_text += f"Der GlobalChat ist nun in {channel.mention} aktiv.\n" + status_text += f"Aktuell verbunden: **{len(self._cached_channels)}** Server." + + container.add_text(status_text) + container.add_separator() + + # Feature-Liste + feature_text = ( + "**Unterstรผtzte Features:**\n" + "โ€ข ๐Ÿ–ผ๏ธ Bilder, ๐ŸŽฅ Videos, ๐ŸŽต Audio\n" + "โ€ข ๐Ÿ“„ Dokumente (Office, PDF, Archive)\n" + "โ€ข ๐ŸŽจ Discord Sticker\n" + "โ€ข ๐Ÿ”— Automatische Link-Previews\n" + "โ€ข โ†ฉ๏ธ Reply auf andere Nachrichten\n\n" + "**Nรคchste Schritte:**\n" + "โ€ข `/globalchat settings` - Einstellungen anpassen\n" + "โ€ข `/globalchat stats` - Statistiken anzeigen\n" + "โ€ข `/globalchat media-info` - Medien-Limits anzeigen" + ) + container.add_text(feature_text) + + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) + + except Exception as e: + logger.error(f"โŒ Setup-Fehler: {e}", exc_info=True) + await ctx.respond("โŒ Ein Fehler ist aufgetreten!", ephemeral=True) + + @globalchat.command( + name="remove", + description="Entfernt den GlobalChat-Channel" + ) + async def remove_globalchat(self, ctx: discord.ApplicationContext): + """Entfernt GlobalChat vom Server""" + if not ctx.author.guild_permissions.manage_guild: + await ctx.respond("โŒ Du benรถtigst die **Server verwalten** Berechtigung!", ephemeral=True) + return + + # Prรผfen ob Channel existiert + channel_id = db.get_globalchat_channel(ctx.guild.id) + if not channel_id: + await ctx.respond("โŒ GlobalChat ist auf diesem Server nicht eingerichtet.", ephemeral=True) + return + + try: + db.set_globalchat_channel(ctx.guild.id, None) + + # Cache aktualisieren + self._cached_channels = await self.sender._fetch_all_channels() + + await ctx.respond( + f"โœ… **GlobalChat entfernt!**\n\n" + f"Der GlobalChat wurde von diesem Server entfernt.\n" + f"Es sind nun noch **{len(self._cached_channels)}** Server verbunden.", + ephemeral=True + ) + except Exception as e: + logger.error(f"โŒ Remove-Fehler: {e}", exc_info=True) + await ctx.respond("โŒ Ein Fehler ist aufgetreten!", ephemeral=True) + + @globalchat.command( + name="settings", + description="Verwaltet Server-spezifische GlobalChat-Einstellungen" + ) + async def settings_globalchat( + self, + ctx: discord.ApplicationContext, + filter_enabled: Optional[bool] = Option(bool, "Content-Filter aktivieren/deaktivieren (Invites, etc.)", required=False), + nsfw_filter: Optional[bool] = Option(bool, "NSFW-Filter aktivieren/deaktivieren", required=False), + embed_color: Optional[str] = Option(str, "Hex-Farbcode fรผr Embeds (z.B. #FF00FF)", required=False), + max_message_length: Optional[int] = Option( + int, + "Maximale Nachrichtenlรคnge", + required=False, + min_value=50, + max_value=2000 + ) + ): + """Verwaltet Server-spezifische Einstellungen""" + if not ctx.author.guild_permissions.manage_guild: + await ctx.respond("โŒ Du benรถtigst die **Server verwalten** Berechtigung!", ephemeral=True) + return + + # Prรผfen ob GlobalChat aktiv + if not db.get_globalchat_channel(ctx.guild.id): + await ctx.respond( + "โŒ Dieser Server nutzt GlobalChat nicht!\n" + "Nutze `/globalchat setup` zuerst.", + ephemeral=True + ) + return + + updated = [] + # Filter aktivieren/deaktivieren + if filter_enabled is not None: + if db.update_guild_setting(ctx.guild.id, 'filter_enabled', filter_enabled): + updated.append(f"Content-Filter: {'โœ… An' if filter_enabled else 'โŒ Aus'}") + + if nsfw_filter is not None: + if db.update_guild_setting(ctx.guild.id, 'nsfw_filter', nsfw_filter): + updated.append(f"NSFW-Filter: {'โœ… An' if nsfw_filter else 'โŒ Aus'}") + + if embed_color: + # Hex-Validierung + if not re.match(r'^#[0-9a-fA-F]{6}$', embed_color): + await ctx.respond("โŒ Ungรผltiger Hex-Farbcode. Erwarte z.B. `#5865F2`.", ephemeral=True) + return + if db.update_guild_setting(ctx.guild.id, 'embed_color', embed_color): + updated.append(f"Embed-Farbe: `{embed_color}`") + + if max_message_length is not None: + if db.update_guild_setting(ctx.guild.id, 'max_message_length', max_message_length): + updated.append(f"Max. Lรคnge: **{max_message_length}** Zeichen") + + if not updated: + await ctx.respond("โ„น๏ธ Keine ร„nderungen vorgenommen.", ephemeral=True) + return + + # Erfolgs-Embed + embed = discord.Embed( + title="โœ… GlobalChat Einstellungen aktualisiert", + description="\n".join(updated), + color=discord.Color.green() + ) + await ctx.respond(embed=embed, ephemeral=True) + + + @globalchat.command( + name="ban", + description="๐Ÿ”จ Bannt einen User oder Server vom GlobalChat" + ) + async def globalchat_ban( + self, + ctx: discord.ApplicationContext, + entity_id: str = Option(str, "ID des Users oder Servers (Guild-ID)", required=True), + entity_type: str = Option(str, "Typ der Entitรคt", choices=["user", "guild"], required=True), + reason: str = Option(str, "Grund fรผr den Ban", required=True), + duration: Optional[int] = Option(int, "Dauer in Stunden (optional, permanent wenn leer)", required=False) + ): + """Bannt eine Entitรคt aus dem GlobalChat""" + if ctx.author.id not in self.config.BOT_OWNERS: + await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) + return + + try: + entity_id_int = int(entity_id) + except ValueError: + await ctx.respond("โŒ Ungรผltige ID. Erwarte eine Zahl.", ephemeral=True) + return + + # Ban ausfรผhren + try: + success = db.add_to_blacklist( + entity_type, + entity_id_int, + reason, + ctx.author.id, + duration + ) + if not success: + await ctx.respond("โŒ Fehler beim Bannen!", ephemeral=True) + return + + # Success-Response + duration_text = f"{duration} Stunden" if duration else "Permanent" + embed = discord.Embed( + title="๐Ÿ”จ GlobalChat-Ban verhรคngt", + color=discord.Color.red(), + timestamp=datetime.utcnow() + ) + embed.add_field(name="Typ", value=entity_type.title(), inline=True) + embed.add_field(name="ID", value=f"`{entity_id_int}`", inline=True) + embed.add_field(name="Dauer", value=duration_text, inline=True) + embed.add_field(name="Grund", value=reason, inline=False) + embed.add_field(name="Von", value=ctx.author.mention, inline=True) + + if duration: + expires = datetime.utcnow() + timedelta(hours=duration) + embed.add_field( + name="Lรคuft ab", + value=f"", + inline=True + ) + + await ctx.respond(embed=embed) + logger.info( + f"๐Ÿ”จ Ban: {entity_type} {entity_id_int} | Grund: {reason} | Dauer: {duration_text} | Von: {ctx.author.id}" + ) + + except Exception as e: + logger.error(f"โŒ Ban-Fehler: {e}", exc_info=True) + await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Bannen!", ephemeral=True) + + + @globalchat.command( + name="unban", + description="๐Ÿ”“ Entfernt einen User oder Server von der GlobalChat-Blacklist" + ) + async def globalchat_unban( + self, + ctx: discord.ApplicationContext, + entity_id: str = Option(str, "ID des Users oder Servers", required=True), + entity_type: str = Option(str, "Typ der Entitรคt", choices=["user", "guild"], required=True) + ): + """Entfernt eine Entitรคt von der GlobalChat Blacklist""" + if ctx.author.id not in self.config.BOT_OWNERS: + await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) + return + + try: + entity_id_int = int(entity_id) + except ValueError: + await ctx.respond("โŒ Ungรผltige ID. Erwarte eine Zahl.", ephemeral=True) + return + + try: + if not db.is_blacklisted(entity_type, entity_id_int): + await ctx.respond(f"โ„น๏ธ {entity_type.title()} `{entity_id_int}` ist nicht auf der Blacklist.", ephemeral=True) + return + + if db.remove_from_blacklist(entity_type, entity_id_int): + embed = discord.Embed( + title="๐Ÿ”“ GlobalChat-Unban erfolgreich", + description=f"{entity_type.title()} mit ID `{entity_id_int}` wurde von der Blacklist entfernt.", + color=discord.Color.green(), + timestamp=datetime.utcnow() + ) + await ctx.respond(embed=embed) + logger.info(f"๐Ÿ”“ Unban: {entity_type} {entity_id_int} | Von: {ctx.author.id}") + else: + await ctx.respond("โŒ Fehler beim Entfernen von der Blacklist!", ephemeral=True) + + except Exception as e: + logger.error(f"โŒ Unban-Fehler: {e}", exc_info=True) + await ctx.respond("โŒ Ein Fehler ist aufgetreten beim Unbannen!", ephemeral=True) + + + @globalchat.command( + name="info", + description="Zeigt Informationen รผber den GlobalChat" + ) + async def globalchat_info(self, ctx: discord.ApplicationContext): + """Zeigt allgemeine Informationen""" + active_servers = await self.sender._get_all_active_channels() + + embed = discord.Embed( + title="๐ŸŒ GlobalChat - Vollstรคndiger Medien-Support", + description=( + "Ein serverรผbergreifendes Chat-System mit vollstรคndigem Medien-Support.\n\n" + f"**๐Ÿ“Š Aktuell verbunden:** **{len(active_servers)}** Server\n\n" + "**๐ŸŽฏ Hauptfeatures:**\n" + "โ€ข Nachrichten werden an alle verbundenen Server gesendet\n" + "โ€ข Vollstรคndiger Medien-Support (Bilder, Videos, Audio, Dokumente)\n" + "โ€ข Discord Sticker und Link-Previews\n" + "โ€ข Reply-Unterstรผtzung mit Kontext\n" + "โ€ข Automatische Moderation und Filter\n" + "โ€ข Rate-Limiting gegen Spam\n" + "โ€ข Individuelle Server-Einstellungen" + ), + color=discord.Color.blue(), + timestamp=datetime.utcnow() + ) + + embed.add_field( + name="๐Ÿ“ Unterstรผtzte Medien (Details: `/globalchat media-info`)", + value=( + "โ€ข ๐Ÿ–ผ๏ธ Bilder\n" + "โ€ข ๐ŸŽฅ Videos\n" + "โ€ข ๐ŸŽต Audio\n" + "โ€ข ๐Ÿ“„ Dokumente (PDF, Office, Archive)" + ), + inline=True + ) + + embed.add_field( + name="๐Ÿ›ก๏ธ Moderation", + value=( + f"โ€ข **Content-Filter:** {db.get_guild_settings(ctx.guild.id).get('filter_enabled', True) and 'โœ… An' or 'โŒ Aus'}\n" + f"โ€ข **NSFW-Filter:** {db.get_guild_settings(ctx.guild.id).get('nsfw_filter', True) and 'โœ… An' or 'โŒ Aus'}\n" + f"โ€ข **Nachrichtenlรคnge:** {db.get_guild_settings(ctx.guild.id).get('max_message_length', self.config.DEFAULT_MAX_MESSAGE_LENGTH)} Zeichen\n" + ), + inline=True + ) + + await ctx.respond(embed=embed, ephemeral=True) + + @globalchat.command( + name="stats", + description="Zeigt GlobalChat-Statistiken" + ) + async def globalchat_stats(self, ctx: discord.ApplicationContext): + """Zeigt Statistiken (z.B. Blacklist-Eintrรคge)""" + if ctx.author.id not in self.config.BOT_OWNERS: + await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) + return + + user_bans, guild_bans = db.get_blacklist_stats() + active_servers = await self.sender._get_all_active_channels() + + embed = discord.Embed( + title="๐Ÿ“Š GlobalChat System-Statistiken", + color=discord.Color.gold(), + timestamp=datetime.utcnow() + ) + + embed.add_field(name="๐ŸŒ Verbundene Server", value=f"**{len(active_servers)}**", inline=True) + embed.add_field(name="๐Ÿ‘ฅ Gebannte User", value=f"**{user_bans}**", inline=True) + embed.add_field(name="๐Ÿ›ก๏ธ Gebannte Server", value=f"**{guild_bans}**", inline=True) + embed.add_field(name="โณ Cache-Dauer", value=f"{self.config.CACHE_DURATION} Sekunden", inline=True) + embed.add_field(name="๐Ÿ“œ Protokoll Bereinigung", value=f"Alle {self.config.CLEANUP_DAYS} Tage", inline=True) + embed.add_field( + name="โฐ Rate-Limit", + value=f"{self.config.RATE_LIMIT_MESSAGES} Nachrichten / {self.config.RATE_LIMIT_SECONDS} Sekunden", + inline=True + ) + + await ctx.respond(embed=embed, ephemeral=True) + + + @globalchat.command( + name="media-info", + description="Zeigt Details zu Medien-Limits und erlaubten Formaten" + ) + async def globalchat_media_info(self, ctx: discord.ApplicationContext): + """Zeigt Medien-Limits und unterstรผtzte Formate""" + embed = discord.Embed( + title="๐Ÿ“ GlobalChat Medien-Limits & Formate", + description="Details zu den maximal erlaubten DateigrรถรŸen und unterstรผtzten Formaten.", + color=discord.Color.purple(), + timestamp=datetime.utcnow() + ) + + # Limits + embed.add_field( + name="โš ๏ธ Wichtige Limits", + value=( + f"โ€ข **Max. {self.config.MAX_ATTACHMENTS} Anhรคnge** pro Nachricht\n" + f"โ€ข **Max. {self.config.MAX_FILE_SIZE_MB} MB** pro Datei (Discord-Limit)\n" + f"โ€ข **Max. {self.config.DEFAULT_MAX_MESSAGE_LENGTH} Zeichen** Textlรคnge\n" + f"โ€ข **Rate-Limit:** {self.config.RATE_LIMIT_MESSAGES} Nachrichten pro {self.config.RATE_LIMIT_SECONDS} Sekunden" + ), + inline=False + ) + + # Unterstรผtzte Formate + embed.add_field( + name="๐Ÿ–ผ๏ธ Bilder", + value=", ".join(self.config.ALLOWED_IMAGE_FORMATS).upper(), + inline=True + ) + embed.add_field( + name="๐ŸŽฅ Videos", + value=", ".join(self.config.ALLOWED_VIDEO_FORMATS).upper(), + inline=True + ) + embed.add_field( + name="๐ŸŽต Audio", + value=", ".join(self.config.ALLOWED_AUDIO_FORMATS).upper(), + inline=True + ) + embed.add_field( + name="๐Ÿ“„ Dokumente/Archive", + value=", ".join(self.config.ALLOWED_DOCUMENT_FORMATS).upper(), + inline=False + ) + + await ctx.respond(embed=embed, ephemeral=True) + + + @globalchat.command( + name="help", + description="Zeigt die Hilfe-Seite fรผr GlobalChat" + ) + async def globalchat_help(self, ctx: discord.ApplicationContext): + """Zeigt eine รœbersicht aller verfรผgbaren Commands und Features.""" + embed = discord.Embed( + title="โ“ GlobalChat Hilfe & รœbersicht", + description="รœbersicht aller verfรผgbaren Commands und Features.", + color=discord.Color.blue(), + timestamp=datetime.utcnow() + ) + + # Setup & Verwaltung + embed.add_field( + name="โš™๏ธ Setup & Verwaltung", + value=( + "`/globalchat setup` - Channel einrichten\n" + "`/globalchat remove` - Channel entfernen\n" + "`/globalchat settings` - Einstellungen anpassen" + ), + inline=False + ) + + # Informationen + embed.add_field( + name="๐Ÿ“Š Informationen", + value=( + "`/globalchat info` - Allgemeine Infos\n" + "`/globalchat stats` - Statistiken anzeigen\n" + "`/globalchat media-info` - Medien-Details\n" + "`/globalchat help` - Diese Hilfe" + ), + inline=False + ) + + # Moderation (Admin) - Nur fรผr Bot Owner + if ctx.author.id in self.config.BOT_OWNERS: + embed.add_field( + name="๐Ÿ›ก๏ธ Moderation (Bot Owner)", + value=( + "`/globalchat ban` - User/Server bannen\n" + "`/globalchat unban` - User/Server entbannen" + ), + inline=False + ) + + # Test & Debug (Admin) + if ctx.author.id in self.config.BOT_OWNERS: + embed.add_field( + name="๐Ÿงช Test & Debug (Bot Owner)", + value=( + "`/globalchat test-media` - Medien-Test\n" + "`/globalchat broadcast` - Nachricht an alle senden\n" + "`/globalchat reload-cache` - Cache neu laden\n" + "`/globalchat debug` - Debug-Info" + ), + inline=False + ) + + await ctx.respond(embed=embed, ephemeral=True) + + + @globalchat.command( + name="test-media", + description="๐Ÿงช Test-Command fรผr Medien-Upload und -Anzeige" + ) + async def globalchat_test_media(self, ctx: discord.ApplicationContext): + """Zeigt Anweisungen fรผr den Medien-Test""" + channel_id = db.get_globalchat_channel(ctx.guild.id) + if not channel_id: + await ctx.respond("โŒ GlobalChat ist auf diesem Server nicht eingerichtet.", ephemeral=True) + return + + embed = discord.Embed( + title="๐Ÿงช GlobalChat Medien-Test", + description=( + "Dieser Test zeigt dir, welche Medien-Typen erfolgreich รผbermittelt werden kรถnnen.\n\n" + "**Unterstรผtzte Medien:**\n" + "โ€ข Bilder, Videos, Audio, Dokumente\n" + "โ€ข Discord Sticker\n" + "โ€ข Antworten auf andere Nachrichten\n\n" + "**So testest du:**\n" + f"1. Gehe zu <#{channel_id}> und sende eine Nachricht mit Anhรคngen.\n" + "2. Die Nachricht erscheint auf allen verbundenen Servern.\n\n" + "Probiere verschiedene Kombinationen aus! (Mehrere Dateien, Sticker + Text, Reply + Datei)" + ), + color=discord.Color.green(), + timestamp=datetime.utcnow() + ) + + embed.add_field( + name="๐Ÿ“Š Aktuelle Limits", + value=( + f"โ€ข Max. {self.config.MAX_ATTACHMENTS} Anhรคnge\n" + f"โ€ข Max. {self.config.MAX_FILE_SIZE_MB} MB pro Datei\n" + f"โ€ข {self.config.RATE_LIMIT_MESSAGES} Nachrichten / {self.config.RATE_LIMIT_SECONDS} Sekunden" + ), + inline=True + ) + + embed.add_field( + name="โœ… Unterstรผtzte Formate", + value=( + "Bilder, Videos, Audio,\n" + "Dokumente, Archive,\n" + "Office-Dateien, PDFs" + ), + inline=True + ) + + embed.set_footer(text=f"Test von {ctx.author}", icon_url=ctx.author.display_avatar.url) + + await ctx.respond(embed=embed, ephemeral=True) + + + @globalchat.command( + name="broadcast", + description="๐Ÿ“ข Sendet eine Nachricht an alle verbundenen GlobalChat-Server" + ) + async def globalchat_broadcast( + self, + ctx: discord.ApplicationContext, + title: str = Option(str, "Der Titel der Broadcast-Nachricht", required=True), + message: str = Option(str, "Die Nachricht selbst", required=True) + ): + """Sendet einen Broadcast (nur Bot Owner)""" + if ctx.author.id not in self.config.BOT_OWNERS: + await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) + return + + await ctx.defer(ephemeral=True) + + try: + # Broadcast Embed erstellen + embed = discord.Embed( + title=f"๐Ÿ“ข GlobalChat Broadcast: {title}", + description=message, + color=discord.Color.red(), + timestamp=datetime.utcnow() + ) + embed.set_footer( + text=f"GlobalChat Broadcast von {ctx.author}", + icon_url=ctx.author.display_avatar.url + ) + + # An alle Channels senden + successful, failed = await self.sender.send_global_broadcast_message(embed) # Annahme: Eine separate Broadcast-Methode in Sender + + # Response + result_embed = discord.Embed( + title="โœ… Broadcast gesendet", + color=discord.Color.green(), + timestamp=datetime.utcnow() + ) + result_embed.add_field( + name="๐Ÿ“Š Ergebnis", + value=( + f"**Erfolgreich:** {successful}\n" + f"**Fehlgeschlagen:** {failed}\n" + f"**Gesamt:** {successful + failed}" + ), + inline=False + ) + result_embed.add_field( + name="๐Ÿ“ Nachricht", + value=f"**{title}**\n{message[:100]}{'...' if len(message) > 100 else ''}", + inline=False + ) + await ctx.respond(embed=result_embed, ephemeral=True) + logger.info( + f"๐Ÿ“ข Broadcast: '{title}' | Von: {ctx.author} | " + f"โœ… {successful} | โŒ {failed}" + ) + except Exception as e: + logger.error(f"โŒ Broadcast-Fehler: {e}", exc_info=True) + await ctx.respond("โŒ Fehler beim Senden des Broadcasts!", ephemeral=True) + + @globalchat.command( + name="reload-cache", + description="๐Ÿง  Lรคdt alle Cache-Daten neu (Admin)" + ) + async def globalchat_reload_cache(self, ctx: discord.ApplicationContext): + """Lรคdt den Channel-Cache neu (Bot Owner)""" + if ctx.author.id not in self.config.BOT_OWNERS: + await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) + return + + await ctx.defer(ephemeral=True) + try: + old_count = len(self._cached_channels or []) + self._cached_channels = await self.sender._fetch_all_channels() + new_count = len(self._cached_channels) + + await ctx.respond( + f"โœ… **Cache neu geladen!**\n\n" + f"Alte Channel-Anzahl: **{old_count}**\n" + f"Neue Channel-Anzahl: **{new_count}**", + ephemeral=True + ) + logger.info(f"๐Ÿง  GlobalChat Cache manuell neu geladen. {old_count} -> {new_count}") + + except Exception as e: + logger.error(f"โŒ Cache Reload Fehler: {e}", exc_info=True) + await ctx.respond("โŒ Ein Fehler ist aufgetreten!", ephemeral=True) + + + @globalchat.command( + name="debug", + description="๐Ÿ› Zeigt Debug-Informationen an (Admin)" + ) + async def globalchat_debug(self, ctx: discord.ApplicationContext): + """Zeigt Debug-Informationen (Bot Owner)""" + if ctx.author.id not in self.config.BOT_OWNERS: + await ctx.respond("โŒ Nur Bot-Owner kรถnnen diesen Befehl nutzen.", ephemeral=True) + return + + await ctx.defer(ephemeral=True) + try: + cached_channels = len(self._cached_channels or []) + all_settings = db.get_all_guild_settings() + + debug_info = ( + f"**Bot-Status:**\n" + f"โ€ข Latency: `{round(self.bot.latency * 1000)}ms`\n" + f"โ€ข Guilds: `{len(self.bot.guilds)}`\n" + f"โ€ข Uptime: ``\n\n" + f"**GlobalChat-Status:**\n" + f"โ€ข Aktive Channels (Cache): `{cached_channels}`\n" + f"โ€ข DB Settings Eintrรคge: `{len(all_settings)}`\n" + f"โ€ข Cleanup Task: `{'Aktiv' if self.cleanup_task.is_running() else 'Inaktiv'}`\n" + ) + + # Beispiel fรผr Blacklist-Info + user_bans, guild_bans = db.get_blacklist_stats() + debug_info += ( + f"โ€ข Gebannte User/Server: `{user_bans} / {guild_bans}`" + ) + + embed = discord.Embed( + title="๐Ÿ› GlobalChat Debug-Informationen", + description=debug_info, + color=discord.Color.orange(), + timestamp=datetime.utcnow() + ) + await ctx.respond(embed=embed, ephemeral=True) + except Exception as e: + logger.error(f"โŒ Debug Fehler: {e}", exc_info=True) + await ctx.respond("โŒ Ein Fehler ist aufgetreten!", ephemeral=True) + + +# ==================== Setup Funktion ==================== +def setup(bot): + """Setup-Funktion fรผr the cog when loaded by classic...""" + # Stelle sicher, dass die Datenbank initialisiert wird, falls nicht schon geschehen + GlobalChatDatabase().create_tables() + # Fรผge die Cog hinzu + bot.add_cog(GlobalChatCog(bot)) \ No newline at end of file diff --git a/src/bot/cogs/guild/levelsystem.py b/src/bot/cogs/guild/levelsystem.py new file mode 100644 index 0000000..e669b69 --- /dev/null +++ b/src/bot/cogs/guild/levelsystem.py @@ -0,0 +1,974 @@ +# Copyright (c) 2025 OPPRO.NET Network +import discord +from discord import SlashCommandGroup, Option +from discord.ext import commands, tasks +import time +import random +from DevTools import LevelDatabase +import asyncio +import io +import csv +from typing import Optional +from discord.ui import Container + + +class PrestigeConfirmView(discord.ui.View): + def __init__(self, db, user, guild): + super().__init__(timeout=300) + self.db = db + self.user = user + self.guild = guild + + @discord.ui.button(label="Bestรคtigen", style=discord.ButtonStyle.danger, emoji="โš ๏ธ") + async def confirm_prestige(self, interaction: discord.Interaction, button: discord.ui.Button): + if interaction.user != self.user: + await interaction.response.send_message("Nur der User kann sein eigenes Prestige bestรคtigen!", ephemeral=True) + return + + success = self.db.prestige_user(self.user.id, self.guild.id) + if success: + embed = discord.Embed( + title="โœจ Prestige erfolgreich!", + description=f"{self.user.mention} hat ein Prestige durchgefรผhrt!\nDu startest wieder bei Level 0, aber behรคltst deinen Prestige-Rang!", + color=0xff69b4 + ) + embed.set_footer(text="Gratulation zu deinem Prestige!") + else: + embed = discord.Embed( + title="โŒ Prestige fehlgeschlagen", + description="Prestige konnte nicht durchgefรผhrt werden. Mรถglicherweise erfรผllst du nicht die Anforderungen.", + color=0xff0000 + ) + + await interaction.response.edit_message(embed=embed, view=None) + + @discord.ui.button(label="Abbrechen", style=discord.ButtonStyle.secondary) + async def cancel_prestige(self, interaction: discord.Interaction, button: discord.ui.Button): + if interaction.user != self.user: + await interaction.response.send_message("Nur der User kann seine eigene Aktion abbrechen!", ephemeral=True) + return + + embed = discord.Embed( + title="โŒ Prestige abgebrochen", + description="Das Prestige wurde abgebrochen.", + color=0x999999 + ) + await interaction.response.edit_message(embed=embed, view=None) + + +class LevelSystem(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.db = LevelDatabase() + self.xp_cooldowns = {} # User-ID -> Timestamp + + # Starte Background Tasks + self.cleanup_expired_boosts.start() + self.cleanup_temporary_roles.start() + + def cog_unload(self): + """Cleanup beim Entladen der Cog""" + self.cleanup_expired_boosts.cancel() + self.cleanup_temporary_roles.cancel() + + levelsystem = SlashCommandGroup("levelsystem", "Verwalte das Levelsystem") + levelrole = SlashCommandGroup("levelrole", "Verwalte Level-Rollen") + xpboost = SlashCommandGroup("xpboost", "Verwalte XP-Boosts") + levelconfig = SlashCommandGroup("levelconfig", "Konfiguriere das Levelsystem") + + @tasks.loop(hours=1) + async def cleanup_expired_boosts(self): + """Entfernt abgelaufene XP-Boosts""" + # Hier wรผrde die DB-Cleanup Logik implementiert werden + pass + + @tasks.loop(hours=1) + async def cleanup_temporary_roles(self): + """Entfernt abgelaufene temporรคre Rollen""" + # Hier wรผrde die temporรคre Rollen Cleanup Logik implementiert werden + pass + + def create_level_up_embed(self, user: discord.Member, level: int, is_role_reward: bool = False, role: Optional[discord.Role] = None): + """Erstellt ein verbessertes Level-Up Embed""" + embed = discord.Embed(color=0x00ff00) + embed.set_author(name="๐ŸŽ‰ Level Up!", icon_url=user.avatar.url if user.avatar else user.default_avatar.url) + embed.description = f"**{user.mention}** erreichte **Level {level}**!" + + if is_role_reward and role: + embed.add_field(name="๐Ÿ† Neue Rolle erhalten", value=f"**{role.name}**", inline=False) + embed.color = 0xffff00 + + embed.set_thumbnail(url=user.avatar.url if user.avatar else user.default_avatar.url) + return embed + + @commands.Cog.listener() + async def on_message(self, message): + # Ignoriere Bot-Nachrichten + if message.author.bot: + return + + # Nur in Servern, nicht in DMs + if message.guild is None: + return + + # Prรผfe ob Levelsystem aktiviert ist + if not self.db.is_levelsystem_enabled(message.guild.id): + return + + # Prรผfe ob Kanal auf Blacklist steht + if self.db.is_channel_blacklisted(message.guild.id, message.channel.id): + return + + user_id = message.author.id + guild_id = message.guild.id + current_time = time.time() + + # Guild-Konfiguration holen + config = self.db.get_guild_config(guild_id) + cooldown = config.get('cooldown', 30) + + # XP-Cooldown prรผfen + if user_id in self.xp_cooldowns: + if current_time - self.xp_cooldowns[user_id] < cooldown: + return + + # Kanal-spezifischen Multiplikator anwenden + channel_multiplier = self.db.get_channel_multiplier(guild_id, message.channel.id) + + # XP berechnen + min_xp = config.get('min_xp', 10) + max_xp = config.get('max_xp', 20) + base_xp = random.randint(min_xp, max_xp) + final_xp = int(base_xp * channel_multiplier) + + # XP hinzufรผgen mit Anti-Spam Protection + level_up, new_level = self.db.add_xp(user_id, guild_id, final_xp, message.content) + + if not level_up and new_level == 0: + return # Anti-Spam blockierte die XP + + # Cooldown setzen + self.xp_cooldowns[user_id] = current_time + + # Level Up Behandlung + if level_up: + # Bestimme Zielkanal fรผr Level-Up Nachrichten + target_channel = message.channel + level_up_channel_id = config.get('level_up_channel') + + if level_up_channel_id: + level_up_channel = message.guild.get_channel(level_up_channel_id) + if level_up_channel: + target_channel = level_up_channel + + embed = self.create_level_up_embed(message.author, new_level) + await target_channel.send(embed=embed) + + # Level-Rolle vergeben + role_id = self.db.get_role_for_level(guild_id, new_level) + if role_id: + role = message.guild.get_role(role_id) + if role: + try: + await message.author.add_roles(role, reason=f"Level {new_level} erreicht") + role_embed = discord.Embed( + title="๐Ÿ† Neue Rolle erhalten!", + description=f"{message.author.mention} hat die Rolle **{role.name}** erhalten!", + color=0xffff00 + ) + role_embed.set_thumbnail(url=message.author.avatar.url if message.author.avatar else message.author.default_avatar.url) + await target_channel.send(embed=role_embed) + except discord.Forbidden: + # Log oder Nachricht an Admins falls Bot keine Berechtigung hat + pass + + @levelsystem.command(description="Zeigt das Server-Leaderboard mit Paginierung") + async def leaderboard(self, ctx, + anzahl: discord.Option(int, "Anzahl der User", default=10, min_value=1, max_value=50)): + if not self.db.is_levelsystem_enabled(ctx.guild.id): + embed = discord.Embed( + title="โŒ Levelsystem deaktiviert", + description="Das Levelsystem ist auf diesem Server deaktiviert.", + color=0xff0000 + ) + await ctx.respond(embed=embed) + return + + leaderboard_data = self.db.get_leaderboard(ctx.guild.id, anzahl) + + if not leaderboard_data: + embed = discord.Embed( + title="๐Ÿ“Š Leaderboard", + description="Noch keine User im Leaderboard!", + color=0x0099ff + ) + await ctx.respond(embed=embed) + return + + embed = discord.Embed( + title=f"๐Ÿ“Š Leaderboard - Top {len(leaderboard_data)}", + color=0x0099ff, + timestamp=discord.utils.utcnow() + ) + + description = "" + for i, (user_id, xp, level, messages, prestige) in enumerate(leaderboard_data, 1): + user = self.bot.get_user(user_id) + username = user.display_name if user else f"User {user_id}" + + if i == 1: + medal = "๐Ÿฅ‡" + elif i == 2: + medal = "๐Ÿฅˆ" + elif i == 3: + medal = "๐Ÿฅ‰" + else: + medal = f"**{i}.**" + + prestige_text = f"โญ{prestige} " if prestige > 0 else "" + description += f"{medal} {prestige_text}**{username}** - Level {level} ({xp:,} XP)\n" + + embed.description = description + embed.set_footer(text=f"Server: {ctx.guild.name}") + + await ctx.respond(embed=embed) + + @levelsystem.command(description="Zeigt erweiterte Benutzerstatistiken") + async def profil(self, ctx, + user: discord.Option(discord.Member, "User dessen Profil angezeigt werden soll", default=None)): + if not self.db.is_levelsystem_enabled(ctx.guild.id): + embed = discord.Embed( + title="โŒ Levelsystem deaktiviert", + description="Das Levelsystem ist auf diesem Server deaktiviert.", + color=0xff0000 + ) + await ctx.respond(embed=embed) + return + + target_user = user or ctx.author + user_stats = self.db.get_user_stats(target_user.id, ctx.guild.id) + + if not user_stats: + embed = discord.Embed( + title="โŒ Kein Profil gefunden", + description=f"{target_user.display_name} hat noch keine XP gesammelt!", + color=0xff0000 + ) + await ctx.respond(embed=embed) + return + + xp, level, messages, xp_needed, prestige, total_earned = user_stats + rank = self.db.get_user_rank(target_user.id, ctx.guild.id) + + embed = discord.Embed( + title=f"๐Ÿ“Š Profil von {target_user.display_name}", + color=target_user.color or 0x0099ff, + timestamp=discord.utils.utcnow() + ) + + # Erste Zeile + embed.add_field(name="๐Ÿ† Level", value=str(level), inline=True) + embed.add_field(name="โญ XP", value=f"{xp:,}", inline=True) + embed.add_field(name="๐Ÿ“ˆ Rang", value=f"#{rank}", inline=True) + + # Zweite Zeile + embed.add_field(name="๐Ÿ’ฌ Nachrichten", value=f"{messages:,}", inline=True) + embed.add_field(name="๐ŸŽฏ XP bis nรคchstes Level", value=f"{xp_needed:,}", inline=True) + + if prestige > 0: + embed.add_field(name="โœจ Prestige", value=f"โญ{prestige}", inline=True) + + # Dritte Zeile + embed.add_field(name="๐Ÿ’ฐ Gesamt verdiente XP", value=f"{total_earned:,}", inline=True) + + # XP pro Nachricht berechnen + xp_per_msg = total_earned / messages if messages > 0 else 0 + embed.add_field(name="๐Ÿ“Š ร˜ XP/Nachricht", value=f"{xp_per_msg:.1f}", inline=True) + + # Aktiver XP-Multiplikator + multiplier = self.db.get_active_xp_multiplier(ctx.guild.id, target_user.id) + if multiplier > 1.0: + embed.add_field(name="๐Ÿš€ Aktiver Boost", value=f"{multiplier}x", inline=True) + + # Fortschrittsbalken + current_level_xp = xp - self.db.xp_for_level(level) + next_level_xp = self.db.xp_for_level(level + 1) - self.db.xp_for_level(level) + progress = current_level_xp / next_level_xp if next_level_xp > 0 else 1 + + progress_bar = "โ–ˆ" * int(progress * 15) + "โ–‘" * (15 - int(progress * 15)) + embed.add_field( + name="๐Ÿ“Š Level-Fortschritt", + value=f"`{progress_bar}` {progress * 100:.1f}%\n`{current_level_xp:,} / {next_level_xp:,} XP`", + inline=False + ) + + embed.set_thumbnail(url=target_user.avatar.url if target_user.avatar else target_user.default_avatar.url) + embed.set_footer(text=f"Server: {ctx.guild.name}") + + await ctx.respond(embed=embed) + + @levelsystem.command(description="Fรผhrt ein Prestige durch (Level 50+)") + async def prestige(self, ctx): + if not self.db.is_levelsystem_enabled(ctx.guild.id): + embed = discord.Embed( + title="โŒ Levelsystem deaktiviert", + description="Das Levelsystem ist auf diesem Server deaktiviert.", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + config = self.db.get_guild_config(ctx.guild.id) + if not config.get('prestige_enabled', True): + embed = discord.Embed( + title="โŒ Prestige deaktiviert", + description="Das Prestige-System ist auf diesem Server deaktiviert.", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + user_stats = self.db.get_user_stats(ctx.author.id, ctx.guild.id) + min_level = config.get('prestige_min_level', 50) + + if not user_stats or user_stats[1] < min_level: + embed = discord.Embed( + title="โŒ Prestige nicht verfรผgbar", + description=f"Du musst mindestens Level {min_level} erreichen!", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + # Bestรคtigung erforderlich + view = PrestigeConfirmView(self.db, ctx.author, ctx.guild) + embed = discord.Embed( + title="โš ๏ธ Prestige Bestรคtigung", + description=f"Mรถchtest du wirklich dein Level zurรผcksetzen?\n\n**Was passiert:**\nโ€ข Dein Level wird auf 0 zurรผckgesetzt\nโ€ข Deine XP werden auf 0 zurรผckgesetzt\nโ€ข Du erhรคltst einen Prestige-Rang (โญ)\nโ€ข Du behรคltst deine Nachrichten-Anzahl\n\n**Aktuelles Level:** {user_stats[1]}", + color=0xffff00 + ) + embed.set_footer(text="Diese Aktion kann nicht rรผckgรคngig gemacht werden!") + await ctx.respond(embed=embed, view=view, ephemeral=True) + + @levelsystem.command(description="Zeigt erweiterte Server-Analytics") + async def analytics(self, ctx): + if not self.db.is_levelsystem_enabled(ctx.guild.id): + embed = discord.Embed( + title="โŒ Levelsystem deaktiviert", + description="Das Levelsystem ist auf diesem Server deaktiviert.", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + analytics = self.db.get_detailed_analytics(ctx.guild.id) + + embed = discord.Embed( + title="๐Ÿ“Š Server Analytics", + color=0x0099ff, + timestamp=discord.utils.utcnow() + ) + + # Grundlegende Statistiken + embed.add_field(name="๐Ÿ‘ฅ Aktive User", value=f"{analytics['total_users']:,}", inline=True) + embed.add_field(name="๐Ÿ“ˆ Durchschnittslevel", value=f"{analytics['avg_level']:.1f}", inline=True) + embed.add_field(name="๐Ÿ† Hรถchstes Level", value=f"{analytics['max_level']}", inline=True) + + embed.add_field(name="โšก Gesamt XP", value=f"{analytics['total_xp']:,}", inline=True) + embed.add_field(name="๐Ÿ’ฌ Gesamt Nachrichten", value=f"{analytics['total_messages']:,}", inline=True) + embed.add_field(name="๐Ÿ•’ Heute aktiv", value=f"{analytics['active_today']}", inline=True) + + # Level-Verteilung + distribution = analytics['level_distribution'] + embed.add_field( + name="๐Ÿ“Š Level-Verteilung", + value=f"๐ŸŒฑ Anfรคnger (1-10): {distribution['novice']}\n" + f"๐Ÿ“š Fortgeschrittene (11-25): {distribution['intermediate']}\n" + f"๐ŸŽฏ Experten (26-50): {distribution['advanced']}\n" + f"๐Ÿ‘‘ Meister (50+): {distribution['expert']}", + inline=False + ) + + embed.set_footer(text=f"Server: {ctx.guild.name}") + await ctx.respond(embed=embed) + + @levelsystem.command(description="Exportiert Leveldaten als CSV") + @commands.has_permissions(administrator=True) + async def export_data(self, ctx): + if not self.db.is_levelsystem_enabled(ctx.guild.id): + embed = discord.Embed( + title="โŒ Levelsystem deaktiviert", + description="Das Levelsystem ist auf diesem Server deaktiviert.", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + await ctx.defer(ephemeral=True) + + data = self.db.export_guild_data(ctx.guild.id) + + output = io.StringIO() + writer = csv.writer(output) + writer.writerow(['User ID', 'Username', 'Level', 'XP', 'Messages', 'Prestige', 'Total XP Earned']) + + for row in data: + user_id, xp, level, messages, prestige, total_earned = row + user = self.bot.get_user(user_id) + username = user.display_name if user else "Unbekannt" + writer.writerow([user_id, username, level, xp, messages, prestige, total_earned]) + + file_content = output.getvalue().encode('utf-8') + file = discord.File(io.BytesIO(file_content), filename=f"leveldata_{ctx.guild.id}_{int(time.time())}.csv") + + embed = discord.Embed( + title="โœ… Datenexport erfolgreich", + description=f"Daten von {len(data)} Usern exportiert.", + color=0x00ff00 + ) + + await ctx.followup.send(embed=embed, file=file) + + # Level-Rollen Commands + @levelrole.command(description="Fรผgt eine Level-Rolle hinzu") + @commands.has_permissions(manage_roles=True) + async def add(self, ctx, + level: discord.Option(int, "Level fรผr die Rolle", min_value=1), + rolle: discord.Option(discord.Role, "Die Rolle die vergeben werden soll"), + temporaer: discord.Option(bool, "Temporรคre Rolle", default=False), + dauer_stunden: discord.Option(int, "Dauer in Stunden (nur bei temporรคren Rollen)", default=0)): + + if rolle.position >= ctx.author.top_role.position and ctx.author != ctx.guild.owner: + embed = discord.Embed( + title="โŒ Keine Berechtigung", + description="Du kannst keine Rolle hinzufรผgen, die hรถher oder gleich deiner hรถchsten Rolle ist!", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if rolle.position >= ctx.guild.me.top_role.position: + embed = discord.Embed( + title="โŒ Bot-Berechtigung fehlt", + description="Ich kann diese Rolle nicht vergeben, da sie hรถher oder gleich meiner hรถchsten Rolle ist!", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if temporaer and dauer_stunden <= 0: + embed = discord.Embed( + title="โŒ Ungรผltige Dauer", + description="Temporรคre Rollen benรถtigen eine Dauer > 0 Stunden!", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + self.db.add_level_role(ctx.guild.id, level, rolle.id, temporaer, dauer_stunden) + + temp_text = f" (temporรคr fรผr {dauer_stunden}h)" if temporaer else "" + embed = discord.Embed( + title="โœ… Level-Rolle hinzugefรผgt", + description=f"Die Rolle **{rolle.name}** wird nun bei **Level {level}**{temp_text} vergeben!", + color=0x00ff00 + ) + await ctx.respond(embed=embed) + + @levelrole.command(description="Fรผgt mehrere Rollen fรผr ein Level hinzu") + @commands.has_permissions(manage_roles=True) + async def add_multiple(self, ctx, level: int, *roles: discord.Role): + if not roles: + await ctx.respond("Du musst mindestens eine Rolle angeben!", ephemeral=True) + return + + added_roles = [] + failed_roles = [] + + for role in roles: + if role.position >= ctx.author.top_role.position and ctx.author != ctx.guild.owner: + failed_roles.append(f"{role.name} (keine Berechtigung)") + continue + + if role.position >= ctx.guild.me.top_role.position: + failed_roles.append(f"{role.name} (Bot-Berechtigung fehlt)") + continue + + self.db.add_level_role(ctx.guild.id, level, role.id) + added_roles.append(role.name) + + embed = discord.Embed(color=0x00ff00 if added_roles else 0xff0000) + + if added_roles: + embed.title = "โœ… Level-Rollen hinzugefรผgt" + embed.description = f"**Level {level}:** {', '.join(added_roles)}" + + if failed_roles: + if added_roles: + embed.add_field(name="โŒ Fehlgeschlagen", value='\n'.join(failed_roles), inline=False) + else: + embed.title = "โŒ Keine Rollen hinzugefรผgt" + embed.description = '\n'.join(failed_roles) + + await ctx.respond(embed=embed) + + @levelrole.command(description="Bearbeitet eine bestehende Level-Rolle") + @commands.has_permissions(manage_roles=True) + async def edit(self, ctx, + level: discord.Option(int, "Level der zu bearbeitenden Rolle", min_value=1), + neue_rolle: discord.Option(discord.Role, "Die neue Rolle")): + # Prรผfen ob Level-Rolle existiert + level_roles = self.db.get_level_roles(ctx.guild.id) + if not any(l == level for l, r, t, d in level_roles): + embed = discord.Embed( + title="โŒ Level-Rolle nicht gefunden", + description=f"Fรผr Level {level} ist keine Rolle konfiguriert!", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if neue_rolle.position >= ctx.author.top_role.position and ctx.author != ctx.guild.owner: + embed = discord.Embed( + title="โŒ Keine Berechtigung", + description="Du kannst keine Rolle setzen, die hรถher oder gleich deiner hรถchsten Rolle ist!", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if neue_rolle.position >= ctx.guild.me.top_role.position: + embed = discord.Embed( + title="โŒ Bot-Berechtigung fehlt", + description="Ich kann diese Rolle nicht vergeben, da sie hรถher oder gleich meiner hรถchsten Rolle ist!", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + self.db.add_level_role(ctx.guild.id, level, neue_rolle.id) + + embed = discord.Embed( + title="โœ… Level-Rolle bearbeitet", + description=f"Die Rolle fรผr **Level {level}** wurde zu **{neue_rolle.name}** geรคndert!", + color=0x00ff00 + ) + await ctx.respond(embed=embed) + + @levelrole.command(description="Entfernt eine Level-Rolle") + @commands.has_permissions(manage_roles=True) + async def remove(self, ctx, level: discord.Option(int, "Level der zu entfernenden Rolle", min_value=1)): + # Prรผfen ob Level-Rolle existiert + level_roles = self.db.get_level_roles(ctx.guild.id) + if not any(l == level for l, r, t, d in level_roles): + embed = discord.Embed( + title="โŒ Level-Rolle nicht gefunden", + description=f"Fรผr Level {level} ist keine Rolle konfiguriert!", + color=0xff0000 + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + self.db.remove_level_role(ctx.guild.id, level) + + embed = discord.Embed( + title="โœ… Level-Rolle entfernt", + description=f"Die Level-Rolle fรผr **Level {level}** wurde entfernt!", + color=0x00ff00 + ) + await ctx.respond(embed=embed) + + @levelrole.command(description="Zeigt alle konfigurierten Level-Rollen") + async def list(self, ctx): + level_roles = self.db.get_level_roles(ctx.guild.id) + + if not level_roles: + embed = discord.Embed( + title="๐Ÿ“ Level-Rollen", + description="Keine Level-Rollen konfiguriert!", + color=0x0099ff + ) + await ctx.respond(embed=embed) + return + + embed = discord.Embed( + title="๐Ÿ“ Level-Rollen", + color=0x0099ff, + timestamp=discord.utils.utcnow() + ) + + description = "" + for level, role_id, is_temp, duration in level_roles: + role = ctx.guild.get_role(role_id) + role_name = role.name if role else f"Gelรถschte Rolle ({role_id})" + + temp_text = f" โฐ({duration}h)" if is_temp else "" + description += f"**Level {level}:** {role_name}{temp_text}\n" + + embed.description = description + embed.set_footer(text=f"Server: {ctx.guild.name}") + + await ctx.respond(embed=embed) + + # XP-Boost Commands + @xpboost.command(description="Fรผgt einen globalen XP-Boost hinzu") + @commands.has_permissions(manage_guild=True) + async def add_global(self, ctx, + multiplier: discord.Option(float, "XP-Multiplikator", min_value=1.1, max_value=5.0), + dauer_stunden: discord.Option(int, "Dauer in Stunden", min_value=1, max_value=168)): + + self.db.add_xp_boost(ctx.guild.id, None, multiplier, dauer_stunden) + + embed = discord.Embed( + title="๐Ÿš€ Globaler XP-Boost aktiviert", + description=f"**{multiplier}x** XP-Multiplikator fรผr **{dauer_stunden} Stunden**\n" + f"Alle Server-Mitglieder erhalten mehr XP!", + color=0x00ff00 + ) + embed.set_footer(text="Der Boost ist sofort aktiv!") + await ctx.respond(embed=embed) + + @xpboost.command(description="Fรผgt einen persรถnlichen XP-Boost hinzu") + @commands.has_permissions(manage_guild=True) + async def add_user(self, ctx, + user: discord.Option(discord.Member, "Benutzer fรผr den Boost"), + multiplier: discord.Option(float, "XP-Multiplikator", min_value=1.1, max_value=5.0), + dauer_stunden: discord.Option(int, "Dauer in Stunden", min_value=1, max_value=168)): + + self.db.add_xp_boost(ctx.guild.id, user.id, multiplier, dauer_stunden) + + embed = discord.Embed( + title="๐Ÿš€ Persรถnlicher XP-Boost aktiviert", + description=f"**{user.mention}** erhรคlt **{multiplier}x** XP fรผr **{dauer_stunden} Stunden**!", + color=0x00ff00 + ) + embed.set_footer(text="Der Boost ist sofort aktiv!") + await ctx.respond(embed=embed) + + # Konfiguration Commands + @levelconfig.command(description="Konfiguriert XP-Einstellungen") + @commands.has_permissions(manage_guild=True) + async def xp_settings(self, ctx, + min_xp: discord.Option(int, "Minimum XP pro Nachricht", default=None, min_value=1, max_value=50), + max_xp: discord.Option(int, "Maximum XP pro Nachricht", default=None, min_value=1, max_value=100), + cooldown: discord.Option(int, "Cooldown in Sekunden", default=None, min_value=5, max_value=300)): + + config_updates = {} + if min_xp is not None: + config_updates['min_xp'] = min_xp + if max_xp is not None: + config_updates['max_xp'] = max_xp + if cooldown is not None: + config_updates['xp_cooldown'] = cooldown + + if max_xp and min_xp and max_xp < min_xp: + await ctx.respond("โŒ Maximum XP kann nicht kleiner als Minimum XP sein!", ephemeral=True) + return + + if not config_updates: + await ctx.respond("โŒ Du musst mindestens einen Wert รคndern!", ephemeral=True) + return + + self.db.set_guild_config(ctx.guild.id, **config_updates) + + current_config = self.db.get_guild_config(ctx.guild.id) + + embed = discord.Embed( + title="โœ… XP-Einstellungen aktualisiert", + color=0x00ff00 + ) + + embed.add_field(name="๐Ÿ’ฐ XP-Bereich", value=f"{current_config['min_xp']}-{current_config['max_xp']}", inline=True) + embed.add_field(name="โฑ๏ธ Cooldown", value=f"{current_config['xp_cooldown']}s", inline=True) + + await ctx.respond(embed=embed) + + @levelconfig.command(description="Setzt XP-Multiplikator fรผr einen Kanal") + @commands.has_permissions(manage_guild=True) + async def channel_multiplier(self, ctx, + channel: discord.Option(discord.TextChannel, "Kanal"), + multiplier: discord.Option(float, "Multiplikator (0.0 = keine XP)", min_value=0.0, max_value=5.0)): + + self.db.set_channel_multiplier(ctx.guild.id, channel.id, multiplier) + + if multiplier == 0: + description = f"{channel.mention} gibt keine XP mehr." + color = 0xff0000 + else: + description = f"{channel.mention} hat **{multiplier}x** XP-Multiplikator." + color = 0x00ff00 + + embed = discord.Embed( + title="โœ… Kanal-Multiplikator gesetzt", + description=description, + color=color + ) + await ctx.respond(embed=embed) + + @levelconfig.command(description="Fรผgt einen Kanal zur XP-Blacklist hinzu") + @commands.has_permissions(manage_guild=True) + async def blacklist_channel(self, ctx, + channel: discord.Option(discord.TextChannel, "Kanal zum AusschlieรŸen")): + + self.db.add_blacklisted_channel(ctx.guild.id, channel.id) + + embed = discord.Embed( + title="โœ… Kanal ausgeschlossen", + description=f"{channel.mention} wurde vom Levelsystem ausgeschlossen.", + color=0x00ff00 + ) + await ctx.respond(embed=embed) + + @levelconfig.command(description="Setzt den Level-Up Nachrichten-Kanal") + @commands.has_permissions(manage_guild=True) + async def levelup_channel(self, ctx, + channel: discord.Option(discord.TextChannel, "Kanal fรผr Level-Up Nachrichten", default=None)): + + if channel: + self.db.set_guild_config(ctx.guild.id, level_up_channel=channel.id) + embed = discord.Embed( + title="โœ… Level-Up Kanal gesetzt", + description=f"Level-Up Nachrichten werden in {channel.mention} gesendet.", + color=0x00ff00 + ) + else: + self.db.set_guild_config(ctx.guild.id, level_up_channel=None) + embed = discord.Embed( + title="โœ… Level-Up Kanal zurรผckgesetzt", + description="Level-Up Nachrichten werden wieder im ursprรผnglichen Kanal gesendet.", + color=0x00ff00 + ) + + await ctx.respond(embed=embed) + + @levelconfig.command(description="Konfiguriert Prestige-Einstellungen") + @commands.has_permissions(manage_guild=True) + async def prestige_settings(self, ctx, + aktiviert: discord.Option(bool, "Prestige-System aktivieren/deaktivieren"), + min_level: discord.Option(int, "Minimum Level fรผr Prestige", default=50, min_value=10, max_value=200)): + + self.db.set_guild_config(ctx.guild.id, prestige_enabled=aktiviert, prestige_min_level=min_level) + + embed = discord.Embed( + title="โœ… Prestige-Einstellungen aktualisiert", + color=0x00ff00 + ) + + status = "aktiviert" if aktiviert else "deaktiviert" + embed.add_field(name="โœจ Status", value=status.title(), inline=True) + if aktiviert: + embed.add_field(name="๐ŸŽฏ Minimum Level", value=str(min_level), inline=True) + + await ctx.respond(embed=embed) + + # System Commands + @levelsystem.command(description="Aktiviert das Levelsystem") + @commands.has_permissions(manage_guild=True) + async def enable(self, ctx): + if self.db.is_levelsystem_enabled(ctx.guild.id): + embed = discord.Embed( + title="โ„น๏ธ Bereits aktiviert", + description="Das Levelsystem ist bereits aktiviert!", + color=0x0099ff + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + self.db.set_levelsystem_enabled(ctx.guild.id, True) + + embed = discord.Embed( + title="โœ… Levelsystem aktiviert", + description="Das Levelsystem wurde erfolgreich aktiviert!\n\nBenutze `/levelconfig` um weitere Einstellungen vorzunehmen.", + color=0x00ff00 + ) + await ctx.respond(embed=embed) + + @levelsystem.command(description="Deaktiviert das Levelsystem") + @commands.has_permissions(manage_guild=True) + async def disable(self, ctx): + if not self.db.is_levelsystem_enabled(ctx.guild.id): + embed = discord.Embed( + title="โ„น๏ธ Bereits deaktiviert", + description="Das Levelsystem ist bereits deaktiviert!", + color=0x0099ff + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + self.db.set_levelsystem_enabled(ctx.guild.id, False) + + embed = discord.Embed( + title="โœ… Levelsystem deaktiviert", + description="Das Levelsystem wurde erfolgreich deaktiviert!\n\n*Hinweis: Alle Daten bleiben erhalten und kรถnnen bei Reaktivierung wiederhergestellt werden.*", + color=0x00ff00 + ) + await ctx.respond(embed=embed) + + @levelsystem.command(description="Zeigt den detaillierten Status des Levelsystems") + async def status(self, ctx): + enabled = self.db.is_levelsystem_enabled(ctx.guild.id) + config = self.db.get_guild_config(ctx.guild.id) + + embed = discord.Embed( + title="๐Ÿ“Š Levelsystem Status", + description=f"Das Levelsystem ist **{'aktiviert' if enabled else 'deaktiviert'}**", + color=0x00ff00 if enabled else 0xff0000, + timestamp=discord.utils.utcnow() + ) + + if enabled: + # Grundkonfiguration + embed.add_field( + name="โš™๏ธ Konfiguration", + value=f"**XP-Bereich:** {config['min_xp']}-{config['max_xp']}\n" + f"**Cooldown:** {config['xp_cooldown']}s\n" + f"**Prestige:** {'โœ…' if config['prestige_enabled'] else 'โŒ'} (Level {config['prestige_min_level']}+)", + inline=True + ) + + # Statistiken + leaderboard = self.db.get_leaderboard(ctx.guild.id, 1) + level_roles = self.db.get_level_roles(ctx.guild.id) + total_users = len(self.db.get_leaderboard(ctx.guild.id, 1000)) + + embed.add_field( + name="๐Ÿ“ˆ Statistiken", + value=f"**Aktive User:** {total_users:,}\n" + f"**Level-Rollen:** {len(level_roles)}\n" + f"**XP-Boosts:** Aktiv", + inline=True + ) + + if leaderboard: + top_user = self.bot.get_user(leaderboard[0][0]) + top_username = top_user.display_name if top_user else f"User {leaderboard[0][0]}" + prestige_text = f"โญ{leaderboard[0][4]} " if leaderboard[0][4] > 0 else "" + + embed.add_field( + name="๐Ÿ‘‘ Top User", + value=f"{prestige_text}**{top_username}**\nLevel {leaderboard[0][2]} ({leaderboard[0][1]:,} XP)", + inline=True + ) + + # Level-Up Kanal + if config['level_up_channel']: + channel = ctx.guild.get_channel(config['level_up_channel']) + channel_text = channel.mention if channel else "Gelรถschter Kanal" + else: + channel_text = "Standard (Nachrichtenkanal)" + + embed.add_field(name="๐Ÿ“ข Level-Up Kanal", value=channel_text, inline=True) + + embed.set_footer(text=f"Server: {ctx.guild.name}") + await ctx.respond(embed=embed) + + # Admin Commands + @levelsystem.command(description="Setzt das Level eines Users (Admin)") + @commands.has_permissions(administrator=True) + async def set_level(self, ctx, + user: discord.Option(discord.Member, "Benutzer"), + level: discord.Option(int, "Neues Level", min_value=0, max_value=1000)): + + required_xp = self.db.xp_for_level(level) + + # User in Datenbank erstellen/aktualisieren + conn = self.db.db_path + import sqlite3 + conn = sqlite3.connect(self.db.db_path) + cursor = conn.cursor() + + cursor.execute(''' + INSERT OR REPLACE INTO user_levels (user_id, guild_id, xp, level, messages, last_message, total_xp_earned) + VALUES (?, ?, ?, ?, + COALESCE((SELECT messages FROM user_levels WHERE user_id = ? AND guild_id = ?), 0), + ?, + COALESCE((SELECT total_xp_earned FROM user_levels WHERE user_id = ? AND guild_id = ?), 0) + ?) + ''', (user.id, ctx.guild.id, required_xp, level, user.id, ctx.guild.id, time.time(), user.id, ctx.guild.id, required_xp)) + + conn.commit() + conn.close() + + embed = discord.Embed( + title="โœ… Level gesetzt", + description=f"{user.mention} ist jetzt **Level {level}** ({required_xp:,} XP)", + color=0x00ff00 + ) + await ctx.respond(embed=embed) + + @levelsystem.command(description="Fรผgt einem User XP hinzu (Admin)") + @commands.has_permissions(administrator=True) + async def add_xp(self, ctx, + user: discord.Option(discord.Member, "Benutzer"), + xp_amount: discord.Option(int, "XP-Menge", min_value=1, max_value=100000)): + + level_up, new_level = self.db.add_xp(user.id, ctx.guild.id, xp_amount, "Admin XP Grant") + + embed = discord.Embed( + title="โœ… XP hinzugefรผgt", + description=f"{user.mention} hat **{xp_amount:,} XP** erhalten!", + color=0x00ff00 + ) + + if level_up: + embed.add_field(name="๐ŸŽ‰ Level Up!", value=f"Neues Level: **{new_level}**", inline=False) + + await ctx.respond(embed=embed) + + @levelsystem.command(description="Setzt die Nachrichten-Anzahl eines Users (Admin)") + @commands.has_permissions(administrator=True) + async def set_messages(self, ctx, + user: discord.Option(discord.Member, "Benutzer"), + messages: discord.Option(int, "Anzahl Nachrichten", min_value=0, max_value=1000000)): + + import sqlite3 + conn = sqlite3.connect(self.db.db_path) + cursor = conn.cursor() + + cursor.execute(''' + UPDATE user_levels SET messages = ? + WHERE user_id = ? AND guild_id = ? + ''', (messages, user.id, ctx.guild.id)) + + conn.commit() + conn.close() + + embed = discord.Embed( + title="โœ… Nachrichten-Anzahl gesetzt", + description=f"{user.mention} hat jetzt **{messages:,} Nachrichten**", + color=0x00ff00 + ) + await ctx.respond(embed=embed) + + @levelsystem.command(description="Lรถscht die Leveldaten eines Users (Admin)") + @commands.has_permissions(administrator=True) + async def reset_user(self, ctx, + user: discord.Option(discord.Member, "Benutzer zum Zurรผcksetzen")): + + import sqlite3 + conn = sqlite3.connect(self.db.db_path) + cursor = conn.cursor() + + cursor.execute('DELETE FROM user_levels WHERE user_id = ? AND guild_id = ?', (user.id, ctx.guild.id)) + + affected_rows = cursor.rowcount + conn.commit() + conn.close() + + if affected_rows > 0: + embed = discord.Embed( + title="โœ… User zurรผckgesetzt", + description=f"Alle Leveldaten von {user.mention} wurden gelรถscht.", + color=0x00ff00 + ) + else: + embed = discord.Embed( + title="โ„น๏ธ Keine Daten gefunden", + description=f"{user.mention} hat keine Leveldaten auf diesem Server.", + color=0x0099ff + ) + + await ctx.respond(embed=embed, ephemeral=True) + + +def setup(bot): + bot.add_cog(LevelSystem(bot)) \ No newline at end of file diff --git a/src/bot/cogs/guild/loggingsystem.py b/src/bot/cogs/guild/loggingsystem.py new file mode 100644 index 0000000..818a863 --- /dev/null +++ b/src/bot/cogs/guild/loggingsystem.py @@ -0,0 +1,1465 @@ +# Copyright (c) 2025 OPPRO.NET Network +# File: logging_cog.py + +import discord +from discord import SlashCommandGroup +from discord.ext import commands +from datetime import datetime, timedelta +from typing import Dict, Set, Optional, List +import asyncio +import logging + +# Import our separate database class +from DevTools import LoggingDatabase + +# Setup logging +logger = logging.getLogger(__name__) + +class LoggingCog(commands.Cog): + """ + Comprehensive Discord logging system with improved performance and features + """ + + def __init__(self, bot): + self.bot = bot + self.db = LoggingDatabase() + + # Improved caching system + self._edit_tasks: Dict[int, asyncio.Task] = {} + self._bulk_deletes: Dict[int, Dict[str, any]] = {} + self._voice_cache: Dict[int, Dict[int, Optional[discord.VoiceState]]] = {} + + # Configuration + self.config = { + 'edit_debounce_time': 3.0, # Sekunden + 'bulk_delete_threshold': 3, # Anzahl fรผr Bulk-Erkennung + 'bulk_delete_window': 2.0, # Sekunden Zeitfenster + 'max_content_length': 1500, # Max Content-Lรคnge in Embeds + 'max_embed_fields': 25, # Discord Limit + 'cleanup_interval': 300, # 5 Minuten Cache-Cleanup + 'max_attachment_display': 5, # Max Attachments in Embed + 'max_role_display': 10, # Max Roles in Embed + } + + # Performance tracking + self._stats = { + 'events_processed': 0, + 'logs_sent': 0, + 'errors': 0, + 'cache_hits': 0, + 'startup_time': datetime.utcnow(), + } + + # Start background tasks + self._cleanup_task = None + self.bot.loop.create_task(self._start_background_tasks()) + + logger.info("LoggingCog initialized successfully") + + async def _start_background_tasks(self): + """Startet Background-Tasks nachdem der Bot bereit ist""" + await self.bot.wait_until_ready() + self._cleanup_task = self.bot.loop.create_task(self._cleanup_loop()) + logger.info("Background tasks started") + + def cog_unload(self): + """Cleanup beim Entladen der Cog""" + logger.info("Unloading LoggingCog...") + + if self._cleanup_task and not self._cleanup_task.done(): + self._cleanup_task.cancel() + + # Cancel all edit tasks + for task in self._edit_tasks.values(): + if not task.done(): + task.cancel() + + # Close database connection + self.db.close() + logger.info("LoggingCog unloaded successfully") + + async def _cleanup_loop(self): + """RegelmรครŸige Cache-Bereinigung mit verbesserter Logik""" + while not self.bot.is_closed(): + try: + await asyncio.sleep(self.config['cleanup_interval']) + await self._cleanup_caches() + except asyncio.CancelledError: + logger.info("Cleanup loop cancelled") + break + except Exception as e: + logger.error(f"Cleanup loop error: {e}") + self._stats['errors'] += 1 + + async def _cleanup_caches(self): + """Bereinigt alle Caches""" + try: + cleanup_count = 0 + + # Edit Tasks bereinigen + completed_tasks = [ + msg_id for msg_id, task in self._edit_tasks.items() + if task.done() + ] + for msg_id in completed_tasks: + del self._edit_tasks[msg_id] + cleanup_count += 1 + + # Bulk Delete Cache bereinigen (รคlter als 5 Minuten) + current_time = datetime.utcnow() + expired_guilds = [] + + for guild_id, data in self._bulk_deletes.items(): + if 'timestamp' in data: + age = (current_time - data['timestamp']).total_seconds() + if age > 300: # 5 Minuten + expired_guilds.append(guild_id) + + for guild_id in expired_guilds: + del self._bulk_deletes[guild_id] + cleanup_count += 1 + + # Voice Cache fรผr offline Mitglieder bereinigen + for guild_id in list(self._voice_cache.keys()): + guild = self.bot.get_guild(guild_id) + if not guild: + del self._voice_cache[guild_id] + cleanup_count += 1 + continue + + offline_members = [] + for member_id in self._voice_cache[guild_id]: + member = guild.get_member(member_id) + if not member or not member.voice: + offline_members.append(member_id) + + for member_id in offline_members: + del self._voice_cache[guild_id][member_id] + cleanup_count += 1 + + if cleanup_count > 0: + logger.debug(f"Cache cleanup: {cleanup_count} items removed") + + except Exception as e: + logger.error(f"Cache cleanup error: {e}") + self._stats['errors'] += 1 + + async def send_log(self, guild_id: int, embed: discord.Embed, log_type: str = "general") -> bool: + """Verbesserte Log-Versendung mit Retry-Logik""" + try: + channel_id = await self.db.get_log_channel(guild_id, log_type) + if not channel_id: + return False + + channel = self.bot.get_channel(channel_id) + if not channel: + # Channel nicht mehr vorhanden, aus DB entfernen + await self.db.remove_log_channel(guild_id, log_type) + logger.warning(f"Removed invalid channel {channel_id} for guild {guild_id}") + return False + + # Embed validieren und anpassen + if len(embed) > 6000: # Discord Limit + embed.description = "โš ๏ธ Inhalt zu lang fรผr Anzeige" + # Felder reduzieren falls nรถtig + while len(embed.fields) > 10: + embed.remove_field(-1) + + # Embed senden + await channel.send(embed=embed) + self._stats['logs_sent'] += 1 + return True + + except discord.Forbidden: + logger.warning(f"No permission for log channel in guild {guild_id}") + await self.db.remove_log_channel(guild_id, log_type) + return False + except discord.NotFound: + logger.warning(f"Log channel not found in guild {guild_id}") + await self.db.remove_log_channel(guild_id, log_type) + return False + except discord.HTTPException as e: + if e.code == 50035: # Invalid form body + logger.error(f"Invalid embed content for guild {guild_id}: {e}") + # Fallback embed senden + try: + fallback_embed = discord.Embed( + title="โš ๏ธ Log-Fehler", + description="Originale Log-Nachricht konnte nicht angezeigt werden (zu lang oder ungรผltig)", + color=discord.Color.orange(), + timestamp=datetime.utcnow() + ) + await channel.send(embed=fallback_embed) + except: + pass + else: + logger.error(f"HTTP error sending log to guild {guild_id}: {e}") + except Exception as e: + logger.error(f"Unexpected error sending log to guild {guild_id}: {e}") + self._stats['errors'] += 1 + + return False + + def _create_user_embed(self, title: str, user: discord.User, color: discord.Color, + extra_fields: Dict[str, str] = None, + description: str = None) -> discord.Embed: + """Verbesserte User-Embed Erstellung""" + embed = discord.Embed( + title=title, + description=description, + color=color, + timestamp=datetime.utcnow() + ) + + # User Info - immer als erstes + embed.add_field( + name="๐Ÿ‘ค User", + value=f"{user.mention}\n`{user}`", + inline=True + ) + embed.add_field( + name="๐Ÿ†” ID", + value=f"`{user.id}`", + inline=True + ) + embed.add_field( + name="๐Ÿ“… Erstellt", + value=f"", + inline=True + ) + + # Extra Felder hinzufรผgen + if extra_fields: + for name, value in extra_fields.items(): + if len(embed.fields) < self.config['max_embed_fields']: + embed.add_field(name=name, value=str(value)[:1000], inline=True) + + # Avatar und Footer + if user.display_avatar: + embed.set_thumbnail(url=user.display_avatar.url) + + embed.set_footer(text=f"User ID: {user.id}") + return embed + + def _truncate_content(self, content: str, max_length: int = None) -> str: + """Kรผrzt Content intelligent""" + if not content: + return "*Leer*" + + max_length = max_length or self.config['max_content_length'] + + if len(content) <= max_length: + return content + + # An Wort-Grenzen kรผrzen wenn mรถglich + truncated = content[:max_length-3] + last_space = truncated.rfind(' ') + + if last_space > max_length * 0.8: # Nur wenn nicht zu viel verloren geht + truncated = truncated[:last_space] + + return f"{truncated}..." + + def _format_content_for_embed(self, content: str, escape_markdown: bool = True) -> str: + """Formatiert Content sicher fรผr Embeds""" + if not content: + return "*Leer*" + + content = self._truncate_content(content) + + if escape_markdown: + # Escape problematische Zeichen + content = content.replace("```", "'''") + content = content.replace("`", "'") + + return f"```\n{content}\n```" + + # ============================================================================= + # SLASH COMMANDS - Improved + # ============================================================================= + + logging = SlashCommandGroup("logging", description="Setze die Logging Systeme") + + @logging.command(name="channel", description="Setzt den Log-Channel fรผr verschiedene Events") + @discord.default_permissions(administrator=True) + async def set_log_channel(self, ctx, + channel: discord.TextChannel, + log_type: discord.Option(str, + choices=["general", "moderation", "voice", "messages", "all"], + description="Art der Logs", + default="general")): + """Verbesserte Log-Channel Konfiguration""" + try: + # Berechtigungen prรผfen + perms = channel.permissions_for(ctx.guild.me) + if not perms.send_messages: + embed = discord.Embed( + title="โŒ Keine Berechtigung", + description=f"Ich kann keine Nachrichten in {channel.mention} senden.", + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if not perms.embed_links: + embed = discord.Embed( + title="โš ๏ธ Fehlende Berechtigung", + description=f"Ich benรถtige die 'Embed Links' Berechtigung in {channel.mention}.", + color=discord.Color.orange() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if log_type == "all": + # Alle Log-Typen setzen + types = ["general", "moderation", "voice", "messages"] + for lt in types: + await self.db.set_log_channel(ctx.guild.id, channel.id, lt) + + embed = discord.Embed( + title="โœ… Alle Log-Channels gesetzt", + description=f"Alle Logs werden nun in {channel.mention} gesendet.\n\n" + + f"**Konfigurierte Typen:** {', '.join(types)}", + color=discord.Color.green() + ) + else: + await self.db.set_log_channel(ctx.guild.id, channel.id, log_type) + + embed = discord.Embed( + title="โœ… Log-Channel gesetzt", + description=f"**{log_type.title()}**-Logs werden nun in {channel.mention} gesendet.", + color=discord.Color.green() + ) + + embed.set_footer(text=f"Konfiguriert von {ctx.author}") + await ctx.respond(embed=embed, ephemeral=True) + + # Test-Nachricht senden + test_embed = discord.Embed( + title="๐Ÿงช Test-Nachricht", + description=f"Log-Channel fรผr **{log_type}** erfolgreich konfiguriert!", + color=discord.Color.blue(), + timestamp=datetime.utcnow() + ) + test_embed.set_footer(text="Dies ist eine Test-Nachricht") + await self.send_log(ctx.guild.id, test_embed, "general" if log_type == "all" else log_type) + + except Exception as e: + embed = discord.Embed( + title="โŒ Fehler", + description=f"Fehler beim Setzen des Log-Channels:\n```{str(e)}```", + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + logger.error(f"Error in set_log_channel: {e}") + + @logging.command(name="remove", description="Entfernt einen Log-Channel") + @discord.default_permissions(administrator=True) + async def remove_log_channel(self, ctx, + log_type: discord.Option(str, + choices=["general", "moderation", "voice", "messages", "all"], + description="Art der Logs", default="all")): + """Entfernt Log-Channel Konfiguration""" + try: + if log_type == "all": + deleted_count = await self.db.remove_all_log_channels(ctx.guild.id) + description = f"Alle Log-Channels wurden entfernt. ({deleted_count} Eintrรคge)" + else: + deleted_count = await self.db.remove_log_channel(ctx.guild.id, log_type) + if deleted_count > 0: + description = f"{log_type.title()}-Logging wurde deaktiviert." + else: + description = f"Kein {log_type.title()}-Logging war konfiguriert." + + embed = discord.Embed( + title="๐Ÿ—‘๏ธ Log-Channel entfernt", + description=description, + color=discord.Color.red(), + timestamp=datetime.utcnow() + ) + embed.set_footer(text=f"Entfernt von {ctx.author}") + await ctx.respond(embed=embed, ephemeral=True) + + except Exception as e: + embed = discord.Embed( + title="โŒ Fehler", + description=f"Fehler beim Entfernen des Log-Channels:\n```{str(e)}```", + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + logger.error(f"Error in remove_log_channel: {e}") + + @logging.command(name="status", description="Zeigt die aktuellen Log-Einstellungen") + @discord.default_permissions(administrator=True) + async def log_status(self, ctx): + """Verbesserter Log-Status mit mehr Details""" + try: + channels = await self.db.get_all_log_channels(ctx.guild.id) + stats = await self.db.get_statistics() + + embed = discord.Embed( + title="๐Ÿ“Š Logging Status", + color=discord.Color.blue(), + timestamp=datetime.utcnow() + ) + + if not channels: + embed.description = "โŒ Keine Log-Channels konfiguriert." + embed.add_field( + name="๐Ÿ’ก Tipp", + value="Nutze `/setlogchannel` um Logging zu aktivieren.", + inline=False + ) + else: + status_text = f"โœ… **{len(channels)}** Log-Typ(en) konfiguriert\n\n" + + for log_type, channel_id in channels.items(): + channel = self.bot.get_channel(channel_id) + if channel: + status_text += f"**{log_type.title()}:** {channel.mention}\n" + else: + status_text += f"**{log_type.title()}:** โŒ *Channel nicht gefunden* (`{channel_id}`)\n" + + embed.description = status_text + + # Bot Statistiken + uptime = datetime.utcnow() - self._stats['startup_time'] + uptime_str = f"{uptime.days}d {uptime.seconds//3600}h {(uptime.seconds%3600)//60}m" + + embed.add_field( + name="๐Ÿ“ˆ Cog Statistiken", + value=f"Events verarbeitet: **{self._stats['events_processed']:,}**\n" + + f"Logs gesendet: **{self._stats['logs_sent']:,}**\n" + + f"Fehler: **{self._stats['errors']}**\n" + + f"Uptime: **{uptime_str}**", + inline=True + ) + + # Cache Info + voice_cache_size = sum(len(vc) for vc in self._voice_cache.values()) + embed.add_field( + name="๐Ÿ—„๏ธ Cache Status", + value=f"Edit Tasks: **{len(self._edit_tasks)}**\n" + + f"Bulk Deletes: **{len(self._bulk_deletes)}**\n" + + f"Voice Cache: **{voice_cache_size}**", + inline=True + ) + + # Datenbank Statistiken + if stats: + embed.add_field( + name="๐Ÿ—ƒ๏ธ Datenbank", + value=f"Aktive Channels: **{stats.get('enabled_entries', 0)}**\n" + + f"Guilds mit Logging: **{stats.get('unique_guilds', 0)}**\n" + + f"Einzigartige Channels: **{stats.get('unique_channels', 0)}**", + inline=True + ) + + embed.set_footer(text=f"Guild ID: {ctx.guild.id}") + await ctx.respond(embed=embed, ephemeral=True) + + except Exception as e: + embed = discord.Embed( + title="โŒ Fehler", + description=f"Fehler beim Abrufen des Status:\n```{str(e)}```", + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + logger.error(f"Error in log_status: {e}") + + @logging.command(name="backup", description="Erstellt ein Backup der Log-Konfiguration") + @discord.default_permissions(administrator=True) + async def log_backup(self, ctx): + """Erstellt ein Datenbank-Backup""" + try: + backup_path = f"data/log_channels_backup_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}.db" + success = await self.db.backup_database(backup_path) + + if success: + embed = discord.Embed( + title="โœ… Backup erstellt", + description=f"Datenbank-Backup wurde erfolgreich erstellt:\n`{backup_path}`", + color=discord.Color.green() + ) + else: + embed = discord.Embed( + title="โŒ Backup fehlgeschlagen", + description="Backup konnte nicht erstellt werden. Prรผfe die Logs fรผr Details.", + color=discord.Color.red() + ) + + await ctx.respond(embed=embed, ephemeral=True) + + except Exception as e: + embed = discord.Embed( + title="โŒ Fehler", + description=f"Fehler beim Backup:\n```{str(e)}```", + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + logger.error(f"Error in log_backup: {e}") + + # ============================================================================= + # EVENT HANDLERS - Enhanced + # ============================================================================= + + @commands.Cog.listener() + async def on_member_join(self, member: discord.Member): + """Verbessertes Member Join Logging""" + try: + self._stats['events_processed'] += 1 + + account_age = datetime.utcnow() - member.created_at + age_days = account_age.days + + # Verdรคchtigkeits-Score + suspicious_factors = [] + if age_days < 1: + suspicious_factors.append("Sehr neues Konto (< 1 Tag)") + elif age_days < 7: + suspicious_factors.append("Neues Konto (< 7 Tage)") + + if member.display_avatar.is_default(): + suspicious_factors.append("Standard Avatar") + + # Default Username Pattern + if len(member.name) > 10 and member.discriminator != "0": + if member.name.lower().startswith(("discord", "user", "member")): + suspicious_factors.append("Verdรคchtiger Username") + + # Farbe basierend auf Verdรคchtigkeits-Level + if member.bot: + color = discord.Color.purple() + elif len(suspicious_factors) >= 2: + color = discord.Color.red() + elif suspicious_factors: + color = discord.Color.orange() + else: + color = discord.Color.green() + + extra_fields = { + "๐ŸŽ‚ Konto-Alter": f"{age_days} Tag{'e' if age_days != 1 else ''}", + "๐Ÿ‘ฅ Member #": f"{member.guild.member_count}", + } + + if suspicious_factors: + extra_fields["โš ๏ธ Verdรคchtig"] = "\n".join(suspicious_factors[:3]) + + if member.bot: + extra_fields["๐Ÿค– Bot"] = "โœ…" + + embed = self._create_user_embed( + "๐Ÿ“ฅ Member beigetreten", + member, + color, + extra_fields + ) + + await self.send_log(member.guild.id, embed, "general") + + except Exception as e: + logger.error(f"Error in on_member_join: {e}") + self._stats['errors'] += 1 + + @commands.Cog.listener() + async def on_member_remove(self, member: discord.Member): + """Verbessertes Member Leave Logging""" + try: + self._stats['events_processed'] += 1 + + extra_fields = { + "๐ŸŽญ Rollen": f"{len(member.roles) - 1}", # -1 fรผr @everyone + "๐Ÿ‘ฅ Member #": f"{member.guild.member_count}", + } + + if member.joined_at: + duration = datetime.utcnow() - member.joined_at + days = duration.days + hours = duration.seconds // 3600 + + if days > 0: + duration_str = f"{days} Tag{'e' if days != 1 else ''}" + elif hours > 0: + duration_str = f"{hours} Stunde{'n' if hours != 1 else ''}" + else: + minutes = duration.seconds // 60 + duration_str = f"{minutes} Minute{'n' if minutes != 1 else ''}" + + extra_fields["โฑ๏ธ Mitgliedschaftsdauer"] = duration_str + + # Top Rollen anzeigen (nicht @everyone) + top_roles = [role for role in member.roles if role.name != "@everyone"] + if top_roles: + top_roles = sorted(top_roles, key=lambda r: r.position, reverse=True)[:3] + extra_fields["๐Ÿ† Top Rollen"] = ", ".join([role.name for role in top_roles]) + + embed = self._create_user_embed( + "๐Ÿ“ค Member verlassen", + member, + discord.Color.red(), + extra_fields + ) + + await self.send_log(member.guild.id, embed, "general") + + except Exception as e: + logger.error(f"Error in on_member_remove: {e}") + self._stats['errors'] += 1 + + @commands.Cog.listener() + async def on_message_delete(self, message: discord.Message): + """Stark verbessertes Message Delete Logging mit Bulk-Detection""" + try: + if message.author.bot or not message.guild: + return + + self._stats['events_processed'] += 1 + guild_id = message.guild.id + + # Bulk Delete Detection + current_time = datetime.utcnow() + + if guild_id not in self._bulk_deletes: + self._bulk_deletes[guild_id] = { + 'messages': set(), + 'timestamp': current_time, + 'channels': set() + } + + bulk_data = self._bulk_deletes[guild_id] + + # Reset wenn zu alt + if (current_time - bulk_data['timestamp']).total_seconds() > self.config['bulk_delete_window']: + bulk_data['messages'].clear() + bulk_data['channels'].clear() + bulk_data['timestamp'] = current_time + + bulk_data['messages'].add(message.id) + bulk_data['channels'].add(message.channel.id) + + # Kurz warten um weitere Deletes zu erfassen + await asyncio.sleep(0.3) + + # Bulk Delete Check + if len(bulk_data['messages']) >= self.config['bulk_delete_threshold']: + embed = discord.Embed( + title="๐Ÿ—‘๏ธ Bulk-Lรถschung erkannt", + description=f"**{len(bulk_data['messages'])}** Nachrichten wurden in kurzer Zeit gelรถscht", + color=discord.Color.dark_red(), + timestamp=datetime.utcnow() + ) + + # Channel Info + affected_channels = [] + for ch_id in bulk_data['channels']: + channel = self.bot.get_channel(ch_id) + if channel: + affected_channels.append(channel.mention) + + if affected_channels: + embed.add_field( + name="๐Ÿ“ Betroffene Channels", + value="\n".join(affected_channels[:5]), + inline=False + ) + + embed.add_field(name="โฑ๏ธ Zeitfenster", value=f"< {self.config['bulk_delete_window']}s", inline=True) + embed.add_field(name="๐Ÿ” Hinweis", value="Mรถgliche Moderator-Aktion oder Bot-Cleanup", inline=True) + + await self.send_log(guild_id, embed, "messages") + + # Cache zurรผcksetzen + bulk_data['messages'].clear() + bulk_data['channels'].clear() + return + + # Normale Delete-Behandlung + if message.id not in bulk_data['messages']: + return # Bereits als Bulk verarbeitet + + embed = discord.Embed( + title="๐Ÿ—‘๏ธ Nachricht gelรถscht", + color=discord.Color.red(), + timestamp=datetime.utcnow() + ) + + # Author Info + embed.add_field( + name="๐Ÿ‘ค Author", + value=f"{message.author.mention}\n`{message.author}`", + inline=True + ) + embed.add_field( + name="๐Ÿ“ Channel", + value=message.channel.mention, + inline=True + ) + embed.add_field( + name="โฐ Erstellt", + value=f"", + inline=True + ) + + # Content + if message.content: + embed.add_field( + name="๐Ÿ’ฌ Inhalt", + value=self._format_content_for_embed(message.content), + inline=False + ) + + # Attachments + if message.attachments: + attachment_info = [] + for att in message.attachments[:self.config['max_attachment_display']]: + size_kb = att.size // 1024 + attachment_info.append(f"๐Ÿ“Ž `{att.filename}` ({size_kb} KB)") + + if len(message.attachments) > self.config['max_attachment_display']: + attachment_info.append(f"... und {len(message.attachments) - self.config['max_attachment_display']} weitere") + + embed.add_field( + name="๐Ÿ“Ž Anhรคnge", + value="\n".join(attachment_info), + inline=False + ) + + # Embeds + if message.embeds: + embed.add_field( + name="๐Ÿ“‹ Embeds", + value=f"{len(message.embeds)} Embed(s)", + inline=True + ) + + # Reactions + if message.reactions: + reaction_count = sum(r.count for r in message.reactions) + embed.add_field( + name="๐Ÿ‘ Reaktionen", + value=f"{reaction_count} Reaktionen", + inline=True + ) + + embed.set_author(name=message.author.display_name, icon_url=message.author.display_avatar.url) + embed.set_footer(text=f"Message ID: {message.id} | User ID: {message.author.id}") + + await self.send_log(guild_id, embed, "messages") + + # Message aus bulk cache entfernen + if message.id in bulk_data['messages']: + bulk_data['messages'].discard(message.id) + + except Exception as e: + logger.error(f"Error in on_message_delete: {e}") + self._stats['errors'] += 1 + + @commands.Cog.listener() + async def on_message_edit(self, before: discord.Message, after: discord.Message): + """Verbessertes Message Edit Logging mit intelligentem Debouncing""" + try: + if (before.author.bot or not before.guild or + before.content == after.content or not before.content): + return + + self._stats['events_processed'] += 1 + message_id = before.id + + # Bestehenden Task canceln + if message_id in self._edit_tasks: + self._edit_tasks[message_id].cancel() + + # Neuen debounced Task erstellen + self._edit_tasks[message_id] = asyncio.create_task( + self._delayed_edit_log(before, after) + ) + + except Exception as e: + logger.error(f"Error in on_message_edit: {e}") + self._stats['errors'] += 1 + + async def _delayed_edit_log(self, before: discord.Message, after: discord.Message): + """Verzรถgertes Edit-Logging mit verbesserter Logik""" + try: + await asyncio.sleep(self.config['edit_debounce_time']) + + # Aktuellste Version der Nachricht holen + try: + fresh_message = await before.channel.fetch_message(before.id) + after = fresh_message # Aktuellste Version verwenden + except (discord.NotFound, discord.Forbidden): + pass # Nachricht wurde gelรถscht oder keine Berechtigung + + await self._log_message_edit(before, after) + + except asyncio.CancelledError: + pass # Task wurde gecancelt + except Exception as e: + logger.error(f"Error in delayed edit log: {e}") + finally: + # Task aus Cache entfernen + if before.id in self._edit_tasks: + del self._edit_tasks[before.id] + + async def _log_message_edit(self, before: discord.Message, after: discord.Message): + """Internes Message Edit Logging mit Diff-Anzeige""" + try: + embed = discord.Embed( + title="โœ๏ธ Nachricht bearbeitet", + color=discord.Color.yellow(), + timestamp=datetime.utcnow() + ) + + embed.add_field( + name="๐Ÿ‘ค Author", + value=f"{before.author.mention}\n`{before.author}`", + inline=True + ) + embed.add_field( + name="๐Ÿ“ Channel", + value=before.channel.mention, + inline=True + ) + embed.add_field( + name="๐Ÿ”— Nachricht", + value=f"[Zur Nachricht]({after.jump_url})", + inline=True + ) + + # Content Comparison - intelligenter + before_content = self._truncate_content(before.content or "", 700) + after_content = self._truncate_content(after.content or "", 700) + + if len(before_content) + len(after_content) < 2000: + embed.add_field( + name="๐Ÿ“ Vorher", + value=self._format_content_for_embed(before_content, escape_markdown=True), + inline=False + ) + embed.add_field( + name="๐Ÿ“ Nachher", + value=self._format_content_for_embed(after_content, escape_markdown=True), + inline=False + ) + else: + # Zu lang - nur ร„nderungsinfo + char_diff = len(after.content) - len(before.content) + diff_text = f"**Zeichen-ร„nderung:** {char_diff:+d}\n" + diff_text += f"**Lรคnge:** {len(before.content)} โ†’ {len(after.content)}" + + embed.add_field( + name="๐Ÿ“Š ร„nderungsinfo", + value=diff_text, + inline=False + ) + + # Timestamp der ursprรผnglichen Nachricht + embed.add_field( + name="๐Ÿ• Original erstellt", + value=f"", + inline=True + ) + + embed.set_author(name=before.author.display_name, icon_url=before.author.display_avatar.url) + embed.set_footer(text=f"Message ID: {before.id} | User ID: {before.author.id}") + + await self.send_log(before.guild.id, embed, "messages") + + except Exception as e: + logger.error(f"Error in _log_message_edit: {e}") + +# ============================================================================= + # VOICE STATE EVENTS + # ============================================================================= + + @commands.Cog.listener() + async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, after: discord.VoiceState): + """Verbessertes Voice State Logging mit intelligenter Filterung""" + try: + if member.bot: + return + + self._stats['events_processed'] += 1 + guild_id = member.guild.id + + # Cache initialisieren + if guild_id not in self._voice_cache: + self._voice_cache[guild_id] = {} + + guild_cache = self._voice_cache[guild_id] + member_id = member.id + + # Vorherigen State aus Cache holen oder setzen + cached_before = guild_cache.get(member_id) + guild_cache[member_id] = after + + # Event-Typ bestimmen + event_type = None + color = discord.Color.blue() + title = "" + + if not before.channel and after.channel: + # Join + event_type = "join" + title = "๐Ÿ”Š Voice Channel beigetreten" + color = discord.Color.green() + elif before.channel and not after.channel: + # Leave + event_type = "leave" + title = "๐Ÿ”‡ Voice Channel verlassen" + color = discord.Color.red() + elif before.channel != after.channel and before.channel and after.channel: + # Move + event_type = "move" + title = "๐Ÿ”„ Voice Channel gewechselt" + color = discord.Color.orange() + elif before.channel == after.channel: + # State changes (mute, deafen, etc.) + changes = [] + if before.self_mute != after.self_mute: + changes.append(f"Self Mute: {'โœ…' if after.self_mute else 'โŒ'}") + if before.self_deaf != after.self_deaf: + changes.append(f"Self Deaf: {'โœ…' if after.self_deaf else 'โŒ'}") + if before.mute != after.mute: + changes.append(f"Server Mute: {'โœ…' if after.mute else 'โŒ'}") + if before.deaf != after.deaf: + changes.append(f"Server Deaf: {'โœ…' if after.deaf else 'โŒ'}") + if before.streaming != after.streaming: + changes.append(f"Streaming: {'โœ…' if after.streaming else 'โŒ'}") + if before.self_video != after.self_video: + changes.append(f"Camera: {'โœ…' if after.self_video else 'โŒ'}") + + if changes: + event_type = "state_change" + title = "๐ŸŽ›๏ธ Voice Status geรคndert" + color = discord.Color.blue() + + if not event_type: + return + + embed = discord.Embed( + title=title, + color=color, + timestamp=datetime.utcnow() + ) + + # User Info + embed.add_field( + name="๐Ÿ‘ค User", + value=f"{member.mention}\n`{member}`", + inline=True + ) + + # Channel Info + if event_type == "join": + embed.add_field( + name="๐Ÿ“ Channel", + value=after.channel.mention, + inline=True + ) + # Wer ist noch im Channel? + other_members = [m for m in after.channel.members if m != member and not m.bot] + if other_members: + embed.add_field( + name="๐Ÿ‘ฅ Andere Mitglieder", + value=f"{len(other_members)} Mitglied{'er' if len(other_members) != 1 else ''}", + inline=True + ) + + elif event_type == "leave": + embed.add_field( + name="๐Ÿ“ Channel", + value=before.channel.mention, + inline=True + ) + # Session-Dauer berechnen wenn im Cache + if cached_before and cached_before.channel: + # Schรคtze Join-Zeit (grober Wert) + embed.add_field( + name="โฑ๏ธ Ungefรคhre Dauer", + value="Session beendet", + inline=True + ) + + elif event_type == "move": + embed.add_field( + name="๐Ÿ“ Von", + value=before.channel.mention, + inline=True + ) + embed.add_field( + name="๐Ÿ“ Nach", + value=after.channel.mention, + inline=True + ) + + elif event_type == "state_change": + embed.add_field( + name="๐Ÿ“ Channel", + value=after.channel.mention, + inline=True + ) + embed.add_field( + name="๐Ÿ”ง ร„nderungen", + value="\n".join(changes), + inline=False + ) + + embed.set_author(name=member.display_name, icon_url=member.display_avatar.url) + embed.set_footer(text=f"User ID: {member.id}") + + await self.send_log(guild_id, embed, "voice") + + except Exception as e: + logger.error(f"Error in on_voice_state_update: {e}") + self._stats['errors'] += 1 + + # ============================================================================= + # MEMBER UPDATE EVENTS + # ============================================================================= + + @commands.Cog.listener() + async def on_member_update(self, before: discord.Member, after: discord.Member): + """Member Update Logging mit intelligenter Filterung""" + try: + if before.bot: + return + + self._stats['events_processed'] += 1 + changes = [] + important_change = False + + # Nickname ร„nderung + if before.display_name != after.display_name: + changes.append({ + 'field': '๐Ÿท๏ธ Nickname', + 'before': before.display_name or "*Kein Nickname*", + 'after': after.display_name or "*Kein Nickname*" + }) + important_change = True + + # Rollen ร„nderung + before_roles = set(before.roles) + after_roles = set(after.roles) + + added_roles = after_roles - before_roles + removed_roles = before_roles - after_roles + + if added_roles or removed_roles: + important_change = True + + if added_roles: + role_names = [role.name for role in added_roles if role.name != "@everyone"] + if role_names: + changes.append({ + 'field': 'โž• Rollen hinzugefรผgt', + 'value': ", ".join(role_names[:5]) # Max 5 anzeigen + }) + + if removed_roles: + role_names = [role.name for role in removed_roles if role.name != "@everyone"] + if role_names: + changes.append({ + 'field': 'โž– Rollen entfernt', + 'value': ", ".join(role_names[:5]) # Max 5 anzeigen + }) + + # Premium Status (Nitro Boost) + if hasattr(before, 'premium_since') and hasattr(after, 'premium_since'): + if before.premium_since != after.premium_since: + if after.premium_since and not before.premium_since: + changes.append({ + 'field': '๐Ÿ’Ž Server Boost', + 'value': 'Begonnen zu boosten' + }) + important_change = True + elif before.premium_since and not after.premium_since: + changes.append({ + 'field': '๐Ÿ’Ž Server Boost', + 'value': 'Boost beendet' + }) + important_change = True + + # Timeout Status + if hasattr(before, 'timed_out_until') and hasattr(after, 'timed_out_until'): + if before.timed_out_until != after.timed_out_until: + if after.timed_out_until: + changes.append({ + 'field': 'โธ๏ธ Timeout', + 'value': f"Bis " + }) + important_change = True + elif before.timed_out_until: + changes.append({ + 'field': 'โธ๏ธ Timeout', + 'value': 'Timeout aufgehoben' + }) + important_change = True + + # Nur loggen wenn wichtige ร„nderungen + if not important_change or not changes: + return + + embed = discord.Embed( + title="๐Ÿ‘ค Member geรคndert", + color=discord.Color.blue(), + timestamp=datetime.utcnow() + ) + + embed.add_field( + name="๐Ÿ‘ค Member", + value=f"{after.mention}\n`{after}`", + inline=True + ) + + # ร„nderungen hinzufรผgen + for change in changes[:self.config['max_embed_fields'] - 2]: # Platz fรผr User und ID + if 'before' in change and 'after' in change: + value = f"**Vorher:** {change['before']}\n**Nachher:** {change['after']}" + else: + value = change['value'] + + embed.add_field( + name=change['field'], + value=value[:1024], # Discord limit + inline=False + ) + + embed.set_author(name=after.display_name, icon_url=after.display_avatar.url) + embed.set_footer(text=f"User ID: {after.id}") + + await self.send_log(after.guild.id, embed, "general") + + except Exception as e: + logger.error(f"Error in on_member_update: {e}") + self._stats['errors'] += 1 + + # ============================================================================= + # CHANNEL EVENTS + # ============================================================================= + + @commands.Cog.listener() + async def on_guild_channel_create(self, channel): + """Channel Creation Logging""" + try: + self._stats['events_processed'] += 1 + + embed = discord.Embed( + title="โž• Channel erstellt", + color=discord.Color.green(), + timestamp=datetime.utcnow() + ) + + # Channel-Typ Icon + type_icons = { + discord.ChannelType.text: "๐Ÿ’ฌ", + discord.ChannelType.voice: "๐Ÿ”Š", + discord.ChannelType.category: "๐Ÿ“", + discord.ChannelType.news: "๐Ÿ“ข", + discord.ChannelType.stage_voice: "๐ŸŽญ", + discord.ChannelType.forum: "๐Ÿ’ญ", + discord.ChannelType.private_thread: "๐Ÿงต", + discord.ChannelType.public_thread: "๐Ÿงต" + } + + icon = type_icons.get(channel.type, "๐Ÿ“") + embed.add_field( + name="๐Ÿ“ Channel", + value=f"{icon} {channel.mention}\n`{channel.name}`", + inline=True + ) + + embed.add_field( + name="๐Ÿ“‹ Typ", + value=channel.type.name.replace('_', ' ').title(), + inline=True + ) + + embed.add_field( + name="๐Ÿ†” ID", + value=f"`{channel.id}`", + inline=True + ) + + # Kategorie info + if hasattr(channel, 'category') and channel.category: + embed.add_field( + name="๐Ÿ“ Kategorie", + value=channel.category.name, + inline=True + ) + + # Position + if hasattr(channel, 'position'): + embed.add_field( + name="๐Ÿ“Š Position", + value=str(channel.position), + inline=True + ) + + embed.set_footer(text=f"Channel ID: {channel.id}") + await self.send_log(channel.guild.id, embed, "general") + + except Exception as e: + logger.error(f"Error in on_guild_channel_create: {e}") + self._stats['errors'] += 1 + + @commands.Cog.listener() + async def on_guild_channel_delete(self, channel): + """Channel Deletion Logging""" + try: + self._stats['events_processed'] += 1 + + embed = discord.Embed( + title="โž– Channel gelรถscht", + color=discord.Color.red(), + timestamp=datetime.utcnow() + ) + + # Channel-Typ Icon + type_icons = { + discord.ChannelType.text: "๐Ÿ’ฌ", + discord.ChannelType.voice: "๐Ÿ”Š", + discord.ChannelType.category: "๐Ÿ“", + discord.ChannelType.news: "๐Ÿ“ข", + discord.ChannelType.stage_voice: "๐ŸŽญ", + discord.ChannelType.forum: "๐Ÿ’ญ" + } + + icon = type_icons.get(channel.type, "๐Ÿ“") + embed.add_field( + name="๐Ÿ“ Channel", + value=f"{icon} `#{channel.name}`", + inline=True + ) + + embed.add_field( + name="๐Ÿ“‹ Typ", + value=channel.type.name.replace('_', ' ').title(), + inline=True + ) + + embed.add_field( + name="๐Ÿ†” ID", + value=f"`{channel.id}`", + inline=True + ) + + # Kategorie info + if hasattr(channel, 'category') and channel.category: + embed.add_field( + name="๐Ÿ“ Kategorie", + value=channel.category.name, + inline=True + ) + + embed.set_footer(text=f"Channel ID: {channel.id}") + await self.send_log(channel.guild.id, embed, "general") + + except Exception as e: + logger.error(f"Error in on_guild_channel_delete: {e}") + self._stats['errors'] += 1 + + # ============================================================================= + # BAN/KICK EVENTS + # ============================================================================= + + @commands.Cog.listener() + async def on_member_ban(self, guild: discord.Guild, user: discord.User): + """Member Ban Logging""" + try: + self._stats['events_processed'] += 1 + + # Versuche Ban-Info mit Grund zu holen + ban_info = None + try: + ban_info = await guild.fetch_ban(user) + except: + pass + + embed = discord.Embed( + title="๐Ÿ”จ Member gebannt", + color=discord.Color.dark_red(), + timestamp=datetime.utcnow() + ) + + embed.add_field( + name="๐Ÿ‘ค User", + value=f"{user.mention}\n`{user}`", + inline=True + ) + + embed.add_field( + name="๐Ÿ†” ID", + value=f"`{user.id}`", + inline=True + ) + + embed.add_field( + name="๐Ÿ“… Account erstellt", + value=f"", + inline=True + ) + + if ban_info and ban_info.reason: + embed.add_field( + name="๐Ÿ“ Grund", + value=ban_info.reason[:1000], + inline=False + ) + + embed.set_author(name=user.display_name, icon_url=user.display_avatar.url) + embed.set_footer(text=f"User ID: {user.id}") + + await self.send_log(guild.id, embed, "moderation") + + except Exception as e: + logger.error(f"Error in on_member_ban: {e}") + self._stats['errors'] += 1 + + @commands.Cog.listener() + async def on_member_unban(self, guild: discord.Guild, user: discord.User): + """Member Unban Logging""" + try: + self._stats['events_processed'] += 1 + + embed = discord.Embed( + title="๐Ÿ”“ Member entbannt", + color=discord.Color.green(), + timestamp=datetime.utcnow() + ) + + embed.add_field( + name="๐Ÿ‘ค User", + value=f"{user.mention}\n`{user}`", + inline=True + ) + + embed.add_field( + name="๐Ÿ†” ID", + value=f"`{user.id}`", + inline=True + ) + + embed.add_field( + name="๐Ÿ“… Account erstellt", + value=f"", + inline=True + ) + + embed.set_author(name=user.display_name, icon_url=user.display_avatar.url) + embed.set_footer(text=f"User ID: {user.id}") + + await self.send_log(guild.id, embed, "moderation") + + except Exception as e: + logger.error(f"Error in on_member_unban: {e}") + self._stats['errors'] += 1 + + # ============================================================================= + # INVITE EVENTS + # ============================================================================= + + @commands.Cog.listener() + async def on_invite_create(self, invite: discord.Invite): + """Invite Creation Logging""" + try: + self._stats['events_processed'] += 1 + + embed = discord.Embed( + title="๐Ÿ”— Invite erstellt", + color=discord.Color.blue(), + timestamp=datetime.utcnow() + ) + + embed.add_field( + name="๐Ÿ”— Invite Code", + value=f"`{invite.code}`", + inline=True + ) + + embed.add_field( + name="๐Ÿ“ Channel", + value=invite.channel.mention if invite.channel else "Unbekannt", + inline=True + ) + + if invite.inviter: + embed.add_field( + name="๐Ÿ‘ค Ersteller", + value=f"{invite.inviter.mention}\n`{invite.inviter}`", + inline=True + ) + + # Invite Settings + settings = [] + if invite.max_uses: + settings.append(f"Max. Nutzungen: {invite.max_uses}") + else: + settings.append("Max. Nutzungen: โˆž") + + if invite.max_age: + settings.append(f"Ablauf: ") + else: + settings.append("Ablauf: Nie") + + if invite.temporary: + settings.append("Temporรคr: Ja") + + if settings: + embed.add_field( + name="โš™๏ธ Einstellungen", + value="\n".join(settings), + inline=False + ) + + if invite.inviter: + embed.set_author(name=invite.inviter.display_name, icon_url=invite.inviter.display_avatar.url) + + embed.set_footer(text=f"Invite Code: {invite.code}") + await self.send_log(invite.guild.id, embed, "general") + + except Exception as e: + logger.error(f"Error in on_invite_create: {e}") + self._stats['errors'] += 1 + + @commands.Cog.listener() + async def on_invite_delete(self, invite: discord.Invite): + """Invite Deletion Logging""" + try: + self._stats['events_processed'] += 1 + + embed = discord.Embed( + title="๐Ÿ—‘๏ธ Invite gelรถscht", + color=discord.Color.red(), + timestamp=datetime.utcnow() + ) + + embed.add_field( + name="๐Ÿ”— Invite Code", + value=f"`{invite.code}`", + inline=True + ) + + embed.add_field( + name="๐Ÿ“ Channel", + value=invite.channel.mention if invite.channel else "Unbekannt", + inline=True + ) + + if invite.uses is not None: + embed.add_field( + name="๐Ÿ“Š Verwendet", + value=f"{invite.uses} mal", + inline=True + ) + + embed.set_footer(text=f"Invite Code: {invite.code}") + await self.send_log(invite.guild.id, embed, "general") + + except Exception as e: + logger.error(f"Error in on_invite_delete: {e}") + self._stats['errors'] += 1 + +def setup(bot): + bot.add_cog(LoggingCog(bot)) \ No newline at end of file diff --git a/src/bot/cogs/guild/tempvc.py b/src/bot/cogs/guild/tempvc.py new file mode 100644 index 0000000..87fb7ec --- /dev/null +++ b/src/bot/cogs/guild/tempvc.py @@ -0,0 +1,612 @@ +# Copyright (c) 2025 OPPRO.NET Network +from DevTools import TempVCDatabase +import discord +from discord import slash_command, option, SlashCommandGroup +from discord.ext import commands +from discord.ui import Container +import ezcord + +db = TempVCDatabase() + + +class TempChannelControlView(discord.ui.View): + def __init__(self, channel_owner_id: int, prefix: str = "๐Ÿ”ง"): + super().__init__(timeout=None) + self.channel_owner_id = channel_owner_id + self.prefix = prefix + + # Update button labels with custom prefix + self.rename_button.label = f"{prefix} Umbenennen" + self.limit_button.label = f"{prefix} Limit" + self.lock_button.label = f"{prefix} Sperren" + self.kick_button.label = f"{prefix} Kick" + + @discord.ui.button(label="๐Ÿ”ง Umbenennen", style=discord.ButtonStyle.primary, custom_id="tempvc_rename") + async def rename_button(self, button: discord.ui.Button, interaction: discord.Interaction): + if interaction.user.id != self.channel_owner_id: + container = Container() + container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") + return await interaction.response.send_message(view=container, ephemeral=True) + + modal = RenameChannelModal(interaction.channel) + await interaction.response.send_modal(modal) + + @discord.ui.button(label="๐Ÿ”ง Limit", style=discord.ButtonStyle.primary, custom_id="tempvc_limit") + async def limit_button(self, button: discord.ui.Button, interaction: discord.Interaction): + if interaction.user.id != self.channel_owner_id: + container = Container() + container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") + return await interaction.response.send_message(view=container, ephemeral=True) + + modal = UserLimitModal(interaction.channel) + await interaction.response.send_modal(modal) + + @discord.ui.button(label="๐Ÿ”ง Sperren", style=discord.ButtonStyle.secondary, custom_id="tempvc_lock") + async def lock_button(self, button: discord.ui.Button, interaction: discord.Interaction): + if interaction.user.id != self.channel_owner_id: + container = Container() + container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") + return await interaction.response.send_message(view=container, ephemeral=True) + + channel = interaction.channel + overwrites = channel.overwrites + + # Toggle lock status + is_locked = not overwrites.get(interaction.guild.default_role, discord.PermissionOverwrite()).connect + + if interaction.guild.default_role not in overwrites: + overwrites[interaction.guild.default_role] = discord.PermissionOverwrite() + + overwrites[interaction.guild.default_role].connect = not is_locked + + try: + await channel.edit(overwrites=overwrites) + status = "๐Ÿ”’ gesperrt" if is_locked else "๐Ÿ”“ entsperrt" + button.label = f"{self.prefix} {'Entsperren' if is_locked else 'Sperren'}" + button.style = discord.ButtonStyle.danger if is_locked else discord.ButtonStyle.secondary + + await interaction.response.edit_message(view=self) + + container = Container() + container.add_text(f"Channel wurde {status}!") + await interaction.followup.send(view=container, ephemeral=True) + except discord.Forbidden: + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen!") + await interaction.response.send_message(view=container, ephemeral=True) + + @discord.ui.button(label="๐Ÿ”ง Kick", style=discord.ButtonStyle.danger, custom_id="tempvc_kick") + async def kick_button(self, button: discord.ui.Button, interaction: discord.Interaction): + if interaction.user.id != self.channel_owner_id: + container = Container() + container.add_text(f"{emoji_no} Keine Berechtigung\nDu bist nicht der Besitzer dieses Channels!") + return await interaction.response.send_message(view=container, ephemeral=True) + + modal = KickUserModal(interaction.channel) + await interaction.response.send_modal(modal) + + +class RenameChannelModal(discord.ui.Modal): + def __init__(self, channel): + super().__init__(title="Channel umbenennen") + self.channel = channel + + self.name_input = discord.ui.InputText( + label="Neuer Channel-Name", + placeholder="Gib einen neuen Namen ein...", + value=channel.name, + max_length=100, + required=True + ) + self.add_item(self.name_input) + + async def callback(self, interaction: discord.Interaction): + new_name = self.name_input.value.strip() + + # Validate name + if len(new_name) < 1: + container = Container() + container.add_text(f"{emoji_no} Ungรผltiger Name\nName darf nicht leer sein!") + return await interaction.response.send_message(view=container, ephemeral=True) + + # Check for forbidden characters + forbidden_chars = ['@', '#', ':', '`', '```'] + if any(char in new_name for char in forbidden_chars): + container = Container() + container.add_text(f"{emoji_no} Ungรผltige Zeichen\nName enthรคlt ungรผltige Zeichen!") + return await interaction.response.send_message(view=container, ephemeral=True) + + try: + old_name = self.channel.name + await self.channel.edit(name=new_name) + + container = Container() + container.add_text( + f"{emoji_yes} Channel umbenannt\n" + f"**{old_name}** โ†’ **{new_name}**" + ) + await interaction.response.send_message(view=container, ephemeral=True) + + except discord.Forbidden: + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen zum Umbenennen!") + await interaction.response.send_message(view=container, ephemeral=True) + except discord.HTTPException as e: + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehler beim Umbenennen: {str(e)}") + await interaction.response.send_message(view=container, ephemeral=True) + + +class UserLimitModal(discord.ui.Modal): + def __init__(self, channel): + super().__init__(title="User-Limit setzen") + self.channel = channel + + current_limit = channel.user_limit if channel.user_limit else "Kein Limit" + + self.limit_input = discord.ui.InputText( + label="Neues User-Limit (0 = Kein Limit)", + placeholder="Gib eine Zahl zwischen 0-99 ein...", + value=str(current_limit) if isinstance(current_limit, int) else "0", + max_length=2, + required=True + ) + self.add_item(self.limit_input) + + async def callback(self, interaction: discord.Interaction): + try: + limit = int(self.limit_input.value.strip()) + + if limit < 0 or limit > 99: + container = Container() + container.add_text(f"{emoji_no} Ungรผltiges Limit\nLimit muss zwischen 0 und 99 liegen!") + return await interaction.response.send_message(view=container, ephemeral=True) + + # 0 means no limit in Discord + limit = None if limit == 0 else limit + + await self.channel.edit(user_limit=limit) + + limit_text = "Kein Limit" if limit is None else f"{limit} User" + + container = Container() + container.add_text( + f"{emoji_yes} User-Limit geรคndert\n" + f"Neues Limit: **{limit_text}**" + ) + await interaction.response.send_message(view=container, ephemeral=True) + + except ValueError: + container = Container() + container.add_text(f"{emoji_no} Ungรผltige Eingabe\nBitte gib eine gรผltige Zahl ein!") + await interaction.response.send_message(view=container, ephemeral=True) + except discord.Forbidden: + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen!") + await interaction.response.send_message(view=container, ephemeral=True) + except discord.HTTPException as e: + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehler beim Setzen des Limits: {str(e)}") + await interaction.response.send_message(view=container, ephemeral=True) + + +class KickUserModal(discord.ui.Modal): + def __init__(self, channel): + super().__init__(title="User kicken") + self.channel = channel + + # Create list of current members (except bot and channel owner) + members_list = [] + for member in channel.members: + if not member.bot and db.get_temp_channel_owner(channel.id) != member.id: + members_list.append(f"{member.display_name} ({member.id})") + + members_text = "\n".join(members_list[:10]) # Limit to first 10 for display + if len(members_list) > 10: + members_text += f"\n... und {len(members_list) - 10} weitere" + + self.user_input = discord.ui.InputText( + label="User zum Kicken", + placeholder="@Username oder User-ID...", + style=discord.InputTextStyle.short, + required=True + ) + self.add_item(self.user_input) + + if members_text: + self.info_input = discord.ui.InputText( + label="Aktuelle Mitglieder:", + value=members_text if members_text else "Keine anderen Mitglieder im Channel", + style=discord.InputTextStyle.paragraph, + required=False + ) + self.add_item(self.info_input) + + async def callback(self, interaction: discord.Interaction): + user_input = self.user_input.value.strip() + + # Try to find user by mention, name or ID + target_user = None + + # Check if it's a mention + if user_input.startswith('<@') and user_input.endswith('>'): + user_id = int(user_input[2:-1].replace('!', '')) + target_user = interaction.guild.get_member(user_id) + else: + # Try by ID first + try: + user_id = int(user_input) + target_user = interaction.guild.get_member(user_id) + except ValueError: + # Try by username/display name + for member in self.channel.members: + if (member.display_name.lower() == user_input.lower() or + member.name.lower() == user_input.lower()): + target_user = member + break + + if not target_user: + container = Container() + container.add_text(f"{emoji_no} Fehler\nUser nicht gefunden!") + return await interaction.response.send_message(view=container, ephemeral=True) + + if target_user not in self.channel.members: + container = Container() + container.add_text(f"{emoji_no} Fehler\nUser ist nicht in diesem Channel!") + return await interaction.response.send_message(view=container, ephemeral=True) + + if target_user.id == db.get_temp_channel_owner(self.channel.id): + container = Container() + container.add_text(f"{emoji_no} Fehler\nDu kannst dich nicht selbst kicken!") + return await interaction.response.send_message(view=container, ephemeral=True) + + if target_user.bot: + container = Container() + container.add_text(f"{emoji_no} Fehler\nBots kรถnnen nicht gekickt werden!") + return await interaction.response.send_message(view=container, ephemeral=True) + + try: + await target_user.move_to(None) # Disconnect from voice + + container = Container() + container.add_text( + f"{emoji_yes} User gekickt\n" + f"**{target_user.display_name}** wurde aus dem Channel gekickt." + ) + await interaction.response.send_message(view=container, ephemeral=True) + + except discord.Forbidden: + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehlende Berechtigungen zum Kicken!") + await interaction.response.send_message(view=container, ephemeral=True) + except discord.HTTPException as e: + container = Container() + container.add_text(f"{emoji_no} Fehler\nFehler beim Kicken: {str(e)}") + await interaction.response.send_message(view=container, ephemeral=True) + + +class TempVC(ezcord.Cog): + def __init__(self, bot): + self.bot = bot + + tempvc = SlashCommandGroup("tempvc", "Verwalte temporรคre Voice-Channel Systeme") + + @tempvc.command(name="create", description="Erstelle ein VC-Erstellungssystem") + @option("creator_channel", description="Channel, den Mitglieder betreten, um ihren VC zu erstellen", + channel_types=[discord.ChannelType.voice]) + @option("category", description="Kategorie, in der die Temp-Channels erstellt werden", + channel_types=[discord.ChannelType.category]) + async def tempvc_create(self, ctx: discord.ApplicationContext, creator_channel: discord.VoiceChannel, + category: discord.CategoryChannel): + if not ctx.author.guild_permissions.administrator: + container = Container() + container.add_text( + f"{emoji_no} Keine Berechtigung\n" + "Du brauchst Administratorrechte." + ) + return await ctx.respond(view=container, ephemeral=True) + + try: + db.set_tempvc_settings(ctx.guild.id, creator_channel.id, category.id) + + container = Container() + container.add_text( + f"{emoji_yes} Temp-VC System aktiviert\n" + "Das temporรคre Voice-Channel System wurde erfolgreich eingerichtet!" + ) + container.add_separator() + container.add_text( + f"**๐ŸŽค Ersteller-Channel:** {creator_channel.mention}\n" + f"**๐Ÿ“ Kategorie:** {category.mention}\n" + "**โ„น๏ธ Information:** Mitglieder kรถnnen nun den Ersteller-Channel betreten, um automatisch einen eigenen temporรคren Voice-Channel zu erhalten." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) + except Exception as e: + container = Container() + container.add_text( + f"{emoji_no} Fehler beim Erstellen\n" + f"```{str(e)}```" + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) + + @tempvc.command(name="remove", description="Entferne das VC-Erstellungssystem") + async def tempvc_remove(self, ctx: discord.ApplicationContext): + if not ctx.author.guild_permissions.administrator: + container = Container() + container.add_text( + f"{emoji_no} Keine Berechtigung\n" + "Du brauchst Administratorrechte." + ) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) + + try: + settings = db.get_tempvc_settings(ctx.guild.id) + if not settings: + container = Container() + container.add_text( + f"{emoji_no} Kein System aktiv\n" + "Es ist derzeit kein Temp-VC System auf diesem Server aktiv." + ) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) + + db.remove_tempvc_settings(ctx.guild.id) + + container = Container() + container.add_text( + f"{emoji_yes} System deaktiviert\n" + "Das Temp-VC System wurde erfolgreich deaktiviert!" + ) + container.add_separator() + container.add_text( + "**โ„น๏ธ Information:** Bestehende temporรคre Channels bleiben bestehen, aber es werden keine neuen mehr erstellt." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) + except Exception as e: + container = Container() + container.add_text( + f"{emoji_no} Fehler beim Entfernen\n" + f"```{str(e)}```" + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) + + @tempvc.command(name="settings", description="Zeige die aktuellen Temp-VC Einstellungen") + async def tempvc_settings(self, ctx: discord.ApplicationContext): + if not ctx.author.guild_permissions.administrator: + container = Container() + container.add_text( + f"{emoji_no} Keine Berechtigung\n" + "Du brauchst Administratorrechte." + ) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) + + settings = db.get_tempvc_settings(ctx.guild.id) + if not settings: + container = Container() + container.add_text( + f"{emoji_no} Kein System aktiv\n" + "Es ist derzeit kein Temp-VC System auf diesem Server aktiv." + ) + container.add_separator() + container.add_text( + "**๐Ÿ’ก Tipp:** Verwende `/tempvc create` um ein Temp-VC System einzurichten." + ) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) + + creator_channel_id, category_id, auto_delete_time = settings + creator_channel = ctx.guild.get_channel(creator_channel_id) + category = ctx.guild.get_channel(category_id) + + container = Container() + container.add_text("๐ŸŽ›๏ธ **Temp-VC Einstellungen**\nAktuelle Konfiguration des temporรคren Voice-Channel Systems") + container.add_separator() + + container.add_text( + f"**๐ŸŽค Ersteller-Channel:**\n" + f"{creator_channel.mention if creator_channel else f'{emoji_no} Channel nicht gefunden (ID: {creator_channel_id})'}" + ) + container.add_separator() + + container.add_text( + f"**๐Ÿ“ Kategorie:**\n" + f"{category.mention if category else f'{emoji_no} Kategorie nicht gefunden (ID: {category_id})'}" + ) + container.add_separator() + + container.add_text(f"**โฐ Auto-Lรถschzeit:**\n{auto_delete_time} Minuten") + container.add_separator() + + # UI Settings + ui_settings = db.get_ui_settings(ctx.guild.id) + if ui_settings: + ui_enabled, ui_prefix = ui_settings + container.add_text( + f"**๐Ÿ–ฅ๏ธ Control-UI:**\n" + f"{'โœ… Aktiviert' if ui_enabled else 'โŒ Deaktiviert'}" + ) + if ui_enabled: + container.add_separator() + container.add_text(f"**๐Ÿท๏ธ UI-Prefix:**\n{ui_prefix}") + else: + container.add_text("**๐Ÿ–ฅ๏ธ Control-UI:**\nโŒ Deaktiviert") + + container.add_separator() + container.add_text( + f"**โ„น๏ธ Status:**\n" + f"{emoji_yes + ' System aktiv' if creator_channel and category else emoji_no + ' Fehlerhafte Konfiguration'}" + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) + + @tempvc.command(name="ui", description="Konfiguriere das Control-UI fรผr Temp-Channels") + @option("enabled", description="Soll das UI aktiviert sein?", choices=[ + discord.OptionChoice(name="Aktiviert", value="true"), + discord.OptionChoice(name="Deaktiviert", value="false") + ]) + @option("prefix", description="Prefix fรผr UI-Buttons (Emoji oder Text)", required=False, default="๐Ÿ”ง") + async def tempvc_ui(self, ctx: discord.ApplicationContext, enabled: str, prefix: str = "๐Ÿ”ง"): + if not ctx.author.guild_permissions.administrator: + container = Container() + container.add_text( + f"{emoji_no} Keine Berechtigung\n" + "Du brauchst Administratorrechte." + ) + return await ctx.respond(view=container, ephemeral=True) + + # Check if TempVC system exists + settings = db.get_tempvc_settings(ctx.guild.id) + if not settings: + container = Container() + container.add_text( + f"{emoji_no} Kein System aktiv\n" + "Du musst zuerst ein Temp-VC System erstellen!" + ) + container.add_separator() + container.add_text( + "**๐Ÿ’ก Tipp:** Verwende `/tempvc create` um ein Temp-VC System einzurichten." + ) + view = discord.ui.View(container, timeout=None) + return await ctx.respond(view=view, ephemeral=True) + + ui_enabled = enabled == "true" + + # Validate prefix + if len(prefix) > 10: + container = Container() + container.add_text(f"{emoji_no} Ungรผltiger Prefix\nPrefix darf maximal 10 Zeichen lang sein!") + return await ctx.respond(view=container, ephemeral=True) + + try: + db.set_ui_settings(ctx.guild.id, ui_enabled, prefix) + + container = Container() + container.add_text(f"{emoji_yes} UI-Einstellungen gespeichert") + container.add_separator() + container.add_text( + f"**๐Ÿ–ฅ๏ธ Control-UI:** {'โœ… Aktiviert' if ui_enabled else 'โŒ Deaktiviert'}" + ) + if ui_enabled: + container.add_separator() + container.add_text(f"**๐Ÿท๏ธ Prefix:** {prefix}") + container.add_separator() + container.add_text( + "**โ„น๏ธ Information:** Das Control-UI wird nun in neu erstellten Temp-Channels angezeigt." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) + + except Exception as e: + container = Container() + container.add_text( + f"{emoji_no} Fehler beim Speichern\n" + f"```{str(e)}```" + ) + await ctx.respond(view=container, ephemeral=True) + + @commands.Cog.listener() + async def on_voice_state_update(self, member, before, after): + try: + if after.channel: + await self.handle_creator_channel_join(member, after.channel) + if before.channel: + await self.handle_channel_leave(before.channel) + except Exception as e: + print(f"Error in voice state update: {e}") + + async def handle_creator_channel_join(self, member: discord.Member, channel: discord.VoiceChannel): + settings = db.get_tempvc_settings(member.guild.id) + if not settings: + return + + creator_channel_id, category_id, auto_delete_time = settings + + if channel.id != creator_channel_id: + return + + guild = member.guild + category = discord.utils.get(guild.categories, id=category_id) + if not category: + print(f"Category with ID {category_id} not found in guild {guild.id}") + return + + overwrites = { + guild.default_role: discord.PermissionOverwrite(view_channel=False), + member: discord.PermissionOverwrite( + view_channel=True, + connect=True, + manage_permissions=True, + move_members=True + ) + } + + try: + temp_channel = await guild.create_voice_channel( + name=f"๐Ÿ”Š {member.display_name}'s Raum", + category=category, + overwrites=overwrites + ) + db.add_temp_channel(temp_channel.id, guild.id, member.id) + await member.move_to(temp_channel) + + # Check if UI is enabled and send control panel + ui_settings = db.get_ui_settings(guild.id) + if ui_settings and ui_settings[0]: # UI enabled + ui_enabled, ui_prefix = ui_settings + + container = Container() + container.add_text( + f"## ๐ŸŽ›๏ธ **Channel-Kontrolle**\n" + f"**{member.display_name}**, du bist der Besitzer dieses Channels!\n" + "Verwende die Buttons unten, um deinen Channel zu verwalten." + ) + container.add_separator() + container.add_text( + "**๐Ÿ”ง Verfรผgbare Aktionen:**\n" + "โ€ข **Umbenennen** - ร„ndere den Channel-Namen\n" + "โ€ข **Limit** - Setze ein User-Limit\n" + "โ€ข **Sperren** - Sperre/Entsperre den Channel\n" + "โ€ข **Kick** - Kicke User aus dem Channel" + ) + container.add_separator() + container.add_text("Diese Buttons funktionieren nur fรผr den Channel-Besitzer.") + + control_view = TempChannelControlView(member.id, ui_prefix) + view = discord.ui.View(container, timeout=None) + await temp_channel.send(view=view) + await temp_channel.send(view=control_view) + + except discord.Forbidden: + print(f"Missing permissions to create voice channel in guild {guild.id}") + except discord.HTTPException as e: + print(f"HTTP error when creating voice channel: {e}") + except Exception as e: + print(f"Unexpected error when creating temp channel: {e}") + + async def handle_channel_leave(self, channel: discord.VoiceChannel): + if len(channel.members) > 0: + return + + if not db.is_temp_channel(channel.id): + return + + try: + db.remove_temp_channel(channel.id) + await channel.delete(reason="Temp channel cleanup - channel empty") + + except discord.Forbidden: + print(f"Missing permissions to delete channel {channel.id}") + except discord.NotFound: + db.remove_temp_channel(channel.id) + except Exception as e: + print(f"Error deleting temp channel {channel.id}: {e}") + + +def setup(bot): + bot.add_cog(TempVC(bot)) \ No newline at end of file diff --git a/src/bot/cogs/guild/welcome.py b/src/bot/cogs/guild/welcome.py new file mode 100644 index 0000000..cc9fb69 --- /dev/null +++ b/src/bot/cogs/guild/welcome.py @@ -0,0 +1,1467 @@ +""" +Welcome System Cog +================== + +Umfassendes Welcome System mit Embed-Support, Auto-Roles, +DM-Nachrichten und Statistiken. +""" + +import discord +from discord.ext import commands +from DevTools import WelcomeDatabase +import asyncio +import json +import io +import logging +from typing import Optional, Dict, Any +import aiosqlite +from datetime import datetime +import ezcord +from discord.ui import Container + + +# Logger Setup +logger = logging.getLogger(__name__) + + +class WelcomeSystem(ezcord.Cog): + """ + Welcome System fรผr Discord Server. + + Bietet umfassende Willkommensnachrichten mit Embed-Support, + automatischen Rollen, privaten Nachrichten und Statistiken. + + Parameters + ---------- + bot : ezcord.Bot + Die Bot-Instanz + + Attributes + ---------- + bot : ezcord.Bot + Die Bot-Instanz + db : WelcomeDatabase + Datenbank-Handler fรผr Welcome-Einstellungen + _settings_cache : dict + Cache fรผr Server-Einstellungen + _cache_timeout : int + Cache-Timeout in Sekunden (Standard: 300) + _rate_limit_cache : dict + Rate-Limiting Cache fรผr Welcome-Messages + """ + + def __init__(self, bot): + """ + Initialisiert das Welcome System. + + Parameters + ---------- + bot : ezcord.Bot + Die Bot-Instanz + """ + self.bot = bot + self.db = WelcomeDatabase() + # Cache fรผr bessere Performance + self._settings_cache = {} + self._cache_timeout = 300 # 5 Minuten Cache + self._rate_limit_cache = {} # Rate Limiting + + async def get_cached_settings(self, guild_id: int): + """ + Holt Einstellungen mit Cache-Unterstรผtzung. + + Parameters + ---------- + guild_id : int + Discord Server ID + + Returns + ------- + dict or None + Server-Einstellungen aus Cache oder Datenbank + + Notes + ----- + Cache wird nach 5 Minuten automatisch invalidiert. + """ + now = asyncio.get_event_loop().time() + + if guild_id in self._settings_cache: + cached_data, timestamp = self._settings_cache[guild_id] + if now - timestamp < self._cache_timeout: + return cached_data + + # Aus Datenbank laden + settings = await self.db.get_welcome_settings(guild_id) + if settings: + self._settings_cache[guild_id] = (settings, now) + return settings + + def invalidate_cache(self, guild_id: int): + """ + Invalidiert Cache fรผr einen Server. + + Parameters + ---------- + guild_id : int + Discord Server ID + + Notes + ----- + Sollte nach jeder Einstellungsรคnderung aufgerufen werden. + """ + if guild_id in self._settings_cache: + del self._settings_cache[guild_id] + + def check_rate_limit(self, guild_id: int) -> bool: + """ + Prรผft Rate Limit fรผr Server. + + Parameters + ---------- + guild_id : int + Discord Server ID + + Returns + ------- + bool + True wenn Rate Limit nicht erreicht, False sonst + + Notes + ----- + Erlaubt maximal eine Welcome Message alle 5 Sekunden pro Server. + """ + now = asyncio.get_event_loop().time() + if guild_id not in self._rate_limit_cache: + self._rate_limit_cache[guild_id] = now + return True + + last_time = self._rate_limit_cache[guild_id] + if now - last_time >= 5: # 5 Sekunden zwischen Welcome Messages + self._rate_limit_cache[guild_id] = now + return True + + return False + + def replace_placeholders(self, text: str, member: discord.Member, guild: discord.Guild) -> str: + """ + Erweiterte Placeholder-Ersetzung mit Rรผckwรคrtskompatibilitรคt. + + Parameters + ---------- + text : str + Text mit Placeholders + member : discord.Member + Discord Member Objekt + guild : discord.Guild + Discord Guild Objekt + + Returns + ------- + str + Text mit ersetzten Placeholders + + Notes + ----- + Unterstรผtzte Placeholder-Kategorien: + - User: %user%, %username%, %mention%, %tag%, %userid% + - Server: %servername%, %server%, %guild%, %serverid%, %membercount% + - Zeit: %joindate%, %jointime%, %createddate%, %createdtime%, %accountage% + - Erweitert: %roles%, %rolecount%, %highestrole%, %avatar% + - Statistiken: %onlinemembers%, %textchannels%, %voicechannels% + + Examples + -------- + >>> text = "Willkommen %mention% auf %servername%!" + >>> replace_placeholders(text, member, guild) + "Willkommen @User auf Mein Server!" + """ + if not text: + return text + + try: + # Basis Placeholder (alte Version) + placeholders = { + '%user%': member.display_name, + '%username%': member.name, + '%mention%': member.mention, + '%tag%': str(member), + '%userid%': str(member.id), + '%servername%': guild.name, + '%serverid%': str(guild.id), + '%membercount%': str(guild.member_count), + '%joindate%': member.joined_at.strftime('%d.%m.%Y') if member.joined_at else 'Unbekannt', + '%createddate%': member.created_at.strftime('%d.%m.%Y'), + '%server%': guild.name, + '%guild%': guild.name, + } + + # Erweiterte Placeholder (neue Version) + try: + # Rolleninformationen + roles = [role.name for role in member.roles if role.name != "@everyone"] + highest_role = member.top_role.name if member.top_role.name != "@everyone" else "Keine" + + # Zeitberechnungen + account_age = (discord.utils.utcnow() - member.created_at).days + + # Online-Member zรคhlen (kann fehlschlagen bei groรŸen Servern) + try: + online_count = sum(1 for m in guild.members if m.status != discord.Status.offline) + except: + online_count = "Unbekannt" + + extended_placeholders = { + # Zeitinformationen + '%jointime%': member.joined_at.strftime('%H:%M') if member.joined_at else 'Unbekannt', + '%createdtime%': member.created_at.strftime('%H:%M'), + '%accountage%': f"{account_age} Tage", + + # Erweiterte Infos + '%discriminator%': member.discriminator if hasattr(member, 'discriminator') else "0000", + '%roles%': ', '.join(roles) if roles else 'Keine', + '%rolecount%': str(len(roles)), + '%highestrole%': highest_role, + '%avatar%': member.display_avatar.url, + '%defaultavatar%': member.default_avatar.url, + + # Server Statistiken + '%onlinemembers%': str(online_count), + '%textchannels%': str(len(guild.text_channels)), + '%voicechannels%': str(len(guild.voice_channels)), + '%categories%': str(len(guild.categories)), + '%emojis%': str(len(guild.emojis)), + } + + placeholders.update(extended_placeholders) + + except Exception as e: + logger.warning(f"Erweiterte Placeholder fehlgeschlagen: {e}") + + except Exception as e: + logger.error(f"Placeholder Fehler: {e}") + return text + + # Placeholder ersetzen + for placeholder, value in placeholders.items(): + text = text.replace(placeholder, str(value)) + + return text + + async def send_welcome_dm(self, member: discord.Member, settings: dict): + """ + Sendet private Willkommensnachricht. + + Parameters + ---------- + member : discord.Member + Neues Mitglied + settings : dict + Server-Einstellungen + + Notes + ----- + Fehler beim DM-Versand werden geloggt aber nicht als Fehler behandelt, + da viele User DMs deaktiviert haben. + """ + try: + if not settings.get('join_dm_enabled'): + return + + dm_message = settings.get('join_dm_message', + 'Willkommen auf **%servername%**! Schรถn, dass du da bist! ๐ŸŽ‰') + + processed_message = self.replace_placeholders(dm_message, member, member.guild) + + await member.send(processed_message) + logger.info(f"Welcome DM an {member} gesendet") + + except discord.Forbidden: + logger.warning(f"Konnte keine DM an {member} senden - DMs deaktiviert") + except Exception as e: + logger.error(f"Fehler beim Senden der Welcome DM: {e}") + + async def assign_auto_role(self, member: discord.Member, settings: dict): + """ + Vergibt automatische Rolle. + + Parameters + ---------- + member : discord.Member + Neues Mitglied + settings : dict + Server-Einstellungen mit auto_role_id + + Notes + ----- + Prรผft automatisch Berechtigungen und Rollen-Hierarchie. + """ + try: + auto_role_id = settings.get('auto_role_id') + if not auto_role_id: + return + + role = member.guild.get_role(auto_role_id) + if not role: + logger.warning(f"Auto-Role {auto_role_id} nicht gefunden in {member.guild.name}") + return + + if role >= member.guild.me.top_role: + logger.warning(f"Auto-Role {role.name} ist hรถher als Bot-Rolle") + return + + await member.add_roles(role, reason="Welcome Auto-Role") + logger.info(f"Auto-Role {role.name} an {member} vergeben") + + except discord.Forbidden: + logger.error(f"Keine Berechtigung fรผr Auto-Role") + except Exception as e: + logger.error(f"Auto-Role Fehler: {e}") + + @commands.Cog.listener() + async def on_member_join(self, member: discord.Member): + """ + Event wird ausgelรถst, wenn ein neuer User dem Server beitritt. + + Parameters + ---------- + member : discord.Member + Neues Mitglied + + Notes + ----- + Fรผhrt folgende Aktionen aus (wenn aktiviert): + 1. Rate Limiting Check + 2. Einstellungen aus Cache/DB laden + 3. Auto-Role vergeben + 4. Welcome Message senden (Channel) + 5. Welcome DM senden + 6. Statistiken aktualisieren + """ + try: + # Rate Limiting prรผfen + if not self.check_rate_limit(member.guild.id): + logger.info(f"Rate Limit aktiv fรผr {member.guild.name}") + return + + settings = await self.get_cached_settings(member.guild.id) + + if not settings or not settings.get('enabled', True): + return + + # Channel validieren + channel_id = settings.get('channel_id') + if not channel_id: + logger.warning(f"Kein Welcome Channel fรผr {member.guild.name} gesetzt") + return + + channel = self.bot.get_channel(channel_id) + if not channel: + logger.error(f"Welcome Channel {channel_id} nicht gefunden") + # Channel aus DB entfernen + await self.db.update_welcome_settings(member.guild.id, channel_id=None) + self.invalidate_cache(member.guild.id) + return + + # Permissions prรผfen + perms = channel.permissions_for(member.guild.me) + if not perms.send_messages: + logger.error(f"Keine Send-Berechtigung in {channel.name}") + return + + # Auto-Role vergeben + await self.assign_auto_role(member, settings) + + # Welcome Message + welcome_message = settings.get('welcome_message', 'Willkommen %mention% auf **%servername%**! ๐ŸŽ‰') + processed_message = self.replace_placeholders(welcome_message, member, member.guild) + + # Embed oder normale Nachricht + if settings.get('embed_enabled', False) and perms.embed_links: + await self.send_embed_welcome(channel, member, settings, processed_message) + else: + msg = await channel.send(processed_message) + await self.handle_auto_delete(msg, settings) + + # Private Nachricht senden + await self.send_welcome_dm(member, settings) + + # Statistiken aktualisieren + if settings.get('welcome_stats_enabled'): + await self.db.update_welcome_stats(member.guild.id, joins=1) + + except Exception as e: + logger.exception(f"Welcome System Fehler fรผr {member}: {e}") + + async def send_embed_welcome(self, channel, member, settings, processed_message): + """ + Sendet Embed Welcome Message. + + Parameters + ---------- + channel : discord.TextChannel + Ziel-Channel + member : discord.Member + Neues Mitglied + settings : dict + Server-Einstellungen + processed_message : str + Verarbeitete Welcome Message (Fallback) + + Notes + ----- + Fallback auf normale Nachricht bei Embed-Fehlern. + """ + try: + embed = discord.Embed() + + # Embed Farbe + color_hex = settings.get('embed_color', '#00ff00') + try: + color = int(color_hex.replace('#', ''), 16) + embed.color = discord.Color(color) + except: + embed.color = discord.Color.green() + + # Embed Titel + embed_title = settings.get('embed_title') + if embed_title: + embed.title = self.replace_placeholders(embed_title, member, member.guild) + + # Embed Beschreibung + embed_description = settings.get('embed_description') + if embed_description: + embed.description = self.replace_placeholders(embed_description, member, member.guild) + else: + embed.description = processed_message + + # Embed Thumbnail + if settings.get('embed_thumbnail', False): + embed.set_thumbnail(url=member.display_avatar.url) + + # Embed Footer + embed_footer = settings.get('embed_footer') + if embed_footer: + embed.set_footer(text=self.replace_placeholders(embed_footer, member, member.guild)) + + # Nachricht senden + content = member.mention if settings.get('ping_user', False) else None + msg = await channel.send(content=content, embed=embed) + + await self.handle_auto_delete(msg, settings) + + except Exception as e: + logger.error(f"Embed Welcome Fehler: {e}") + # Fallback auf normale Nachricht + msg = await channel.send(processed_message) + await self.handle_auto_delete(msg, settings) + + async def handle_auto_delete(self, message, settings): + """ + Behandelt automatisches Lรถschen von Nachrichten. + + Parameters + ---------- + message : discord.Message + Zu lรถschende Nachricht + settings : dict + Server-Einstellungen mit delete_after + + Notes + ----- + Wartet die angegebene Zeit und lรถscht dann die Nachricht. + Fehler beim Lรถschen werden geloggt aber nicht weitergegeben. + """ + try: + delete_after = settings.get('delete_after', 0) + if delete_after > 0: + await asyncio.sleep(delete_after) + try: + await message.delete() + except discord.NotFound: + pass # Message bereits gelรถscht + except discord.Forbidden: + logger.warning("Keine Berechtigung zum Lรถschen der Welcome Message") + except Exception as e: + logger.error(f"Auto-Delete Fehler: {e}") + + # Alle Commands bleiben gleich, aber mit Cache-Invalidierung + welcome = discord.SlashCommandGroup("welcome", "Welcome System Einstellungen") + + @welcome.command(name="channel", description="Setzt den Welcome Channel") + @commands.has_permissions(manage_guild=True) + async def set_welcome_channel(self, ctx, channel: discord.TextChannel): + """ + Setzt den Channel fรผr Welcome Messages. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + channel : discord.TextChannel + Ziel-Channel fรผr Welcome Messages + """ + success = await self.db.update_welcome_settings(ctx.guild.id, channel_id=channel.id) + self.invalidate_cache(ctx.guild.id) + + if success: + container = Container() + container.add_text( + f"{emoji_yes} Welcome Channel gesetzt" + ) + container.add_separator() + container.add_text( + f"Welcome Messages werden nun in {channel.mention} gesendet." + ) + view = discord.ui.View(container, timeout=None) + else: + container = Container() + container.add_text( + f"{emoji_no} Fehler" + ) + container.add_separator() + container.add_text( + "Der Welcome Channel konnte nicht gesetzt werden." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) + + @welcome.command(name="message", description="Setzt die Welcome Message รผber ein Modal") + @commands.has_permissions(manage_guild=True) + async def set_welcome_message(self, ctx): + """ + ร–ffnet ein Modal zum Setzen der Welcome Message. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + + Notes + ----- + Zeigt ein Modal mit der aktuellen Message als Vorausfรผllung. + Bietet nach dem Speichern eine Vorschau der neuen Message. + """ + + # Aktuelle Einstellungen laden fรผr Vorausfรผllung + current_settings = await self.get_cached_settings(ctx.guild.id) + current_message = current_settings.get('welcome_message', '') if current_settings else '' + + class WelcomeMessageModal(discord.ui.Modal): + """ + Modal fรผr Welcome Message Konfiguration. + + Parameters + ---------- + cog : WelcomeSystem + Parent Cog Instanz + current_msg : str, optional + Aktuelle Message fรผr Vorausfรผllung + """ + + def __init__(self, cog, current_msg=""): + super().__init__(title="Welcome Message konfigurieren") + self.cog = cog + + self.message_input = discord.ui.InputText( + label="Welcome Message", + placeholder="z.B: Willkommen %mention% auf **%servername%**! ๐ŸŽ‰", + style=discord.InputTextStyle.long, + value=current_msg, + max_length=2000, + required=True + ) + self.add_item(self.message_input) + + async def callback(self, interaction: discord.Interaction): + """ + Callback nach Modal-Submit. + + Parameters + ---------- + interaction : discord.Interaction + Modal Interaction + """ + message = self.message_input.value.strip() + + if not message: + embed = discord.Embed( + title="โŒ Fehler", + description="Die Welcome Message darf nicht leer sein.", + color=discord.Color.red() + ) + await interaction.response.send_message(embed=embed, ephemeral=True) + return + + success = await self.cog.db.update_welcome_settings(interaction.guild.id, welcome_message=message) + self.cog.invalidate_cache(interaction.guild.id) + + if success: + # Vorschau erstellen + preview = self.cog.replace_placeholders(message, interaction.user, interaction.guild) + + container = Container() + container.add_text( + "# โœ… Welcome Message gesetzt" + ) + container.add_separator() + container.add_text( + "## ๐Ÿ’ฌ Neue Message\n\n" + f"```{message[:500]}{'...' if len(message) > 500 else ''}```" + ) + container.add_separator() + container.add_text( + "## ๐Ÿ‘€ Vorschau (mit deinen Daten)\n\n" + f"{preview[:500] + ("..." if len(preview) > 500 else "")}\n\n" + "-# ๐Ÿ’ก Tipp: Verwende `/welcome test` fรผr eine vollstรคndige Vorschau oder `/welcome placeholders` fรผr alle verfรผgbaren Optionen." + ) + view = discord.ui.View(container, timeout=None) + else: + container = Container() + container.add_text( + "# โŒ Fehler\nDie Welcome Message konnte nicht gesetzt werden." + ) + view = discord.ui.View(container, timeout=None) + await interaction.response.send_message(view=view) + + modal = WelcomeMessageModal(self, current_message) + await ctx.send_modal(modal) + + @welcome.command(name="toggle", description="Schaltet das Welcome System ein/aus") + @commands.has_permissions(manage_guild=True) + async def toggle_welcome(self, ctx): + """ + Schaltet das Welcome System ein oder aus. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + """ + new_state = await self.db.toggle_welcome(ctx.guild.id) + self.invalidate_cache(ctx.guild.id) + + if new_state is None: + container = Container() + container.add_text( + "# โŒ Fehler\nEs sind noch keine Welcome Einstellungen vorhanden. Setze zuerst einen Channel." + ) + view = discord.ui.View(container, timeout=None) + else: + status = "aktiviert" if new_state else "deaktiviert" + container = Container() + container.add_text( + f"# โœ… Welcome System {status}" + ) + container.add_separator() + container.add_text( + f"Das Welcome System wurde **{status}**." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) + + @welcome.command(name="embed", description="Aktiviert/Deaktiviert Embed Modus") + @commands.has_permissions(manage_guild=True) + async def toggle_embed(self, ctx, enabled: bool): + """ + Aktiviert oder deaktiviert Embed Welcome Messages. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + enabled : bool + True fรผr Embed-Modus, False fรผr normale Nachrichten + """ + success = await self.db.update_welcome_settings(ctx.guild.id, embed_enabled=enabled) + self.invalidate_cache(ctx.guild.id) + + if success: + status = "aktiviert" if enabled else "deaktiviert" + container = Container( + f"# โœ… Embed Modus {status}" + ) + container.add_separator() + container.add_text( + f"Welcome Messages werden nun {'als Embed' if enabled else 'als normale Nachricht'} gesendet." + ) + view = discord.ui.View(container, timeout=None) + else: + container = Container() + container.add_text( + "# โŒ Fehler\nDer Embed Modus konnte nicht geรคndert werden." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) + + @welcome.command(name="autorole", description="Setzt eine Rolle die automatisch vergeben wird") + @commands.has_permissions(manage_roles=True) + async def set_auto_role(self, ctx, role: discord.Role = None): + """ + Setzt eine Rolle die bei Join automatisch vergeben wird. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + role : discord.Role, optional + Rolle zum automatischen Vergeben (None zum Entfernen) + + Notes + ----- + Prรผft automatisch die Rollen-Hierarchie. + """ + if role is None: + # Auto-Role entfernen + success = await self.db.update_welcome_settings(ctx.guild.id, auto_role_id=None) + self.invalidate_cache(ctx.guild.id) + + container = Container() + container.add_text( + "# โœ… Auto-Role entfernt" + ) + container.add_separator() + container.add_text( + "Neue Mitglieder erhalten keine automatische Rolle mehr." + ) + view = discord.ui.View(container, timeout=None) + + else: + # Rolle validieren + if role >= ctx.guild.me.top_role: + container = Container() + container.add_text( + "# โŒ Fehler\nDiese Rolle ist hรถher als meine hรถchste Rolle. Ich kann sie nicht vergeben." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) + return + + success = await self.db.update_welcome_settings(ctx.guild.id, auto_role_id=role.id) + self.invalidate_cache(ctx.guild.id) + + if success: + container = Container() + container.add_text( + "# โœ… Auto-Role gesetzt" + ) + container.add_separator() + container.add_text( + f"Neue Mitglieder erhalten automatisch die Rolle {role.mention}." + ) + view = discord.ui.View(container, timeout=None) + else: + container = Container() + container.add_text( + "# โŒ Fehler\nDie Auto-Role konnte nicht gesetzt werden." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) + + @welcome.command(name="dm", description="Aktiviert/Konfiguriert private Willkommensnachrichten") + @commands.has_permissions(manage_guild=True) + async def setup_join_dm(self, ctx, enabled: bool, *, message: str = None): + """ + Konfiguriert private Willkommensnachrichten. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + enabled : bool + True zum Aktivieren, False zum Deaktivieren + message : str, optional + Custom DM Message (verwendet Standard wenn nicht angegeben) + """ + settings = {'join_dm_enabled': enabled} + if message and enabled: + settings['join_dm_message'] = message + + success = await self.db.update_welcome_settings(ctx.guild.id, **settings) + self.invalidate_cache(ctx.guild.id) + + if success: + if enabled: + if message: + description = f"Private Welcome Messages aktiviert!\n**Nachricht:** {message[:500]}{'...' if len(message) > 500 else ''}" + else: + description = "Private Welcome Messages aktiviert! (Standard-Nachricht wird verwendet)" + else: + description = "Private Welcome Messages deaktiviert." + + container = Container() + container.add_text( + "# โœ… DM Einstellungen aktualisiert" + ) + container.add_separator() + container.add_text( + f"{description}" + ) + view = discord.ui.View(container, timeout=None) + else: + container = Container() + container.add_text( + "# โŒ Fehler\nDie DM Einstellungen konnten nicht aktualisiert werden." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) + + @welcome.command(name="template", description="Lรคdt eine Vorlage") + @commands.has_permissions(manage_guild=True) + async def load_template(self, ctx, template_name: str): + """ + Lรคdt eine vordefinierte Vorlage. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + template_name : str + Name der Vorlage (basic, fancy, minimal, detailed) + + Notes + ----- + Verfรผgbare Vorlagen: + - basic: Einfache Text-Nachricht + - fancy: Embed mit Thumbnail und Farbe + - minimal: Minimalistischer Text + - detailed: Detailliertes Embed mit vielen Infos + """ + templates = { + "basic": { + "welcome_message": "Willkommen %mention% auf **%servername%**! ๐ŸŽ‰", + "embed_enabled": False, + "template_name": "basic" + }, + "fancy": { + "welcome_message": None, + "embed_enabled": True, + "embed_title": "Willkommen auf %servername%! ๐ŸŽ‰", + "embed_description": "Hey %user%! Du bist unser **%membercount%.** Mitglied!\n\nViel SpaรŸ auf unserem Server! ๐Ÿš€", + "embed_color": "#ff6b6b", + "embed_thumbnail": True, + "embed_footer": "Beigetreten am %joindate%", + "template_name": "fancy" + }, + "minimal": { + "welcome_message": "%user% ist dem Server beigetreten.", + "embed_enabled": False, + "template_name": "minimal" + }, + "detailed": { + "welcome_message": None, + "embed_enabled": True, + "embed_title": "๐ŸŽŠ Neues Mitglied!", + "embed_description": "**%mention%** ist **%servername%** beigetreten!\n\n๐Ÿ‘ค **Username:** %username%\n๐Ÿ“… **Account erstellt:** %createddate%\n๐Ÿ“Š **Mitglied Nr.:** %membercount%\nโฐ **Beigetreten um:** %jointime%", + "embed_color": "#00d4ff", + "embed_thumbnail": True, + "embed_footer": "%servername% โ€ข %membercount% Mitglieder", + "template_name": "detailed" + } + } + + if template_name not in templates: + available = ", ".join(templates.keys()) + embed = discord.Embed( + title="โŒ Unbekannte Vorlage", + description=f"**Verfรผgbare Vorlagen:** {available}", + color=discord.Color.red() + ) + await ctx.respond(embed=embed) + return + + template = templates[template_name] + success = await self.db.update_welcome_settings(ctx.guild.id, **template) + self.invalidate_cache(ctx.guild.id) + + if success: + embed = discord.Embed( + title=f"โœ… Vorlage '{template_name}' geladen", + description="Die Welcome-Konfiguration wurde aktualisiert.", + color=discord.Color.green() + ) + + # Vorschau anzeigen + if template_name == "basic": + embed.add_field(name="Vorschau", value="Willkommen @User auf **Servername**! ๐ŸŽ‰", inline=False) + elif template_name == "minimal": + embed.add_field(name="Vorschau", value="Username ist dem Server beigetreten.", inline=False) + else: + embed.add_field(name="Typ", value="Embed-Nachricht", inline=False) + else: + embed = discord.Embed( + title="โŒ Fehler", + description="Die Vorlage konnte nicht geladen werden.", + color=discord.Color.red() + ) + + await ctx.respond(embed=embed) + + @welcome.command(name="config", description="Zeigt die aktuelle Konfiguration") + @commands.has_permissions(manage_messages=True) + async def show_config(self, ctx): + """ + Zeigt die aktuelle Welcome Konfiguration. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + + Notes + ----- + Zeigt alle konfigurierten Einstellungen รผbersichtlich an. + """ + settings = await self.get_cached_settings(ctx.guild.id) + + if not settings: + container = Container() + container.add_text( + "# โŒ Keine Konfiguration gefunden\nEs sind noch keine Welcome Einstellungen vorhanden." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) + return + + channel = self.bot.get_channel(settings.get('channel_id')) if settings.get('channel_id') else None + auto_role = ctx.guild.get_role(settings.get('auto_role_id')) if settings.get('auto_role_id') else None + container = Container() + container.add_text( + "# โš™๏ธ Welcome System Konfiguration" + ) + container.add_separator() + container.add_text( + "## ๐Ÿ“Š Status\n" + f"{'โœ… Aktiviert' if settings.get('enabled') else 'โŒ Deaktiviert'}" + ) + + container.add_text( + "## ๐Ÿ“ข Channel\n" + f"{channel.mention if channel else 'โŒ Nicht gesetzt'}" + ) + + container.add_text( + "## ๐ŸŽจ Embed Modus\n" + f"{'โœ… Aktiviert' if settings.get('embed_enabled') else 'โŒ Deaktiviert'}" + ) + + container.add_text( + "## ๐Ÿท๏ธ Auto-Role\n" + f"{auto_role.mention if auto_role else 'โŒ Rolle nicht gefunden'}" + ) + + if settings.get('join_dm_enabled'): + container.add_text( + "## ๐Ÿ’Œ Private Nachricht\nโœ… Aktiviert" + ) + + if settings.get('template_name'): + container.add_text( + "## ๐Ÿ“‹ Vorlage\n" + f"{settings.get('template_name').title()}" + ) + + message = settings.get('welcome_message', 'Nicht gesetzt') + if len(message) > 100: + message = message[:100] + "..." + container.add_text( + "## ๐Ÿ’ฌ Welcome Message\n" + f"{message}" + ) + + if settings.get('delete_after', 0) > 0: + container.add_text( + "## ๐Ÿ—‘๏ธ Auto-Delete\n" + f"{settings.get('delete_after')} Sekunden" + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view) + + @welcome.command(name="test", description="Testet die Welcome Message") + @commands.has_permissions(manage_messages=True) + async def test_welcome(self, ctx): + """ + Testet die Welcome Message mit dem aktuellen User. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + + Notes + ----- + Simuliert einen Member Join mit den aktuellen Einstellungen. + Zeigt eine Vorschau ohne tatsรคchlich eine Welcome Message zu senden. + """ + settings = await self.get_cached_settings(ctx.guild.id) + + if not settings: + container = Container() + container.add_text( + "# โŒ Fehler\nEs sind noch keine Welcome Einstellungen vorhanden." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) + return + + if not settings.get('channel_id'): + container = Container() + container.add_text( + "# โŒ Fehler\nEs ist kein Welcome Channel gesetzt." + ) + view = discord.ui.View(container, timeout=None) + await ctx.respond(view=view, ephemeral=True) + return + + # Simuliere Member Join Event + member = ctx.author + welcome_message = settings.get('welcome_message', 'Willkommen %mention% auf **%servername%**! ๐ŸŽ‰') + processed_message = self.replace_placeholders(welcome_message, member, ctx.guild) + + embed = discord.Embed( + title="๐Ÿงช Welcome Message Test", + color=discord.Color.blue() + ) + + if settings.get('embed_enabled'): + embed.add_field( + name="Typ", + value="Embed-Nachricht", + inline=True + ) + + test_embed_title = settings.get('embed_title', 'Kein Titel') + if test_embed_title: + test_embed_title = self.replace_placeholders(test_embed_title, member, ctx.guild) + embed.add_field(name="Embed Titel", value=test_embed_title, inline=False) + + test_embed_desc = settings.get('embed_description', processed_message) + if test_embed_desc: + test_embed_desc = self.replace_placeholders(test_embed_desc, member, ctx.guild) + embed.add_field(name="Embed Beschreibung", value=test_embed_desc[:500] + ("..." if len(test_embed_desc) > 500 else ""), inline=False) + else: + embed.add_field( + name="Typ", + value="Normale Nachricht", + inline=True + ) + embed.add_field( + name="Vorschau", + value=processed_message[:500] + ("..." if len(processed_message) > 500 else ""), + inline=False + ) + + # Zusรคtzliche Infos + if settings.get('auto_role_id'): + auto_role = ctx.guild.get_role(settings.get('auto_role_id')) + embed.add_field( + name="๐Ÿท๏ธ Auto-Role", + value=auto_role.mention if auto_role else "โŒ Rolle nicht gefunden", + inline=True + ) + + if settings.get('join_dm_enabled'): + embed.add_field( + name="๐Ÿ’Œ Private Nachricht", + value="โœ… Wรผrde gesendet werden", + inline=True + ) + + await ctx.respond(embed=embed, ephemeral=True) + + @welcome.command(name="placeholders", description="Zeigt alle verfรผgbaren Placeholder") + async def show_placeholders(self, ctx): + """ + Zeigt alle verfรผgbaren Placeholder. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + + Notes + ----- + Liste aller unterstรผtzten Placeholder mit Beschreibungen. + """ + embed = discord.Embed( + title="๐Ÿ“ Verfรผgbare Placeholder", + description="Diese Placeholder kรถnnen in Welcome Messages verwendet werden:", + color=discord.Color.blue() + ) + + embed.add_field( + name="๐Ÿ‘ค User Informationen", + value=( + "`%user%` - Username (Display Name)\n" + "`%username%` - Echter Username\n" + "`%mention%` - User erwรคhnen (@User)\n" + "`%tag%` - User#1234\n" + "`%userid%` - User ID\n" + "`%discriminator%` - User Discriminator" + ), + inline=False + ) + + embed.add_field( + name="๐Ÿ  Server Informationen", + value=( + "`%servername%` - Servername\n" + "`%server%` - Servername (Alternative)\n" + "`%guild%` - Servername (Alternative)\n" + "`%serverid%` - Server ID\n" + "`%membercount%` - Mitgliederanzahl\n" + "`%onlinemembers%` - Online Mitglieder" + ), + inline=False + ) + + embed.add_field( + name="โฐ Zeit & Datum", + value=( + "`%joindate%` - Beitrittsdatum (DD.MM.YYYY)\n" + "`%jointime%` - Beitrittszeit (HH:MM)\n" + "`%createddate%` - Account Erstellung (DD.MM.YYYY)\n" + "`%createdtime%` - Account Erstellung (HH:MM)\n" + "`%accountage%` - Account Alter in Tagen" + ), + inline=False + ) + + embed.add_field( + name="๐ŸŽญ Erweiterte Informationen", + value=( + "`%roles%` - Alle Rollen (auรŸer @everyone)\n" + "`%rolecount%` - Anzahl der Rollen\n" + "`%highestrole%` - Hรถchste Rolle\n" + "`%avatar%` - Avatar URL\n" + "`%defaultavatar%` - Standard Avatar URL" + ), + inline=False + ) + + embed.add_field( + name="๐Ÿ“Š Server Statistiken", + value=( + "`%textchannels%` - Anzahl Textchannels\n" + "`%voicechannels%` - Anzahl Voicechannels\n" + "`%categories%` - Anzahl Kategorien\n" + "`%emojis%` - Anzahl Emojis" + ), + inline=False + ) + + embed.set_footer(text="Beispiel: Willkommen %mention%! Du bist Mitglied #%membercount% auf %servername%") + + await ctx.respond(embed=embed, ephemeral=True) + + @welcome.command(name="export", description="Exportiert die Welcome Konfiguration") + @commands.has_permissions(administrator=True) + async def export_config(self, ctx): + """ + Exportiert die aktuelle Konfiguration als JSON-Datei. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + + Notes + ----- + Erstellt eine JSON-Datei mit allen Einstellungen. + Sensible Daten (IDs, Timestamps) werden entfernt. + """ + settings = await self.get_cached_settings(ctx.guild.id) + if not settings: + embed = discord.Embed( + title="โŒ Keine Konfiguration zum Exportieren", + description="Es sind noch keine Welcome Einstellungen vorhanden.", + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + try: + # Sensible Daten entfernen + export_data = {k: v for k, v in settings.items() + if k not in ['guild_id', 'created_at', 'updated_at']} + + # JSON Export erstellen + config_json = json.dumps(export_data, indent=2, ensure_ascii=False) + + # Als Datei senden + file_content = f"# Welcome System Export fรผr {ctx.guild.name}\n# Exportiert am {datetime.now().strftime('%d.%m.%Y %H:%M')}\n\n{config_json}" + file = discord.File( + io.StringIO(file_content), + filename=f"welcome_config_{ctx.guild.name.replace(' ', '_')}.json" + ) + + embed = discord.Embed( + title="๐Ÿ“„ Konfiguration exportiert", + description="Die aktuelle Welcome-Konfiguration wurde als Datei exportiert.", + color=discord.Color.green() + ) + + await ctx.respond(embed=embed, file=file, ephemeral=True) + + except Exception as e: + logger.error(f"Export Fehler: {e}") + embed = discord.Embed( + title="โŒ Export fehlgeschlagen", + description="Es ist ein Fehler beim Exportieren aufgetreten.", + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + + @welcome.command(name="stats", description="Zeigt Welcome Statistiken") + @commands.has_permissions(manage_messages=True) + async def show_stats(self, ctx): + """ + Zeigt Welcome Statistiken fรผr den Server. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + + Notes + ----- + Zeigt Statistiken fรผr: + - Heute + - Diese Woche (letzte 7 Tage) + - Gesamt (seit Aktivierung) + """ + try: + await self.db.migrate_database() + + # Statistiken aktivieren falls noch nicht geschehen + settings = await self.get_cached_settings(ctx.guild.id) + if settings and not settings.get('welcome_stats_enabled'): + await self.db.update_welcome_settings(ctx.guild.id, welcome_stats_enabled=True) + self.invalidate_cache(ctx.guild.id) + + # Aktuelle Statistiken aus der DB holen + try: + async with aiosqlite.connect(self.db.db_path) as conn: + # Heute + today = datetime.now().strftime('%Y-%m-%d') + cursor = await conn.execute( + 'SELECT joins, leaves FROM welcome_stats WHERE guild_id = ? AND date = ?', + (ctx.guild.id, today) + ) + today_stats = await cursor.fetchone() + + # Letzte 7 Tage + cursor = await conn.execute(''' + SELECT SUM(joins) as total_joins, SUM(leaves) as total_leaves + FROM welcome_stats + WHERE guild_id = ? AND date >= date('now', '-7 days') + ''', (ctx.guild.id,)) + week_stats = await cursor.fetchone() + + # Gesamt + cursor = await conn.execute(''' + SELECT SUM(joins) as total_joins, SUM(leaves) as total_leaves + FROM welcome_stats + WHERE guild_id = ? + ''', (ctx.guild.id,)) + total_stats = await cursor.fetchone() + + embed = discord.Embed( + title="๐Ÿ“Š Welcome Statistiken", + description=f"Statistiken fรผr **{ctx.guild.name}**", + color=discord.Color.blue() + ) + + # Heute + today_joins = today_stats[0] if today_stats else 0 + today_leaves = today_stats[1] if today_stats else 0 + embed.add_field( + name="๐Ÿ“… Heute", + value=f"๐Ÿ‘‹ **Beigetreten:** {today_joins}\n๐Ÿšช **Verlassen:** {today_leaves}", + inline=True + ) + + # Diese Woche + week_joins = week_stats[0] if week_stats and week_stats[0] else 0 + week_leaves = week_stats[1] if week_stats and week_stats[1] else 0 + embed.add_field( + name="๐Ÿ“… Diese Woche", + value=f"๐Ÿ‘‹ **Beigetreten:** {week_joins}\n๐Ÿšช **Verlassen:** {week_leaves}", + inline=True + ) + + # Gesamt + total_joins = total_stats[0] if total_stats and total_stats[0] else 0 + total_leaves = total_stats[1] if total_stats and total_stats[1] else 0 + embed.add_field( + name="๐Ÿ“Š Gesamt", + value=f"๐Ÿ‘‹ **Beigetreten:** {total_joins}\n๐Ÿšช **Verlassen:** {total_leaves}", + inline=True + ) + + # Aktuelle Server Info + embed.add_field( + name="โ„น๏ธ Server Info", + value=f"๐Ÿ‘ฅ **Aktuelle Mitglieder:** {ctx.guild.member_count}\n๐Ÿ“ˆ **Netto Wachstum:** {total_joins - total_leaves}", + inline=False + ) + + embed.set_footer(text="Statistiken werden seit der Aktivierung des Systems gesammelt") + + except Exception as e: + logger.error(f"Stats DB Error: {e}") + embed = discord.Embed( + title="๐Ÿ“Š Welcome Statistiken", + description="Statistiken werden ab sofort gesammelt und beim nรคchsten Aufruf angezeigt.", + color=discord.Color.blue() + ) + embed.add_field( + name="โ„น๏ธ Server Info", + value=f"๐Ÿ‘ฅ **Aktuelle Mitglieder:** {ctx.guild.member_count}", + inline=False + ) + + await ctx.respond(embed=embed) + + except Exception as e: + logger.error(f"Stats Command Error: {e}") + embed = discord.Embed( + title="โŒ Fehler", + description="Statistiken konnten nicht geladen werden.", + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + + @welcome.command(name="reset", description="Setzt alle Welcome Einstellungen zurรผck") + @commands.has_permissions(administrator=True) + async def reset_welcome(self, ctx): + """ + Setzt alle Welcome Einstellungen zurรผck. + + Parameters + ---------- + ctx : discord.ApplicationContext + Slash Command Context + + Notes + ----- + Zeigt eine Bestรคtigungsabfrage vor dem Lรถschen. + Diese Aktion kann nicht rรผckgรคngig gemacht werden. + """ + + # Bestรคtigungs-View + class ConfirmView(discord.ui.View): + """ + Bestรคtigungs-View fรผr Reset. + + Attributes + ---------- + confirmed : bool + Ob der Reset bestรคtigt wurde + """ + + def __init__(self): + super().__init__(timeout=30) + self.confirmed = False + + @discord.ui.button(label="โœ… Ja, zurรผcksetzen", style=discord.ButtonStyle.danger) + async def confirm_button(self, button: discord.ui.Button, interaction: discord.Interaction): + """ + Bestรคtigung des Resets. + + Parameters + ---------- + button : discord.ui.Button + Geklickter Button + interaction : discord.Interaction + Button Interaction + """ + self.confirmed = True + self.stop() + + success = await ctx.cog.db.delete_welcome_settings(ctx.guild.id) + ctx.cog.invalidate_cache(ctx.guild.id) + + if success: + embed = discord.Embed( + title="โœ… Einstellungen zurรผckgesetzt", + description="Alle Welcome Einstellungen wurden erfolgreich gelรถscht.", + color=discord.Color.green() + ) + else: + embed = discord.Embed( + title="โŒ Fehler", + description="Die Einstellungen konnten nicht zurรผckgesetzt werden.", + color=discord.Color.red() + ) + + await interaction.response.edit_message(embed=embed, view=None) + + @discord.ui.button(label="โŒ Abbrechen", style=discord.ButtonStyle.secondary) + async def cancel_button(self, button: discord.ui.Button, interaction: discord.Interaction): + """ + Abbruch des Resets. + + Parameters + ---------- + button : discord.ui.Button + Geklickter Button + interaction : discord.Interaction + Button Interaction + """ + self.stop() + + embed = discord.Embed( + title="โŒ Abgebrochen", + description="Die Einstellungen wurden nicht zurรผckgesetzt.", + color=discord.Color.orange() + ) + + await interaction.response.edit_message(embed=embed, view=None) + + embed = discord.Embed( + title="โš ๏ธ Einstellungen zurรผcksetzen", + description="Bist du sicher, dass du **alle** Welcome Einstellungen lรถschen mรถchtest?\n\n**Diese Aktion kann nicht rรผckgรคngig gemacht werden!**", + color=discord.Color.orange() + ) + + view = ConfirmView() + await ctx.respond(embed=embed, view=view, ephemeral=True) + + # Event Listeners fรผr Statistiken + @commands.Cog.listener() + async def on_member_remove(self, member: discord.Member): + """ + Tracking fรผr Member Leaves. + + Parameters + ---------- + member : discord.Member + Mitglied das den Server verlassen hat + + Notes + ----- + Aktualisiert die Statistiken wenn aktiviert. + """ + try: + settings = await self.get_cached_settings(member.guild.id) + if settings and settings.get('welcome_stats_enabled'): + await self.db.update_welcome_stats(member.guild.id, leaves=1) + except Exception as e: + logger.error(f"Leave Stats Error: {e}") + + +def setup(bot): + """ + Setup-Funktion fรผr das Cog. + + Parameters + ---------- + bot : ezcord.Bot + Bot-Instanz + + Notes + ----- + Wird automatisch von discord.py beim Laden des Cogs aufgerufen. + """ + bot.add_cog(WelcomeSystem(bot)) \ No newline at end of file diff --git a/src/bot/cogs/management/autodelete.py b/src/bot/cogs/management/autodelete.py new file mode 100644 index 0000000..9ba365c --- /dev/null +++ b/src/bot/cogs/management/autodelete.py @@ -0,0 +1,309 @@ +from DevTools import AutoDeleteDB +import discord +from discord.ext import tasks +from discord.commands import SlashCommandGroup, Option +import ezcord +import asyncio +from datetime import datetime, timedelta +import logging + +logger = logging.getLogger(__name__) + + +class AutoDelete(ezcord.Cog): + def __init__(self, bot): + self.bot = bot + self.delete_task.start() + self.processing_channels = set() # Verhindert doppelte Verarbeitung + + autodelete = SlashCommandGroup("autodelete", "Automatische Nachrichtenlรถschung") + + @autodelete.command(name="setup", description="Richtet AutoDelete fรผr einen Kanal ein.") + async def setup(self, ctx, + channel: Option(discord.TextChannel, "Kanal", required=True), + duration: Option(int, "Zeit in Sekunden (min: 60, max: 604800)", required=True), + exclude_pinned: Option(bool, "Angepinnte Nachrichten ausschlieรŸen", default=True), + exclude_bots: Option(bool, "Bot-Nachrichten ausschlieรŸen", default=False)): + + # Validierung + if duration < 60: + await ctx.respond("โŒ Mindestdauer ist 60 Sekunden (1 Minute).", ephemeral=True) + return + if duration > 604800: + await ctx.respond("โŒ Maximaldauer ist 604800 Sekunden (7 Tage).", ephemeral=True) + return + + # Permissions prรผfen + if not channel.permissions_for(ctx.guild.me).manage_messages: + await ctx.respond("โŒ Ich habe keine Berechtigung, Nachrichten in diesem Kanal zu lรถschen.", ephemeral=True) + return + + db = AutoDeleteDB() + db.add_autodelete(channel.id, duration, exclude_pinned, exclude_bots) + + duration_str = self._format_duration(duration) + await ctx.respond( + f"โœ… AutoDelete fรผr {channel.mention} wurde aktiviert!\n" + f"๐Ÿ“… Dauer: {duration_str}\n" + f"๐Ÿ“Œ Angepinnte Nachrichten: {'Ausgeschlossen' if exclude_pinned else 'Eingeschlossen'}\n" + f"๐Ÿค– Bot-Nachrichten: {'Ausgeschlossen' if exclude_bots else 'Eingeschlossen'}", + ephemeral=True + ) + + @autodelete.command(name="list", description="Zeigt alle aktiven AutoDelete-Kanรคle.") + async def list(self, ctx): + db = AutoDeleteDB() + channels = db.get_all() + if not channels: + await ctx.respond("โŒ Keine AutoDelete-Kanรคle gefunden.", ephemeral=True) + return + + embed = discord.Embed( + title="๐Ÿ—‘๏ธ Aktive AutoDelete-Kanรคle", + color=discord.Color.blue(), + timestamp=datetime.utcnow() + ) + + for chan_id, duration, exclude_pinned, exclude_bots in channels: + channel = self.bot.get_channel(chan_id) + if channel: + duration_str = self._format_duration(duration) + settings = [] + if exclude_pinned: + settings.append("๐Ÿ“Œ Angepinnte ausgeschlossen") + if exclude_bots: + settings.append("๐Ÿค– Bots ausgeschlossen") + + settings_str = "\n".join(settings) if settings else "Keine besonderen Einstellungen" + + embed.add_field( + name=f"#{channel.name}", + value=f"โฑ๏ธ {duration_str}\n{settings_str}", + inline=True + ) + else: + embed.add_field( + name="โŒ Unbekannter Kanal", + value=f"ID: {chan_id}\nโฑ๏ธ {self._format_duration(duration)}", + inline=True + ) + + await ctx.respond(embed=embed, ephemeral=True) + + @autodelete.command(name="remove", description="Entfernt AutoDelete von einem Kanal.") + async def remove(self, ctx, + channel: Option(discord.TextChannel, "Kanal", required=True)): + db = AutoDeleteDB() + if db.get_autodelete(channel.id): + db.remove_autodelete(channel.id) + await ctx.respond(f"๐Ÿ—‘๏ธ AutoDelete fรผr {channel.mention} wurde entfernt.", ephemeral=True) + else: + await ctx.respond(f"โŒ AutoDelete war fรผr {channel.mention} nicht aktiviert.", ephemeral=True) + + @autodelete.command(name="stats", description="Zeigt Statistiken fรผr einen AutoDelete-Kanal.") + async def stats(self, ctx, + channel: Option(discord.TextChannel, "Kanal", required=True)): + db = AutoDeleteDB() + config = db.get_autodelete_full(channel.id) + if not config: + await ctx.respond(f"โŒ AutoDelete ist fรผr {channel.mention} nicht aktiviert.", ephemeral=True) + return + + duration, exclude_pinned, exclude_bots = config + stats = db.get_stats(channel.id) + + embed = discord.Embed( + title=f"๐Ÿ“Š AutoDelete Statistiken - #{channel.name}", + color=discord.Color.green(), + timestamp=datetime.utcnow() + ) + + embed.add_field(name="โฑ๏ธ Lรถschzeit", value=self._format_duration(duration), inline=True) + embed.add_field(name="๐Ÿ“Œ Angepinnte", value="Ausgeschlossen" if exclude_pinned else "Eingeschlossen", + inline=True) + embed.add_field(name="๐Ÿค– Bots", value="Ausgeschlossen" if exclude_bots else "Eingeschlossen", inline=True) + + if stats: + embed.add_field(name="๐Ÿ—‘๏ธ Gelรถschte Nachrichten", value=str(stats['deleted_count']), inline=True) + embed.add_field(name="โŒ Fehler", value=str(stats['error_count']), inline=True) + if stats['last_deletion']: + embed.add_field(name="๐Ÿ•’ Letzte Lรถschung", value=f"", inline=True) + + await ctx.respond(embed=embed, ephemeral=True) + + @autodelete.command(name="test", description="Testet die AutoDelete-Funktion fรผr einen Kanal.") + async def test(self, ctx, + channel: Option(discord.TextChannel, "Kanal", required=True)): + db = AutoDeleteDB() + config = db.get_autodelete_full(channel.id) + if not config: + await ctx.respond(f"โŒ AutoDelete ist fรผr {channel.mention} nicht aktiviert.", ephemeral=True) + return + + await ctx.defer(ephemeral=True) + + try: + deleted_count = await self._process_channel_deletion(channel.id, test_mode=True) + await ctx.followup.send( + f"โœ… Test erfolgreich!\n" + f"๐Ÿ“ {deleted_count} Nachrichten wรผrden gelรถscht werden.", + ephemeral=True + ) + except Exception as e: + await ctx.followup.send(f"โŒ Test fehlgeschlagen: {str(e)}", ephemeral=True) + + @tasks.loop(seconds=30) # Erhรถht auf 30 Sekunden fรผr bessere Performance + async def delete_task(self): + try: + db = AutoDeleteDB() + channels = db.get_all() + + # Verarbeite Kanรคle parallel, aber begrenzt + semaphore = asyncio.Semaphore(3) # Max 3 Kanรคle gleichzeitig + tasks = [] + + for chan_id, duration, exclude_pinned, exclude_bots in channels: + if chan_id not in self.processing_channels: + task = self._process_channel_with_semaphore(semaphore, chan_id) + tasks.append(task) + + if tasks: + await asyncio.gather(*tasks, return_exceptions=True) + + except Exception as e: + logger.error(f"Fehler im delete_task: {e}") + + async def _process_channel_with_semaphore(self, semaphore, channel_id): + async with semaphore: + await self._process_channel_deletion(channel_id) + + async def _process_channel_deletion(self, channel_id, test_mode=False): + if channel_id in self.processing_channels and not test_mode: + return 0 + + if not test_mode: + self.processing_channels.add(channel_id) + + try: + db = AutoDeleteDB() + config = db.get_autodelete_full(channel_id) + if not config: + return 0 + + duration, exclude_pinned, exclude_bots = config + + # Zeitplan-Prรผfung + if not self._is_in_schedule(channel_id): + return 0 + + channel = self.bot.get_channel(channel_id) + if not channel: + return 0 + + deleted_count = 0 + error_count = 0 + cutoff_time = datetime.utcnow() - timedelta(seconds=duration) + + try: + messages_to_delete = [] + async for msg in channel.history(limit=200, oldest_first=True): + if msg.created_at >= cutoff_time: + break + + # Filterlogik + if exclude_pinned and msg.pinned: + continue + if exclude_bots and msg.author.bot: + continue + + # Whitelist-Prรผfung + if self._check_whitelist(msg, channel_id): + continue + + messages_to_delete.append(msg) + + # Batch-Lรถschung fรผr bessere Performance + if len(messages_to_delete) >= 10: + if not test_mode: + deleted, errors = await self._bulk_delete_messages(channel, messages_to_delete) + deleted_count += deleted + error_count += errors + else: + deleted_count += len(messages_to_delete) + messages_to_delete.clear() + + # Restliche Nachrichten lรถschen + if messages_to_delete: + if not test_mode: + deleted, errors = await self._bulk_delete_messages(channel, messages_to_delete) + deleted_count += deleted + error_count += errors + else: + deleted_count += len(messages_to_delete) + + # Statistiken aktualisieren + if not test_mode and (deleted_count > 0 or error_count > 0): + db.update_stats(channel_id, deleted_count, error_count) + + except discord.errors.Forbidden: + logger.warning(f"Keine Berechtigung fรผr Kanal {channel_id}") + except Exception as e: + logger.error(f"Fehler beim Verarbeiten von Kanal {channel_id}: {e}") + if not test_mode: + db.update_stats(channel_id, 0, 1) + + return deleted_count + + finally: + if not test_mode: + self.processing_channels.discard(channel_id) + + async def _bulk_delete_messages(self, channel, messages): + deleted_count = 0 + error_count = 0 + + # Trenne alte und neue Nachrichten (Discord API Limitation) + old_messages = [] + new_messages = [] + two_weeks_ago = datetime.utcnow() - timedelta(days=14) + + for msg in messages: + if msg.created_at < two_weeks_ago: + old_messages.append(msg) + else: + new_messages.append(msg) + + # Bulk delete fรผr neue Nachrichten + if new_messages: + try: + await channel.delete_messages(new_messages) + deleted_count += len(new_messages) + except Exception as e: + logger.error(f"Bulk delete Fehler: {e}") + + return deleted_count, error_count + + # Platzhalter fรผr fehlende Methoden, um den Code lauffรคhig zu machen + def _format_duration(self, duration: int) -> str: + """Formatiert die Dauer in eine lesbare Zeichenkette (z.B. '1 Stunde').""" + if duration >= 86400 and duration % 86400 == 0: + return f"{duration // 86400} Tage" + if duration >= 3600 and duration % 3600 == 0: + return f"{duration // 3600} Stunden" + if duration >= 60 and duration % 60 == 0: + return f"{duration // 60} Minuten" + return f"{duration} Sekunden" + + def _is_in_schedule(self, channel_id: int) -> bool: + """Platzhalter: Prรผft, ob der Kanal gerade gelรถscht werden soll (immer True im Platzhalter).""" + # Da diese Methode in Ihrem Originalcode nicht definiert ist, aber aufgerufen wird, + # muss sie entweder in der DB/Config abrufbar sein oder als Platzhalter existieren. + # Wir lassen sie hier True zurรผckgeben, um die Lรถschlogik nicht zu blockieren. + return True + + def _check_whitelist(self, message: discord.Message, channel_id: int) -> bool: + """Platzhalter: Prรผft, ob die Nachricht von der Lรถschung ausgenommen ist (immer False im Platzhalter).""" + return False + +def setup(bot): + bot.add_cog(AutoDelete(bot)) \ No newline at end of file diff --git a/src/bot/cogs/management/autorole.py b/src/bot/cogs/management/autorole.py new file mode 100644 index 0000000..3e3613c --- /dev/null +++ b/src/bot/cogs/management/autorole.py @@ -0,0 +1,273 @@ +import discord +from discord.ext import commands +from discord import option +from DevTools import AutoRoleDatabase +from mx_handler import TranslationHandler as TH + +class AutoRole(commands.Cog): + def __init__(self, bot): + self.bot = bot + self.db = AutoRoleDatabase() + + async def cog_load(self): + """Wird aufgerufen, wenn der Cog geladen wird""" + await self.db.init_db() + + autorole = discord.SlashCommandGroup( + name="autorole", + description="Verwalte das Autorole-System", + default_member_permissions=discord.Permissions(administrator=True) + ) + + @autorole.command(name="add", description="Fรผge eine neue Autorole hinzu") + @option( + name="rolle", + description="Die Rolle, die vergeben werden soll", + type=discord.Role, + required=True + ) + async def autorole_add(self, ctx: discord.ApplicationContext, rolle: discord.Role): + """Fรผgt eine neue Autorole hinzu""" + + # Prรผfe, ob der Bot die Rolle vergeben kann + if rolle.position >= ctx.guild.me.top_role.position: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_to_high.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_to_high.desc"), + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if rolle.managed: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_managed.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_managed.desc"), + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + # Fรผge die Autorole hinzu + autorole_id = await self.db.add_autorole(ctx.guild.id, rolle.id) + + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.add_success.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.add_success.desc", role=rolle.mention, autorole_id=autorole_id), + color=discord.Color.green() + ) + await ctx.respond(embed=embed) + + @autorole.command(name="remove", description="Entferne eine Autorole") + @option( + name="autorole_id", + description="Die ID der Autorole (z.B. 26-25-153)", + type=str, + required=True + ) + async def autorole_remove(self, ctx: discord.ApplicationContext, autorole_id: str): + """Entfernt eine Autorole anhand der ID""" + + config = await self.db.get_autorole(autorole_id) + + if not config: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.desc", autorole_id=autorole_id), + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if config["guild_id"] != ctx.guild.id: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.desc"), + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + await self.db.remove_autorole(autorole_id) + + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.remove_success.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.remove_success.desc", autorole_id=autorole_id), + color=discord.Color.green() + ) + await ctx.respond(embed=embed) + + @autorole.command(name="toggle", description="Aktiviere oder deaktiviere eine Autorole") + @option( + name="autorole_id", + description="Die ID der Autorole (z.B. 26-25-153)", + type=str, + required=True + ) + @option( + name="status", + description="Status der Autorole", + type=str, + choices=["aktivieren", "deaktivieren"], + required=True + ) + async def autorole_toggle(self, ctx: discord.ApplicationContext, autorole_id: str, status: str): + """Aktiviert oder deaktiviert eine Autorole""" + + config = await self.db.get_autorole(autorole_id) + + if not config: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.desc", autorole_id=autorole_id), + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if config["guild_id"] != ctx.guild.id: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.desc"), + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + enabled = status == "aktivieren" + await self.db.toggle_autorole(autorole_id, enabled) + + status_text = "enabled" if enabled else "disabled" + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, f"cog_autorole.messages.toggle_success.{status_text}_title"), + description=await TH.get_for_user(self.bot, ctx.author.id, f"cog_autorole.messages.toggle_success.{status_text}_desc", autorole_id=autorole_id), + color=discord.Color.green() + ) + await ctx.respond(embed=embed) + + @autorole.command(name="list", description="Zeige alle Autoroles auf diesem Server") + async def autorole_list(self, ctx: discord.ApplicationContext): + """Zeigt alle Autoroles fรผr den Server""" + + autoroles = await self.db.get_all_autoroles(ctx.guild.id) + + if not autoroles: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.no_roles.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.no_roles.desc"), + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.list.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.list.desc", guild_name=ctx.guild.name), + color=discord.Color.blue() + ) + + for ar in autoroles: + role = ctx.guild.get_role(ar["role_id"]) + if role: + status = "๐ŸŸข Aktiv" if ar["enabled"] else "๐Ÿ”ด Inaktiv" + embed.add_field( + name=f"ID: `{ar['autorole_id']}`", + value=f"**Rolle:** {role.mention}\n**Status:** {status}\n**Mitglieder:** {len(role.members)}", + inline=False + ) + else: + embed.add_field( + name=f"ID: `{ar['autorole_id']}`", + value=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.list.role_deleted"), + inline=False + ) + + await ctx.respond(embed=embed) + + @autorole.command(name="info", description="Zeige Details zu einer spezifischen Autorole") + @option( + name="autorole_id", + description="Die ID der Autorole (z.B. 26-25-153)", + type=str, + required=True + ) + async def autorole_info(self, ctx: discord.ApplicationContext, autorole_id: str): + """Zeigt Details zu einer spezifischen Autorole""" + + config = await self.db.get_autorole(autorole_id) + + if not config: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.not_found.desc", autorole_id=autorole_id), + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + if config["guild_id"] != ctx.guild.id: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.wrong_guild.desc"), + color=discord.Color.red() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + role = ctx.guild.get_role(config["role_id"]) + + if not role: + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_deleted.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.error_types.role_deleted.desc", autorole_id=autorole_id), + color=discord.Color.orange() + ) + await ctx.respond(embed=embed, ephemeral=True) + return + + embed = discord.Embed( + title=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.info.title"), + description=await TH.get_for_user(self.bot, ctx.author.id, "cog_autorole.messages.info.desc", autorole_id=autorole_id), + color=discord.Color.blue() + ) + embed.add_field(name="Rolle", value=role.mention, inline=True) + embed.add_field(name="Status", value="๐ŸŸข Aktiviert" if config["enabled"] else "๐Ÿ”ด Deaktiviert", inline=True) + embed.add_field(name="Mitglieder mit dieser Rolle", value=str(len(role.members)), inline=True) + embed.add_field(name="Rollen-ID", value=f"`{role.id}`", inline=True) + embed.add_field(name="Autorole-ID", value=f"`{autorole_id}`", inline=True) + + await ctx.respond(embed=embed) + + @commands.Cog.listener() + async def on_member_join(self, member: discord.Member): + """Event: Wird ausgelรถst, wenn ein neues Mitglied dem Server beitritt""" + + role_ids = await self.db.get_enabled_autoroles(member.guild.id) + + if not role_ids: + return + + roles_to_add = [] + + for role_id in role_ids: + role = member.guild.get_role(role_id) + if role and role.position < member.guild.me.top_role.position: + roles_to_add.append(role) + + if not roles_to_add: + return + + try: + audit_reason = TH.get("de", "cog_autorole.system.audit_reason") + await member.add_roles(*roles_to_add, reason=audit_reason) + + role_names = ", ".join([r.name for r in roles_to_add]) + log_msg = TH.get("de", "cog_autorole.system.console_log", role_names=role_names, member_name=member.name) + print(log_msg) + except discord.Forbidden: + print(TH.get("de", "cog_autorole.system.error_forbidden")) + except discord.HTTPException as e: + print(TH.get("de", "cog_autorole.system.error_http", error=str(e))) + +def setup(bot): + bot.add_cog(AutoRole(bot)) \ No newline at end of file diff --git a/src/bot/cogs/moderation/antispam.py b/src/bot/cogs/moderation/antispam.py new file mode 100644 index 0000000..5bdce7f --- /dev/null +++ b/src/bot/cogs/moderation/antispam.py @@ -0,0 +1,435 @@ +# Copyright (c) 2025 OPPRO.NET Network +from collections import defaultdict +import asyncio +import discord +from discord import SlashCommandGroup +import ezcord +import datetime +from datetime import timedelta + + +from DevTools import AntiSpamDatabase as SpamDB + +antispam = SlashCommandGroup("antispam") +class AntiSpam(ezcord.Cog): + + def __init__(self, bot: ezcord.Bot): + self.bot = bot + self.db = SpamDB() + # Track user message timestamps per guild + self.user_messages = defaultdict(lambda: defaultdict(list)) + # Track users currently in timeout to prevent duplicate actions + self.users_in_timeout = set() + + @ezcord.Cog.listener() + async def on_message(self, message): + """Monitor messages for spam detection.""" + # Ignore bot messages and DMs + if message.author.bot or not message.guild: + return + + # Check if user is whitelisted + if self.is_whitelisted(message.guild.id, message.author.id): + return + + # Get spam settings for this guild + settings = self.db.get_spam_settings(message.guild.id) + if not settings: + # If no settings are configured, don't process spam detection + return + + # Check if log channel is set + if not settings.get('log_channel_id'): + return + + # Record this message timestamp + user_id = message.author.id + guild_id = message.guild.id + current_time = datetime.now() + + # Add current message to tracking + self.user_messages[guild_id][user_id].append(current_time) + + # Clean old messages outside the time frame + time_threshold = current_time - timedelta(seconds=settings['time_frame']) + self.user_messages[guild_id][user_id] = [ + timestamp for timestamp in self.user_messages[guild_id][user_id] + if timestamp > time_threshold + ] + + # Check if user exceeded message limit + message_count = len(self.user_messages[guild_id][user_id]) + if message_count > settings['max_messages']: + await self.handle_spam_violation(message, settings) + + async def handle_spam_violation(self, message, settings): + """Handle a user who violated spam limits.""" + user = message.author + guild = message.guild + + # Prevent duplicate actions for the same user + user_timeout_key = f"{guild.id}_{user.id}" + if user_timeout_key in self.users_in_timeout: + return + + self.users_in_timeout.add(user_timeout_key) + + try: + # Log the spam incident + self.db.log_spam(guild.id, user.id, message.content[:100]) # Limit message length + + # Delete recent messages from this user + await self.delete_recent_messages(message.channel, user, limit=settings['max_messages']) + + # Apply timeout (5 minutes) + timeout_duration = timedelta(minutes=5) + timeout_applied = False + + try: + await user.timeout_for(timeout_duration, reason="Anti-Spam: Zu viele Nachrichten") + timeout_applied = True + except discord.Forbidden: + pass # Continue to log even if timeout fails + + # Send log to designated channel + await self.send_spam_log(guild, user, message, settings, timeout_applied) + + # Send warning message in channel + embed = discord.Embed( + title=f"{emoji_forbidden} ร— Anti-Spam Warnung", + description=f"{user.mention} wurde wegen zu vieler Nachrichten {'stumm geschaltet' if timeout_applied else 'verwarnt'}.", + color=ERROR_COLOR + ) + embed.add_field( + name="Limit รผberschritten", + value=f"Maximal {settings['max_messages']} Nachrichten in {settings['time_frame']} Sekunden erlaubt", + inline=False + ) + await message.channel.send(embed=embed, delete_after=10) + + # Clear user's message tracking after violation + if guild.id in self.user_messages and user.id in self.user_messages[guild.id]: + self.user_messages[guild_id][user.id].clear() + + # Remove from timeout tracking after delay + await asyncio.sleep(300) # 5 minutes + self.users_in_timeout.discard(user_timeout_key) + + except Exception as e: + print(f"Error handling spam violation: {e}") + self.users_in_timeout.discard(user_timeout_key) + + async def send_spam_log(self, guild, user, message, settings, timeout_applied): + """Send spam log to designated log channel.""" + log_channel_id = settings.get('log_channel_id') + if not log_channel_id: + return + + log_channel = guild.get_channel(log_channel_id) + if not log_channel: + return + + try: + embed = discord.Embed( + title=f"{emoji_warn} ร— Anti-Spam VerstoรŸ", + color=discord.Color.red(), + timestamp=datetime.now() + ) + embed.add_field( + name=f"{emoji_member} ร— Benutzer", + value=f"{user.mention} ({user.id})", + inline=True + ) + embed.add_field( + name=f"{emoji_channel} ร— Kanal", + value=message.channel.mention, + inline=True + ) + embed.add_field( + name=f"{emoji_moderator} ร— Aktion", + value="Timeout (5 Min)" if timeout_applied else "Warnung", + inline=True + ) + embed.add_field( + name=f"{emoji_statistics} ร— Limit", + value=f"{settings['max_messages']} Nachrichten in {settings['time_frame']}s", + inline=True + ) + embed.add_field( + name=f"{emoji_annoattention} ร— Nachricht (Vorschau)", + value=f"```{message.content[:100]}{'...' if len(message.content) > 100 else ''}```", + inline=False + ) + embed.set_footer(text=f"User ID: {user.id}") + embed.set_thumbnail(url=user.display_avatar.url) + + await log_channel.send(embed=embed) + except Exception as e: + print(f"Error sending spam log: {e}") + + async def delete_recent_messages(self, channel, user, limit=5): + """Delete recent messages from a user.""" + try: + messages_to_delete = [] + async for msg in channel.history(limit=50): # Check last 50 messages + if msg.author == user and len(messages_to_delete) < limit: + messages_to_delete.append(msg) + if len(messages_to_delete) >= limit: + break + + for msg in messages_to_delete: + try: + await msg.delete() + except discord.NotFound: + pass # Message already deleted + except discord.Forbidden: + break # No permission to delete + + except Exception as e: + print(f"Error deleting messages: {e}") + + @antispam.command(name="setup", description="Richte das Anti-Spam-System ein.") + async def setup_antispam(self, ctx, log_channel: discord.TextChannel, max_messages: int = 5, time_frame: int = 10): + """Richte das Anti-Spam-System mit einem Log-Channel ein.""" + if not ctx.author.guild_permissions.manage_guild: + await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) + return + + if max_messages < 1 or max_messages > 50: + await ctx.respond(f"{emoji_no} ร— Maximale Nachrichten mรผssen zwischen 1 und 50 liegen.", ephemeral=True) + return + + if time_frame < 1 or time_frame > 300: + await ctx.respond(f"{emoji_no} ร— Zeitrahmen muss zwischen 1 und 300 Sekunden liegen.", ephemeral=True) + return + + # Check if bot can send messages to log channel + if not log_channel.permissions_for(ctx.guild.me).send_messages: + await ctx.respond(f"{emoji_no} ร— Ich habe keine Berechtigung, Nachrichten in den angegebenen Log-Channel zu senden.", + ephemeral=True) + return + + self.db.set_spam_settings(ctx.guild.id, max_messages, time_frame, log_channel.id) + + embed = discord.Embed( + title=f"{emoji_yes} ร— Anti-Spam-System eingerichtet", + color=discord.Color.green() + ) + embed.add_field( + name=f"{emoji_channel} ร— Log-Channel", + value=log_channel.mention, + inline=True + ) + embed.add_field( + name=f"{emoji_annoattention} ร— Nachrichtenlimit", + value=f"{max_messages} Nachrichten", + inline=True + ) + embed.add_field( + name=f"{emoji_statistics} ร— Zeitrahmen", + value=f"{time_frame} Sekunden", + inline=True + ) + embed.add_field( + name=f"{emoji_owner} ร— Status", + value="๐ŸŸข Aktiv", + inline=False + ) + await ctx.respond(embed=embed, ephemeral=True) + + @antispam.command(name="set", description="ร„ndere Anti-Spam-Parameter.") + async def set_parameters(self, ctx, max_messages: int = None, time_frame: int = None): + """ร„ndere die Anti-Spam-Parameter (Log-Channel bleibt unverรคndert).""" + if not ctx.author.guild_permissions.manage_guild: + await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) + return + + # Get current settings + current_settings = self.db.get_spam_settings(ctx.guild.id) + if not current_settings: + await ctx.respond(f"{emoji_no} ร— Anti-Spam-System wurde noch nicht eingerichtet. Verwende `/antispam setup` zuerst.", + ephemeral=True) + return + + # Use current values if not provided + new_max_messages = max_messages if max_messages is not None else current_settings['max_messages'] + new_time_frame = time_frame if time_frame is not None else current_settings['time_frame'] + + if new_max_messages < 5 or new_max_messages > 50: + await ctx.respond(f"{emoji_no} ร— Maximale Nachrichten mรผssen zwischen 5 und 50 liegen.", ephemeral=True) + return + + if new_time_frame < 5 or new_time_frame > 300: + await ctx.respond(f"{emoji_no} ร— Zeitrahmen muss zwischen 5 und 300 Sekunden liegen.", ephemeral=True) + return + + self.db.set_spam_settings(ctx.guild.id, new_max_messages, new_time_frame, current_settings['log_channel_id']) + + embed = discord.Embed( + title=f"{emoji_owner} ร— Anti-Spam Einstellungen aktualisiert", + description=f"Maximal **{new_max_messages}** Nachrichten in **{new_time_frame}** Sekunden erlaubt.", + color=discord.Color.green() + ) + await ctx.respond(embed=embed, ephemeral=True) + + @antispam.command(name="log-channel", description="ร„ndere den Log-Channel.") + async def set_log_channel(self, ctx, log_channel: discord.TextChannel): + """ร„ndere den Log-Channel fรผr Anti-Spam.""" + if not ctx.author.guild_permissions.manage_guild: + await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) + return + + # Check if bot can send messages to log channel + if not log_channel.permissions_for(ctx.guild.me).send_messages: + await ctx.respond(f"{emoji_no} ร— Ich habe keine Berechtigung, Nachrichten in den angegebenen Log-Channel zu senden.", + ephemeral=True) + return + + self.db.set_log_channel(ctx.guild.id, log_channel.id) + + embed = discord.Embed( + title=f"{emoji_owner} ร— Log-Channel aktualisiert", + description=f"Anti-Spam-Logs werden nun in {log_channel.mention} gesendet.", + color=discord.Color.green() + ) + await ctx.respond(embed=embed, ephemeral=True) + + @antispam.command(name="view", description="Zeige aktuelle Anti-Spam-Einstellungen an.") + async def view_settings(self, ctx): + """Zeigt die aktuellen Anti-Spam-Einstellungen an.""" + settings = self.db.get_spam_settings(ctx.guild.id) + + if settings and settings.get('log_channel_id'): + log_channel = ctx.guild.get_channel(settings['log_channel_id']) + log_channel_display = log_channel.mention if log_channel else f"{emoji_warn} ร— Channel nicht gefunden" + + embed = discord.Embed( + title=f"{emoji_owner} ร— Anti-Spam Einstellungen", + color=discord.Color.blue() + ) + embed.add_field( + name=f"{emoji_channel} ร— Log-Channel", + value=log_channel_display, + inline=True + ) + embed.add_field( + name=f"{emoji_annoattention} ร— Nachrichtenlimit", + value=f"{settings['max_messages']} Nachrichten", + inline=True + ) + embed.add_field( + name=f"{emoji_statistics} ร— Zeitrahmen", + value=f"{settings['time_frame']} Sekunden", + inline=True + ) + embed.add_field( + name=f"{emoji_owner} ร— Status", + value="๐ŸŸข Aktiv", + inline=False + ) + else: + embed = discord.Embed( + title=f"{emoji_owner} ร— Anti-Spam Einstellungen", + description=f"{emoji_no} ร— **Anti-Spam-System nicht eingerichtet**\n\nVerwende `/antispam setup` um das System zu konfigurieren.", + color=discord.Color.red() + ) + + await ctx.respond(embed=embed, ephemeral=True) + + @antispam.command(name="logs", description="Zeige Anti-Spam-Logs an.") + async def view_logs(self, ctx, limit: int = 10): + """Zeigt die Anti-Spam-Protokolle an.""" + if not ctx.author.guild_permissions.manage_guild: + await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) + return + + logs = self.db.get_spam_logs(ctx.guild.id, limit) + + if logs: + embed = discord.Embed( + title=f"{emoji_statistics} ร— Anti-Spam Protokolle", + color=discord.Color.red() + ) + + log_text = "" + for i, log in enumerate(logs, 1): + user_id, message_preview, timestamp = log + # Try to get user mention, fallback to ID + try: + user = self.bot.get_user(user_id) + user_display = user.mention if user else f"<@{user_id}>" + except: + user_display = f"User ID: {user_id}" + + log_text += f"**{i}.** {user_display}\n" + log_text += f"๐Ÿ“ `{message_preview[:50]}{'...' if len(message_preview) > 50 else ''}`\n" + log_text += f"๐Ÿ•’ {timestamp}\n\n" + + embed.description = log_text + embed.set_footer(text=f"Zeige die letzten {len(logs)} Eintrรคge") + else: + embed = discord.Embed( + title=f"{emoji_statistics} ร— Anti-Spam Protokolle", + description="Fรผr diesen Server wurden keine Anti-Spam-Logs gefunden.", + color=discord.Color.green() + ) + + await ctx.respond(embed=embed, ephemeral=True) + + @antispam.command(name="clear", description="Lรถsche alle Anti-Spam-Logs fรผr diesen Server.") + async def clear_logs(self, ctx): + """Lรถscht alle Anti-Spam-Protokolle fรผr den Server.""" + if not ctx.author.guild_permissions.administrator: + await ctx.respond(f"{emoji_no} ร— Du benรถtigst Administrator-Rechte fรผr diesen Befehl.", ephemeral=True) + return + + self.db.clear_spam_logs(ctx.guild.id) + + embed = discord.Embed( + title=f"{emoji_yes} ร— Protokolle gelรถscht", + description="Alle Anti-Spam-Protokolle fรผr diesen Server wurden gelรถscht.", + color=discord.Color.green() + ) + await ctx.respond(embed=embed, ephemeral=True) + + @antispam.command(name="whitelist", description="Fรผge einen Benutzer zur Whitelist hinzu.") + async def add_whitelist(self, ctx, user: discord.Member): + """Fรผgt einen Benutzer zur Anti-Spam Whitelist hinzu.""" + if not ctx.author.guild_permissions.manage_guild: + await ctx.respond(f"{emoji_no} ร— Du benรถtigst die 'Server verwalten' Berechtigung fรผr diesen Befehl.", ephemeral=True) + return + + self.db.add_to_whitelist(ctx.guild.id, user.id) + + embed = discord.Embed( + title=f"{emoji_yes} ร— Zur Whitelist hinzugefรผgt", + description=f"{user.mention} wurde zur Anti-Spam Whitelist hinzugefรผgt.", + color=discord.Color.green() + ) + await ctx.respond(embed=embed, ephemeral=True) + + @antispam.command(name="disable", description="Deaktiviere das Anti-Spam-System.") + async def disable_antispam(self, ctx): + """Deaktiviert das Anti-Spam-System fรผr diesen Server.""" + if not ctx.author.guild_permissions.administrator: + await ctx.respond(f"{emoji_no} ร— Du benรถtigst Administrator-Rechte fรผr diesen Befehl.", ephemeral=True) + return + + # Remove settings to disable the system + with self.db.conn: + self.db.conn.execute('DELETE FROM spam_settings WHERE guild_id = ?', (ctx.guild.id,)) + + embed = discord.Embed( + title=f"{emoji_delete} ร— Anti-Spam-System deaktiviert", + description="Das Anti-Spam-System wurde fรผr diesen Server deaktiviert.\nVerwende `/antispam setup` um es wieder zu aktivieren.", + color=discord.Color.orange() + ) + await ctx.respond(embed=embed, ephemeral=True) + + def is_whitelisted(self, guild_id, user_id): + """Check if user is whitelisted.""" + return self.db.is_whitelisted(guild_id, user_id) + + +def setup(bot: ezcord.Bot): + bot.add_cog(AntiSpam(bot)) \ No newline at end of file diff --git a/src/bot/cogs/moderation/moderation.py b/src/bot/cogs/moderation/moderation.py new file mode 100644 index 0000000..de7e7cc --- /dev/null +++ b/src/bot/cogs/moderation/moderation.py @@ -0,0 +1,550 @@ +# Copyright (c) 2025 OPPRO.NET Network +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Imports +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +import asyncio +import re +from datetime import datetime, timezone +from typing import Optional, Dict, List +import logging + +import discord +import ezcord +from discord import slash_command, option +import timedelta +from discord.ui import Container +from discord import SlashCommandGroup +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Cogs +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class moderationCog(ezcord.Cog): + """Erweiterte Moderations-Cog mit verbesserter Sicherheit und Fehlerbehandlung""" + + def __init__(self, bot): + self.bot = bot + self.max_timeout_days = 28 + self._active_votes: Dict[int, Dict] = {} + self.logger = logging.getLogger(__name__) + moderation = SlashCommandGroup("mod") + + + def _has_permission(self, member: discord.Member, permission: str) -> bool: + """รœberprรผft ob ein Member eine bestimmte Berechtigung hat""" + return getattr(member.guild_permissions, permission, False) + + def _can_moderate_member(self, moderator: discord.Member, target: discord.Member) -> tuple[bool, str]: + """Erweiterte รœberprรผfung ob ein Moderator ein Ziel-Mitglied moderieren kann""" + if target.id == target.guild.owner_id: + return False, "Der Server-Owner kann nicht moderiert werden." + if moderator.id == target.id: + return False, "Du kannst dich nicht selbst moderieren." + if target.id == self.bot.user.id: + return False, "Ich kann mich nicht selbst moderieren." + if target.bot and not moderator.guild_permissions.administrator: + return False, "Nur Administratoren kรถnnen Bots moderieren." + if moderator.id != target.guild.owner_id: + if moderator.top_role <= target.top_role: + return False, "Du kannst keine Mitglieder mit gleicher oder hรถherer Rolle moderieren." + bot_member = target.guild.get_member(self.bot.user.id) + if bot_member and bot_member.top_role <= target.top_role: + return False, "Meine Rolle ist nicht hoch genug, um dieses Mitglied zu moderieren." + return True, "" + + def _parse_duration(self, duration_str: str) -> Optional[timedelta]: + """Erweiterte Dauer-Parsing mit mehr Formaten und besserer Validierung""" + duration_str = duration_str.lower().strip() + pattern = r'(\d+)([smhdw])' + matches = re.findall(pattern, duration_str) + if not matches: + return None + total_seconds = 0 + for amount_str, unit in matches: + try: + amount = int(amount_str) + except ValueError: + return None + if amount < 0: + return None + if unit == 's': + total_seconds += amount + elif unit == 'm': + total_seconds += amount * 60 + elif unit == 'h': + total_seconds += amount * 3600 + elif unit == 'd': + total_seconds += amount * 86400 + elif unit == 'w': + total_seconds += amount * 604800 + else: + return None + if total_seconds < 1: + return None + max_seconds = self.max_timeout_days * 86400 + if total_seconds > max_seconds: + return None + return timedelta(seconds=total_seconds) + + def _format_duration(self, duration: timedelta) -> str: + """Formatiert eine timedelta in einen lesbaren String""" + total_seconds = int(duration.total_seconds()) + weeks = total_seconds // 604800 + days = (total_seconds % 604800) // 86400 + hours = (total_seconds % 86400) // 3600 + minutes = (total_seconds % 3600) // 60 + seconds = total_seconds % 60 + parts = [] + if weeks: parts.append(f"{weeks}w") + if days: parts.append(f"{days}d") + if hours: parts.append(f"{hours}h") + if minutes: parts.append(f"{minutes}m") + if seconds: parts.append(f"{seconds}s") + return " ".join(parts) if parts else "0s" + + def _create_moderation_embed(self, action: str, moderator: discord.Member, target: discord.Member, + reason: str, duration: str = None, additional_info: str = None) -> discord.Embed: + """Erstellt ein einheitliches Moderations-Embed""" + color_map = { + "Bann": discord.Color.dark_red(), + "Kick": discord.Color.red(), + "Timeout": discord.Color.orange(), + "Timeout aufgehoben": discord.Color.green(), + "Slowmode aktiviert": discord.Color.blue(), + "Slowmode deaktiviert": discord.Color.green(), + } + embed = discord.Embed( + title=f"{emoji_yes} ร— {action} erfolgreich", + color=color_map.get(action, SUCCESS_COLOR), + timestamp=datetime.now(timezone.utc) + ) + embed.set_author(name=AUTHOR) + if target: + embed.add_field(name=f"{emoji_member} ร— Ziel", value=f"{target.mention} ({target})", inline=True) + embed.add_field(name=f"{emoji_staff} ร— Moderator", value=moderator.mention, inline=True) + if duration: + embed.add_field(name=f"{emoji_slowmode} ร— Dauer", value=duration, inline=True) + embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) + if additional_info: + embed.add_field(name=f"{emoji_summary} ร— Zusรคtzlich", value=additional_info, inline=False) + if target: + embed.set_footer(text=f"User ID: {target.id}") + else: + embed.set_footer(text=FLOOTER) + return embed + + def _create_error_embed(self, title: str, description: str, additional_info: str = None) -> discord.Embed: + """Erstellt ein einheitliches Error-Embed""" + embed = discord.Embed( + title=f"{emoji_no} {title}", + description=description, + color=ERROR_COLOR, + timestamp=datetime.now(timezone.utc) + ) + embed.set_author(name=AUTHOR) + if additional_info: + embed.add_field(name=f"{emoji_summary} ร— Details", value=additional_info, inline=False) + embed.set_footer(text=FLOOTER) + return embed + + @moderation.command(name="ban", description="Bannt ein Mitglied vom Server") + @option("member", discord.Member, description="Das zu bannende Mitglied") + @option("reason", str, description="Grund fรผr den Bann", max_length=500, required=False) + @option("notify_user", bool, description="User per DM benachrichtigen?", required=False, default=True) + async def ban(self, ctx: discord.ApplicationContext, member: discord.Member, + reason: str = "Kein Grund angegeben", notify_user: bool = True): + await ctx.defer(ephemeral=True) + try: + if not self._has_permission(ctx.author, BAN): + embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder bannen` Berechtigung.") + return await ctx.followup.send(embed=embed) + if not self._has_permission(ctx.guild.me, BAN): + embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder bannen` Berechtigung.") + return await ctx.followup.send(embed=embed) + can_moderate, error_msg = self._can_moderate_member(ctx.author, member) + if not can_moderate: + embed = self._create_error_embed("Moderation nicht mรถglich", error_msg) + return await ctx.followup.send(embed=embed) + notification_sent = False + if notify_user: + try: + dm_embed = discord.Embed( + title=f"{emoji_warn} ร— Du wurdest gebannt", + color=ERROR_COLOR, + description=f"Du wurdest von **{ctx.guild.name}** gebannt." + ) + dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) + dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) + dm_embed.set_footer(text="Bei Fragen wende dich an die Serverleitung.") + await member.send(embed=dm_embed) + notification_sent = True + except discord.Forbidden: + pass + ban_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" + await member.ban(reason=ban_reason) + additional_info = [] + if notification_sent: + additional_info.append(f"{emoji_yes} ร— User per DM benachrichtigt") + elif notify_user: + additional_info.append(f"{emoji_no} ร— DM-Benachrichtigung fehlgeschlagen") + embed = self._create_moderation_embed("Bann", ctx.author, member, reason, additional_info="\n".join(additional_info) if additional_info else None) + await ctx.followup.send(embed=embed) + self.logger.info(f"User {member} ({member.id}) banned by {ctx.author} ({ctx.author.id}): {reason}") + except discord.Forbidden: + embed = self._create_error_embed("Berechtigung verweigert", f"Mir fehlen die Berechtigungen, um {member.mention} zu bannen.", "Stelle sicher, dass meine Rolle hรถher als die des Ziels ist.") + await ctx.followup.send(embed=embed) + except discord.HTTPException as e: + embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Bannen: {str(e)}") + await ctx.followup.send(embed=embed) + except Exception as e: + embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") + await ctx.followup.send(embed=embed) + self.logger.error(f"Unexpected error in ban command: {e}", exc_info=True) + + @moderation.command(name="kick", description="Kickt ein Mitglied vom Server") + @option("member", discord.Member, description="Das zu kickende Mitglied") + @option("reason", str, description="Grund fรผr den Kick", max_length=500, required=False) + @option("notify_user", bool, description="User per DM benachrichtigen?", required=False, default=True) + async def kick(self, ctx: discord.ApplicationContext, member: discord.Member, + reason: str = "Kein Grund angegeben", notify_user: bool = True): + await ctx.defer(ephemeral=True) + try: + if not self._has_permission(ctx.author, KICK): + embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder kicken` Berechtigung.") + return await ctx.followup.send(embed=embed) + if not self._has_permission(ctx.guild.me, KICK): + embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder kicken` Berechtigung.") + return await ctx.followup.send(embed=embed) + can_moderate, error_msg = self._can_moderate_member(ctx.author, member) + if not can_moderate: + embed = self._create_error_embed("Moderation nicht mรถglich", error_msg) + return await ctx.followup.send(embed=embed) + notification_sent = False + if notify_user: + try: + dm_embed = discord.Embed( + title=f"{emoji_warn} ร— Du wurdest gekickt", + color=ERROR_COLOR, + description=f"Du wurdest von **{ctx.guild.name}** gekickt." + ) + dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) + dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) + dm_embed.set_footer(text="Du kannst dem Server erneut beitreten.") + await member.send(embed=dm_embed) + notification_sent = True + except discord.Forbidden: + pass + kick_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" + await member.kick(reason=kick_reason) + additional_info = None + if notification_sent: + additional_info = f"{emoji_yes} ร— User per DM benachrichtigt" + elif notify_user: + additional_info = f"{emoji_no} ร— DM-Benachrichtigung fehlgeschlagen" + embed = self._create_moderation_embed("Kick", ctx.author, member, reason, additional_info=additional_info) + await ctx.followup.send(embed=embed) + self.logger.info(f"User {member} ({member.id}) kicked by {ctx.author} ({ctx.author.id}): {reason}") + except discord.Forbidden: + embed = self._create_error_embed("Berechtigung verweigert", f"Mir fehlen die Berechtigungen, um {member.mention} zu kicken.", "Stelle sicher, dass meine Rolle hรถher als die des Ziels ist.") + await ctx.followup.send(embed=embed) + except discord.HTTPException as e: + embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Kicken: {str(e)}") + await ctx.followup.send(embed=embed) + except Exception as e: + embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") + await ctx.followup.send(embed=embed) + self.logger.error(f"Unexpected error in kick command: {e}", exc_info=True) + + @moderation.command(name="timeout", description="Versetzt ein Mitglied in Timeout") + @option("member", discord.Member, description="Das zu mutende Mitglied") + @option("duration", str, description="Dauer (z.B. 10m, 1h30m, 2d, 1w)") + @option("reason", str, description="Grund fรผr den Timeout", max_length=500, required=False) + @option("notify_user", bool, description="User per DM benachrichtigen?", required=False, default=True) + async def timeout(self, ctx: discord.ApplicationContext, member: discord.Member, + duration: str, reason: str = "Kein Grund angegeben", notify_user: bool = True): + await ctx.defer(ephemeral=True) + try: + if not self._has_permission(ctx.author, MODERATE): + embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder moderieren` Berechtigung.") + return await ctx.followup.send(embed=embed) + if not self._has_permission(ctx.guild.me, MODERATE): + embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder moderieren` Berechtigung.") + return await ctx.followup.send(embed=embed) + can_moderate, error_msg = self._can_moderate_member(ctx.author, member) + if not can_moderate: + embed = self._create_error_embed("Moderation nicht mรถglich", error_msg) + return await ctx.followup.send(embed=embed) + parsed_duration = self._parse_duration(duration) + if parsed_duration is None: + embed = self._create_error_embed("Ungรผltige Dauer", f"Konnte '{duration}' nicht als gรผltige Dauer erkennen.", f"Beispiele: `10m`, `1h30m`, `2d`, `1w`\nMaximum: {self.max_timeout_days} Tage") + return await ctx.followup.send(embed=embed) + if member.communication_disabled_until and member.communication_disabled_until > datetime.now(timezone.utc): + current_timeout = member.communication_disabled_until + embed = self._create_error_embed("User bereits in Timeout", f"{member.mention} ist bereits bis {discord.utils.format_dt(current_timeout, 'F')} in Timeout.", "Verwende `/moderation untimeout` um den aktuellen Timeout zu beenden.") + return await ctx.followup.send(embed=embed) + notification_sent = False + if notify_user: + try: + dm_embed = discord.Embed( + title=f"{emoji_warn} ร— Du wurdest in Timeout versetzt", + color=ERROR_COLOR, + description=f"Du wurdest auf **{ctx.guild.name}** in Timeout versetzt." + ) + dm_embed.add_field(name=f"{emoji_slowmode} ร— Dauer", value=self._format_duration(parsed_duration), inline=True) + dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) + dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) + end_time = datetime.now(timezone.utc) + parsed_duration + dm_embed.add_field(name="๐Ÿ• Ende", value=discord.utils.format_dt(end_time, 'F'), inline=True) + dm_embed.set_footer(text="Bitte beachte die Serverregeln.") + await member.send(embed=dm_embed) + notification_sent = True + except discord.Forbidden: + pass + timeout_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" + await member.timeout_for(parsed_duration, reason=timeout_reason) + additional_info = None + if notification_sent: + additional_info = f"{emoji_yes} ร— User per DM benachrichtigt" + elif notify_user: + additional_info = f"{emoji_no} ร— DM-Benachrichtigung fehlgeschlagen" + embed = self._create_moderation_embed("Timeout", ctx.author, member, reason, duration=self._format_duration(parsed_duration), additional_info=additional_info) + end_time = datetime.now(timezone.utc) + parsed_duration + embed.add_field(name="๐Ÿ• Ende", value=discord.utils.format_dt(end_time, 'F'), inline=False) + await ctx.followup.send(embed=embed) + self.logger.info(f"User {member} ({member.id}) timed out by {ctx.author} ({ctx.author.id}) for {duration}: {reason}") + except discord.Forbidden: + embed = self._create_error_embed("Berechtigung verweigert", f"Mir fehlen die Berechtigungen, um {member.mention} zu timeouten.", "Stelle sicher, dass meine Rolle hรถher als die des Ziels ist.") + await ctx.followup.send(embed=embed) + except discord.HTTPException as e: + embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Timeout: {str(e)}") + await ctx.followup.send(embed=embed) + except Exception as e: + embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") + await ctx.followup.send(embed=embed) + self.logger.error(f"Unexpected error in timeout command: {e}", exc_info=True) + + @moderation.command(name="untimeout", description="Hebt einen Timeout auf") + @option("member", discord.Member, description="Das Mitglied, dessen Timeout aufgehoben werden soll") + @option("reason", str, description="Grund fรผr die Aufhebung", max_length=500, required=False) + @option("notify_user", bool, description="User per DM benachrichtigen?", required=False, default=True) + async def untimeout(self, ctx: discord.ApplicationContext, member: discord.Member, + reason: str = "Kein Grund angegeben", notify_user: bool = True): + await ctx.defer(ephemeral=True) + try: + if not self._has_permission(ctx.author, MODERATE): + embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder moderieren` Berechtigung.") + return await ctx.followup.send(embed=embed) + if not self._has_permission(ctx.guild.me, MODERATE): + embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder moderieren` Berechtigung.") + return await ctx.followup.send(embed=embed) + if (member.communication_disabled_until is None or member.communication_disabled_until <= datetime.now(timezone.utc)): + embed = self._create_error_embed("Kein aktiver Timeout", f"{member.mention} ist derzeit nicht in Timeout.") + return await ctx.followup.send(embed=embed) + notification_sent = False + if notify_user: + try: + dm_embed = discord.Embed( + title=f"{emoji_yes} ร— Dein Timeout wurde aufgehoben", + color=SUCCESS_COLOR, + description=f"Dein Timeout auf **{ctx.guild.name}** wurde vorzeitig aufgehoben." + ) + dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) + dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) + dm_embed.set_footer(text="Bitte beachte weiterhin die Serverregeln.") + await member.send(embed=dm_embed) + notification_sent = True + except discord.Forbidden: + pass + untimeout_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" + await member.remove_timeout(reason=untimeout_reason) + additional_info = None + if notification_sent: + additional_info = f"{emoji_yes} ร— User per DM benachrichtigt" + elif notify_user: + additional_info = f"{emoji_no} ร— DM-Benachrichtigung fehlgeschlagen" + embed = self._create_moderation_embed("Timeout aufgehoben", ctx.author, member, reason, additional_info=additional_info) + await ctx.followup.send(embed=embed) + self.logger.info(f"Timeout removed from {member} ({member.id}) by {ctx.author} ({ctx.author.id}): {reason}") + except discord.Forbidden: + embed = self._create_error_embed("Berechtigung verweigert", f"Mir fehlen die Berechtigungen, um den Timeout von {member.mention} aufzuheben.") + await ctx.followup.send(embed=embed) + except discord.HTTPException as e: + embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Aufheben des Timeouts: {str(e)}") + await ctx.followup.send(embed=embed) + except Exception as e: + embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") + await ctx.followup.send(embed=embed) + self.logger.error(f"Unexpected error in untimeout command: {e}", exc_info=True) + + @moderation.command(name="slowmode", description="Setzt den Slowmode fรผr den aktuellen Channel") + @option("duration", str, description="Dauer (z.B. 10s, 5m, 1h) oder '0' zum Deaktivieren", default="0") + @option("reason", str, description="Grund fรผr den Slowmode", max_length=500, required=False) + async def slowmode(self, ctx: discord.ApplicationContext, duration: str = "0", reason: str = "Kein Grund angegeben"): + await ctx.defer(ephemeral=True) + try: + if not ctx.author.guild_permissions.manage_channels: + embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Kanรคle verwalten` Berechtigung.") + return await ctx.followup.send(embed=embed) + if not ctx.guild.me.guild_permissions.manage_channels: + embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Kanรคle verwalten` Berechtigung.") + return await ctx.followup.send(embed=embed) + if duration == "0": + seconds = 0 + else: + parsed_duration = self._parse_duration(duration) + if parsed_duration is None: + embed = self._create_error_embed("Ungรผltige Dauer", f"Konnte '{duration}' nicht als gรผltige Dauer erkennen.", "Beispiele: `10s`, `5m`, `1h` oder `0` zum Deaktivieren") + return await ctx.followup.send(embed=embed) + seconds = int(parsed_duration.total_seconds()) + if seconds < 0 or seconds > 21600: + embed = self._create_error_embed("Ungรผltiger Zeitraum", f"Slowmode muss zwischen 0 Sekunden und 6 Stunden liegen.", f"Eingabe: {seconds} Sekunden") + return await ctx.followup.send(embed=embed) + old_slowmode = ctx.channel.slowmode_delay + slowmode_reason = f"{reason} | Moderator: {ctx.author} ({ctx.author.id})" + await ctx.channel.edit(slowmode_delay=seconds, reason=slowmode_reason) + if seconds == 0: + action = "Slowmode deaktiviert" + additional_info = f"Vorheriger Slowmode: {old_slowmode}s" if old_slowmode > 0 else None + else: + action = "Slowmode aktiviert" + additional_info = f"{emoji_slowmode} Slowmode auf {seconds} Sekunden gesetzt" + embed = self._create_moderation_embed(action, ctx.author, None, reason, duration=f"{seconds} Sekunden" if seconds > 0 else "Deaktiviert", additional_info=additional_info) + embed.add_field(name="๐Ÿ“ข ร— Kanal", value=ctx.channel.mention, inline=True) + await ctx.followup.send(embed=embed) + self.logger.info(f"Slowmode set to {seconds}s in {ctx.channel} by {ctx.author} ({ctx.author.id}): {reason}") + except discord.Forbidden: + embed = self._create_error_embed("Berechtigung verweigert", "Mir fehlen die Berechtigungen, um den Slowmode zu setzen.") + await ctx.followup.send(embed=embed) + except discord.HTTPException as e: + embed = self._create_error_embed("Discord-Fehler", f"Fehler beim Setzen des Slowmodes: {str(e)}") + await ctx.followup.send(embed=embed) + except Exception as e: + embed = self._create_error_embed("Unerwarteter Fehler", f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}") + await ctx.followup.send(embed=embed) + self.logger.error(f"Unexpected error in slowmode command: {e}", exc_info=True) + + @moderation.command(name="votekick", description="Startet eine Votekick-Abstimmung fรผr ein Mitglied") + @option("member", discord.Member, description="Das zu kickende Mitglied") + @option("reason", str, description="Grund fรผr den Kick", max_length=500, required=False) + @option("duration", int, description="Abstimmungsdauer in Minuten (Standard: 5)", min_value=1, max_value=30, required=False) + async def votekick(self, ctx: discord.ApplicationContext, member: discord.Member, reason: str = "Kein Grund angegeben", duration: int = 5): + await ctx.defer() + try: + if not self._has_permission(ctx.author, KICK): + embed = self._create_error_embed("Keine Berechtigung", "Du benรถtigst die `Mitglieder kicken` Berechtigung.") + return await ctx.followup.send(embed=embed, ephemeral=True) + if not self._has_permission(ctx.guild.me, KICK): + embed = self._create_error_embed("Bot-Berechtigung fehlt", "Mir fehlt die `Mitglieder kicken` Berechtigung.") + return await ctx.followup.send(embed=embed, ephemeral=True) + can_moderate, error_msg = self._can_moderate_member(ctx.author, member) + if not can_moderate: + embed = self._create_error_embed("Moderation nicht mรถglich", error_msg) + return await ctx.followup.send(embed=embed, ephemeral=True) + if member.id in self._active_votes: + embed = self._create_error_embed("Abstimmung bereits aktiv", f"Es lรคuft bereits eine Abstimmung fรผr {member.mention}.") + return await ctx.followup.send(embed=embed, ephemeral=True) + end_time = datetime.now(timezone.utc) + timedelta(minutes=duration) + embed = discord.Embed( + title=f"๐Ÿ—ณ๏ธ ร— Votekick fรผr {member.display_name}", + description=f"{ctx.author.mention} mรถchte {member.mention} kicken.\n\n" + f"**{emoji_summary} Grund:** {reason}\n\n" + f"Reagiere mit {emoji_yes} zum Kicken oder {emoji_no} zum Ablehnen.\n" + f"**๐Ÿ• Ende:** {discord.utils.format_dt(end_time, 'R')}", + color=discord.Color.orange(), + timestamp=datetime.now(timezone.utc) + ) + embed.set_author(name=f"Gestartet von {ctx.author}", icon_url=ctx.author.display_avatar.url) + embed.add_field(name=f"{emoji_member} ร— Ziel", value=f"{member.mention}", inline=True) + embed.add_field(name=f"{emoji_slowmode} ร— Dauer", value=f"{duration} Minuten", inline=True) + embed.set_footer(text=f"Votekick ID: {member.id}") + message = await ctx.followup.send(embed=embed) + await message.add_reaction(emoji_yes) + await message.add_reaction(emoji_no) + self._active_votes[member.id] = { + 'message': message, + 'initiator': ctx.author, + 'target': member, + 'reason': reason, + 'end_time': end_time, + 'guild': ctx.guild + } + asyncio.create_task(self._handle_votekick(member.id, duration * 60)) + except Exception as e: + embed = self._create_error_embed("Unerwarteter Fehler", f"Fehler bei der Votekick-Abstimmung: {str(e)}") + try: + await ctx.followup.send(embed=embed, ephemeral=True) + except: + await ctx.respond(embed=embed, ephemeral=True) + self.logger.error(f"Unexpected error in votekick command: {e}", exc_info=True) + + async def _handle_votekick(self, member_id: int, duration_seconds: int): + """Verwaltet eine Votekick-Abstimmung""" + await asyncio.sleep(duration_seconds) + if member_id not in self._active_votes: + return + vote_data = self._active_votes[member_id] + message = vote_data['message'] + target = vote_data['target'] + initiator = vote_data['initiator'] + reason = vote_data['reason'] + guild = vote_data['guild'] + try: + message = await message.channel.fetch_message(message.id) + yes_count = 0 + no_count = 0 + voters = set() + for reaction in message.reactions: + if str(reaction.emoji) == emoji_yes: + async for user in reaction.users(): + if not user.bot and user.id not in voters: + yes_count += 1 + voters.add(user.id) + elif str(reaction.emoji) == emoji_no: + async for user in reaction.users(): + if not user.bot and user.id not in voters: + no_count += 1 + voters.add(user.id) + total_members = len([m for m in guild.members if not m.bot]) + required_votes = max(3, total_members // 4) + if yes_count >= required_votes and yes_count > no_count: + try: + kick_reason = f"Votekick | Grund: {reason} | Initiator: {initiator} | Ja: {yes_count}, Nein: {no_count}" + await target.kick(reason=kick_reason) + result_embed = discord.Embed( + title=f"{emoji_yes} Votekick erfolgreich", + description=f"{emoji_member} {target.mention} wurde gekickt.", + color=discord.Color.green(), + timestamp=datetime.now(timezone.utc) + ) + result_embed.add_field(name="๐Ÿ“Š ร— Ergebnis", value=f"{emoji_yes} Ja: {yes_count} | {emoji_no} Nein: {no_count}\n{emoji_summary} Benรถtigt: {required_votes}", inline=False) + self.logger.info(f"Votekick successful: {target} ({target.id}) kicked with {yes_count} votes") + except discord.Forbidden: + result_embed = discord.Embed( + title=f"{emoji_no} ร— Votekick fehlgeschlagen", + description=f"Berechtigung fehlt, um {target.mention} zu kicken.", + color=discord.Color.red(), + timestamp=datetime.now(timezone.utc) + ) + except discord.HTTPException as e: + result_embed = discord.Embed( + title=f"{emoji_no} ร— Votekick fehlgeschlagen", + description=f"Fehler beim Kicken: {str(e)}", + color=discord.Color.red(), + timestamp=datetime.now(timezone.utc) + ) + else: + result_embed = discord.Embed( + title=f"{emoji_no} ร— Votekick abgelehnt", + description=f"{emoji_member} {target.mention} wurde nicht gekickt.", + color=discord.Color.red(), + timestamp=datetime.now(timezone.utc) + ) + result_embed.add_field(name="๐Ÿ“Š ร— Ergebnis", value=f"{emoji_yes} Ja: {yes_count} | {emoji_no} Nein: {no_count}\n{emoji_summary} Benรถtigt: {required_votes}", inline=False) + await message.edit(embed=result_embed, view=None) + except Exception as e: + self.logger.error(f"Error handling votekick result: {e}", exc_info=True) + finally: + if member_id in self._active_votes: + del self._active_votes[member_id] + + +def setup(bot): + bot.add_cog(moderationCog(bot)) \ No newline at end of file diff --git a/src/bot/cogs/moderation/notes.py b/src/bot/cogs/moderation/notes.py new file mode 100644 index 0000000..0aeae4b --- /dev/null +++ b/src/bot/cogs/moderation/notes.py @@ -0,0 +1,70 @@ +# Copyright (c) 2025 OPPRO.NET Network +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Imports +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +import discord +from discord import SlashCommandGroup +import datetime +import ezcord +from DevTools import NotesDatabase + +notes = SlashCommandGroup("notes") +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Cog +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class NotesCog(ezcord.Cog, group="moderation"): + + def __init__(self, bot): + self.bot = bot + self.db = NotesDatabase("data") + + @notes.command(name="add", description="๐Ÿ“ Speichere eine Notiz fรผr einen User") + async def add( + self, + ctx: discord.ApplicationContext, + user: discord.Member, + *, + content: str + ): + if not content: + return await ctx.respond("Bitte gib den Inhalt der Notiz an.", ephemeral=True) + + timestamp = datetime.datetime.now().strftime("%d.%m.%Y %H:%M") + self.db.add_note(ctx.guild.id, user.id, ctx.author.id, ctx.author.name, content, timestamp) + await ctx.respond(f"Notiz fรผr {user.mention} gespeichert.", ephemeral=True) + + @notes.command(name="list", description="๐Ÿ“œ Zeige alle Notizen eines Users an") + async def list(self, ctx: discord.ApplicationContext, user: discord.Member): + notes = self.db.get_notes(ctx.guild.id, user.id) + + if not notes: + return await ctx.respond(f"{emoji_no} {emoji_user}{user.mention} hat keine Notizen.", ephemeral=True) + + embed = discord.Embed(title=f"Notizen fรผr {user.name}", color=discord.Color.blurple()) + for note in notes: + embed.add_field( + name=f"ID: {note['id']} โ€“ von {note['author_name']} am {note['timestamp']}", + value=note['content'], + inline=False + ) + + await ctx.respond(embed=embed, ephemeral=True) + + @notes.command(name="delete", description="๐Ÿ—‘๏ธ Lรถsche eine Notiz eines Users") + async def delete(self, ctx: discord.ApplicationContext, user: discord.Member, note_id: int): + notes = self.db.get_notes(ctx.guild.id, user.id) + if not notes: + return await ctx.respond(f"User {user} (ID: {user.id}) hat keine Notizen.", ephemeral=True) + + note_ids = [note['id'] for note in notes] + if note_id not in note_ids: + return await ctx.respond(f"{emoji_no} Notiz mit ID {note_id} existiert nicht fรผr User {user}.", ephemeral=True) + + if self.db.delete_note(note_id): + await ctx.respond(f"{emoji_yes} Notiz mit ID {note_id} von User {user} wurde gelรถscht.", ephemeral=True) + else: + await ctx.respond(f"{emoji_no} Fehler beim Lรถschen der Notiz mit ID {note_id}.", ephemeral=True) + + +def setup(bot): + bot.add_cog(NotesCog(bot)) diff --git a/src/bot/cogs/moderation/warn.py b/src/bot/cogs/moderation/warn.py new file mode 100644 index 0000000..c56dd7f --- /dev/null +++ b/src/bot/cogs/moderation/warn.py @@ -0,0 +1,557 @@ +# Copyright (c) 2025 OPPRO.NET Network +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Imports +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +from DevTools import WarnDatabase +import discord +from discord import slash_command, Option +import os +import datetime +import ezcord +import asyncio +from typing import Optional + + +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# >> Cogs +# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +class WarnSystem(ezcord.Cog, group="moderation"): + """Erweiterte Warn-System Cog mit verbesserter Funktionalitรคt""" + + def __init__(self, bot): + self.bot = bot + base_path = os.path.dirname(__file__) + self.db = WarnDatabase(base_path) + # Cache fรผr bessere Performance + self._warn_cache = {} + + def _has_moderate_permissions(self, member: discord.Member) -> bool: + """รœberprรผft ob ein Member Moderationsrechte hat""" + return ( + member.guild_permissions.kick_members or + member.guild_permissions.ban_members or + member.guild_permissions.manage_messages or + member.guild_permissions.moderate_members + ) + + def _can_warn_member(self, moderator: discord.Member, target: discord.Member) -> tuple[bool, str]: + """รœberprรผft ob ein Moderator ein Ziel-Mitglied verwarnen kann""" + + # Server-Owner kann nicht verwarnt werden + if target.id == target.guild.owner_id: + return False, "Der Server Owner kann nicht verwarnt werden." + + # Selbst-Verwarnung verhindern + if moderator.id == target.id: + return False, "Du kannst dich nicht selbst verwarnen." + + # Bot kann nicht verwarnt werden + if target.bot: + return False, "Du kannst keine Bots verwarnen." + + # Rollen-Hierarchie prรผfen (auรŸer bei Owner) + if (moderator.top_role <= target.top_role and + moderator.id != target.guild.owner_id): + return False, "Du kannst keine Mitglieder mit gleicher oder hรถherer Rolle verwarnen." + + return True, "" + + def _create_warn_embed(self, action: str, moderator: discord.Member, + target: discord.Member, reason: str, + timestamp: str, warn_id: int = None) -> discord.Embed: + """Erstellt ein einheitliches Warn-Embed""" + + if action == "warn": + embed = discord.Embed( + title=f"{emoji_warn} Warnung erteilt", + color=SUCCESS_COLOR, + description=f"{target.mention} wurde erfolgreich verwarnt." + ) + elif action == "unwarn": + embed = discord.Embed( + title=f"{emoji_yes} Warnung entfernt", + color=SUCCESS_COLOR, + description=f"Warnung wurde erfolgreich entfernt." + ) + else: + embed = discord.Embed( + title=f" {action}", + color=SUCCESS_COLOR + ) + + embed.set_author(name=AUTHOR) + + if action == "warn": + embed.add_field(name=f"{emoji_member} ร— Verwarnter User", value=target.mention, inline=True) + embed.add_field(name=f"{emoji_staff} ร— Verwarnt von", value=moderator.mention, inline=True) + embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) + embed.add_field(name=f"{emoji_slowmode} ร— Zeitstempel", value=timestamp, inline=False) + embed.set_footer(text="Powered by ManagerX") + + elif action == "unwarn": + embed.add_field(name=f" Entfernt von", value=moderator.mention, inline=True) + if warn_id: + embed.add_field(name=f" Warnung ID", value=f"`{warn_id}`", inline=True) + embed.set_footer(text=FLOOTER) + + return embed + + def _create_error_embed(self, title: str, message: str) -> discord.Embed: + """Erstellt ein einheitliches Error-Embed""" + embed = discord.Embed(title=title, color=ERROR_COLOR) + embed.set_author(name=AUTHOR) + embed.add_field(name=f"{emoji_no} {title}", value=message, inline=False) + embed.set_footer(text=FLOOTER) + return embed + + @slash_command(name="warn", description="Warnen Sie einen Benutzer") + async def warn( + self, + ctx, + user: Option(discord.Member, "User to warn"), + reason: Option(str, "Reason for the warning", max_length=500) + ): + try: + # Berechtigung prรผfen + if not self._has_moderate_permissions(ctx.author): + embed = self._create_error_embed( + "Keine Berechtigung", + "Du benรถtigst Moderationsrechte, um Mitglieder zu verwarnen." + ) + return await ctx.respond(embed=embed, ephemeral=True) + + # Kann Mitglied verwarnt werden? + can_warn, error_msg = self._can_warn_member(ctx.author, user) + if not can_warn: + embed = self._create_error_embed("Verwarnung nicht mรถglich", error_msg) + return await ctx.respond(embed=embed, ephemeral=True) + + # Warn-Daten erstellen + timestamp = datetime.datetime.utcnow().strftime("%d.%m.%Y %H:%M") + + # In Datenbank speichern + try: + self.db.add_warning(ctx.guild.id, user.id, ctx.author.id, reason, timestamp) + + # Cache invalidieren + cache_key = f"{ctx.guild.id}_{user.id}" + if cache_key in self._warn_cache: + del self._warn_cache[cache_key] + + except Exception as e: + embed = self._create_error_embed( + "Datenbankfehler", + f"Fehler beim Speichern der Warnung: {str(e)}" + ) + return await ctx.respond(embed=embed, ephemeral=True) + + # Erfolgs-Embed + success_embed = self._create_warn_embed("warn", ctx.author, user, reason, timestamp) + await ctx.respond(embed=success_embed, ephemeral=True) + + # Optional: DM an verwarnten User senden + try: + dm_embed = discord.Embed( + title=f"{emoji_warn} Du wurdest verwarnt", + color=ERROR_COLOR, + description=f"Du wurdest auf **{ctx.guild.name}** verwarnt." + ) + dm_embed.add_field(name=f"{emoji_summary} ร— Grund", value=reason, inline=False) + dm_embed.add_field(name=f"{emoji_staff} ร— Moderator", value=str(ctx.author), inline=True) + dm_embed.add_field(name=f"{emoji_slowmode} ร— Zeitpunkt", value=timestamp, inline=True) + dm_embed.set_footer(text="Powered by ManagerX") + + await user.send(embed=dm_embed) + except discord.Forbidden: + # User hat DMs deaktiviert - ignorieren + pass + + except Exception as e: + embed = self._create_error_embed( + "Unerwarteter Fehler", + f"Ein unerwarteter Fehler ist aufgetreten: {str(e)}" + ) + await ctx.respond(embed=embed, ephemeral=True) + + @slash_command(name="warnings", description="Zeigt die Verwarnungen eines Users an") + async def warnings( + self, + ctx, + user: Option(discord.Member, "User whose warnings to show", required=False) + ): + try: + # Wenn kein User angegeben, eigene Warnungen zeigen + target_user = user if user else ctx.author + + # Cache prรผfen + cache_key = f"{ctx.guild.id}_{target_user.id}" + + if cache_key in self._warn_cache: + results = self._warn_cache[cache_key] + else: + # Warnungen aus Datenbank laden + results = self.db.get_warnings(ctx.guild.id, target_user.id) + self._warn_cache[cache_key] = results + + # รœberprรผfung ob User Warnungen einsehen darf + if target_user != ctx.author and not self._has_moderate_permissions(ctx.author): + embed = self._create_error_embed( + "Keine Berechtigung", + "Du kannst nur deine eigenen Warnungen einsehen." + ) + return await ctx.respond(embed=embed, ephemeral=True) + + if not results: + # Keine Warnungen vorhanden + no_warnings_embed = discord.Embed( + title=f"{emoji_circleinfo} Keine Verwarnungen", + color=SUCCESS_COLOR, + description=f"{target_user.mention} hat keine Verwarnungen." + ) + no_warnings_embed.set_author(name=AUTHOR) + no_warnings_embed.set_footer(text=FLOOTER) + return await ctx.respond(embed=no_warnings_embed, ephemeral=True) + + # Warnungen-Liste aufteilen falls zu viele (max 10 pro Seite) + warnings_per_page = 10 + total_warnings = len(results) + total_pages = (total_warnings + warnings_per_page - 1) // warnings_per_page + + if total_pages == 1: + # Alle Warnungen auf einer Seite + warn_list = "\n".join([ + f"**ID `{warn_id}`** | {timestamp}\nโ”” **Grund:** {reason[:100]}{'...' if len(reason) > 100 else ''}" + for warn_id, reason, timestamp in results[:warnings_per_page] + ]) + + warnings_embed = discord.Embed( + title=f"{emoji_warn} Verwarnungen fรผr {target_user.display_name}", + color=ERROR_COLOR, + description=warn_list + ) + warnings_embed.set_author(name=AUTHOR) + warnings_embed.add_field(name=f"{emoji_member} User", value=target_user.mention, inline=True) + warnings_embed.add_field(name=f"{emoji_summary} Anzahl Verwarnungen", value=str(total_warnings), inline=True) + warnings_embed.set_footer(text=FLOOTER) + + await ctx.respond(embed=warnings_embed, ephemeral=True) + else: + # Mehrere Seiten - ersten 10 zeigen mit Navigation + await self._send_paginated_warnings(ctx, target_user, results, 0) + + except Exception as e: + embed = self._create_error_embed( + "Unerwarteter Fehler", + f"Fehler beim Laden der Warnungen: {str(e)}" + ) + await ctx.respond(embed=embed, ephemeral=True) + + async def _send_paginated_warnings(self, ctx, target_user: discord.Member, + warnings: list, page: int = 0): + """Sendet paginierte Warnungen mit Navigation""" + warnings_per_page = 10 + total_pages = (len(warnings) + warnings_per_page - 1) // warnings_per_page + + start_idx = page * warnings_per_page + end_idx = min(start_idx + warnings_per_page, len(warnings)) + page_warnings = warnings[start_idx:end_idx] + + warn_list = "\n".join([ + f"**ID `{warn_id}`** | {timestamp}\nโ”” **Grund:** {reason[:100]}{'...' if len(reason) > 100 else ''}" + for warn_id, reason, timestamp in page_warnings + ]) + + embed = discord.Embed( + title=f"{emoji_warn} Verwarnungen fรผr {target_user.display_name}", + color=ERROR_COLOR, + description=warn_list + ) + embed.set_author(name=AUTHOR) + embed.add_field(name=f"{emoji_member} User", value=target_user.mention, inline=True) + embed.add_field(name=f"{emoji_summary} Anzahl Verwarnungen", value=str(len(warnings)), inline=True) + embed.set_footer(text=f"Seite {page + 1}/{total_pages} โ€ข {FLOOTER}") + + # View fรผr Navigation erstellen + view = WarningsView(self, target_user, warnings, page, total_pages) + + if ctx.response.is_done(): + await ctx.followup.send(embed=embed, view=view, ephemeral=True) + else: + await ctx.respond(embed=embed, view=view, ephemeral=True) + + @slash_command(name="unwarn", description="Lรถscht eine Verwarnung mit ID") + async def unwarn( + self, + ctx, + warn_id: Option(int, "Die ID der Verwarnung", min_value=1) + ): + try: + # Berechtigung prรผfen + if not self._has_moderate_permissions(ctx.author): + embed = self._create_error_embed( + "Keine Berechtigung", + "Du benรถtigst Moderationsrechte, um Verwarnungen zu lรถschen." + ) + return await ctx.respond(embed=embed, ephemeral=True) + + # Warnung suchen + result = self.db.get_warning_by_id(warn_id) + if not result: + embed = self._create_error_embed( + "Verwarnung nicht gefunden", + f"Keine Verwarnung mit der ID `{warn_id}` gefunden." + ) + return await ctx.respond(embed=embed, ephemeral=True) + + # รœberprรผfen ob Warnung zu diesem Server gehรถrt + warn_guild_id = result[1] # guild_id ist der zweite Wert + if warn_guild_id != ctx.guild.id: + embed = self._create_error_embed( + "Verwarnung nicht gefunden", + f"Keine Verwarnung mit der ID `{warn_id}` in diesem Server gefunden." + ) + return await ctx.respond(embed=embed, ephemeral=True) + + # Warnung lรถschen + success = self.db.delete_warning(warn_id) + if not success: + embed = self._create_error_embed( + "Lรถschfehler", + f"Fehler beim Lรถschen der Verwarnung `{warn_id}`." + ) + return await ctx.respond(embed=embed, ephemeral=True) + + # Cache invalidieren + user_id = result[2] # user_id ist der dritte Wert + cache_key = f"{ctx.guild.id}_{user_id}" + if cache_key in self._warn_cache: + del self._warn_cache[cache_key] + + # Erfolgs-Embed + removal_embed = self._create_warn_embed("unwarn", ctx.author, None, None, None, warn_id) + await ctx.respond(embed=removal_embed, ephemeral=True) + + except Exception as e: + embed = self._create_error_embed( + "Unerwarteter Fehler", + f"Fehler beim Lรถschen der Verwarnung: {str(e)}" + ) + await ctx.respond(embed=embed, ephemeral=True) + + @slash_command(name="clearwarns", description="Lรถscht alle Verwarnungen eines Users") + async def clearwarns( + self, + ctx, + user: Option(discord.Member, "User dessen Warnungen gelรถscht werden sollen"), + reason: Option(str, "Grund fรผr das Lรถschen", required=False, default="Kein Grund angegeben") + ): + try: + # Nur Administratoren kรถnnen alle Warnungen lรถschen + if not ctx.author.guild_permissions.administrator: + embed = self._create_error_embed( + "Keine Berechtigung", + "Du benรถtigst Administrator-Rechte, um alle Warnungen zu lรถschen." + ) + return await ctx.respond(embed=embed, ephemeral=True) + + # Aktuelle Warnungen zรคhlen + warn_count = self.db.get_warning_count(ctx.guild.id, user.id) + + if warn_count == 0: + embed = discord.Embed( + title=f"{emoji_summary} Keine Verwarnungen", + color=SUCCESS_COLOR, + description=f"{user.mention} hat keine Verwarnungen zum Lรถschen." + ) + embed.set_author(name=AUTHOR) + return await ctx.respond(embed=embed, ephemeral=True) + + # Bestรคtigung anfordern + confirm_embed = discord.Embed( + title=f"{emoji_warn} Bestรคtigung erforderlich", + color=ERROR_COLOR, + description=f"Mรถchtest du wirklich **{warn_count}** Warnungen von {user.mention} lรถschen?\n\n**Grund:** {reason}" + ) + confirm_embed.set_footer(text="Diese Aktion kann nicht rรผckgรคngig gemacht werden! ร— Powered by ManagerX") + + view = ClearWarningsConfirmView(self, user, ctx.author, reason, warn_count) + await ctx.respond(embed=confirm_embed, view=view, ephemeral=True) + + except Exception as e: + embed = self._create_error_embed( + "Unerwarteter Fehler", + f"Fehler beim Vorbereiten der Lรถschung: {str(e)}" + ) + await ctx.respond(embed=embed, ephemeral=True) + + async def clear_all_user_warnings(self, guild_id: int, user_id: int) -> int: + """Lรถscht alle Warnungen eines Users und gibt die Anzahl zurรผck""" + try: + # Alle Warn-IDs fรผr den User holen + warnings = self.db.get_warnings(guild_id, user_id) + deleted_count = 0 + + for warn_id, _, _ in warnings: + if self.db.delete_warning(warn_id): + deleted_count += 1 + + # Cache invalidieren + cache_key = f"{guild_id}_{user_id}" + if cache_key in self._warn_cache: + del self._warn_cache[cache_key] + + return deleted_count + + except Exception as e: + print(f"Fehler beim Lรถschen aller Warnungen: {e}") + return 0 + + +class WarningsView(discord.ui.View): + """View fรผr die Navigation durch paginierte Warnungen""" + + def __init__(self, cog, target_user: discord.Member, warnings: list, current_page: int, total_pages: int): + super().__init__(timeout=300) # 5 Minuten Timeout + self.cog = cog + self.target_user = target_user + self.warnings = warnings + self.current_page = current_page + self.total_pages = total_pages + + # Buttons aktivieren/deaktivieren + self.previous_button.disabled = current_page == 0 + self.next_button.disabled = current_page >= total_pages - 1 + + @discord.ui.button(label="โ—€ Vorherige", style=discord.ButtonStyle.secondary, disabled=True) + async def previous_button(self, button: discord.ui.Button, interaction: discord.Interaction): + if self.current_page > 0: + self.current_page -= 1 + await self._update_page(interaction) + + @discord.ui.button(label="Nรคchste โ–ถ", style=discord.ButtonStyle.secondary) + async def next_button(self, button: discord.ui.Button, interaction: discord.Interaction): + if self.current_page < self.total_pages - 1: + self.current_page += 1 + await self._update_page(interaction) + + async def _update_page(self, interaction: discord.Interaction): + """Aktualisiert die angezeigte Seite""" + warnings_per_page = 10 + start_idx = self.current_page * warnings_per_page + end_idx = min(start_idx + warnings_per_page, len(self.warnings)) + page_warnings = self.warnings[start_idx:end_idx] + + warn_list = "\n".join([ + f"**ID `{warn_id}`** | {timestamp}\nโ”” **Grund:** {reason[:100]}{'...' if len(reason) > 100 else ''}" + for warn_id, reason, timestamp in page_warnings + ]) + + embed = discord.Embed( + title=f"{emoji_warn} Verwarnungen fรผr {self.target_user.display_name}", + color=ERROR_COLOR, + description=warn_list + ) + embed.set_author(name=AUTHOR) + embed.add_field(name=f"{emoji_member} User", value=self.target_user.mention, inline=True) + embed.add_field(name=f"{emoji_summary} Anzahl Verwarnungen", value=str(len(self.warnings)), inline=True) + embed.set_footer(text=f"Seite {self.current_page + 1}/{self.total_pages} โ€ข {FLOOTER}") + + # Buttons aktualisieren + self.previous_button.disabled = self.current_page == 0 + self.next_button.disabled = self.current_page >= self.total_pages - 1 + + await interaction.response.edit_message(embed=embed, view=self) + + async def on_timeout(self): + """Deaktiviert alle Buttons nach Timeout""" + for item in self.children: + item.disabled = True + + +class ClearWarningsConfirmView(discord.ui.View): + """View fรผr die Bestรคtigung beim Lรถschen aller Warnungen""" + + def __init__(self, cog, target_user: discord.Member, moderator: discord.Member, reason: str, warn_count: int): + super().__init__(timeout=60) # 1 Minute Timeout + self.cog = cog + self.target_user = target_user + self.moderator = moderator + self.reason = reason + self.warn_count = warn_count + + @discord.ui.button(label="โœ… Bestรคtigen", style=discord.ButtonStyle.danger) + async def confirm_button(self, button: discord.ui.Button, interaction: discord.Interaction): + # รœberprรผfen ob der richtige User geantwortet hat + if interaction.user.id != self.moderator.id: + await interaction.response.send_message( + "โŒ Nur der ursprรผngliche Moderator kann diese Aktion bestรคtigen.", + ephemeral=True + ) + return + + try: + # Alle Warnungen lรถschen + deleted_count = await self.cog.clear_all_user_warnings( + interaction.guild.id, self.target_user.id + ) + + if deleted_count > 0: + success_embed = discord.Embed( + title=f"{emoji_yes} Warnungen gelรถscht", + color=SUCCESS_COLOR, + description=f"**{deleted_count}** Warnungen von {self.target_user.mention} wurden gelรถscht." + ) + success_embed.add_field(name="Grund", value=self.reason, inline=False) + success_embed.add_field(name="Moderator", value=self.moderator.mention, inline=True) + success_embed.set_footer(text=FLOOTER) + else: + success_embed = discord.Embed( + title=f"{emoji_no} Keine Warnungen gelรถscht", + color=ERROR_COLOR, + description="Es konnten keine Warnungen gelรถscht werden." + ) + + # View deaktivieren + for item in self.children: + item.disabled = True + + await interaction.response.edit_message(embed=success_embed, view=self) + + except Exception as e: + error_embed = discord.Embed( + title=ERROR_TITLE, + color=ERROR_COLOR, + description=f"Fehler beim Lรถschen: {str(e)}" + ) + await interaction.response.edit_message(embed=error_embed, view=None) + + @discord.ui.button(label="โŒ Abbrechen", style=discord.ButtonStyle.secondary) + async def cancel_button(self, button: discord.ui.Button, interaction: discord.Interaction): + # รœberprรผfen ob der richtige User geantwortet hat + if interaction.user.id != self.moderator.id: + await interaction.response.send_message( + "โŒ Nur der ursprรผngliche Moderator kann diese Aktion abbrechen.", + ephemeral=True + ) + return + + cancel_embed = discord.Embed( + title=f"{emoji_yes} Abgebrochen", + color=SUCCESS_COLOR, + description="Das Lรถschen der Warnungen wurde abgebrochen." + ) + + # View deaktivieren + for item in self.children: + item.disabled = True + + await interaction.response.edit_message(embed=cancel_embed, view=self) + + async def on_timeout(self): + """Deaktiviert alle Buttons nach Timeout""" + for item in self.children: + item.disabled = True + + +def setup(bot): + bot.add_cog(WarnSystem(bot)) \ No newline at end of file diff --git a/src/bot/cogs/user/settings.py b/src/bot/cogs/user/settings.py new file mode 100644 index 0000000..381ff7b --- /dev/null +++ b/src/bot/cogs/user/settings.py @@ -0,0 +1,108 @@ +import discord +from discord.ext import commands +from discord import SlashCommandGroup +import ezcord + +from mx_handler import TranslationHandler + + +class Settings(ezcord.Cog): + """Cog for setting user language preferences.""" + + user = SlashCommandGroup("user", "User settings commands") + + language = user.create_subgroup( + "language") + + AVAILABLE_LANGUAGES = { + "de": "Deutsch ๐Ÿ‡ฉ๐Ÿ‡ช", + "en": "English ๐Ÿ‡ฌ๐Ÿ‡ง" + } + + @language.command( + name="set", + description="Set your preferred language for bot messages." + ) + @discord.option( + "language", + description="Choose a language", + choices=[ + discord.OptionChoice(name=name, value=code) + for code, name in AVAILABLE_LANGUAGES.items() + ], + required=True + ) + async def set_language(self, ctx: discord.ApplicationContext, language: str): + """ + Set the user's preferred language. + + Args: + ctx: Discord application context + language: Selected language code + """ + # Save language preference + self.bot.settings_db.set_user_language(ctx.author.id, language) + + # Get display name for the selected language + lang_name = self.AVAILABLE_LANGUAGES.get(language, language) + + # Load response message using TranslationHandler + response_text = await TranslationHandler.get_async( + language, + "cog_settings.language.message.language_set", + default="Language has been set to {language}.", + language=lang_name + ) + + await ctx.respond(response_text, ephemeral=True) + + + @language.command() + async def get(self, ctx: discord.ApplicationContext): + """ + Get the user's current preferred language. + + Args: + ctx: Discord application context + """ + # Retrieve user's language preference + language = self.bot.settings_db.get_user_language(ctx.author.id) + + if not language: + response_text = await TranslationHandler.get_async( + "en", + "cog_settings.language.error_types.language_not_set", + default="You have not set a preferred language yet." + ) + else: + lang_name = self.AVAILABLE_LANGUAGES.get(language, language) + response_text = await TranslationHandler.get_async( + language, + "cog_settings.language.message.current_language", + default="Your current preferred language is {language}.", + language=lang_name + ) + + await ctx.respond(response_text, ephemeral=True) + + @language.command( + name="list", + description="List all available languages." + ) + + async def list_languages(self, ctx: discord.ApplicationContext): + """ + List all available languages. + + Args: + ctx: Discord application context + """ + languages_list = "\n".join( + f"{code}: {name}" for code, name in self.AVAILABLE_LANGUAGES.items() + ) + response_text = f"**Available Languages:**\n{languages_list}" + await ctx.respond(response_text, ephemeral=True) + +def setup(bot): + """Setup function to add the cog to the bot.""" + bot.add_cog(Settings(bot)) \ No newline at end of file diff --git a/src/bot/cogs/user/stats.py b/src/bot/cogs/user/stats.py new file mode 100644 index 0000000..99c35a6 --- /dev/null +++ b/src/bot/cogs/user/stats.py @@ -0,0 +1,598 @@ +# Copyright (c) 2025 OPPRO.NET Network +import discord +from discord.ext import commands, tasks +from discord import SlashCommandGroup +import logging +from typing import Optional +from DevTools import StatsDB +import asyncio +from datetime import datetime, timedelta +import math + + +logger = logging.getLogger(__name__) + + +class EnhancedStatsCog(commands.Cog): + """ + Enhanced Discord Cog for tracking user statistics with global level system. + Provides comprehensive tracking of messages, voice activity, and user progression. + """ + + def __init__(self, bot: commands.Bot): + self.bot = bot + self.db = StatsDB() + self.cleanup_task.start() + logger.info("Enhanced StatsCog initialized") + + stats = SlashCommandGroup("stats", "Statistiken") + + def cog_unload(self): + """Called when the cog is unloaded.""" + self.cleanup_task.cancel() + self.db.close() + logger.info("Enhanced StatsCog unloaded") + + @tasks.loop(hours=24) + async def cleanup_task(self): + """Daily cleanup of old data.""" + await self.db.cleanup_old_data(days=90) + + @cleanup_task.before_loop + async def before_cleanup(self): + await self.bot.wait_until_ready() + + @commands.Cog.listener() + async def on_ready(self): + """Called when the bot is ready and connected to Discord.""" + logger.info(f"Enhanced StatsCog ready - Bot connected as {self.bot.user}") + + @commands.Cog.listener() + async def on_voice_state_update(self, member: discord.Member, before: discord.VoiceState, + after: discord.VoiceState): + """Track voice channel activity with enhanced features.""" + if member.bot: + return + + try: + user_id = member.id + guild_id = member.guild.id + + # User left a voice channel + if before.channel and not after.channel: + await self.db.end_voice_session(user_id, before.channel.id) + logger.debug(f"User {member.display_name} left voice channel {before.channel.name}") + + # User joined a voice channel + elif not before.channel and after.channel: + await self.db.start_voice_session(user_id, guild_id, after.channel.id) + logger.debug(f"User {member.display_name} joined voice channel {after.channel.name}") + + # User switched voice channels + elif before.channel and after.channel and before.channel.id != after.channel.id: + await self.db.end_voice_session(user_id, before.channel.id) + await self.db.start_voice_session(user_id, guild_id, after.channel.id) + logger.debug(f"User {member.display_name} switched from {before.channel.name} to {after.channel.name}") + + except Exception as e: + logger.error(f"Error handling voice state update for {member.display_name}: {e}") + + @commands.Cog.listener() + async def on_message(self, message: discord.Message): + """Track messages with enhanced analysis.""" + if message.author.bot or not message.guild: + return + + try: + # Analyze message content + word_count = len(message.content.split()) if message.content else 0 + has_attachment = len(message.attachments) > 0 + message_type = 'text' + + if message.attachments: + message_type = 'attachment' + elif message.embeds: + message_type = 'embed' + elif message.stickers: + message_type = 'sticker' + + await self.db.log_message( + user_id=message.author.id, + guild_id=message.guild.id, + channel_id=message.channel.id, + message_id=message.id, + word_count=word_count, + has_attachment=has_attachment, + message_type=message_type + ) + + logger.debug(f"Logged enhanced message {message.id} from {message.author.display_name}") + + except Exception as e: + logger.error(f"Error logging enhanced message from {message.author.display_name}: {e}") + + @stats.command( + name="statsistics", + description="Zeige deine Aktivitรคtsstatistiken an" + ) + async def stats_command( + self, + ctx: discord.ApplicationContext, + zeitraum: discord.Option( + str, + description="Zeitraum fรผr die Statistiken", + choices=["24h", "7d", "30d"], + required=False, + default="24h" + ), + user: discord.Option( + discord.Member, + description="Statistiken eines anderen Users anzeigen (optional)", + required=False + ) + ): + """Enhanced stats command with more detailed information.""" + await ctx.defer() + + try: + target_user = user if user else ctx.author + time_periods = { + "24h": (24, "24 Stunden"), + "7d": (24 * 7, "7 Tagen"), + "30d": (24 * 30, "30 Tagen") + } + + hours, period_name = time_periods[zeitraum] + + # Get regular stats + message_count, voice_minutes = await self.db.get_user_stats( + target_user.id, hours, ctx.guild.id + ) + + # Get global user info + global_info = await self.db.get_global_user_info(target_user.id) + + # Format voice time + voice_hours = int(voice_minutes // 60) + voice_mins = int(voice_minutes % 60) + voice_time_str = f"{voice_hours}h {voice_mins}m" if voice_hours > 0 else f"{voice_mins}m" + + # Create main embed + embed = discord.Embed( + title=f"๐Ÿ“Š {'Deine' if target_user == ctx.author else f'{target_user.display_name}s'} Statistiken", + description=f"Aktivitรคt der letzten {period_name}", + color=discord.Color.blue() + ) + + # Local server stats + embed.add_field( + name="๐Ÿ“… Server Aktivitรคt", + value=f"๐Ÿ’ฌ **{message_count}** Nachrichten\n๐ŸŽค **{voice_time_str}** Voice-Zeit", + inline=True + ) + + # Global stats if available + if global_info: + level = global_info['level'] + xp_progress = global_info['xp_progress'] + xp_needed = global_info['xp_needed'] + progress_bar = self._create_progress_bar(xp_progress, xp_needed) + + embed.add_field( + name="๐ŸŒ Global Level", + value=f"**Level {level}** {self._get_level_emoji(level)}\n{progress_bar}\n`{int(xp_progress)}/{int(xp_needed)} XP`", + inline=True + ) + + # Global totals + total_voice_hours = int(global_info['total_voice_minutes'] // 60) + embed.add_field( + name="๐Ÿ† Global Totals", + value=f"๐Ÿ“จ **{global_info['total_messages']:,}** Nachrichten\n" + f"๐ŸŽค **{total_voice_hours:,}** Stunden Voice\n" + f"๐Ÿ”ฅ **{global_info['daily_streak']}** Tage Streak", + inline=True + ) + + embed.set_thumbnail(url=target_user.display_avatar.url) + embed.set_footer(text=f"Angefragt von {ctx.author.display_name}") + + await ctx.followup.send(embed=embed) + + except Exception as e: + logger.error(f"Error executing enhanced stats command: {e}") + error_embed = discord.Embed( + title="โŒ Fehler", + description="Es gab einen Fehler beim Abrufen der Statistiken.", + color=discord.Color.red() + ) + await ctx.followup.send(embed=error_embed, ephemeral=True) + + @stats.command( + name="globalstats", + description="Zeige deine globalen Level-Statistiken รผber alle Server an" + ) + async def global_stats_command( + self, + ctx: discord.ApplicationContext, + user: discord.Option( + discord.Member, + description="Global Stats eines anderen Users anzeigen", + required=False + ) + ): + """Show detailed global statistics and achievements.""" + await ctx.defer() + + try: + target_user = user if user else ctx.author + global_info = await self.db.get_global_user_info(target_user.id) + + if not global_info: + embed = discord.Embed( + title="๐Ÿ“Š Keine Daten", + description=f"{'Du hast' if target_user == ctx.author else f'{target_user.display_name} hat'} noch keine globalen Statistiken.", + color=discord.Color.orange() + ) + await ctx.followup.send(embed=embed) + return + + level = global_info['level'] + xp = global_info['xp'] + xp_progress = global_info['xp_progress'] + xp_needed = global_info['xp_needed'] + + # Create embed + embed = discord.Embed( + title=f"๐ŸŒ {'Deine' if target_user == ctx.author else f'{target_user.display_name}s'} Globalen Stats", + description=f"Level-System รผber alle Server", + color=self._get_level_color(level) + ) + + # Level info + progress_bar = self._create_progress_bar(xp_progress, xp_needed) + level_emoji = self._get_level_emoji(level) + + embed.add_field( + name=f"{level_emoji} Level & XP", + value=f"**Level {level}**\n{progress_bar}\n`{int(xp_progress):,} / {int(xp_needed):,} XP`\n`Total: {int(xp):,} XP`", + inline=False + ) + + # Activity stats + total_voice_hours = int(global_info['total_voice_minutes'] // 60) + days_since_joined = (datetime.now() - datetime.fromisoformat(global_info['first_seen'])).days + 1 + avg_messages_per_day = global_info['total_messages'] / days_since_joined + + embed.add_field( + name="๐Ÿ“ˆ Aktivitรคts-Statistiken", + value=f"๐Ÿ“จ **{global_info['total_messages']:,}** Nachrichten gesamt\n" + f"๐ŸŽค **{total_voice_hours:,}** Stunden in Voice\n" + f"๐Ÿข **{global_info['total_servers']}** Server aktiv\n" + f"๐Ÿ“Š **{avg_messages_per_day:.1f}** Nachrichten/Tag", + inline=True + ) + + # Streak info + embed.add_field( + name="๐Ÿ”ฅ Streak Statistiken", + value=f"๐Ÿ”ฅ **{global_info['daily_streak']}** Tage aktuell\n" + f"๐Ÿ† **{global_info['best_streak']}** Tage Rekord\n" + f"๐Ÿ“… Dabei seit **{days_since_joined}** Tagen", + inline=True + ) + + # Recent achievements + achievements = global_info['achievements'][-3:] # Last 3 achievements + if achievements: + achievement_text = "\n".join( + [f"{ach.get('icon', '๐Ÿ†')} {ach.get('name', 'Unknown')}" for ach in achievements]) + embed.add_field( + name="๐Ÿ† Neueste Erfolge", + value=achievement_text, + inline=True + ) + + embed.set_thumbnail(url=target_user.display_avatar.url) + embed.set_footer(text=f"Angefragt von {ctx.author.display_name} โ€ข Globales Level-System") + + await ctx.followup.send(embed=embed) + + except Exception as e: + logger.error(f"Error executing global stats command: {e}") + error_embed = discord.Embed( + title="โŒ Fehler", + description="Es gab einen Fehler beim Abrufen der globalen Statistiken.", + color=discord.Color.red() + ) + await ctx.followup.send(embed=error_embed, ephemeral=True) + + @stats.command( + name="leaderboard", + description="Zeige die Top-User Rangliste an" + ) + async def leaderboard_command( + self, + ctx: discord.ApplicationContext, + typ: discord.Option( + str, + description="Art der Rangliste", + choices=["global", "server"], + required=False, + default="server" + ), + limit: discord.Option( + int, + description="Anzahl der angezeigten User (max 20)", + min_value=5, + max_value=20, + required=False, + default=10 + ) + ): + """Show leaderboard for global or server stats.""" + await ctx.defer() + + try: + if typ == "global": + leaderboard_data = await self.db.get_leaderboard(limit) + title = "๐ŸŒ Globale Rangliste" + description = "Top User nach globalem Level & XP" + else: + leaderboard_data = await self.db.get_leaderboard(limit, ctx.guild.id) + title = f"๐Ÿข {ctx.guild.name} Rangliste" + description = "Top User der letzten 30 Tage" + + if not leaderboard_data: + embed = discord.Embed( + title="๐Ÿ“Š Keine Daten", + description="Keine Ranglisten-Daten verfรผgbar.", + color=discord.Color.orange() + ) + await ctx.followup.send(embed=embed) + return + + embed = discord.Embed( + title=title, + description=description, + color=discord.Color.gold() + ) + + leaderboard_text = "" + for i, data in enumerate(leaderboard_data, 1): + try: + user = self.bot.get_user(data[0]) + username = user.display_name if user else "Unbekannter User" + + # Position emoji + if i == 1: + pos_emoji = "๐Ÿฅ‡" + elif i == 2: + pos_emoji = "๐Ÿฅˆ" + elif i == 3: + pos_emoji = "๐Ÿฅ‰" + else: + pos_emoji = f"{i}." + + if typ == "global": + # Global leaderboard format: user_id, level, xp, messages, voice + level, xp, messages, voice = data[1], data[2], data[3], data[4] + level_emoji = self._get_level_emoji(level) + leaderboard_text += f"{pos_emoji} **{username}** {level_emoji}\n" + leaderboard_text += f" Level {level} โ€ข {int(xp):,} XP\n\n" + else: + # Server leaderboard format: user_id, messages, words + messages, words = data[1], data[2] + leaderboard_text += f"{pos_emoji} **{username}**\n" + leaderboard_text += f" {messages:,} Nachrichten โ€ข {words:,} Wรถrter\n\n" + + except Exception as e: + logger.error(f"Error processing leaderboard entry: {e}") + continue + + if leaderboard_text: + embed.description = leaderboard_text + else: + embed.description = "Fehler beim Laden der Rangliste." + + embed.set_footer(text=f"Angefragt von {ctx.author.display_name}") + await ctx.followup.send(embed=embed) + + except Exception as e: + logger.error(f"Error executing leaderboard command: {e}") + error_embed = discord.Embed( + title="โŒ Fehler", + description="Es gab einen Fehler beim Laden der Rangliste.", + color=discord.Color.red() + ) + await ctx.followup.send(embed=error_embed, ephemeral=True) + + @stats.command( + name="achievements", + description="Zeige deine freigeschalteten Erfolge an" + ) + async def achievements_command( + self, + ctx: discord.ApplicationContext, + user: discord.Option( + discord.Member, + description="Erfolge eines anderen Users anzeigen", + required=False + ) + ): + """Show user achievements.""" + await ctx.defer() + + try: + target_user = user if user else ctx.author + global_info = await self.db.get_global_user_info(target_user.id) + + if not global_info: + embed = discord.Embed( + title="๐Ÿ† Keine Erfolge", + description=f"{'Du hast' if target_user == ctx.author else f'{target_user.display_name} hat'} noch keine Erfolge freigeschaltet.", + color=discord.Color.orange() + ) + await ctx.followup.send(embed=embed) + return + + achievements = global_info.get('achievements', []) + + if not achievements: + embed = discord.Embed( + title="๐Ÿ† Noch keine Erfolge", + description=f"{'Du hast' if target_user == ctx.author else f'{target_user.display_name} hat'} noch keine Erfolge freigeschaltet.\nWerde aktiver um Erfolge zu sammeln!", + color=discord.Color.blue() + ) + await ctx.followup.send(embed=embed) + return + + embed = discord.Embed( + title=f"๐Ÿ† {'Deine' if target_user == ctx.author else f'{target_user.display_name}s'} Erfolge", + description=f"**{len(achievements)}** Erfolge freigeschaltet", + color=discord.Color.gold() + ) + + # Group achievements by category or show all + achievement_text = "" + for ach in achievements: + icon = ach.get('icon', '๐Ÿ†') + name = ach.get('name', 'Unbekannter Erfolg') + desc = ach.get('description', 'Keine Beschreibung') + unlocked = ach.get('unlocked_at', 'Unbekannt') + + achievement_text += f"{icon} **{name}**\n" + achievement_text += f" {desc}\n" + if unlocked != 'Unbekannt': + try: + unlock_date = datetime.fromisoformat(unlocked).strftime("%d.%m.%Y") + achievement_text += f" Freigeschaltet: {unlock_date}\n" + except: + pass + achievement_text += "\n" + + # Split into multiple fields if too long + if len(achievement_text) > 1024: + # Split achievements into chunks + chunks = [achievements[i:i + 5] for i in range(0, len(achievements), 5)] + for i, chunk in enumerate(chunks): + field_text = "" + for ach in chunk: + icon = ach.get('icon', '๐Ÿ†') + name = ach.get('name', 'Unbekannter Erfolg') + field_text += f"{icon} **{name}**\n" + + embed.add_field( + name=f"Erfolge {i * 5 + 1}-{min((i + 1) * 5, len(achievements))}", + value=field_text, + inline=True + ) + else: + embed.description = achievement_text + + embed.set_thumbnail(url=target_user.display_avatar.url) + embed.set_footer(text=f"Angefragt von {ctx.author.display_name}") + + await ctx.followup.send(embed=embed) + + except Exception as e: + logger.error(f"Error executing achievements command: {e}") + error_embed = discord.Embed( + title="โŒ Fehler", + description="Es gab einen Fehler beim Laden der Erfolge.", + color=discord.Color.red() + ) + await ctx.followup.send(embed=error_embed, ephemeral=True) + + @stats.command( + name="stats_info", + description="Informationen รผber das erweiterte Statistik-System" + ) + async def stats_info_command(self, ctx: discord.ApplicationContext): + """Provide information about the enhanced statistics system.""" + embed = discord.Embed( + title="โ„น๏ธ Erweitertes Statistik-System", + description="Informationen รผber das Activity-Tracking & Level-System", + color=discord.Color.green() + ) + + embed.add_field( + name="๐Ÿ“Š Was wird getrackt?", + value="โ€ข **Server-spezifisch:** Nachrichten & Voice-Zeit\n" + "โ€ข **Global:** Level, XP, Gesamtaktivitรคt\n" + "โ€ข **Erweitert:** Wortanzahl, Anhรคnge, Streaks", + inline=False + ) + + embed.add_field( + name="๐ŸŒ Globales Level-System", + value="โ€ข **XP-Quellen:** Nachrichten (+1-6 XP), Voice-Chat (+0.5 XP/min)\n" + "โ€ข **Level:** Basiert auf Gesamt-XP รผber alle Server\n" + "โ€ข **Erfolge:** Automatisch fรผr Meilensteine freigeschaltet", + inline=False + ) + + embed.add_field( + name="๐Ÿ† Verfรผgbare Kommandos", + value="โ€ข `/stats` - Server Aktivitรคts-Statistiken\n" + "โ€ข `/globalstats` - Globale Level & Erfolge\n" + "โ€ข `/leaderboard` - Ranglisten (global/server)\n" + "โ€ข `/achievements` - Freigeschaltete Erfolge", + inline=False + ) + + embed.add_field( + name="๐Ÿ”’ Datenschutz", + value="โ€ข Nur Metadaten werden gespeichert (keine Inhalte)\n" + "โ€ข Automatische Bereinigung alter Daten nach 90 Tagen\n" + "โ€ข [Vollstรคndige Datenschutzerklรคrung](https://medicopter117.github.io/ManagerX-Web/privacy.html)", + inline=False + ) + + embed.set_footer(text="Das globale Level-System funktioniert serverรผbergreifend!") + await ctx.respond(embed=embed, ephemeral=True) + + def _create_progress_bar(self, current: float, maximum: float, length: int = 10) -> str: + """Create a visual progress bar.""" + if maximum <= 0: + return "โ–“" * length + + filled = int((current / maximum) * length) + bar = "โ–“" * filled + "โ–‘" * (length - filled) + percentage = (current / maximum) * 100 + return f"{bar} {percentage:.1f}%" + + def _get_level_emoji(self, level: int) -> str: + """Get emoji based on user level.""" + if level >= 100: + return "๐Ÿ‘‘" + elif level >= 50: + return "๐Ÿ†" + elif level >= 25: + return "๐Ÿ…" + elif level >= 10: + return "โญ" + elif level >= 5: + return "๐ŸŒŸ" + else: + return "๐Ÿ”ฐ" + + def _get_level_color(self, level: int) -> discord.Color: + """Get embed color based on user level.""" + if level >= 100: + return discord.Color.gold() + elif level >= 50: + return discord.Color.purple() + elif level >= 25: + return discord.Color.red() + elif level >= 10: + return discord.Color.orange() + elif level >= 5: + return discord.Color.green() + else: + return discord.Color.blue() + + +def setup(bot: commands.Bot): + """Setup function to add the enhanced cog to the bot.""" + bot.add_cog(EnhancedStatsCog(bot)) \ No newline at end of file diff --git a/src/bot/core/__init__.py b/src/bot/core/__init__.py index a269625..61d58e5 100644 --- a/src/bot/core/__init__.py +++ b/src/bot/core/__init__.py @@ -11,7 +11,6 @@ from .database import DatabaseManager from .dashboard import DashboardTask from .utils import print_logo, format_uptime, truncate_text -from .groups import * __all__ = [ 'ConfigLoader', diff --git a/translation/en_en.json b/translation/en_en.json new file mode 100644 index 0000000..f62542d --- /dev/null +++ b/translation/en_en.json @@ -0,0 +1,31 @@ +{ + "times": { + "min": "minute", + "sec": "second", + "hour": "hour", + "day": "day" + }, + "bot": { + "error_title": "โ›” โจฏ Error", + "error": "An **unexpected error** has occurred. {}\nI have informed my developer about this issue.", + "cooldown_title": "โŒ› โจฏ Cooldown", + "cooldown": "Try again {}.", + "no_perms_title": "\uD83D\uDEA8 โจฏ Missing permissions", + "no_perms": "I'm missing the following permissions to execute this command.", + "no_user_perms": "You do not have permission to run this command." + }, + "help": { + "cmd_name": "help", + "cmd_description": "\uD83D\uDD25 Displays a list of all commands.", + "wrong_user": "This help command does not belong to you!", + "placeholder": "\uD83D\uDD30 โ€บ Choose a category", + "embed_title": "My commands", + "default_description": "All commands of category **{}**.", + "no_commands": "Oops, I couldn't find any commands that you have access to." + }, + "blacklist": { + "admin_group": "admin", + "no_perms": "You have been banned from using this bot. If you think this is a mistake, please contact my owner.", + "guild_error": "I left your server **{}** because you don't have permissions to use me. If you think this is a mistake, please contact my owner." + } +} \ No newline at end of file diff --git a/translation/ez_de.json b/translation/ez_de.json new file mode 100644 index 0000000..b4f48bb --- /dev/null +++ b/translation/ez_de.json @@ -0,0 +1,32 @@ + +{ + "times": { + "min": "Minute", + "sec": "Sekunde", + "hour": "Stunde", + "day": "Tag" + }, + "bot": { + "error_title": "โ›” โจฏ Error", + "error": "Ein **unbekannter Fehler** ist aufgetreten. {}\nIch habe meinen Entwickler รผber dieses Problem informiert.", + "cooldown_title": "โŒ› โจฏ Cooldown", + "cooldown": "Versuche es {} erneut.", + "no_perms_title": "\uD83D\uDEA8 โจฏ Fehlende Rechte", + "no_perms": "Mir fehlen die folgenden Berechtigungen, um diesen Befehl auszufรผhren.", + "no_user_perms": "Du hast keine Rechte, um diesen Befehl auszufรผhren." + }, + "help": { + "cmd_name": "help", + "cmd_description": "\uD83D\uDD25 Zeigt eine Liste aller Befehle an.", + "wrong_user": "Dieser Help Command gehรถrt dir nicht!", + "placeholder": "\uD83D\uDD30 โ€บ Wรคhle eine Kategorie", + "embed_title": "Meine Befehle", + "default_description": "Alle Befehle der Kategorie **{}**.", + "no_commands": "Ups, ich konnte keine Befehle finden, auf die du Zugriff hast." + }, + "blacklist": { + "admin_group": "admin", + "no_perms": "Du wurdest von der Nutzung dieses Bots ausgeschlossen. Wenn du denkst, dass dies ein Fehler ist, kontaktiere meinen Owner.", + "guild_error": "Ich habe deinen Server **{}** verlassen, da du keine Rechte hast, um mich zu nutzen. Wenn du denkst, dass dies ein Fehler ist, kontaktiere meinen Owner." + } +} \ No newline at end of file diff --git a/translation/messages/de.yaml b/translation/messages/de.yaml new file mode 100644 index 0000000..fc883c2 --- /dev/null +++ b/translation/messages/de.yaml @@ -0,0 +1,122 @@ +general: + + error_types: + no_permission: "Du hast keine Berechtigung, diesen Befehl auszufรผhren." + user_not_found: "Benutzer nicht gefunden." + bot_error: "Ein Fehler ist im Bot aufgetreten. Bitte versuche es spรคter erneut." + option_missing: "Eine erforderliche Option fehlt." + bot_has_no_permission: "Der Bot hat nicht die erforderlichen Berechtigungen, um diesen Befehl auszufรผhren." + + +cog_settings: + language: + error_types: + unsupported_language: "Die angegebene Sprache wird nicht unterstรผtzt." + same_language: "Die angegebene Sprache ist bereits eingestellt." + failed_set_language: "Fehler beim Einstellen der Sprache." + language_not_set: "Du hast noch keine bevorzugte Sprache eingestellt." + + + message: + language_set: "Die Sprache wurde auf {language} gesetzt." + current_language: "Deine aktuelle bevorzugte Sprache ist {language}." + +######################################################### +# Fun Cogs +######################################################### + +cog_4gewinnt: + error_types: + not_your_turn: "Es ist nicht dein Zug." + this_column_full: "Diese Spalte ist voll!" + is_opponent_bot: "Du kannst nicht gegen einen Bot spielen!" + is_opponent_self: "Du kannst nicht gegen dich selbst spielen!" + + + + win_types: + win: "Spiel vorbei! {winner} hat gewonnen!\n\n{board_str}" + draw: "Unentschieden!\n\n{board_str}" + + message: + start_game: "4 Gewinnt: {author_mention} (๐Ÿ”ด) vs {opponent_mention} (๐ŸŸก)\n{author_mention} fรคngt an!\n\n" + player_turn: "{view.current_player.mention} ist jetzt dran!\n\n{board_str}" + + + +cog_tictactoe: + error_types: + not_your_turn: "Es ist nicht dein Zug." + this_cell_taken: "Dieses Feld ist bereits belegt!" + is_opponent_bot: "Du kannst nicht gegen einen Bot spielen!" + is_opponent_self: "Du kannst nicht gegen dich selbst spielen!" + + + + win_types: + win: "Spiel vorbei! {winner} hat gewonnen!" + draw: "Unentschieden!" + + message: + start_game: "Tic Tac Toe: {author_mention} (X) gegen {opponent_mention} (O)\n{author_mention} fรคngt an!" + +cog_weather: + error_types: + city_not_found: "โš ๏ธ Stadt nicht gefunden." + api_error: "โŒ Fehler bei der Wetter-API." + + messages: + weather_report: "# ๐ŸŒค๏ธ Wetterbericht fรผr {city}, {country}:\n\n" + temperature: "**๐ŸŒก๏ธ Temperatur:** {temperature}ยฐC\n" + humidity: "**๐Ÿ’ง Luftfeuchtigkeit:** {humidity}%\n" + wind_speed: "**๐Ÿ’จ Windgeschwindigkeit:** {wind_speed} km/h ({wind_dir})\n" + condition: "**โ˜๏ธ Wetterbedingungen:** {condition}\n" + visibility: "**๐ŸŒซ๏ธ Sichtweite:** {visibility} km\n" + pressure: "**๐Ÿงญ Luftdruck:** {pressure} hPa\n" + +cog_autorole: + error_types: + role_to_high: + title: "โŒ Fehler" + desc: "Ich kann diese Rolle nicht vergeben, da sie hรถher oder gleich meiner hรถchsten Rolle ist!" + role_managed: + title: "โŒ Fehler" + desc: "Diese Rolle wird von einer Integration verwaltet und kann nicht als Autorole hinzugefรผgt werden!" + not_found: + title: "โŒ Autorole nicht gefunden" + desc: "Es existiert keine Autorole mit der ID `{autorole_id}`!" + wrong_guild: + title: "โŒ Fehler" + desc: "Diese Autorole gehรถrt nicht zu diesem Server!" + no_roles: + title: "โŒ Keine Autoroles" + desc: "Es sind keine Autoroles fรผr diesen Server eingerichtet!" + role_deleted: + title: "โš ๏ธ Rolle nicht gefunden" + desc: "Die konfigurierte Rolle fรผr `{autorole_id}` existiert nicht mehr!" + + messages: + add_success: + title: "โœ… Autorole hinzugefรผgt" + desc: "Neue Mitglieder erhalten automatisch die Rolle {role}\n\n**Autorole-ID:** `{autorole_id}`" + remove_success: + title: "โœ… Autorole entfernt" + desc: "Die Autorole `{autorole_id}` wurde erfolgreich entfernt!" + toggle_success: + enabled_title: "โœ… Autorole aktiviert" + enabled_desc: "Die Autorole `{autorole_id}` wurde aktiviert!" + disabled_title: "โœ… Autorole deaktiviert" + disabled_desc: "Die Autorole `{autorole_id}` wurde deaktiviert!" + list: + title: "๐Ÿ“‹ Autoroles Liste" + desc: "Alle Autoroles fรผr **{guild_name}**" + role_deleted: "โš ๏ธ **Rolle gelรถscht**" + info: + title: "โ„น๏ธ Autorole Information" + desc: "Details zur Autorole `{autorole_id}`" + + system: + audit_reason: "Autorole System" + console_log: "โœ… Autoroles [{role_names}] wurden {member_name} zugewiesen" + error_forbidden: "โŒ Keine Berechtigung, um Rollen zu vergeben" + error_http: "โŒ Fehler beim Zuweisen der Rollen: {error}" \ No newline at end of file diff --git a/translation/messages/en.yaml b/translation/messages/en.yaml new file mode 100644 index 0000000..495906d --- /dev/null +++ b/translation/messages/en.yaml @@ -0,0 +1,119 @@ +general: + error_types: + no_permission: "You do not have permission to execute this command." + user_not_found: "User not found." + bot_error: "An error occurred within the bot. Please try again later." + option_missing: "A required option is missing." + bot_has_no_permission: "The bot does not have the necessary permissions to execute this command." + +cog_settings: + language: + error_types: + unsupported_language: "The specified language is not supported." + same_language: "The specified language is already set." + failed_set_language: "Failed to set the language." + language_not_set: "You have not set a preferred language yet." + + message: + language_set: "Language has been set to {language}." + current_language: "Your current preferred language is {language}." + +################################################################### +# +# Cog Folder: cogs/fun +# +#################################################################### +cog_4gewinnt: + error_types: + not_your_turn: "It's not your turn." + this_column_full: "This column is full!" + is_opponent_bot: "You cannot play against a bot!" + is_opponent_self: "You cannot play against yourself!" + + win_types: + win: "Game over! {winner} won!\n\n{board_str}" + draw: "It's a draw!\n\n{board_str}" + + message: + start_game: "Connect Four: {author_mention} (๐Ÿ”ด) vs {opponent_mention} (๐ŸŸก)\n{author_mention} starts!\n\n" + player_turn: "{view.current_player.mention}'s turn now!\n\n{board_str}" + +cog_tictactoe: + error_types: + not_your_turn: "It's not your turn." + this_cell_taken: "This cell is already taken!" + is_opponent_bot: "You cannot play against a bot!" + is_opponent_self: "You cannot play against yourself!" + + win_types: + win: "Game over! {winner} won!" + draw: "It's a draw!" + + message: + # NEU: Nur einfache Schlรผssel verwenden + start_game: "Tic Tac Toe: {author_mention} (X) vs {opponent_mention} (O)\n{author_mention} starts!" + +cog_weather: + error_types: + city_not_found: "โš ๏ธ City not found." + api_error: "โŒ Error with the weather API." + + messages: + weather_report: "# ๐ŸŒค๏ธ Weather report for {city}, {country}:\n\n" + temperature: "**๐ŸŒก๏ธ Temperature:** {temperature}ยฐC\n" + humidity: "**๐Ÿ’ง Humidity:** {humidity}%\n" + wind_speed: "**๐Ÿ’จ Wind:** {wind_speed} km/h ({wind_dir})\n" + condition: "**โ˜๏ธ Condition:** {condition}\n" + visibility: "**๐ŸŒซ๏ธ Visibility:** {visibility} km\n" + pressure: "**๐Ÿงญ Pressure:** {pressure} hPa\n" + +######################################################### +# Server Management +######################################################### + +cog_autorole: + error_types: + role_to_high: + title: "โŒ Error" + desc: "I cannot assign this role because it is higher than or equal to my highest role!" + role_managed: + title: "โŒ Error" + desc: "This role is managed by an integration and cannot be added as an autorole!" + not_found: + title: "โŒ Autorole Not Found" + desc: "There is no autorole with the ID `{autorole_id}`!" + wrong_guild: + title: "โŒ Error" + desc: "This autorole does not belong to this server!" + no_roles: + title: "โŒ No Autoroles" + desc: "No autoroles have been set up for this server!" + role_deleted: + title: "โš ๏ธ Role Not Found" + desc: "The configured role for `{autorole_id}` no longer exists!" + + messages: + add_success: + title: "โœ… Autorole Added" + desc: "New members will now automatically receive the role {role}\n\n**Autorole-ID:** `{autorole_id}`" + remove_success: + title: "โœ… Autorole Removed" + desc: "The autorole `{autorole_id}` was successfully removed!" + toggle_success: + enabled_title: "โœ… Autorole Enabled" + enabled_desc: "The autorole `{autorole_id}` has been enabled!" + disabled_title: "โœ… Autorole Disabled" + disabled_desc: "The autorole `{autorole_id}` has been disabled!" + list: + title: "๐Ÿ“‹ Autoroles List" + desc: "All autoroles for **{guild_name}**" + role_deleted: "โš ๏ธ **Role deleted**" + info: + title: "โ„น๏ธ Autorole Information" + desc: "Details for autorole `{autorole_id}`" + + system: + audit_reason: "Autorole System" + console_log: "โœ… Autoroles [{role_names}] were assigned to {member_name}" + error_forbidden: "โŒ Missing permissions to assign roles" + error_http: "โŒ Error while assigning roles: {error}" \ No newline at end of file From 74b6597013bdcb5b5adcbcdc75623505a2b25c8b Mon Sep 17 00:00:00 2001 From: Medicopter117 Date: Mon, 19 Jan 2026 11:19:56 +0100 Subject: [PATCH 8/8] FEAT: Site updated --- .gitignore | 3 +- components.json | 20 + eslint.config.js | 26 + index.html | 28 + package-lock.json | 8311 ++++++++++++++++++++ package.json | 90 + postcss.config.js | 6 + renovate.json | 34 + requirements/bot_req.txt | 14 + requirements/dev_req.txt | 19 + requirements/docs_req.txt | 7 + requirements/req.txt | 44 + src/site/App.css | 42 + src/site/App.tsx | 33 + src/site/components/CTA.tsx | 70 + src/site/components/FAQ.tsx | 104 + src/site/components/FeatureCard.tsx | 75 + src/site/components/Features.tsx | 112 + src/site/components/Footer.tsx | 140 + src/site/components/Hero.tsx | 135 + src/site/components/NavLink.tsx | 28 + src/site/components/Navbar.tsx | 149 + src/site/components/Testimonials.tsx | 168 + src/site/components/ui/accordion.tsx | 52 + src/site/components/ui/alert-dialog.tsx | 104 + src/site/components/ui/alert.tsx | 43 + src/site/components/ui/aspect-ratio.tsx | 5 + src/site/components/ui/avatar.tsx | 38 + src/site/components/ui/badge.tsx | 29 + src/site/components/ui/breadcrumb.tsx | 90 + src/site/components/ui/button.tsx | 51 + src/site/components/ui/calendar.tsx | 54 + src/site/components/ui/card.tsx | 43 + src/site/components/ui/carousel.tsx | 224 + src/site/components/ui/chart.tsx | 303 + src/site/components/ui/checkbox.tsx | 26 + src/site/components/ui/collapsible.tsx | 9 + src/site/components/ui/command.tsx | 132 + src/site/components/ui/context-menu.tsx | 178 + src/site/components/ui/dialog.tsx | 95 + src/site/components/ui/drawer.tsx | 87 + src/site/components/ui/dropdown-menu.tsx | 179 + src/site/components/ui/form.tsx | 129 + src/site/components/ui/hover-card.tsx | 27 + src/site/components/ui/input-otp.tsx | 61 + src/site/components/ui/input.tsx | 22 + src/site/components/ui/label.tsx | 17 + src/site/components/ui/menubar.tsx | 207 + src/site/components/ui/navigation-menu.tsx | 120 + src/site/components/ui/pagination.tsx | 81 + src/site/components/ui/popover.tsx | 29 + src/site/components/ui/progress.tsx | 23 + src/site/components/ui/radio-group.tsx | 36 + src/site/components/ui/resizable.tsx | 37 + src/site/components/ui/scroll-area.tsx | 38 + src/site/components/ui/select.tsx | 143 + src/site/components/ui/separator.tsx | 20 + src/site/components/ui/sheet.tsx | 107 + src/site/components/ui/sidebar.tsx | 637 ++ src/site/components/ui/skeleton.tsx | 7 + src/site/components/ui/slider.tsx | 23 + src/site/components/ui/sonner.tsx | 27 + src/site/components/ui/switch.tsx | 27 + src/site/components/ui/table.tsx | 72 + src/site/components/ui/tabs.tsx | 53 + src/site/components/ui/textarea.tsx | 21 + src/site/components/ui/toast.tsx | 111 + src/site/components/ui/toaster.tsx | 24 + src/site/components/ui/toggle-group.tsx | 49 + src/site/components/ui/toggle.tsx | 37 + src/site/components/ui/tooltip.tsx | 28 + src/site/components/ui/use-toast.ts | 3 + src/site/hooks/use-mobile.tsx | 19 + src/site/hooks/use-toast.ts | 186 + src/site/index.css | 282 + src/site/lib/utils.ts | 6 + src/site/main.tsx | 10 + src/site/pages/Datenschutz.tsx | 129 + src/site/pages/Impressum.tsx | 79 + src/site/pages/Index.tsx | 23 + src/site/pages/NotFound.tsx | 24 + src/site/pages/Nutzungsbedingungen.tsx | 107 + src/site/test/example.test.ts | 7 + src/site/test/setup.ts | 15 + src/site/vite-env.d.ts | 1 + tailwind.config.ts | 95 + tsconfig.app.json | 31 + tsconfig.json | 16 + tsconfig.node.json | 22 + vite.config.ts | 21 + vitest.config.ts | 16 + 91 files changed, 14704 insertions(+), 1 deletion(-) create mode 100644 components.json create mode 100644 eslint.config.js create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.js create mode 100644 renovate.json create mode 100644 requirements/bot_req.txt create mode 100644 requirements/dev_req.txt create mode 100644 requirements/docs_req.txt create mode 100644 requirements/req.txt create mode 100644 src/site/App.css create mode 100644 src/site/App.tsx create mode 100644 src/site/components/CTA.tsx create mode 100644 src/site/components/FAQ.tsx create mode 100644 src/site/components/FeatureCard.tsx create mode 100644 src/site/components/Features.tsx create mode 100644 src/site/components/Footer.tsx create mode 100644 src/site/components/Hero.tsx create mode 100644 src/site/components/NavLink.tsx create mode 100644 src/site/components/Navbar.tsx create mode 100644 src/site/components/Testimonials.tsx create mode 100644 src/site/components/ui/accordion.tsx create mode 100644 src/site/components/ui/alert-dialog.tsx create mode 100644 src/site/components/ui/alert.tsx create mode 100644 src/site/components/ui/aspect-ratio.tsx create mode 100644 src/site/components/ui/avatar.tsx create mode 100644 src/site/components/ui/badge.tsx create mode 100644 src/site/components/ui/breadcrumb.tsx create mode 100644 src/site/components/ui/button.tsx create mode 100644 src/site/components/ui/calendar.tsx create mode 100644 src/site/components/ui/card.tsx create mode 100644 src/site/components/ui/carousel.tsx create mode 100644 src/site/components/ui/chart.tsx create mode 100644 src/site/components/ui/checkbox.tsx create mode 100644 src/site/components/ui/collapsible.tsx create mode 100644 src/site/components/ui/command.tsx create mode 100644 src/site/components/ui/context-menu.tsx create mode 100644 src/site/components/ui/dialog.tsx create mode 100644 src/site/components/ui/drawer.tsx create mode 100644 src/site/components/ui/dropdown-menu.tsx create mode 100644 src/site/components/ui/form.tsx create mode 100644 src/site/components/ui/hover-card.tsx create mode 100644 src/site/components/ui/input-otp.tsx create mode 100644 src/site/components/ui/input.tsx create mode 100644 src/site/components/ui/label.tsx create mode 100644 src/site/components/ui/menubar.tsx create mode 100644 src/site/components/ui/navigation-menu.tsx create mode 100644 src/site/components/ui/pagination.tsx create mode 100644 src/site/components/ui/popover.tsx create mode 100644 src/site/components/ui/progress.tsx create mode 100644 src/site/components/ui/radio-group.tsx create mode 100644 src/site/components/ui/resizable.tsx create mode 100644 src/site/components/ui/scroll-area.tsx create mode 100644 src/site/components/ui/select.tsx create mode 100644 src/site/components/ui/separator.tsx create mode 100644 src/site/components/ui/sheet.tsx create mode 100644 src/site/components/ui/sidebar.tsx create mode 100644 src/site/components/ui/skeleton.tsx create mode 100644 src/site/components/ui/slider.tsx create mode 100644 src/site/components/ui/sonner.tsx create mode 100644 src/site/components/ui/switch.tsx create mode 100644 src/site/components/ui/table.tsx create mode 100644 src/site/components/ui/tabs.tsx create mode 100644 src/site/components/ui/textarea.tsx create mode 100644 src/site/components/ui/toast.tsx create mode 100644 src/site/components/ui/toaster.tsx create mode 100644 src/site/components/ui/toggle-group.tsx create mode 100644 src/site/components/ui/toggle.tsx create mode 100644 src/site/components/ui/tooltip.tsx create mode 100644 src/site/components/ui/use-toast.ts create mode 100644 src/site/hooks/use-mobile.tsx create mode 100644 src/site/hooks/use-toast.ts create mode 100644 src/site/index.css create mode 100644 src/site/lib/utils.ts create mode 100644 src/site/main.tsx create mode 100644 src/site/pages/Datenschutz.tsx create mode 100644 src/site/pages/Impressum.tsx create mode 100644 src/site/pages/Index.tsx create mode 100644 src/site/pages/NotFound.tsx create mode 100644 src/site/pages/Nutzungsbedingungen.tsx create mode 100644 src/site/test/example.test.ts create mode 100644 src/site/test/setup.ts create mode 100644 src/site/vite-env.d.ts create mode 100644 tailwind.config.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts create mode 100644 vitest.config.ts diff --git a/.gitignore b/.gitignore index 5758c0f..696efa8 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ fontawesome.js.LICENSE.txt .map docs/build/* ManagerX.egg-info/ -dist/ \ No newline at end of file +dist/ +node_modules diff --git a/components.json b/components.json new file mode 100644 index 0000000..295891d --- /dev/null +++ b/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/site/index.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + } +} \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..40f72cc --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,26 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { ignores: ["dist"] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ["**/*.{ts,tsx}"], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], + "@typescript-eslint/no-unused-vars": "off", + }, + }, +); diff --git a/index.html b/index.html new file mode 100644 index 0000000..0632865 --- /dev/null +++ b/index.html @@ -0,0 +1,28 @@ + + + + + + ManagerX - Der ultimative Discord Bot + + + + + + + + + + + + + + + + + + +
      + + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f15f094 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8311 @@ +{ + "name": "vite_react_shadcn_ts", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vite_react_shadcn_ts", + "version": "0.0.0", + "dependencies": { + "@hookform/resolvers": "^3.10.0", + "@radix-ui/react-accordion": "^1.2.11", + "@radix-ui/react-alert-dialog": "^1.1.14", + "@radix-ui/react-aspect-ratio": "^1.1.7", + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.2", + "@radix-ui/react-collapsible": "^1.1.11", + "@radix-ui/react-context-menu": "^2.2.15", + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-menubar": "^1.1.15", + "@radix-ui/react-navigation-menu": "^1.2.13", + "@radix-ui/react-popover": "^1.1.14", + "@radix-ui/react-progress": "^1.1.7", + "@radix-ui/react-radio-group": "^1.3.7", + "@radix-ui/react-scroll-area": "^1.2.9", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slider": "^1.3.5", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tabs": "^1.1.12", + "@radix-ui/react-toast": "^1.2.14", + "@radix-ui/react-toggle": "^1.1.9", + "@radix-ui/react-toggle-group": "^1.1.10", + "@radix-ui/react-tooltip": "^1.2.7", + "@tanstack/react-query": "^5.83.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "^3.6.0", + "embla-carousel-react": "^8.6.0", + "framer-motion": "^12.26.2", + "input-otp": "^1.4.2", + "lucide-react": "^0.462.0", + "next-themes": "^0.3.0", + "react": "^18.3.1", + "react-day-picker": "^8.10.1", + "react-dom": "^18.3.1", + "react-hook-form": "^7.61.1", + "react-resizable-panels": "^2.1.9", + "react-router-dom": "^6.30.1", + "recharts": "^2.15.4", + "sonner": "^1.7.4", + "tailwind-merge": "^2.6.0", + "tailwindcss-animate": "^1.0.7", + "vaul": "^0.9.9", + "zod": "^3.25.76" + }, + "devDependencies": { + "@eslint/js": "^9.32.0", + "@tailwindcss/typography": "^0.5.16", + "@testing-library/jest-dom": "^6.6.0", + "@testing-library/react": "^16.0.0", + "@types/node": "^22.16.5", + "@types/react": "^18.3.23", + "@types/react-dom": "^18.3.7", + "@vitejs/plugin-react-swc": "^3.11.0", + "autoprefixer": "^10.4.21", + "eslint": "^9.32.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^15.15.0", + "jsdom": "^20.0.3", + "lovable-tagger": "^1.1.13", + "postcss": "^8.5.6", + "tailwindcss": "^3.4.17", + "typescript": "^5.8.3", + "typescript-eslint": "^8.38.0", + "vite": "^5.4.19", + "vitest": "^3.2.4" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@hookform/resolvers": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.10.0.tgz", + "integrity": "sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==", + "license": "MIT", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.8.tgz", + "integrity": "sha512-5nZrJTF7gH+e0nZS7/QxFz6tJV4VimhQb1avEgtsJxvvIp5JilL+c58HICsKzPxghdwaDt48hEfPM1au4zGy+w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", + "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", + "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", + "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz", + "integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", + "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", + "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", + "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", + "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", + "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@remix-run/router": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", + "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", + "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", + "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", + "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", + "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", + "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", + "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", + "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", + "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", + "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", + "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", + "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", + "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", + "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", + "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", + "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", + "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", + "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", + "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", + "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", + "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", + "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", + "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", + "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/core": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.8.tgz", + "integrity": "sha512-T8keoJjXaSUoVBCIjgL6wAnhADIb09GOELzKg10CjNg+vLX48P93SME6jTfte9MZIm5m+Il57H3rTSk/0kzDUw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.8", + "@swc/core-darwin-x64": "1.15.8", + "@swc/core-linux-arm-gnueabihf": "1.15.8", + "@swc/core-linux-arm64-gnu": "1.15.8", + "@swc/core-linux-arm64-musl": "1.15.8", + "@swc/core-linux-x64-gnu": "1.15.8", + "@swc/core-linux-x64-musl": "1.15.8", + "@swc/core-win32-arm64-msvc": "1.15.8", + "@swc/core-win32-ia32-msvc": "1.15.8", + "@swc/core-win32-x64-msvc": "1.15.8" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.8.tgz", + "integrity": "sha512-M9cK5GwyWWRkRGwwCbREuj6r8jKdES/haCZ3Xckgkl8MUQJZA3XB7IXXK1IXRNeLjg6m7cnoMICpXv1v1hlJOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.8.tgz", + "integrity": "sha512-j47DasuOvXl80sKJHSi2X25l44CMc3VDhlJwA7oewC1nV1VsSzwX+KOwE5tLnfORvVJJyeiXgJORNYg4jeIjYQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.8.tgz", + "integrity": "sha512-siAzDENu2rUbwr9+fayWa26r5A9fol1iORG53HWxQL1J8ym4k7xt9eME0dMPXlYZDytK5r9sW8zEA10F2U3Xwg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.8.tgz", + "integrity": "sha512-o+1y5u6k2FfPYbTRUPvurwzNt5qd0NTumCTFscCNuBksycloXY16J8L+SMW5QRX59n4Hp9EmFa3vpvNHRVv1+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.8.tgz", + "integrity": "sha512-koiCqL09EwOP1S2RShCI7NbsQuG6r2brTqUYE7pV7kZm9O17wZ0LSz22m6gVibpwEnw8jI3IE1yYsQTVpluALw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.8.tgz", + "integrity": "sha512-4p6lOMU3bC+Vd5ARtKJ/FxpIC5G8v3XLoPEZ5s7mLR8h7411HWC/LmTXDHcrSXRC55zvAVia1eldy6zDLz8iFQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.8.tgz", + "integrity": "sha512-z3XBnbrZAL+6xDGAhJoN4lOueIxC/8rGrJ9tg+fEaeqLEuAtHSW2QHDHxDwkxZMjuF/pZ6MUTjHjbp8wLbuRLA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.8.tgz", + "integrity": "sha512-djQPJ9Rh9vP8GTS/Df3hcc6XP6xnG5c8qsngWId/BLA9oX6C7UzCPAn74BG/wGb9a6j4w3RINuoaieJB3t+7iQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.8.tgz", + "integrity": "sha512-/wfAgxORg2VBaUoFdytcVBVCgf1isWZIEXB9MZEUty4wwK93M/PxAkjifOho9RN3WrM3inPLabICRCEgdHpKKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.8.tgz", + "integrity": "sha512-GpMePrh9Sl4d61o4KAHOOv5is5+zt6BEXCOCgs/H0FLGeii7j9bWDE8ExvKFy2GRRZVNR1ugsnzaGWHKM6kuzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.25", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz", + "integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz", + "integrity": "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.90.19", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.19.tgz", + "integrity": "sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.19", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.19.tgz", + "integrity": "sha512-qTZRZ4QyTzQc+M0IzrbKHxSeISUmRB3RPGmao5bT+sI6ayxSRhn0FXEnT5Hg3as8SBFcRosrXXRFB+yAcxVxJQ==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.1.tgz", + "integrity": "sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.7.tgz", + "integrity": "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz", + "integrity": "sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.53.0", + "@typescript-eslint/type-utils": "8.53.0", + "@typescript-eslint/utils": "8.53.0", + "@typescript-eslint/visitor-keys": "8.53.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.53.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.0.tgz", + "integrity": "sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.53.0", + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/typescript-estree": "8.53.0", + "@typescript-eslint/visitor-keys": "8.53.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.0.tgz", + "integrity": "sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.53.0", + "@typescript-eslint/types": "^8.53.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.0.tgz", + "integrity": "sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/visitor-keys": "8.53.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.0.tgz", + "integrity": "sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.0.tgz", + "integrity": "sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/typescript-estree": "8.53.0", + "@typescript-eslint/utils": "8.53.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.0.tgz", + "integrity": "sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.0.tgz", + "integrity": "sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.53.0", + "@typescript-eslint/tsconfig-utils": "8.53.0", + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/visitor-keys": "8.53.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.0.tgz", + "integrity": "sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.53.0", + "@typescript-eslint/types": "8.53.0", + "@typescript-eslint/typescript-estree": "8.53.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.0.tgz", + "integrity": "sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.53.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.11.0.tgz", + "integrity": "sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.27", + "@swc/core": "^1.12.11" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.23", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", + "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001760", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.15", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.15.tgz", + "integrity": "sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001765", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz", + "integrity": "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cmdk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.2" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/embla-carousel": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", + "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", + "license": "MIT" + }, + "node_modules/embla-carousel-react": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-react/-/embla-carousel-react-8.6.0.tgz", + "integrity": "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==", + "license": "MIT", + "dependencies": { + "embla-carousel": "8.6.0", + "embla-carousel-reactive-utils": "8.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/embla-carousel-reactive-utils": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/embla-carousel-reactive-utils/-/embla-carousel-reactive-utils-8.6.0.tgz", + "integrity": "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A==", + "license": "MIT", + "peerDependencies": { + "embla-carousel": "8.6.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", + "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "12.27.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.27.0.tgz", + "integrity": "sha512-gJtqOKEDJH/jrn0PpsWp64gdOjBvGX8hY6TWstxjDot/85daIEtJHl1UsiwHSXiYmJF2QXUoXP6/3gGw5xY2YA==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.27.0", + "motion-utils": "^12.24.10", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/input-otp": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.2.tgz", + "integrity": "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lovable-tagger": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/lovable-tagger/-/lovable-tagger-1.1.13.tgz", + "integrity": "sha512-RBEYDxao7Xf8ya29L0cd+ocE7Gs80xPOIOwwck65Hoie8YDKViuXi3UYV14DoNWIvaJ7WVPf7SG3cc844nFqGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "tailwindcss": "^3.4.17" + }, + "peerDependencies": { + "vite": ">=5.0.0 <8.0.0" + } + }, + "node_modules/lucide-react": { + "version": "0.462.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.462.0.tgz", + "integrity": "sha512-NTL7EbAao9IFtuSivSZgrAh4fZd09Lr+6MTkqIxuHaH2nnYiYIzXPo06cOxHg9wKLdj6LL8TByG4qpePqwgx/g==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/motion-dom": { + "version": "12.27.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.27.0.tgz", + "integrity": "sha512-oDjl0WoAsWIWKl3GCDxmh7GITrNjmLX+w5+jwk4+pzLu3VnFvsOv2E6+xCXeH72O65xlXsr84/otiOYQKW/nQA==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.24.10" + } + }, + "node_modules/motion-utils": { + "version": "12.24.10", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.24.10.tgz", + "integrity": "sha512-x5TFgkCIP4pPsRLpKoI86jv/q8t8FQOiM/0E8QKBzfMozWHfkKap2gA1hOki+B5g3IsBNpxbUnfOum1+dgvYww==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next-themes": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz", + "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-day-picker": { + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz", + "integrity": "sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "date-fns": "^2.28.0 || ^3.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-hook-form": { + "version": "7.71.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.1.tgz", + "integrity": "sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-resizable-panels": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.1.9.tgz", + "integrity": "sha512-z77+X08YDIrgAes4jl8xhnUu1LNIRp4+E7cv4xHmLOxxUPO/ML7PSrE813b90vj7xvQ1lcf7g2uA9GeMZonjhQ==", + "license": "MIT", + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/react-router": { + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz", + "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz", + "integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2", + "react-router": "6.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recharts": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.4", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.55.1", + "@rollup/rollup-android-arm64": "4.55.1", + "@rollup/rollup-darwin-arm64": "4.55.1", + "@rollup/rollup-darwin-x64": "4.55.1", + "@rollup/rollup-freebsd-arm64": "4.55.1", + "@rollup/rollup-freebsd-x64": "4.55.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", + "@rollup/rollup-linux-arm-musleabihf": "4.55.1", + "@rollup/rollup-linux-arm64-gnu": "4.55.1", + "@rollup/rollup-linux-arm64-musl": "4.55.1", + "@rollup/rollup-linux-loong64-gnu": "4.55.1", + "@rollup/rollup-linux-loong64-musl": "4.55.1", + "@rollup/rollup-linux-ppc64-gnu": "4.55.1", + "@rollup/rollup-linux-ppc64-musl": "4.55.1", + "@rollup/rollup-linux-riscv64-gnu": "4.55.1", + "@rollup/rollup-linux-riscv64-musl": "4.55.1", + "@rollup/rollup-linux-s390x-gnu": "4.55.1", + "@rollup/rollup-linux-x64-gnu": "4.55.1", + "@rollup/rollup-linux-x64-musl": "4.55.1", + "@rollup/rollup-openbsd-x64": "4.55.1", + "@rollup/rollup-openharmony-arm64": "4.55.1", + "@rollup/rollup-win32-arm64-msvc": "4.55.1", + "@rollup/rollup-win32-ia32-msvc": "4.55.1", + "@rollup/rollup-win32-x64-gnu": "4.55.1", + "@rollup/rollup-win32-x64-msvc": "4.55.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/sonner": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.7.4.tgz", + "integrity": "sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwind-merge": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", + "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.53.0.tgz", + "integrity": "sha512-xHURCQNxZ1dsWn0sdOaOfCSQG0HKeqSj9OexIxrz6ypU6wHYOdX2I3D2b8s8wFSsSOYJb+6q283cLiLlkEsBYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.53.0", + "@typescript-eslint/parser": "8.53.0", + "@typescript-eslint/typescript-estree": "8.53.0", + "@typescript-eslint/utils": "8.53.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/vaul": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/vaul/-/vaul-0.9.9.tgz", + "integrity": "sha512-7afKg48srluhZwIkaU+lgGtFCUsYBSGOl8vcc8N/M3YQlZFlynHD15AE+pwrYdc826o7nrIND4lL9Y6b9WWZZQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-dialog": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..e666902 --- /dev/null +++ b/package.json @@ -0,0 +1,90 @@ +{ + "name": "vite_react_shadcn_ts", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "build:dev": "vite build --mode development", + "lint": "eslint .", + "preview": "vite preview", + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "@hookform/resolvers": "^3.10.0", + "@radix-ui/react-accordion": "^1.2.11", + "@radix-ui/react-alert-dialog": "^1.1.14", + "@radix-ui/react-aspect-ratio": "^1.1.7", + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.2", + "@radix-ui/react-collapsible": "^1.1.11", + "@radix-ui/react-context-menu": "^2.2.15", + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-menubar": "^1.1.15", + "@radix-ui/react-navigation-menu": "^1.2.13", + "@radix-ui/react-popover": "^1.1.14", + "@radix-ui/react-progress": "^1.1.7", + "@radix-ui/react-radio-group": "^1.3.7", + "@radix-ui/react-scroll-area": "^1.2.9", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slider": "^1.3.5", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tabs": "^1.1.12", + "@radix-ui/react-toast": "^1.2.14", + "@radix-ui/react-toggle": "^1.1.9", + "@radix-ui/react-toggle-group": "^1.1.10", + "@radix-ui/react-tooltip": "^1.2.7", + "@tanstack/react-query": "^5.83.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "cmdk": "^1.1.1", + "date-fns": "^3.6.0", + "embla-carousel-react": "^8.6.0", + "framer-motion": "^12.26.2", + "input-otp": "^1.4.2", + "lucide-react": "^0.462.0", + "next-themes": "^0.3.0", + "react": "^18.3.1", + "react-day-picker": "^8.10.1", + "react-dom": "^18.3.1", + "react-hook-form": "^7.61.1", + "react-resizable-panels": "^2.1.9", + "react-router-dom": "^6.30.1", + "recharts": "^2.15.4", + "sonner": "^1.7.4", + "tailwind-merge": "^2.6.0", + "tailwindcss-animate": "^1.0.7", + "vaul": "^0.9.9", + "zod": "^3.25.76" + }, + "devDependencies": { + "@eslint/js": "^9.32.0", + "@tailwindcss/typography": "^0.5.16", + "@testing-library/jest-dom": "^6.6.0", + "@testing-library/react": "^16.0.0", + "@types/node": "^22.16.5", + "@types/react": "^18.3.23", + "@types/react-dom": "^18.3.7", + "@vitejs/plugin-react-swc": "^3.11.0", + "autoprefixer": "^10.4.21", + "eslint": "^9.32.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^15.15.0", + "jsdom": "^20.0.3", + "lovable-tagger": "^1.1.13", + "postcss": "^8.5.6", + "tailwindcss": "^3.4.17", + "typescript": "^5.8.3", + "typescript-eslint": "^8.38.0", + "vite": "^5.4.19", + "vitest": "^3.2.4" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..2aa7205 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..402960c --- /dev/null +++ b/renovate.json @@ -0,0 +1,34 @@ +{ + "extends": [ + "config:recommended" + ], + "labels": [ + "dependencies" + ], + "prHourlyLimit": 1, + "prConcurrentLimit": 3, + "dependencyDashboard": true, + "dependencyDashboardTitle": "ManagerX โ€“ Dependency Updates", + "automerge": false, + "rangeStrategy": "pin", + "timezone": "Europe/Berlin", + "pip_requirements": { + "fileMatch": ["^requirements/.*\\.txt$"] + }, + "packageRules": [ + { + "matchDepTypes": ["dependencies"], + "matchUpdateTypes": ["patch", "minor"], + "groupName": "All Patch & Minor Python Updates" + }, + { + "matchDepTypes": ["dependencies"], + "matchUpdateTypes": ["major"], + "groupName": "All Major Python Updates" + }, + { + "matchManagers": ["github-actions"], + "groupName": "All GitHub Actions Updates" + } + ] +} \ No newline at end of file diff --git a/requirements/bot_req.txt b/requirements/bot_req.txt new file mode 100644 index 0000000..71eee76 --- /dev/null +++ b/requirements/bot_req.txt @@ -0,0 +1,14 @@ +ezcord==0.7.4 +py-cord==2.7.0 +aiosqlite==0.22.1 +aiohttp==3.13.3 +aiocache==0.12.3 +propcache==0.4.1 +requests==2.32.5 +wikipedia==1.4.0 +beautifulsoup4==4.14.3 +soupsieve==2.8.1 +yarl==1.22.0 +frozenlist==1.8.0 +h11==0.16.0 +multidict==6.7.0 \ No newline at end of file diff --git a/requirements/dev_req.txt b/requirements/dev_req.txt new file mode 100644 index 0000000..bc0bcf2 --- /dev/null +++ b/requirements/dev_req.txt @@ -0,0 +1,19 @@ +python-dotenv==1.2.1 +click==8.3.1 +colorama==0.4.6 +typing_extensions==4.15.0 +typing-inspection==0.4.2 +attrs==25.4.0 +annotated-types==0.7.0 +anyio==4.12.1 +certifi==2026.1.4 +charset-normalizer==3.4.4 +idna==3.11 +urllib3==2.6.3 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +starlette==0.50.0 +FastAPI +uvicorn +SimpleColoredLogs +timedelta==2020.12.3 \ No newline at end of file diff --git a/requirements/docs_req.txt b/requirements/docs_req.txt new file mode 100644 index 0000000..c593d1e --- /dev/null +++ b/requirements/docs_req.txt @@ -0,0 +1,7 @@ +# You need to install Sphinx with `pip install sphinx` and these extensions to build the docs +pydata-sphinx-theme # for a modern documentation theme +sphinx-autodoc-typehints # for better type hinting support +myst-parser # for Markdown support +sphinx-copybutton # adds copy buttons to code blocks +sphinx-autobuild # optional: live preview during development + # (remove this before pushing; ReadTheDocs doesn't need it) \ No newline at end of file diff --git a/requirements/req.txt b/requirements/req.txt new file mode 100644 index 0000000..6052307 --- /dev/null +++ b/requirements/req.txt @@ -0,0 +1,44 @@ +ezcord==0.7.4 +py-cord==2.7.0 +aiosqlite==0.22.1 +aiohttp==3.13.3 +aiocache==0.12.3 +propcache==0.4.1 +requests==2.32.5 +wikipedia==1.4.0 +beautifulsoup4==4.14.3 +soupsieve==2.8.1 +yarl==1.22.0 +frozenlist==1.8.0 +h11==0.16.0 +multidict==6.7.0 + + +# Dev +python-dotenv==1.2.1 +click==8.3.1 +colorama==0.4.6 +typing_extensions==4.15.0 +typing-inspection==0.4.2 +attrs==25.4.0 +annotated-types==0.7.0 +anyio==4.12.1 +certifi==2026.1.4 +charset-normalizer==3.4.4 +idna==3.11 +urllib3==2.6.3 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +starlette==0.50.0 +FastAPI +uvicorn +SimpleColoredLogs +timedelta==2020.12.3 + +# Docs +sphinx +pydata-sphinx-theme +sphinx-autodoc-typehints +myst-parser +sphinx-copybutton +sphinx-autobuild \ No newline at end of file diff --git a/src/site/App.css b/src/site/App.css new file mode 100644 index 0000000..b9d355d --- /dev/null +++ b/src/site/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/src/site/App.tsx b/src/site/App.tsx new file mode 100644 index 0000000..f432120 --- /dev/null +++ b/src/site/App.tsx @@ -0,0 +1,33 @@ +import { Toaster } from "@/components/ui/toaster"; +import { Toaster as Sonner } from "@/components/ui/sonner"; +import { TooltipProvider } from "@/components/ui/tooltip"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import Index from "./pages/Index"; +import NotFound from "./pages/NotFound"; +import Impressum from "./pages/Impressum"; +import Datenschutz from "./pages/Datenschutz"; +import Nutzungsbedingungen from "./pages/Nutzungsbedingungen"; + +const queryClient = new QueryClient(); + +const App = () => ( + + + + + + + } /> + } /> + } /> + } /> + {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */} + } /> + + + + +); + +export default App; diff --git a/src/site/components/CTA.tsx b/src/site/components/CTA.tsx new file mode 100644 index 0000000..d5b5923 --- /dev/null +++ b/src/site/components/CTA.tsx @@ -0,0 +1,70 @@ +import { memo } from "react"; +import { motion } from "framer-motion"; +import { Button } from "@/components/ui/button"; +import { ArrowRight, Sparkles } from "lucide-react"; + +const stats = [ + { label: "Aktive Server", value: "10K+" }, + { label: "Befehle ausgefรผhrt", value: "1M+" }, + { label: "Zufriedene User", value: "50K+" }, +]; + +export const CTA = memo(function CTA() { + return ( +
      + {/* Simple Background */} +
      + +
      + +
      + + 100% Kostenlos +
      + +

      + Bereit fรผr das + nรคchste + Level + ? +

      + +

      + Fรผge ManagerX jetzt zu deinem Server hinzu und erlebe die Zukunft + der Discord Server-Verwaltung. +

      + + + + {/* Bottom Stats */} +
      + {stats.map((stat) => ( +
      +
      {stat.value}
      +
      {stat.label}
      +
      + ))} +
      +
      +
      +
      + ); +}); diff --git a/src/site/components/FAQ.tsx b/src/site/components/FAQ.tsx new file mode 100644 index 0000000..780ff24 --- /dev/null +++ b/src/site/components/FAQ.tsx @@ -0,0 +1,104 @@ +import { memo } from "react"; +import { motion } from "framer-motion"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { HelpCircle, Sparkles } from "lucide-react"; + +const faqs = [ + { + question: "Wie fรผge ich ManagerX zu meinem Server hinzu?", + answer: "Klicke einfach auf den 'Zum Server hinzufรผgen' Button oben auf der Seite. Du wirst zu Discord weitergeleitet, wo du den Server auswรคhlen kannst, auf dem du ManagerX installieren mรถchtest. Stelle sicher, dass du Administrator-Rechte auf diesem Server hast." + }, + { + question: "Ist ManagerX kostenlos?", + answer: "Ja! ManagerX ist vollstรคndig kostenlos nutzbar. Alle Kernfunktionen wie Moderation, Levelsystem, Globalchat und mehr stehen dir ohne Einschrรคnkungen zur Verfรผgung." + }, + { + question: "Wie funktioniert das Levelsystem?", + answer: "Das Levelsystem vergibt automatisch XP fรผr Nachrichten und Voice-Chat-Aktivitรคt. Du kannst XP-Raten, Level-Rollen und Benachrichtigungen vollstรคndig anpassen. Server-weite und globale Leaderboards zeigen die aktivsten Mitglieder." + }, + { + question: "Was ist der Globalchat?", + answer: "Der Globalchat verbindet deinen Server mit anderen ManagerX-Servern in Echtzeit. Nachrichten werden moderiert und gefiltert. Du hast volle Kontrolle รผber Blacklists und kannst User blockieren oder reporten." + }, + { + question: "Wie kann ich Support erhalten?", + answer: "Tritt unserem Support-Server bei! Dort findest du eine aktive Community und unser Team, das dir bei allen Fragen hilft. Du kannst auch die Dokumentation und FAQ auf unserer Website nutzen." + }, + { + question: "Kann ich die Bot-Befehle anpassen?", + answer: "Absolut! Du kannst Prรคfixe รคndern, Befehle aktivieren/deaktivieren, Berechtigungen fรผr bestimmte Rollen festlegen und vieles mehr. Die meisten Einstellungen sind รผber das Dashboard oder Slash-Commands konfigurierbar." + }, +]; + +export const FAQ = memo(function FAQ() { + return ( +
      + {/* Simple Background */} +
      + +
      + {/* Section Header */} + +
      + + Hรคufige Fragen +
      + +

      + Hast du + + Fragen + + + ? +

      +

      + Hier findest du Antworten auf die hรคufigsten Fragen zu ManagerX. +

      +
      + + {/* FAQ Accordion */} + + + {faqs.map((faq, index) => ( + + + + + {index + 1} + + {faq.question} + + + + {faq.answer} + + + ))} + + +
      +
      + ); +}); diff --git a/src/site/components/FeatureCard.tsx b/src/site/components/FeatureCard.tsx new file mode 100644 index 0000000..88e71ef --- /dev/null +++ b/src/site/components/FeatureCard.tsx @@ -0,0 +1,75 @@ +import { memo } from "react"; +import { motion } from "framer-motion"; +import { LucideIcon, Check } from "lucide-react"; +import { cn } from "@/lib/utils"; + +interface FeatureCardProps { + icon: LucideIcon; + title: string; + features: string[]; + category: "moderation" | "community" | "social" | "interactive"; + delay?: number; +} + +const categoryColors = { + moderation: "text-red-400", + community: "text-purple-400", + social: "text-blue-400", + interactive: "text-yellow-400", +}; + +const categoryBgColors = { + moderation: "bg-red-500/10", + community: "bg-purple-500/10", + social: "bg-blue-500/10", + interactive: "bg-yellow-500/10", +}; + +export const FeatureCard = memo(function FeatureCard({ + icon: Icon, + title, + features, + category, + delay = 0 +}: FeatureCardProps) { + return ( + + {/* Header */} +
      +
      + +
      +
      + +

      + {title} +

      + +
        + {features.map((feature, index) => ( +
      • +
        + +
        + {feature} +
      • + ))} +
      +
      + ); +}); diff --git a/src/site/components/Features.tsx b/src/site/components/Features.tsx new file mode 100644 index 0000000..da08024 --- /dev/null +++ b/src/site/components/Features.tsx @@ -0,0 +1,112 @@ +import { memo } from "react"; +import { motion } from "framer-motion"; +import { FeatureCard } from "./FeatureCard"; +import { + Shield, + Award, + Globe, + Gamepad2, + Sparkles +} from "lucide-react"; + +const featureCategories = [ + { + icon: Shield, + title: "Moderation & Sicherheit", + category: "moderation" as const, + features: [ + "Ban, Kick, Mute, Warn Befehle", + "Intelligentes Anti-Spam System", + "Automatisches Warning-Management", + "Detaillierte Moderation-Logs", + "Temporรคre Strafen (Timeout)", + "Reason-Tracking fรผr alle Actions", + ], + }, + { + icon: Award, + title: "Community Engagement", + category: "community" as const, + features: [ + "Vollstรคndig anpassbares XP-System", + "Rollenbelohnungen fรผr Level-Ups", + "Server & Global Leaderboards", + "XP-Multiplikatoren & Boosts", + "Voice-Channel XP-Tracking", + "Automatische BegrรผรŸungsnachrichten", + ], + }, + { + icon: Globe, + title: "Social & Information", + category: "social" as const, + features: [ + "Echtzeit-Chat mit anderen Servern", + "Wikipedia Integration", + "Live-Wetterinformationen", + "Server-รผbergreifende Reputation", + "Mehrsprachige Unterstรผtzung", + "Report & Block Funktionen", + ], + }, + { + icon: Gamepad2, + title: "Interaktive Features", + category: "interactive" as const, + features: [ + "Temporary Voice Channels", + "Individuelle Kanalverwaltung", + "Server-Statistiken in Echtzeit", + "User-Activity Tracking", + "Command-Usage Analytics", + "Auto-Delete bei Inaktivitรคt", + ], + }, +]; + +export const Features = memo(function Features() { + return ( +
      + {/* Simple Background */} +
      + +
      + {/* Section Header */} + +
      + + รœber 90 Befehle +
      + +

      + Alles was du + brauchst +

      +

      + Ein Bot fรผr alle deine Server-Bedรผrfnisse. Moderation, Engagement, Social Features und mehr. +

      +
      + + {/* Feature Cards Grid */} +
      + {featureCategories.map((category, index) => ( + + ))} +
      +
      +
      + ); +}); diff --git a/src/site/components/Footer.tsx b/src/site/components/Footer.tsx new file mode 100644 index 0000000..72e435d --- /dev/null +++ b/src/site/components/Footer.tsx @@ -0,0 +1,140 @@ +import { memo } from "react"; +import { Link } from "react-router-dom"; +import { motion } from "framer-motion"; +import { Shield, Heart, Github, MessageCircle, ExternalLink } from "lucide-react"; + +const socialLinks = [ + { icon: Github, href: "https://github.com", label: "GitHub" }, + { icon: MessageCircle, href: "https://discord.gg", label: "Discord" }, +]; + +const footerLinks = [ + { label: "Features", href: "#features" }, + { label: "Commands", href: "#commands" }, + { label: "Dokumentation", href: "https://docs.oppro-network.de", external: true }, + { label: "Support", href: "#support" }, +]; + +const legalLinks = [ + { label: "Datenschutz", href: "/datenschutz" }, + { label: "Impressum", href: "/impressum" }, + { label: "Nutzungsbedingungen", href: "/nutzungsbedingungen" }, +]; + +export const Footer = memo(function Footer() { + return ( +
      + {/* Background Gradient */} +
      + +
      +
      + {/* Brand */} + +
      +
      + +
      + + ManagerX + +
      +

      + Der ultimative Discord Bot fรผr Moderation, Community-Engagement und vieles mehr. +

      +
      + {socialLinks.map((link) => ( + + + + ))} +
      +
      + + {/* Quick Links */} + +

      Navigation

      + +
      + + {/* Legal */} + +

      Rechtliches

      +
        + {legalLinks.map((link) => ( +
      • + + {link.label} + +
      • + ))} +
      +
      +
      + + {/* Bottom Bar */} + +
      + Made with + + + + in Germany +
      + +
      + ยฉ {new Date().getFullYear()} ManagerX. Alle Rechte vorbehalten. +
      +
      +
      +
      + ); +}); \ No newline at end of file diff --git a/src/site/components/Hero.tsx b/src/site/components/Hero.tsx new file mode 100644 index 0000000..37cf158 --- /dev/null +++ b/src/site/components/Hero.tsx @@ -0,0 +1,135 @@ +import { memo } from "react"; +import { motion } from "framer-motion"; +import { Button } from "@/components/ui/button"; +import { Shield, Users, MessageCircle, Sparkles } from "lucide-react"; + +const stats = [ + { label: "Server", value: "10,000+", icon: Users }, + { label: "Befehle", value: "90+", icon: MessageCircle }, + { label: "Uptime", value: "99.9%", icon: Sparkles }, +]; + +const StatCard = memo(({ stat, index }: { stat: typeof stats[0]; index: number }) => ( + +
      + + {stat.value} +
      + {stat.label} +
      +)); + +StatCard.displayName = "StatCard"; + +export const Hero = memo(function Hero() { + return ( +
      + {/* Static Background - no blur for performance */} +
      + + {/* Simple gradient orbs without blur */} +
      +
      + + {/* Grid Pattern - static */} +
      + +
      +
      + {/* Badge */} + + + Version 2.0 jetzt verfรผgbar + + + + {/* Logo */} + +
      +
      + +
      +
      + +
      +
      +
      + + {/* Title */} + + Manager + X + + + {/* Description */} + + Der ultimative Discord Bot fรผr{" "} + Moderation,{" "} + Levelsystem,{" "} + Globalchat und mehr. + + + {/* CTA Buttons */} + + + + + + {/* Stats */} +
      + {stats.map((stat, index) => ( + + ))} +
      +
      +
      + + {/* Bottom Gradient */} +
      +
      + ); +}); diff --git a/src/site/components/NavLink.tsx b/src/site/components/NavLink.tsx new file mode 100644 index 0000000..a561a95 --- /dev/null +++ b/src/site/components/NavLink.tsx @@ -0,0 +1,28 @@ +import { NavLink as RouterNavLink, NavLinkProps } from "react-router-dom"; +import { forwardRef } from "react"; +import { cn } from "@/lib/utils"; + +interface NavLinkCompatProps extends Omit { + className?: string; + activeClassName?: string; + pendingClassName?: string; +} + +const NavLink = forwardRef( + ({ className, activeClassName, pendingClassName, to, ...props }, ref) => { + return ( + + cn(className, isActive && activeClassName, isPending && pendingClassName) + } + {...props} + /> + ); + }, +); + +NavLink.displayName = "NavLink"; + +export { NavLink }; diff --git a/src/site/components/Navbar.tsx b/src/site/components/Navbar.tsx new file mode 100644 index 0000000..284f147 --- /dev/null +++ b/src/site/components/Navbar.tsx @@ -0,0 +1,149 @@ +import { useState, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { Button } from "@/components/ui/button"; +import { Shield, Menu, X, Sparkles } from "lucide-react"; +import { cn } from "@/lib/utils"; + +const navLinks = [ + { label: "Features", href: "#features" }, + { label: "Commands", href: "#commands" }, + { label: "Support", href: "#support" }, +]; + +export function Navbar() { + const [isScrolled, setIsScrolled] = useState(false); + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + + useEffect(() => { + const handleScroll = () => { + setIsScrolled(window.scrollY > 20); + }; + window.addEventListener("scroll", handleScroll); + return () => window.removeEventListener("scroll", handleScroll); + }, []); + + return ( + +
      + + + {/* Mobile Menu */} + + {isMobileMenuOpen && ( + +
      +
      + {navLinks.map((link, index) => ( + setIsMobileMenuOpen(false)} + initial={{ opacity: 0, x: -20 }} + animate={{ opacity: 1, x: 0 }} + transition={{ delay: index * 0.1 }} + className="text-muted-foreground hover:text-foreground transition-colors py-3 px-4 rounded-xl hover:bg-card/50 font-medium" + > + {link.label} + + ))} + + + +
      +
      +
      + )} +
      +
      +
      + ); +} \ No newline at end of file diff --git a/src/site/components/Testimonials.tsx b/src/site/components/Testimonials.tsx new file mode 100644 index 0000000..2dca055 --- /dev/null +++ b/src/site/components/Testimonials.tsx @@ -0,0 +1,168 @@ +import { memo } from "react"; +import { motion } from "framer-motion"; +import { Star, MessageSquare, Users } from "lucide-react"; + +const testimonials = [ + { + name: "Max Mustermann", + role: "Server Admin", + server: "Gaming Community DE", + members: "15.000+", + avatar: "M", + rating: 5, + text: "ManagerX hat unseren Server komplett transformiert. Das Levelsystem motiviert unsere Mitglieder unglaublich und die Moderation ist ein Traum!", + }, + { + name: "Sarah Schmidt", + role: "Community Manager", + server: "Creative Hub", + members: "8.000+", + avatar: "S", + rating: 5, + text: "Der Globalchat verbindet uns mit anderen Communities - das ist einzigartig! Und der Support ist super schnell und hilfsbereit.", + }, + { + name: "Tom Weber", + role: "Grรผnder", + server: "Tech Talk Germany", + members: "25.000+", + avatar: "T", + rating: 5, + text: "Wir haben viele Bots getestet, aber ManagerX ist der beste. Alle Features funktionieren perfekt zusammen und die Konfiguration ist super einfach.", + }, + { + name: "Lisa Mรผller", + role: "Moderatorin", + server: "Anime World", + members: "12.000+", + avatar: "L", + rating: 5, + text: "Das Anti-Spam System und die Moderations-Tools machen meinen Job so viel einfacher. Endlich ein Bot, der wirklich durchdacht ist!", + }, + { + name: "Jan Hoffmann", + role: "Server Owner", + server: "Music Lounge", + members: "5.000+", + avatar: "J", + rating: 5, + text: "Die Temporary Voice Channels sind genial! Unsere Mitglieder lieben es, eigene Rรคume erstellen zu kรถnnen. Absolute Empfehlung!", + }, + { + name: "Emma Fischer", + role: "Admin Team Lead", + server: "Study Together", + members: "20.000+", + avatar: "E", + rating: 5, + text: "ManagerX ist stabil, schnell und hat alles was wir brauchen. Das Dashboard ist รผbersichtlich und die Docs sind hervorragend.", + }, +]; + +const TestimonialCard = memo(({ testimonial, index }: { testimonial: typeof testimonials[0]; index: number }) => ( + + {/* Stars */} +
      + {[...Array(testimonial.rating)].map((_, i) => ( + + ))} +
      + + {/* Text */} +

      + "{testimonial.text}" +

      + + {/* Author */} +
      +
      + {testimonial.avatar} +
      +
      +
      {testimonial.name}
      +
      {testimonial.role}
      +
      +
      + + {/* Server Info */} +
      + {testimonial.server} + + + {testimonial.members} + +
      +
      +)); + +TestimonialCard.displayName = "TestimonialCard"; + +export const Testimonials = memo(function Testimonials() { + return ( +
      + {/* Simple Background */} +
      + +
      + {/* Section Header */} + +
      + + Testimonials +
      + +

      + Was unsere + Community + sagt +

      +

      + Tausende Server-Admins vertrauen ManagerX. Hier sind ihre Erfahrungen. +

      +
      + + {/* Testimonials Grid */} +
      + {testimonials.map((testimonial, index) => ( + + ))} +
      + + {/* Stats Bar */} + + {[ + { value: "4.9/5", label: "Durchschnittliche Bewertung", icon: Star }, + { value: "10.000+", label: "Zufriedene Server", icon: Users }, + { value: "99%", label: "Wรผrden uns empfehlen", icon: MessageSquare }, + ].map((stat, index) => ( +
      +
      + + {stat.value} +
      + {stat.label} +
      + ))} +
      +
      +
      + ); +}); diff --git a/src/site/components/ui/accordion.tsx b/src/site/components/ui/accordion.tsx new file mode 100644 index 0000000..1e7878c --- /dev/null +++ b/src/site/components/ui/accordion.tsx @@ -0,0 +1,52 @@ +import * as React from "react"; +import * as AccordionPrimitive from "@radix-ui/react-accordion"; +import { ChevronDown } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +const Accordion = AccordionPrimitive.Root; + +const AccordionItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AccordionItem.displayName = "AccordionItem"; + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-180", + className, + )} + {...props} + > + {children} + + + +)); +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
      {children}
      +
      +)); + +AccordionContent.displayName = AccordionPrimitive.Content.displayName; + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/src/site/components/ui/alert-dialog.tsx b/src/site/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..6dfbfb4 --- /dev/null +++ b/src/site/components/ui/alert-dialog.tsx @@ -0,0 +1,104 @@ +import * as React from "react"; +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; + +import { cn } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button"; + +const AlertDialog = AlertDialogPrimitive.Root; + +const AlertDialogTrigger = AlertDialogPrimitive.Trigger; + +const AlertDialogPortal = AlertDialogPrimitive.Portal; + +const AlertDialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; + +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + +)); +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; + +const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
      +); +AlertDialogHeader.displayName = "AlertDialogHeader"; + +const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( +
      +); +AlertDialogFooter.displayName = "AlertDialogFooter"; + +const AlertDialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; + +const AlertDialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName; + +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; + +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +}; diff --git a/src/site/components/ui/alert.tsx b/src/site/components/ui/alert.tsx new file mode 100644 index 0000000..2efc3c8 --- /dev/null +++ b/src/site/components/ui/alert.tsx @@ -0,0 +1,43 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const alertVariants = cva( + "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + { + variants: { + variant: { + default: "bg-background text-foreground", + destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +const Alert = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & VariantProps +>(({ className, variant, ...props }, ref) => ( +
      +)); +Alert.displayName = "Alert"; + +const AlertTitle = React.forwardRef>( + ({ className, ...props }, ref) => ( +
      + ), +); +AlertTitle.displayName = "AlertTitle"; + +const AlertDescription = React.forwardRef>( + ({ className, ...props }, ref) => ( +
      + ), +); +AlertDescription.displayName = "AlertDescription"; + +export { Alert, AlertTitle, AlertDescription }; diff --git a/src/site/components/ui/aspect-ratio.tsx b/src/site/components/ui/aspect-ratio.tsx new file mode 100644 index 0000000..c9e6f4b --- /dev/null +++ b/src/site/components/ui/aspect-ratio.tsx @@ -0,0 +1,5 @@ +import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"; + +const AspectRatio = AspectRatioPrimitive.Root; + +export { AspectRatio }; diff --git a/src/site/components/ui/avatar.tsx b/src/site/components/ui/avatar.tsx new file mode 100644 index 0000000..68d21bb --- /dev/null +++ b/src/site/components/ui/avatar.tsx @@ -0,0 +1,38 @@ +import * as React from "react"; +import * as AvatarPrimitive from "@radix-ui/react-avatar"; + +import { cn } from "@/lib/utils"; + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/src/site/components/ui/badge.tsx b/src/site/components/ui/badge.tsx new file mode 100644 index 0000000..0853c44 --- /dev/null +++ b/src/site/components/ui/badge.tsx @@ -0,0 +1,29 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +export interface BadgeProps extends React.HTMLAttributes, VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return
      ; +} + +export { Badge, badgeVariants }; diff --git a/src/site/components/ui/breadcrumb.tsx b/src/site/components/ui/breadcrumb.tsx new file mode 100644 index 0000000..ca91ff5 --- /dev/null +++ b/src/site/components/ui/breadcrumb.tsx @@ -0,0 +1,90 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { ChevronRight, MoreHorizontal } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +const Breadcrumb = React.forwardRef< + HTMLElement, + React.ComponentPropsWithoutRef<"nav"> & { + separator?: React.ReactNode; + } +>(({ ...props }, ref) =>