diff --git a/examples/bot/containers.py b/examples/bot/containers.py new file mode 100644 index 0000000..c3ae647 --- /dev/null +++ b/examples/bot/containers.py @@ -0,0 +1,25 @@ +# How Works Containers? + +# First import the Modul +import discord +from discord.ui import Container # Import the Container Modul +import ezcord + +class ContainerExample(ezcord.Cog): + def __init__(self, bot): + self.bot = bot + + @discord.slash_command(name="container", description="Zeigt ein Container an") + async def container(self, ctx: discord.ApplicationContext): + container = Container() # Define the Container + container.add_text("Hello World") # Add a Text to the Container + container.add_separator() # Add a Separator to the Container + container.add_text("Hello World") # Add a Text to the Container + view = discord.ui.DesignerView(container, timeout=0) # Define the View + await ctx.respond(view=view) + +def setup(bot): + bot.add_cog(ContainerExample(bot)) # Add the Cog to the Bot + + + \ No newline at end of file diff --git a/index.html b/index.html index e00b723..def070b 100644 --- a/index.html +++ b/index.html @@ -10,11 +10,11 @@ - + - + diff --git a/package.json b/package.json index e666902..08f973c 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "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", @@ -87,4 +86,4 @@ "vite": "^5.4.19", "vitest": "^3.2.4" } -} +} \ No newline at end of file diff --git a/requirements/req.txt b/requirements/req.txt index 6052307..fb4faa0 100644 --- a/requirements/req.txt +++ b/requirements/req.txt @@ -1,44 +1,85 @@ +# --- Deine Online Packages (ManagerX Ecosystem) --- +ManagerX-DevTools==1.2026.1.11.1 +ManagerX-Handler==1.2026.1.10 + +# --- Core Frameworks & Discord --- ezcord==0.7.4 py-cord==2.7.0 -aiosqlite==0.22.1 -aiohttp==3.13.3 +better-ipc==2.0.3 +fastapi==0.115.6 +uvicorn==0.34.0 +starlette==0.46.2 + +# --- Async & Performance --- 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 +aiohappyeyeballs==2.6.1 +aiohttp==3.13.2 +aiosignal==1.4.0 +aiosqlite==0.22.1 +anyio==4.9.0 frozenlist==1.8.0 -h11==0.16.0 multidict==6.7.0 +propcache==0.4.1 +sniffio==1.3.1 +websockets==14.1 - -# 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 +# --- Data & Validation --- annotated-types==0.7.0 -anyio==4.12.1 -certifi==2026.1.4 -charset-normalizer==3.4.4 +pydantic==2.11.7 +pydantic_core==2.33.2 +PyYAML==6.0.1 +typing_extensions==4.15.0 +typing-inspection==0.4.1 + +# --- HTTP & Web --- +requests==2.32.3 +requests-toolbelt==1.0.0 +httpx==0.24.1 +httpcore==0.17.3 +h11==0.14.0 +urllib3==2.4.0 +yarl==1.22.0 +certifi==2025.4.26 +charset-normalizer==3.4.2 idna==3.11 -urllib3==2.6.3 -Jinja2==3.1.6 -MarkupSafe==3.0.3 -starlette==0.50.0 -FastAPI -uvicorn -SimpleColoredLogs +rfc3986==2.0.0 + +# --- UI, Imaging & Logging --- +beautifulsoup4==4.13.4 +soupsieve==2.7 +easy-pil==0.4.0 +pillow==10.4.0 +SimpleColoredLogs==1.3.0 +colorama==0.4.6 +rich==13.5.2 +Pygments==2.19.2 +markdown-it-py==4.0.0 +mdurl==0.1.2 + +# --- System & Utilities --- +click==8.2.1 +psutil==5.9.5 +python-dotenv==1.1.0 timedelta==2020.12.3 +pytz==2025.2 +DateTime==5.1 +six==1.17.0 +cffi==1.17.1 +pycparser==2.22 +PyNaCl==1.5.0 +zope.interface==8.2 -# Docs -sphinx -pydata-sphinx-theme -sphinx-autodoc-typehints -myst-parser -sphinx-copybutton -sphinx-autobuild \ No newline at end of file +# --- Template Engines --- +Jinja2==3.1.6 +MarkupSafe==3.0.2 + +# --- Helpers & Docs --- +wikipedia==1.4.0 +packaging==25.0 +pathlib==1.0.1 +more-itertools==10.8.0 +jaraco.classes==3.4.0 +jaraco.context==6.0.1 +jaraco.functools==4.3.0 +docutils==0.22.3 +nh3==0.3.2Ne \ No newline at end of file diff --git a/src/bot/cogs/bot/about.py b/src/bot/cogs/bot/about.py new file mode 100644 index 0000000..e6fb919 --- /dev/null +++ b/src/bot/cogs/bot/about.py @@ -0,0 +1,86 @@ +# Copyright (c) 2025 OPPRO.NET Network +import discord +from discord.ext import commands +import ezcord +from datetime import datetime +import platform +import sys +import time +from discord.ui import Container + + +class AboutCog(commands.Cog): + def __init__(self, bot): + self.bot = bot + # Fallback for uptime if bot.uptime is not set + if not hasattr(self.bot, 'uptime'): + self.bot.uptime = datetime.now() + + @discord.slash_command(name="about", description="Zeigt Informationen über den Bot an") + async def about(self, ctx: discord.ApplicationContext): + """Shows advanced information about the bot.""" + await ctx.defer() + + # Determine versions + python_version = platform.python_version() + discord_version = discord.__version__ + ezcord_version = ezcord.__version__ + + # Calculate uptime + uptime = discord.utils.format_dt(self.bot.uptime, style="R") + + # Calculate ping + ping = f"**{round(self.bot.latency * 1000)}ms**" + + # Counts + server_count = len(self.bot.guilds) + member_count = sum(g.member_count for g in self.bot.guilds) + + # Create Container + container = Container() + + # Header + container.add_text(f"# ℹ️ Über {self.bot.user.name}") + container.add_text( + "Ein fortschrittlicher Management-Bot entwickelt für professionelle Communities.\n" + "ManagerX bietet umfangreiche Tools für Moderation, Statistiken und Server-Verwaltung." + ) + container.add_separator() + + # Development + container.add_text("## 👨💻 Entwicklung") + container.add_text( + "Entwickelt von **ManagerX Development**\n" + "❯ [🌐 Website](https://managerx-bot.de)\n" + "❯ [💬 Support Server](https://discord.gg/uDDWzsZNzD)" + ) + container.add_separator() + + # Stats + container.add_text("## 📊 Statistiken") + container.add_text( + f"❯ **Server:** `{server_count}`\n" + f"❯ **User:** `{member_count:,}`\n" + f"❯ **Ping:** {ping}\n" + f"❯ **Uptime:** {uptime}" + ) + container.add_separator() + + # Technical + container.add_text("## 🛠️ Technik & Versionen") + container.add_text( + f"❯ **Python:** `v{python_version}`\n" + f"❯ **PyCord:** `v{discord_version}`\n" + f"❯ **EzCord:** `v{ezcord_version}`" + ) + container.add_separator() + + # Footer + container.add_text(f"{datetime.now().year} ManagerX Development • ManagerX v2.0.0") + + # Send View + view = discord.ui.DesignerView(container, timeout=0) + await ctx.respond(view=view) + +def setup(bot): + bot.add_cog(AboutCog(bot)) \ No newline at end of file diff --git a/src/bot/cogs/guild/utility.py b/src/bot/cogs/guild/utility.py new file mode 100644 index 0000000..6e163e6 --- /dev/null +++ b/src/bot/cogs/guild/utility.py @@ -0,0 +1,163 @@ +import discord +from discord.ext import commands +from discord import SlashCommandGroup +import ezcord +import time +import os +from datetime import datetime + +from discord.ui import Container, DesignerView, Thumbnail, Section, TextDisplay +from discord.ui.separator import SeparatorSpacingSize +from src.bot.core.constants import FOOTER + +class Utility(ezcord.Cog): + """Premium Utility commands for server and user information.""" + + @discord.slash_command(name="ping", description="Prüft die Latenz des Bots.") + async def ping(self, ctx: discord.ApplicationContext): + start_time = time.time() + # Initial response to measure round-trip + await ctx.defer(ephemeral=True) + end_time = time.time() + + round_trip = round((end_time - start_time) * 1000) + api_latency = round(self.bot.latency * 1000) + + container = Container() + container.add_text("📡 **Bot Latenz Übersicht**") + container.add_separator(spacing=SeparatorSpacingSize.small) + container.add_text(f"❯ **API-Latenz:** `{api_latency}ms`") + container.add_text(f"❯ **Round Trip:** `{round_trip}ms`") + + view = DesignerView(container, timeout=60) + await ctx.respond(view=view, ephemeral=True) + + @discord.slash_command(name="serverinfo", description="Zeigt detaillierte Informationen über den Server.") + async def serverinfo(self, ctx: discord.ApplicationContext): + guild = ctx.guild + owner = guild.owner + + container = Container() + + # Header Section with Icon + header_text = f"🏰 **Server Übersicht: {guild.name}**" + if guild.icon: + container.add_section(TextDisplay(header_text), accessory=Thumbnail(guild.icon.url)) + else: + container.add_text(header_text) + + container.add_separator(spacing=SeparatorSpacingSize.small) + + general_info = ( + f"❯ **Besitzer:** {owner.mention}\n" + f"❯ **Erstellt:** \n" + f"❯ **ID:** `{guild.id}`" + ) + container.add_text(general_info) + + container.add_separator(spacing=SeparatorSpacingSize.large) + + stats_info = ( + f"👥 **Mitglieder:** `{guild.member_count}`\n" + f"🛡️ **Sicherheit:** `{str(guild.verification_level).capitalize()}`\n" + f"🚀 **Boosts:** `{guild.premium_subscription_count}` (Level {guild.premium_tier})" + ) + container.add_text(stats_info) + + container.add_separator(spacing=SeparatorSpacingSize.large) + + channels_info = ( + f"📁 **Kategorien:** `{len(guild.categories)}`\n" + f"💬 **Textkanäle:** `{len(guild.text_channels)}`\n" + f"🔊 **Sprachkanäle:** `{len(guild.voice_channels)}`" + ) + container.add_text(channels_info) + + view = DesignerView(container, timeout=120) + await ctx.respond(view=view) + + @discord.slash_command(name="userinfo", description="Zeigt detaillierte Informationen über einen Nutzer.") + @discord.option("user", description="Wähle einen Nutzer", required=False) + async def userinfo(self, ctx: discord.ApplicationContext, user: discord.Member = None): + user = user or ctx.author + + container = Container() + + # Status Map + status_map = { + discord.Status.online: "🟢 Online", + discord.Status.idle: "🟡 Abwesend", + discord.Status.dnd: "🔴 Bitte nicht stören", + discord.Status.offline: "⚫ Offline", + discord.Status.invisible: "⚫ Unsichtbar" + } + status_text = status_map.get(user.status, "⚫ Unbekannt") + + # Activity Header + activity_text = None + if user.activities: + activity = user.activities[0] + if activity.type == discord.ActivityType.listening: + activity_text = f"🎵 Hört gerade: *{activity.name}*" + elif activity.type == discord.ActivityType.playing: + activity_text = f"🎮 Spielt gerade: *{activity.name}*" + else: + activity_text = f"❯ Aktivität: *{activity.name}*" + + # Profile Section with Avatar + header_items = [TextDisplay(f"👤 **Nutzerprofil: {user.name}**")] + header_items.append(TextDisplay(f"❯ Status: {status_text}")) + if activity_text: + header_items.append(TextDisplay(activity_text)) + + container.add_section(*header_items, accessory=Thumbnail(user.display_avatar.url)) + + container.add_separator(spacing=SeparatorSpacingSize.small) + + # Identity Block + is_bot = "🤖 Ja" if user.bot else "👤 Nein" + identity_info = ( + f"🆔 **ID:** `{user.id}`\n" + f"🤖 **Bot:** {is_bot}\n" + f"📅 **Erstellt:** " + ) + container.add_text(identity_info) + + container.add_separator(spacing=SeparatorSpacingSize.large) + + # Server Status Block + server_info = ( + f"📥 **Beigetreten:** \n" + f"🔝 **Höchste Rolle:** {user.top_role.mention if user.top_role else 'Keine'}" + ) + container.add_text(server_info) + + container.add_separator(spacing=SeparatorSpacingSize.small) + + # Roles Block + roles = [role.mention for role in reversed(user.roles[1:])] + roles_text = ", ".join(roles[:8]) + (f" (+{len(roles)-8})" if len(roles) > 8 else "") + container.add_text(f"🎭 **Rollen ({len(roles)})**\n{roles_text or '*Keine Rollen*'}") + + container.add_separator(spacing=SeparatorSpacingSize.large) + + # Privileges Block + perms = [] + if user.guild_permissions.administrator: perms.append("Administrator") + if user.guild_permissions.manage_guild: perms.append("Server verwalten") + if user.guild_permissions.manage_roles: perms.append("Rollen verwalten") + if user.guild_permissions.manage_channels: perms.append("Kanäle verwalten") + if user.guild_permissions.kick_members: perms.append("Mitglieder kicken") + if user.guild_permissions.ban_members: perms.append("Mitglieder bannen") + + if perms: + container.add_text(f"🛡️ **Wichtige Berechtigungen:**\n`{'`, `'.join(perms)}`") + else: + container.add_text("🛡️ **Wichtige Berechtigungen:** Keine speziellen Berechtigungen") + + view = DesignerView(container, timeout=120) + await ctx.respond(view=view) + + +def setup(bot): + bot.add_cog(Utility(bot)) diff --git a/src/bot/core/bot_setup.py b/src/bot/core/bot_setup.py index 9c81795..a6caee1 100644 --- a/src/bot/core/bot_setup.py +++ b/src/bot/core/bot_setup.py @@ -26,6 +26,7 @@ def create_bot(self) -> ezcord.Bot: intents = discord.Intents.default() intents.members = True intents.message_content = True + intents.presences = True # Bot erstellen bot = ezcord.Bot( @@ -33,6 +34,9 @@ def create_bot(self) -> ezcord.Bot: language="de" ) + # Ezcord Help Command aktivieren + bot.add_help_command() + # Bot-Konfiguration anhängen bot.config = self._build_bot_config() diff --git a/src/web/pages/Status.tsx b/src/web/pages/Status.tsx index 8a4f704..d08d581 100644 --- a/src/web/pages/Status.tsx +++ b/src/web/pages/Status.tsx @@ -24,7 +24,7 @@ const Status = memo(function Status() { const fetchStatus = async () => { try { // Abfrage an die neue FastAPI-Route für echte Bot-Daten - const response = await fetch("http://localhost:8040/api/v1/managerx/stats"); + const response = await fetch("https://api.managerx-bot.de/api/v1/managerx/stats"); if (!response.ok) throw new Error("Offline"); const result = await response.json(); diff --git a/vite.config.ts b/vite.config.ts index ffb1d23..81cfebb 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,12 +1,11 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react-swc"; import path from "path"; -import { componentTagger } from "lovable-tagger"; export default defineConfig(({ mode }) => ({ // WICHTIG: Erlaubt korrekte Pfade auf deiner Subdomain - base: "/", - + base: "/", + server: { host: "::", port: 8080, @@ -15,9 +14,8 @@ export default defineConfig(({ mode }) => ({ }, }, plugins: [ - react(), - mode === "development" && componentTagger() - ].filter(Boolean), + react() + ], resolve: { alias: { // Dein Alias zeigt auf ./src/web - das ist wichtig für deine Imports