diff --git a/docs/source/dev_guide/index.rst b/docs/source/dev_guide/index.rst index b80075d..b447d5c 100644 --- a/docs/source/dev_guide/index.rst +++ b/docs/source/dev_guide/index.rst @@ -1,234 +1,4 @@ -=============================== -đšâđ» Developer Guide -=============================== +Developer Guide +======================= -**Welcome to the ManagerX Developer Guide!** - -This comprehensive documentation is your resource for understanding ManagerX's architecture, extending the bot, deploying it to production, and contributing to the project. Whether you're building a new feature, self-hosting ManagerX, or simply curious about how it works, you'll find everything you need here. - -.. note:: - **New to ManagerX?** Start with :doc:`getting_started/index` to set up your development environment. - -.. important:: - This project is under active development. Features and APIs may change. Check back regularly for updates! - ---- - -đ Quick Start Paths -==================== - -**Want to get up and running immediately?** - -1. Install dependencies â :doc:`installation/index` -2. Understand the structure â :doc:`project_structure/index` -3. Learn the architecture â :doc:`architecture/index` -4. Start coding â :doc:`bot_development/index` - -**Deploying to production?** - -1. Review deployment options â :doc:`deployment/index` -2. Set up your server â :doc:`deployment/index` -3. Configure monitoring â :doc:`deployment/index` -4. Establish backups â :doc:`database/index` - -**Want to contribute?** - -1. Fork the repository -2. Read :doc:`contributing/index` -3. Create a feature branch -4. Follow code style â :doc:`contributing/index` -5. Write tests â :doc:`testing/index` -6. Submit a pull request! - ---- - -đ Documentation Structure -=========================== - -**Getting Started** - -- :doc:`getting_started/index` â Installation, setup, first steps -- :doc:`installation/index` â Detailed installation instructions -- :doc:`project_structure/index` â Repository organization - -**Understanding ManagerX** - -- :doc:`architecture/index` â System design and components -- :doc:`database/index` â SQLite database schema and operations -- :doc:`bot_development/index` â Building bot features and cogs -- :doc:`api_development/index` â Creating API endpoints - -**Development** - -- :doc:`testing/index` â Unit tests, integration tests, testing strategy -- :doc:`deployment/index` â Production deployment, hosting options -- :doc:`contributing/index` â Contribution guidelines, PR process -- :doc:`troubleshooting/index` â Debugging and common issues - ---- - -đïž Architecture Overview -========================= - -ManagerX consists of three main components: - -**Bot Core (Python)** - -Discord.py/py-cord based bot with modular cog system. Handles Discord events, commands, and business logic. - -- Location: ``src/bot/`` -- Main entry: ``main.py`` - -**API Server (FastAPI)** - -REST API providing bot data to frontend and external services. - -- Location: ``src/api/`` -- Port: 8040 -- Runs in same process as bot - -**Web Dashboard (React)** - -Modern TypeScript/React frontend with real-time statistics and management interface. - -- Location: ``src/web/`` -- Port: 8080 -- Built with Vite - -See :doc:`architecture/index` for detailed architecture documentation. - ---- - -đ ïž Development Environment -============================ - -**Prerequisites:** - -- Python 3.11+ -- Node.js 18+ (for web development) -- Git -- SQLite3 (usually included with Python) - -**Quick Setup:** - -.. code-block:: bash - - # Clone repository - git clone https://github.com/ManagerX-Development/ManagerX.git - cd ManagerX - - # Create virtual environment - python -m venv .venv - source .venv/bin/activate # On Windows: .venv\\Scripts\\activate - - # Install dependencies - pip install -r requirements/bot_req.txt - - # Set up configuration - cp config/config.yaml config/config.local.yaml - # Edit config/config.local.yaml with your settings - - # Run the bot - python main.py - -For detailed setup, see :doc:`getting_started/index`. - ---- - -đ Common Development Tasks -============================ - -**Creating a New Command** - -See :doc:`bot_development/index` for complete example - -**Adding a Database Table** - -See :doc:`database/index` for schema modifications - -**Creating an API Endpoint** - -See :doc:`api_development/index` for REST endpoint examples - -**Writing Tests** - -See :doc:`testing/index` for testing patterns - -**Deploying to Production** - -See :doc:`deployment/index` for deployment procedures - ---- - -đ€ Contributing -================ - -We welcome contributions! Whether it's bug fixes, new features, or documentation improvements: - -1. Fork the repository -2. Create a feature branch: ``git checkout -b feature/amazing-feature`` -3. Follow code style (see :doc:`contributing/index`) -4. Write or update tests (see :doc:`testing/index`) -5. Commit with clear messages (see :doc:`contributing/index`) -6. Push and create a Pull Request - -See :doc:`contributing/index` for complete contribution guidelines. - ---- - -đ Project Statistics -====================== - -- **Language:** Python (bot) + TypeScript (web) -- **Framework:** discord.py + FastAPI + React -- **Database:** SQLite -- **Lines of Code:** 10,000+ -- **Cogs/Modules:** 10+ -- **API Endpoints:** 20+ -- **Commands:** 50+ - ---- - -đ Quick Navigation -==================== - -Key Sections: - -.. toctree:: - :maxdepth: 1 - :caption: Getting Started - :hidden: - - getting_started - installation - project_structure - -.. toctree:: - :maxdepth: 1 - :caption: Core Concepts - :hidden: - - architecture - design_patterns - database_design - -.. toctree:: - :maxdepth: 1 - :caption: Development - :hidden: - - bot_development - api_development - frontend_development - testing - -.. toctree:: - :maxdepth: 1 - :caption: Community - :hidden: - - contributing - code_style - deployment - - \ No newline at end of file +Welcome to the \ No newline at end of file diff --git a/src/bot/cogs/moderation/moderation.py b/src/bot/cogs/moderation/moderation.py index de7e7cc..3f67077 100644 --- a/src/bot/cogs/moderation/moderation.py +++ b/src/bot/cogs/moderation/moderation.py @@ -14,6 +14,14 @@ import timedelta from discord.ui import Container from discord import SlashCommandGroup + +# Importiere zentrale Konstanten +from src.bot.core import ( + SUCCESS_COLOR, ERROR_COLOR, WARN_COLOR, INFO_COLOR, + emoji_yes, emoji_no, emoji_warn, emoji_info, + emoji_member, emoji_staff, emoji_summary, emoji_slowmode, + AUTHOR, FLOOTER +) # âââââââââââââââââââââââââââââââââââââââââââââââ # >> Cogs # âââââââââââââââââââââââââââââââââââââââââââââââ @@ -126,7 +134,7 @@ def _create_moderation_embed(self, action: str, moderator: discord.Member, targe 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}") + embed.set_footer(text=f"User ID: {target.id} | {FLOOTER}") else: embed.set_footer(text=FLOOTER) return embed diff --git a/src/bot/cogs/moderation/warn.py b/src/bot/cogs/moderation/warn.py index c56dd7f..005e161 100644 --- a/src/bot/cogs/moderation/warn.py +++ b/src/bot/cogs/moderation/warn.py @@ -7,10 +7,19 @@ from discord import slash_command, Option import os import datetime +import datetime import ezcord import asyncio from typing import Optional +# Importiere zentrale Konstanten +from src.bot.core import ( + SUCCESS_COLOR, ERROR_COLOR, WARN_COLOR, INFO_COLOR, + emoji_yes, emoji_no, emoji_warn, emoji_info, + emoji_member, emoji_staff, emoji_summary, emoji_slowmode, + emoji_circleinfo, AUTHOR, FLOOTER +) + # âââââââââââââââââââââââââââââââââââââââââââââââ # >> Cogs @@ -98,7 +107,7 @@ def _create_warn_embed(self, action: str, moderator: discord.Member, 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 = discord.Embed(title=title, color=ERROR_COLOR, timestamp=datetime.datetime.now(datetime.timezone.utc)) embed.set_author(name=AUTHOR) embed.add_field(name=f"{emoji_no} {title}", value=message, inline=False) embed.set_footer(text=FLOOTER) diff --git a/src/bot/cogs/user/settings.py b/src/bot/cogs/user/settings.py index 381ff7b..5f8bdd6 100644 --- a/src/bot/cogs/user/settings.py +++ b/src/bot/cogs/user/settings.py @@ -4,6 +4,10 @@ import ezcord from mx_handler import TranslationHandler +import os +from src.bot.core.constants import ERROR_COLOR, SUCCESS_COLOR, emoji_warn, emoji_delete, AUTHOR, FOOTER +from DevTools import StatsDB, WarnDatabase, NotesDatabase, LevelDatabase +import sqlite3 class Settings(ezcord.Cog): @@ -14,6 +18,8 @@ class Settings(ezcord.Cog): language = user.create_subgroup( "language") + data = user.create_subgroup("data", "Manage your data") + AVAILABLE_LANGUAGES = { "de": "Deutsch đ©đȘ", "en": "English đŹđ§" @@ -103,6 +109,128 @@ async def list_languages(self, ctx: discord.ApplicationContext): response_text = f"**Available Languages:**\n{languages_list}" await ctx.respond(response_text, ephemeral=True) + @data.command( + name="delete", + description="Lösche alle deine Daten von ManagerX permanent." + ) + async def delete_all_data(self, ctx: discord.ApplicationContext): + """Startet den doppelten BestĂ€tigungsprozess zum Löschen aller User-Daten.""" + + embed = discord.Embed( + title=f"{emoji_warn} ACHTUNG: Datenlöschung", + description=( + "Bist du sicher, dass du alle deine Daten löschen möchtest?\n\n" + "**Was gelöscht wird:**\n" + "âą XP, Level und Statistiken (Global & Server)\n" + "âą Deine persönlichen Einstellungen\n\n" + "**Was NICHT gelöscht wird:**\n" + "âą Moderationsdaten (Warnungen & Notizen)\n" + "*Hinweis: ManagerX ist es nicht gestattet, Moderationsdaten zu löschen.*\n\n" + "â ïž **WICHTIG:** Dieser Vorgang ist **unwiderruflich**. " + "Deine persönlichen Daten sind **fĂŒr immer** weg!" + ), + color=ERROR_COLOR + ) + embed.set_author(name=AUTHOR) + embed.set_footer(text=FOOTER) + + view = DeletionView(ctx.author.id, self.bot) + await ctx.respond(embed=embed, view=view, ephemeral=True) + +class DeletionView(discord.ui.View): + def __init__(self, user_id, bot): + super().__init__(timeout=60) + self.user_id = user_id + self.bot = bot + + @discord.ui.button(label="Daten löschen", style=discord.ButtonStyle.danger, emoji="đïž") + async def delete_button(self, button: discord.ui.Button, interaction: discord.Interaction): + if interaction.user.id != self.user_id: + return await interaction.response.send_message("Das ist nicht dein MenĂŒ!", ephemeral=True) + + embed = discord.Embed( + title="â ïž LETZTE BESTĂTIGUNG", + description=( + "Bist du wirklich ABSOLUT sicher?\n\n" + "Alle deine Statistiken, Level und Einstellungen werden **permanent** gelöscht.\n" + "ManagerX wird alle persönlichen Informationen ĂŒber dich vergessen.\n\n" + "**WICHTIG:** Moderationsdaten (Warns/Notes) dĂŒrfen vom Bot nicht gelöscht werden und bleiben erhalten." + ), + color=ERROR_COLOR + ) + embed.set_author(name=AUTHOR) + embed.set_footer(text=FOOTER) + + view = DeletionConfirmationView(self.user_id, self.bot) + await interaction.response.edit_message(embed=embed, view=view) + +class DeletionConfirmationView(discord.ui.View): + def __init__(self, user_id, bot): + super().__init__(timeout=60) + self.user_id = user_id + self.bot = bot + + @discord.ui.button(label="JA, ALLES LĂSCHEN", style=discord.ButtonStyle.danger, emoji="đ„") + async def confirm_button(self, button: discord.ui.Button, interaction: discord.Interaction): + if interaction.user.id != self.user_id: + return await interaction.response.send_message("Das ist nicht dein MenĂŒ!", ephemeral=True) + + # Deletion logic implementation + try: + # Paths to databases + stats_db_path = "data/stats.db" + level_db_path = "data/levelsystem.db" + warn_db_path = "src/bot/cogs/moderation/Datenbanken/warns.db" + notes_db_path = "data/data/notes.db" + + # 1. Stats & Level + # StatsDB cleanup + if os.path.exists(stats_db_path): + conn = sqlite3.connect(stats_db_path) + cursor = conn.cursor() + tables = ["messages", "voice_sessions", "global_user_levels", "daily_stats", "user_achievements", "active_voice_sessions"] + for table in tables: + cursor.execute(f"DELETE FROM {table} WHERE user_id = ?", (self.user_id,)) + conn.commit() + conn.close() + + # LevelDatabase cleanup + if os.path.exists(level_db_path): + conn = sqlite3.connect(level_db_path) + cursor = conn.cursor() + tables = ["user_levels", "xp_boosts", "achievements", "temporary_roles"] + for table in tables: + cursor.execute(f"DELETE FROM {table} WHERE user_id = ?", (self.user_id,)) + conn.commit() + conn.close() + + # 2. Settings (using the existing reset method if available) + if hasattr(self.bot, 'settings_db'): + if hasattr(self.bot.settings_db, 'reset_user_settings'): + self.bot.settings_db.reset_user_settings(self.user_id) + elif hasattr(self.bot.settings_db, 'delete_user_data'): # Fallback to original code's preference + self.bot.settings_db.delete_user_data(self.user_id) + + # 3. Moderationsdaten (Warns & Notes) bleiben bestehen (User-Wunsch/Wichtigkeit) + pass + + except Exception as e: + # Log error but proceed with message + print(f"Error during manual data deletion for {self.user_id}: {e}") + + embed = discord.Embed( + title="â Daten erfolgreich gelöscht", + description="Alle deine Daten wurden permanent aus unserem System entfernt.", + color=SUCCESS_COLOR + ) + embed.set_footer(text=FOOTER) + + 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): + await interaction.response.edit_message(content="Vorgang abgebrochen. Deine Daten sind sicher.", embed=None, view=None) + 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/core/__init__.py b/src/bot/core/__init__.py index 61d58e5..5e7678d 100644 --- a/src/bot/core/__init__.py +++ b/src/bot/core/__init__.py @@ -11,6 +11,7 @@ from .database import DatabaseManager from .dashboard import DashboardTask from .utils import print_logo, format_uptime, truncate_text +from .constants import * __all__ = [ 'ConfigLoader', @@ -21,5 +22,28 @@ 'DashboardTask', 'print_logo', 'format_uptime', - 'truncate_text' + 'truncate_text', + 'SUCCESS_COLOR', + 'ERROR_COLOR', + 'WARN_COLOR', + 'INFO_COLOR', + 'emoji_yes', + 'emoji_no', + 'emoji_warn', + 'emoji_info', + 'emoji_forbidden', + 'emoji_member', + 'emoji_staff', + 'emoji_summary', + 'emoji_slowmode', + 'emoji_channel', + 'emoji_moderator', + 'emoji_statistics', + 'emoji_annoattention', + 'emoji_owner', + 'emoji_delete', + 'emoji_circleinfo', + 'AUTHOR', + 'FLOOTER', + 'FOOTER' ] \ No newline at end of file diff --git a/src/bot/core/constants.py b/src/bot/core/constants.py new file mode 100644 index 0000000..3e4498f --- /dev/null +++ b/src/bot/core/constants.py @@ -0,0 +1,38 @@ +""" +ManagerX - Constants +==================== + +Zentrale Definition von Emojis, Farben und anderen Konstanten. +""" + +import discord + +# --- Farben --- +SUCCESS_COLOR = discord.Color.green() +ERROR_COLOR = discord.Color.red() +WARN_COLOR = discord.Color.orange() +INFO_COLOR = discord.Color.blue() + +# --- Emojis (Standard-Sets) --- +# Hinweis: Diese können spĂ€ter durch Custom-Emojis ersetzt werden +emoji_yes = "â " +emoji_no = "â" +emoji_warn = "â ïž" +emoji_info = "âčïž" +emoji_forbidden = "đ«" +emoji_member = "đ€" +emoji_staff = "đĄïž" +emoji_summary = "đ" +emoji_slowmode = "âł" +emoji_channel = "đ" +emoji_moderator = "đź" +emoji_statistics = "đ" +emoji_annoattention = "đŁ" +emoji_owner = "đ" +emoji_delete = "đïž" +emoji_circleinfo = "âčïž" + +# --- Texte --- +AUTHOR = "ManagerX Network" +FLOOTER = "Powered by OPPRO.NET Network" # Typo im Original ("FLOOTER"), behalte es fĂŒr KompatibilitĂ€t oder korrigiere es +FOOTER = "Powered by OPPRO.NET Network" diff --git a/src/bot/core/dashboard.py b/src/bot/core/dashboard.py index e39f610..00ea0d8 100644 --- a/src/bot/core/dashboard.py +++ b/src/bot/core/dashboard.py @@ -57,7 +57,7 @@ async def _update_stats(self): json.dump(stats, f, indent=4, ensure_ascii=False) except Exception as e: - logger.error(Category.BOT, f"Dashboard-Update fehlgeschlagen: {e}") + logger.error(Category.DISCORD_BOT, f"Dashboard-Update fehlgeschlagen: {e}") def _get_uptime(self) -> str: """Berechnet die Bot-Uptime""" @@ -77,19 +77,19 @@ 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: """ diff --git a/src/web/App.tsx b/src/web/App.tsx index 35d4a00..beabac2 100644 --- a/src/web/App.tsx +++ b/src/web/App.tsx @@ -1,17 +1,42 @@ +import { lazy, Suspense } from "react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { BrowserRouter, Routes, Route, useLocation } from "react-router-dom"; import { motion, AnimatePresence } from "framer-motion"; -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"; -import PluginsPage from "./pages/PluginsPage"; -import Status from "./pages/Status"; -import { License } from "./pages/License"; + +// Lazy load all route components for better performance +const Index = lazy(() => import("./pages/Index")); +const NotFound = lazy(() => import("./pages/NotFound")); +const Impressum = lazy(() => import("./pages/Impressum")); +const Datenschutz = lazy(() => import("./pages/Datenschutz")); +const Nutzungsbedingungen = lazy(() => import("./pages/Nutzungsbedingungen")); +const PluginsPage = lazy(() => import("./pages/PluginsPage")); +const Status = lazy(() => import("./pages/Status")); +const License = lazy(() => import("./pages/License").then(module => ({ default: module.License }))); const queryClient = new QueryClient(); +// Loading fallback component +const PageLoader = () => ( +
LĂ€dt...
+