Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ python main.py

Brauchst du Hilfe oder möchtest du das Projekt unterstützen?

[![Discord](https://img.shields.io/badge/Discord-Join%20Now-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/oppro)
[![Discord](https://img.shields.io/badge/Discord-Join%20Now-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/9T28DWup3g)
[![GitHub Issues](https://img.shields.io/github/issues/Oppro-net-Development/ManagerX?style=for-the-badge&logo=github&logoColor=white)](https://github.com/Oppro-net-Development/ManagerX/issues)

<br>
Expand Down
10 changes: 8 additions & 2 deletions config/example.env
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ DISCORD_CLIENT_ID=12345678900
DISCORD_CLIENT_SECRET=abc123
DISCORD_REDIRECT_URI=https://

URL=https://
URL=https://my-super-discord-bot.com

DASHBOARD_API_KEYS=abc123
DASHBOARD_API_KEYS=abc123

JWT_SECRET=abc123
DASHBOARD_URL=https://my-super-discord-bot.com
VITE_API_URL=https://api.my-super-discord-bot.com

TOPGG_TOKEN=abc123
13 changes: 9 additions & 4 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,6 @@ async def on_ready():
)
)

# Commands sync
await bot.sync_commands()
logger.success("COMMANDS", "Application Commands synchronisiert")

# --- LIMIT CHECK START ---
all_cmds = bot.pending_application_commands
# Wir zählen nur die echten Top-Level Slash Commands (Slots)
Expand All @@ -155,6 +151,15 @@ async def on_ready():
logger.info("LIMITS", f"Discord-API Slots belegt: {len(root_slots)} / 100")
# --- LIMIT CHECK ENDE ---

@bot.event
async def on_application_command_completion(ctx: discord.ApplicationContext):
"""Track command usage across all guilds."""
if ctx.guild and hasattr(bot, 'stats_db'):
try:
await bot.stats_db.log_command(ctx.guild.id, ctx.command.qualified_name)
except Exception as e:
logger.error("STATS", f"Fehler beim Loggen des Commands: {e}")

# Minimaler KeepAlive Cog
class KeepAlive(discord.ext.commands.Cog):
def __init__(self, bot):
Expand Down
94 changes: 53 additions & 41 deletions src/bot/cogs/bot/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,7 @@
AUDIT_LOG_FILE = Path("data/admin_audit.json")
BLACKLIST_FILE = Path("data/blacklist.json")

class ConfirmView(View):
"""Bestätigungsdialog für kritische Aktionen"""
def __init__(self, timeout=30):
super().__init__(timeout=timeout)
self.value = None

@discord.ui.button(label="✅ Bestätigen", style=discord.ButtonStyle.danger)
async def confirm(self, button: discord.ui.Button, interaction: discord.Interaction):
self.value = True
self.stop()
await interaction.response.defer()

@discord.ui.button(label="❌ Abbrechen", style=discord.ButtonStyle.secondary)
async def cancel(self, button: discord.ui.Button, interaction: discord.Interaction):
self.value = False
self.stop()
await interaction.response.defer()


class ServerListView:
Expand Down Expand Up @@ -322,6 +306,34 @@ async def cog_check(self, ctx):

return True

async def request_confirmation(self, ctx: discord.ApplicationContext, container: Container, timeout: int = 30) -> bool:
"""Helper to create a confirmation dialog with buttons and a designer container."""
view = discord.ui.DesignerView(container, timeout=timeout)
view.value = None

async def confirm_callback(interaction: discord.Interaction):
view.value = True
view.stop()
await interaction.response.defer()

async def cancel_callback(interaction: discord.Interaction):
view.value = False
view.stop()
await interaction.response.defer()

confirm_btn = Button(label="✅ Bestätigen", style=discord.ButtonStyle.danger)
confirm_btn.callback = confirm_callback

cancel_btn = Button(label="❌ Abbrechen", style=discord.ButtonStyle.secondary)
cancel_btn.callback = cancel_callback

view.add_item(confirm_btn)
view.add_item(cancel_btn)

await ctx.respond(view=view, ephemeral=True)
await view.wait()
return view.value if view.value is not None else False

def log_command(self, ctx):
"""Loggt Admin-Commands"""
AUDIT_LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -414,11 +426,7 @@ async def shutdown(self, ctx: discord.ApplicationContext):
container.add_text("# ⚠️ Shutdown bestätigen")
container.add_text("Bist du sicher, dass du den Bot herunterfahren möchtest?")

view = ConfirmView()
await ctx.respond(view=discord.ui.DesignerView(container, timeout=30), ephemeral=True)
await view.wait()

if view.value:
if await self.request_confirmation(ctx, container):
container = Container(color=discord.Color.red())
container.add_text("# ⚠️ ManagerX wird heruntergefahren...")
container.add_separator()
Expand All @@ -437,11 +445,7 @@ async def restart(self, ctx: discord.ApplicationContext):
container.add_text("# ⚠️ Restart bestätigen")
container.add_text("Bist du sicher, dass du den Bot neustarten möchtest?")

view = ConfirmView()
await ctx.respond(view=discord.ui.DesignerView(container, timeout=30), ephemeral=True)
await view.wait()

if view.value:
if await self.request_confirmation(ctx, container):
container = Container(color=discord.Color.orange())
container.add_text("# 🔄 ManagerX wird neugestartet...")
container.add_separator()
Expand Down Expand Up @@ -804,11 +808,7 @@ async def reload_all(self, ctx: discord.ApplicationContext):
container.add_text("# ⚠️ Reload All bestätigen")
container.add_text("Alle Cogs (außer Admin) werden neu geladen. Fortfahren?")

view = ConfirmView()
await ctx.respond(view=discord.ui.DesignerView(container, timeout=30), ephemeral=True)
await view.wait()

if not view.value:
if not await self.request_confirmation(ctx, container):
container = Container(color=discord.Color.green())
container.add_text("## ✅ Reload abgebrochen")
await ctx.edit(view=discord.ui.DesignerView(container, timeout=0))
Expand Down Expand Up @@ -924,11 +924,7 @@ async def leave_server(
container.add_text(f"**ID:** `{guild_id}`")
container.add_text(f"**Mitglieder:** {guild.member_count:,}")

view = ConfirmView()
await ctx.respond(view=discord.ui.DesignerView(container, timeout=30), ephemeral=True)
await view.wait()

if view.value:
if await self.request_confirmation(ctx, container):
await guild.leave()

container = Container(color=discord.Color.green())
Expand Down Expand Up @@ -1075,6 +1071,26 @@ async def server_info(

container.add_text("## ✨ Features")
container.add_text(features_text)
container.add_separator()

# Befehls-Statistiken (NEU)
if hasattr(self.bot, "stats_db"):
guild_top = await self.bot.stats_db.get_top_commands(guild.id, 3)
global_top = await self.bot.stats_db.get_global_top_commands(3)

container.add_text("## 📊 Top 3 Befehle")

if guild_top:
gt_text = "\n".join([f"• `/{name}` ({count}x)" for name, count in guild_top])
container.add_text(f"**Dieser Server:**\n{gt_text}")
else:
container.add_text("**Dieser Server:** Keine Daten")

if global_top:
glob_text = "\n".join([f"• `/{name}` ({count}x)" for name, count in global_top])
container.add_text(f"**Global:**\n{glob_text}")
else:
container.add_text("**Global:** Keine Daten")

await ctx.respond(view=discord.ui.DesignerView(container, timeout=0), ephemeral=True)

Expand Down Expand Up @@ -1374,11 +1390,7 @@ async def clear_logs(self, ctx: discord.ApplicationContext):
container.add_text("# ⚠️ Logs löschen bestätigen")
container.add_text("Alle Admin-Logs werden permanent gelöscht!")

view = ConfirmView()
await ctx.respond(view=discord.ui.DesignerView(container, timeout=30), ephemeral=True)
await view.wait()

if view.value:
if await self.request_confirmation(ctx, container):
if AUDIT_LOG_FILE.exists():
AUDIT_LOG_FILE.unlink()

Expand Down
5 changes: 3 additions & 2 deletions src/bot/cogs/user/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ class EnhancedStatsCog(ezcord.Cog):

def __init__(self, bot: commands.Bot):
self.bot = bot
self.db = StatsDB()
self.bot.stats_db = self.db
self.db = getattr(bot, "stats_db", None) or StatsDB()
if not hasattr(bot, "stats_db"):
bot.stats_db = self.db
self.level_db = LevelDatabase()
self.cleanup_task.start()
self.monthly_reset_task.start()
Expand Down
2 changes: 1 addition & 1 deletion src/bot/core/bot_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def create_bot(self) -> ezcord.Bot:
name="🔗 **Important Links**",
value=(
"🌐 [**Website**](https://managerx-bot.de) • "
"🚑 [**Support**](https://discord.gg/SrcE6zJZ) • "
"🚑 [**Support**](https://discord.gg/9T28DWup3g) • "
"💻 [**GitHub**](https://github.com/ManagerX-Development/ManagerX)"
),
inline=False
Expand Down
10 changes: 8 additions & 2 deletions src/bot/core/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
from logger import logger, Category

try:
from mx_devtools import SettingsDB
from mx_devtools import SettingsDB, StatsDB
except ImportError as e:
logger.critical(Category.DATABASE, f"SettingsDB Import fehlgeschlagen: {e}")
logger.critical(Category.DATABASE, f"Database Imports fehlgeschlagen: {e}")
SettingsDB = None
StatsDB = None

class DatabaseManager:
"""Verwaltet die Datenbank-Initialisierung"""
Expand All @@ -38,6 +39,11 @@ def initialize(self, bot) -> bool:
self.db = SettingsDB()
bot.settings_db = self.db
logger.success(Category.DATABASE, "Settings Database initialized ✓")

if StatsDB:
bot.stats_db = StatsDB()
logger.success(Category.DATABASE, "Stats Database initialized ✓")

return True

except Exception as e:
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/web/components/CTA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export const CTA = memo(function CTA() {
<motion.a
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.98 }}
href="https://discord.gg/oppro"
href="https://discord.gg/9T28DWup3g"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-3 px-10 py-4.5 rounded-2xl glass border border-white/10 font-bold text-lg text-white shadow-xl"
Expand Down
4 changes: 2 additions & 2 deletions src/web/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Shield, Heart, Github, MessageCircle, ExternalLink, Terminal, Sparkles,

const socialLinks = [
{ icon: Github, href: "https://github.com/ManagerX-Development/ManagerX", label: "GitHub" },
{ icon: MessageCircle, href: "https://discord.gg/dein-link", label: "Discord Support" },
{ icon: MessageCircle, href: "https://discord.gg/9T28DWup3g", label: "Discord Support" },
];

export const Footer = memo(function Footer() {
Expand Down Expand Up @@ -113,7 +113,7 @@ export const Footer = memo(function Footer() {
<div className="flex flex-col gap-5">
<span className="text-[10px] font-bold uppercase tracking-[0.3em] text-primary mb-2">Ressourcen</span>
<a href="https://docs.managerx-bot.de/" target="_blank" rel="noopener noreferrer" className="text-sm text-muted-foreground hover:text-foreground transition-colors font-medium">Dokumentation</a>
<a href="https://discord.gg/oppro" target="_blank" rel="noopener noreferrer" className="text-sm text-muted-foreground hover:text-foreground transition-colors font-medium">Support Server</a>
<a href="https://discord.gg/9T28DWup3g" target="_blank" rel="noopener noreferrer" className="text-sm text-muted-foreground hover:text-foreground transition-colors font-medium">Support Server</a>
<a href="https://github.com/ManagerX-Development/ManagerX" target="_blank" rel="noopener noreferrer" className="text-sm text-muted-foreground hover:text-foreground transition-colors font-medium">GitHub Repository</a>
</div>

Expand Down
2 changes: 1 addition & 1 deletion src/web/dashboard/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export default function LoginPage() {
>
<Link to="/legal/privacy" className="text-xs text-muted-foreground hover:text-white transition-colors no-underline">Datenschutz</Link>
<Link to="/legal/terms" className="text-xs text-muted-foreground hover:text-white transition-colors no-underline">Nutzungsbedingungen</Link>
<a href="https://discord.gg/managerx" target="_blank" rel="noopener noreferrer" className="text-xs text-muted-foreground hover:text-white transition-colors no-underline">Hilfe erhalten</a>
<a href="https://discord.gg/9T28DWup3g" target="_blank" rel="noopener noreferrer" className="text-xs text-muted-foreground hover:text-white transition-colors no-underline">Hilfe erhalten</a>
</motion.div>
</motion.div>

Expand Down
2 changes: 1 addition & 1 deletion src/web/pages/CommandsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export const CommandsPage = memo(function CommandsPage() {
</p>
<div className="flex flex-wrap gap-4 justify-center">
<a
href="https://discord.gg/dein-link"
href="https://discord.gg/9T28DWup3g"
target="_blank"
rel="noopener noreferrer"
className="px-10 py-4 bg-primary text-white rounded-2xl font-black uppercase tracking-widest hover:scale-105 transition-transform shadow-xl shadow-primary/20 flex items-center gap-3"
Expand Down
2 changes: 1 addition & 1 deletion src/web/pages/RoadmapPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export const RoadmapPage = memo(function RoadmapPage() {
<p className="text-slate-400 font-medium max-w-md mx-auto mb-10 relative z-10">
ManagerX wird für euch entwickelt. Schlag uns neue Features auf unserem Support-Server vor!
</p>
<a href="https://discord.gg/nWWBWy6EbX" className="relative z-10 px-10 py-4 bg-accent text-white rounded-2xl font-black uppercase tracking-widest shadow-xl shadow-accent/20">
<a href="https://discord.gg/9T28DWup3g" className="relative z-10 px-10 py-4 bg-accent text-white rounded-2xl font-black uppercase tracking-widest shadow-xl shadow-accent/20">
Feedback geben
</a>
</section>
Expand Down
2 changes: 1 addition & 1 deletion translation/messages/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ cog_about:
title: "# ℹ️ Über ManagerX"
description: "Ein fortschrittlicher Management-Bot entwickelt für professionelle Communities.\nManagerX bietet umfangreiche Tools für Moderation, Statistiken und Server-Verwaltung."
dev_header: "## 👨💻 Entwicklung"
dev_info: "Entwickelt von **ManagerX Development**\n❯ [🌐 Website](https://managerx-bot.de)\n❯ [💬 Support Server](https://discord.gg/uDDWzsZNzD)"
dev_info: "Entwickelt von **ManagerX Development**\n❯ [🌐 Website](https://managerx-bot.de)\n❯ [💬 Support Server](https://discord.gg/9T28DWup3g)"
stats_header: "## 📊 Statistiken"
stats_info: "❯ **Server:** `{server_count}`\n❯ **User:** `{member_count}`\n❯ **Ping:** {ping}\n❯ **Uptime:** {uptime}"
tech_header: "## 🛠️ Technik & Versionen"
Expand Down
2 changes: 1 addition & 1 deletion translation/messages/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ cog_about:
title: "# ℹ️ About ManagerX"
description: "An advanced management bot developed for professional communities.\nManagerX offers comprehensive tools for moderation, statistics, and server management."
dev_header: "## 👨💻 Development"
dev_info: "Developed by **ManagerX Development**\n❯ [🌐 Website](https://managerx-bot.de)\n❯ [💬 Support Server](https://discord.gg/uDDWzsZNzD)"
dev_info: "Developed by **ManagerX Development**\n❯ [🌐 Website](https://managerx-bot.de)\n❯ [💬 Support Server](https://discord.gg/9T28DWup3g)"
stats_header: "## 📊 Statistics"
stats_info: "❯ **Servers:** `{server_count}`\n❯ **Users:** `{member_count}`\n❯ **Ping:** {ping}\n❯ **Uptime:** {uptime}"
tech_header: "## 🛠️ Technology & Versions"
Expand Down
Loading