VisionApp/bot.py
Mathis 5d9baee102
All checks were successful
ci / ci (push) Successful in 1m1s
feat: full feature suite — welcome, modmail, security, staff, avis, rules, links, shop, custom
features/shared.py: per-guild JSON config store
features/welcome.py: on_member_join message + invite tracking + /invites
features/modmail.py: DM-based tickets with staff relay
features/security.py: antiraid (join rate detection), ban protection, join/leave log
features/staff.py: staff ranks, promote/demote, /staff_list
features/avis.py: /avis modal -> embed in configured channel
features/rules.py: /rules_setup with accept button + role assignment
features/links.py: /links panel, /links_setup, /links_remove
features/shop.py: /shop_announce new product embeds
features/custom.py: /botstatus, /custom_send, /embed
2026-10-02 19:45:46 +02:00

86 lines
3 KiB
Python

import logging
import os
import discord
from discord.ext import commands
import config
logger = logging.getLogger("vision")
DEV_GUILD_IDS = [int(x) for x in os.getenv("DEV_GUILD_IDS", "").split(",") if x.strip()]
class VisionBot(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.message_content = True
intents.members = True
super().__init__(
command_prefix="!",
intents=intents,
application_id=config.APPLICATION_ID,
)
async def setup_hook(self):
logger.info("Chargement des cogs...")
extensions = [
"commandes.hello",
"tickets.cog",
"features.welcome",
"features.modmail",
"features.security",
"features.staff",
"features.avis",
"features.rules",
"features.links",
"features.shop",
"features.custom",
]
for ext in extensions:
try:
await self.load_extension(ext)
logger.info(f" ✓ {ext}")
except Exception as e:
logger.error(f" ✗ {ext}: {e}")
self.tree.on_error = self.on_app_command_error
if config.DEV and DEV_GUILD_IDS:
logger.info(f"Mode DEV — sync des commands sur les guilds: {DEV_GUILD_IDS}")
for guild_id in DEV_GUILD_IDS:
guild = discord.Object(id=guild_id)
self.tree.copy_global_to(guild=guild)
try:
await self.tree.sync(guild=guild)
logger.info(f" ✓ Sync guild {guild_id}")
except discord.HTTPException as e:
logger.warning(f" ✗ Sync guild {guild_id} impossible ({e}). Le bot est-il invité sur ce serveur ?")
else:
logger.info("Mode PROD — sync global des slash commands...")
await self.tree.sync()
logger.info("Slash commands synchronisées (global)")
async def on_app_command_error(self, interaction: discord.Interaction, error: discord.app_commands.AppCommandError):
logger.error(
f"Erreur commande /{interaction.command.name if interaction.command else '?'} : {error}", exc_info=error
)
try:
if interaction.response.is_done():
await interaction.followup.send(f"Erreur : `{error}`", ephemeral=True)
else:
await interaction.response.send_message(f"Erreur : `{error}`", ephemeral=True)
except discord.HTTPException:
pass
async def on_ready(self):
instance = "DEV" if config.DEV else "PROD"
logger.info(f"[{instance}] Connecté en tant que {self.user} (ID: {self.user.id})")
logger.info(f"[{instance}] Serveurs : {len(self.guilds)}")
await self.change_presence(
activity=discord.Activity(
type=discord.ActivityType.watching,
name="Vision Studio",
)
)