Merge branch 'dev' into 'main'
Fix(Ticket Whitelist): Ajout système async et tracking pour le deblocage des validation rate limitees (10 min) + infos MP See merge request Omega_Kube/kuby!10
This commit is contained in:
commit
c9b098d87b
46 changed files with 930 additions and 3283 deletions
19
commandes/PENDING_TASKS.md
Normal file
19
commandes/PENDING_TASKS.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# À RÉGLER - Session Suivante (Ticket Whitelist)
|
||||
|
||||
### Bug Identifié
|
||||
La commande **"validé"** par message (on_message) n'est pas détectée ou ne réagit pas si le ticket a été refermé puis réouvert avec le statut "Ouvert".
|
||||
|
||||
### État Actuel
|
||||
- Le bouton "Fermer" fonctionne et détecte l'ID via Regex.
|
||||
- Le bouton "Réouvrir" synchronise maintenant les rôles (Écrit/Oral/Accepté).
|
||||
- Le design des MPs (Orange/Vert) est restauré conforme aux captures.
|
||||
- **Reste** : Vérifier pourquoi `on_message` ignore parfois le message "validé" (probablement un problème de sujet (topic) ou de permissions au moment de la lecture).
|
||||
|
||||
### Prochaine Étape (À faire lors de la reprise)
|
||||
1. **Ticket Ouvert/Réouvert** : Le bot est actuellement en ligne avec des messages de debug (❌).
|
||||
2. **Test "validé"** : Taper "validé" dans un ticket (neuf ou réouvert).
|
||||
3. **Analyser les retours** :
|
||||
- `❌ Debug: message.channel.topic est vide ou None.` (Cache d.py obsolète ?)
|
||||
- `❌ Debug: Topic trouvé mais pas d'ID matché.` (Format de topic invalide ?)
|
||||
- `❌ Debug: Permission refusée.` (Rôle Staff ou Permissions Admin non reconnus ?)
|
||||
4. **Action** : Une fois la cause identifiée, implémenter le "fetch_channel" ou une méthode alternative de récupération de l'owner.
|
||||
|
|
@ -9,10 +9,12 @@ import os
|
|||
import asyncio
|
||||
|
||||
kuby_logger = logging.getLogger("KubyBot")
|
||||
REPORTS_FILE = "data/gitlab_reports.json"
|
||||
# Utilisation de chemins absolus pour la persistance après reboot
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
REPORTS_FILE = os.path.join(BASE_DIR, "data", "gitlab_reports.json")
|
||||
|
||||
def save_report(issue_iid, user_id):
|
||||
os.makedirs("data", exist_ok=True)
|
||||
os.makedirs(os.path.dirname(REPORTS_FILE), exist_ok=True)
|
||||
try:
|
||||
if os.path.exists(REPORTS_FILE):
|
||||
with open(REPORTS_FILE, "r") as f:
|
||||
|
|
@ -116,16 +118,59 @@ class BugReport(commands.Cog):
|
|||
self.web_app.router.add_post('/bot_event', self.handle_bot_event)
|
||||
self.runner = web.AppRunner(self.web_app)
|
||||
await self.runner.setup()
|
||||
self.site = web.TCPSite(self.runner, '127.0.0.1', 5001)
|
||||
await self.site.start()
|
||||
kuby_logger.info("Internal Bot Webhook Server started on 127.0.0.1:5001")
|
||||
|
||||
max_retries = 5
|
||||
retry_delay = 2
|
||||
|
||||
for attempt in range(1, max_retries + 1):
|
||||
try:
|
||||
self.site = web.TCPSite(self.runner, '127.0.0.1', 5001)
|
||||
await self.site.start()
|
||||
kuby_logger.info(f"Internal Bot Webhook Server started on 127.0.0.1:5001 (Attempt {attempt})")
|
||||
return
|
||||
except OSError as e:
|
||||
if e.errno == 98: # Address already in use
|
||||
if attempt < max_retries:
|
||||
kuby_logger.warning(f"Port 5001 already in use, retrying in {retry_delay}s... ({attempt}/{max_retries})")
|
||||
await asyncio.sleep(retry_delay)
|
||||
else:
|
||||
kuby_logger.error(f"Failed to bind to port 5001 after {max_retries} attempts.")
|
||||
raise e
|
||||
else:
|
||||
raise e
|
||||
|
||||
def cog_unload(self):
|
||||
if hasattr(self, 'runner'):
|
||||
self.bot.loop.create_task(self.runner.cleanup())
|
||||
# On utilise create_task car cog_unload est synchrone
|
||||
async def cleanup():
|
||||
try:
|
||||
if hasattr(self, 'site'):
|
||||
await self.site.stop()
|
||||
await self.runner.cleanup()
|
||||
kuby_logger.info("Internal Bot Webhook Server stopped and cleaned up.")
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Error during webhook server cleanup: {e}")
|
||||
|
||||
self.bot.loop.create_task(cleanup())
|
||||
|
||||
async def handle_bot_event(self, request):
|
||||
# Vérification de la sécurité (Secret Token GitLab)
|
||||
webhook_secret = os.getenv("GITLAB_WEBHOOK_SECRET")
|
||||
if webhook_secret:
|
||||
provided_token = request.headers.get("X-Gitlab-Token")
|
||||
if provided_token != webhook_secret:
|
||||
kuby_logger.warning("Unauthorised webhook attempt detected (invalid X-Gitlab-Token).")
|
||||
return web.json_response({"status": "unauthorised"}, status=401)
|
||||
|
||||
try:
|
||||
# On attend que le bot soit prêt si on vient de rebooter
|
||||
if not self.bot.is_ready():
|
||||
kuby_logger.info("Webhook received but bot is not ready yet. Waiting up to 10s...")
|
||||
try:
|
||||
await asyncio.wait_for(self.bot.wait_until_ready(), timeout=10.0)
|
||||
except asyncio.TimeoutError:
|
||||
kuby_logger.warning("Bot still not ready after 10s. Proceeding anyway (best effort).")
|
||||
|
||||
payload = await request.json()
|
||||
|
||||
event_type = payload.get("object_kind")
|
||||
|
|
@ -187,13 +232,22 @@ class BugReport(commands.Cog):
|
|||
color=discord.Color.blue()
|
||||
)
|
||||
embed.add_field(name="Nouveaux Labels / Statuts", value=current_labels_str)
|
||||
await user.send(embed=embed)
|
||||
|
||||
if dev:
|
||||
await dev.send(f"✅ [FIABLE] L'utilisateur {user} ({user.id}) a bien reçu la notification de statut **{current_labels_str}** pour l'issue #{issue_iid} ({issue_title}).")
|
||||
try:
|
||||
await user.send(embed=embed)
|
||||
if dev and dev.id != user.id:
|
||||
await dev.send(f"✅ [FIABLE] L'utilisateur {user} ({user.id}) a bien reçu la notification de statut **{current_labels_str}** pour l'issue #{issue_iid} ({issue_title}).")
|
||||
except discord.Forbidden:
|
||||
kuby_logger.warning(f"Unable to DM user {user} ({user.id}) - DMs are disabled or bot is blocked.")
|
||||
if dev and dev.id != user.id:
|
||||
try:
|
||||
await dev.send(f"⚠️ [DM BLOQUÉ] Impossible de notifier l'utilisateur {user} ({user.id}) pour l'issue #{issue_iid} (DMs désactivés).")
|
||||
except discord.Forbidden:
|
||||
pass
|
||||
except discord.HTTPException as e:
|
||||
kuby_logger.error(f"HTTP error sending DM to {user}: {e}")
|
||||
except Exception as e:
|
||||
if dev:
|
||||
await dev.send(f"❌ [ERREUR] Impossible de notifier l'utilisateur {user} pour l'issue #{issue_iid} : {e}")
|
||||
kuby_logger.error(f"Unexpected error in label update notification: {e}")
|
||||
|
||||
# Check if it was closed
|
||||
if action == "close" or payload.get("object_attributes", {}).get("state") == "closed":
|
||||
|
|
@ -205,14 +259,22 @@ class BugReport(commands.Cog):
|
|||
)
|
||||
embed.add_field(name="Prochaine étape", value="La mise à jour arrive prochainement (ou est déjà là) !")
|
||||
embed.set_footer(text="Merci pour votre aide !")
|
||||
await user.send(embed=embed)
|
||||
|
||||
if dev:
|
||||
await dev.send(f"✅ [FIABLE] L'utilisateur {user} ({user.id}) a bien reçu la notification de CLÔTURE pour l'issue #{issue_iid}.")
|
||||
|
||||
try:
|
||||
await user.send(embed=embed)
|
||||
if dev and dev.id != user.id:
|
||||
await dev.send(f"✅ [FIABLE] L'utilisateur {user} ({user.id}) a bien reçu la notification de CLÔTURE pour l'issue #{issue_iid}.")
|
||||
except discord.Forbidden:
|
||||
kuby_logger.warning(f"Unable to DM user {user} ({user.id}) - DMs are disabled or bot is blocked during closure.")
|
||||
if dev and dev.id != user.id:
|
||||
try:
|
||||
await dev.send(f"⚠️ [DM BLOQUÉ] Impossible d'annoncer la clôture à {user} ({user.id}) pour l'issue #{issue_iid} (DMs désactivés).")
|
||||
except discord.Forbidden:
|
||||
pass
|
||||
except discord.HTTPException as e:
|
||||
kuby_logger.error(f"HTTP error sending closure DM to {user}: {e}")
|
||||
except Exception as e:
|
||||
if dev:
|
||||
await dev.send(f"❌ [ERREUR] Impossible d'annoncer la clôture à {user} pour l'issue #{issue_iid} : {e}")
|
||||
kuby_logger.error(f"Unexpected error in closure notification: {e}")
|
||||
|
||||
elif event_type == "note":
|
||||
note_attr = payload.get("object_attributes", {})
|
||||
|
|
@ -229,14 +291,22 @@ class BugReport(commands.Cog):
|
|||
color=discord.Color.orange()
|
||||
)
|
||||
embed.set_footer(text=f"Par {author_name}")
|
||||
await user.send(embed=embed)
|
||||
|
||||
if dev:
|
||||
await dev.send(f"✅ [FIABLE] L'utilisateur {user} ({user.id}) a bien reçu votre commentaire pour l'issue #{issue_iid}.")
|
||||
|
||||
|
||||
try:
|
||||
await user.send(embed=embed)
|
||||
if dev and dev.id != user.id:
|
||||
await dev.send(f"✅ [FIABLE] L'utilisateur {user} ({user.id}) a bien reçu votre commentaire pour l'issue #{issue_iid}.")
|
||||
except discord.Forbidden:
|
||||
kuby_logger.warning(f"Unable to DM user {user} ({user.id}) - DMs are disabled or bot is blocked during comment notification.")
|
||||
if dev and dev.id != user.id:
|
||||
try:
|
||||
await dev.send(f"⚠️ [DM BLOQUÉ] Impossible d'envoyer votre commentaire à {user} ({user.id}) pour l'issue #{issue_iid} (DMs désactivés).")
|
||||
except discord.Forbidden:
|
||||
pass
|
||||
except discord.HTTPException as e:
|
||||
kuby_logger.error(f"HTTP error sending comment DM to {user}: {e}")
|
||||
except Exception as e:
|
||||
if dev:
|
||||
await dev.send(f"❌ [ERREUR] Impossible d'envoyer votre commentaire à {user} pour l'issue #{issue_iid} : {e}")
|
||||
kuby_logger.error(f"Unexpected error in comment notification: {e}")
|
||||
|
||||
return web.json_response({"status": "success"}, status=200)
|
||||
|
||||
|
|
|
|||
|
|
@ -960,53 +960,49 @@ class Security(commands.Cog):
|
|||
Commande principale pour ouvrir l'interface de sécurité.
|
||||
Accessible uniquement aux administrateurs et propriétaires whitelistés.
|
||||
"""
|
||||
# On diffère la réponse immédiatement car le chargement des réglages peut prendre du temps
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
|
||||
# Vérification des permissions
|
||||
if not is_immune(interaction.guild, interaction.user):
|
||||
if interaction.response.is_done():
|
||||
return await interaction.followup.send(
|
||||
"❌ **Accès refusé**\n\nVous devez être administrateur, propriétaire du serveur, ou être dans la whitelist pour accéder à ce panneau.",
|
||||
ephemeral=True
|
||||
)
|
||||
return await interaction.response.send_message(
|
||||
return await interaction.followup.send(
|
||||
"❌ **Accès refusé**\n\nVous devez être administrateur, propriétaire du serveur, ou être dans la whitelist pour accéder à ce panneau.",
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
# Chargement des paramètres
|
||||
settings = load_settings(interaction.guild.id)
|
||||
try:
|
||||
# Chargement des paramètres
|
||||
settings = load_settings(interaction.guild.id)
|
||||
|
||||
# Création de la vue
|
||||
view = SecurityView(interaction, settings, bot=self.bot)
|
||||
embed = view.create_main_embed(interaction.user)
|
||||
# Création de la vue
|
||||
view = SecurityView(interaction, settings, bot=self.bot)
|
||||
embed = view.create_main_embed(interaction.user)
|
||||
|
||||
if interaction.response.is_done():
|
||||
await interaction.followup.send(
|
||||
embed=embed,
|
||||
view=view,
|
||||
ephemeral=True
|
||||
)
|
||||
else:
|
||||
await interaction.response.send_message(
|
||||
embed=embed,
|
||||
view=view,
|
||||
except Exception as e:
|
||||
await interaction.followup.send(
|
||||
f"❌ Une erreur est survenue lors de l'ouverture du panneau : {e}",
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
@security.error
|
||||
async def security_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError):
|
||||
"""Gestion des erreurs de la commande security"""
|
||||
# Ne pas envoyer de message si l'interaction a déjà été traitée
|
||||
if interaction.response.is_done():
|
||||
return
|
||||
# Utilisation de followup si l'interaction est déjà différée ou répondue
|
||||
send_method = interaction.followup.send if interaction.response.is_done() else interaction.response.send_message
|
||||
|
||||
if isinstance(error, app_commands.MissingPermissions):
|
||||
await interaction.response.send_message(
|
||||
await send_method(
|
||||
"❌ Permissions insuffisantes.",
|
||||
ephemeral=True
|
||||
)
|
||||
else:
|
||||
await interaction.response.send_message(
|
||||
f"❌ Une erreur est survenue.",
|
||||
await send_method(
|
||||
f"❌ Une erreur est survenue lors de l'exécution de la commande : {error}",
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1707,14 +1707,14 @@ class ConfigPanelView(discord.ui.View):
|
|||
self.category_btn.callback = self._category_callback
|
||||
self.add_item(self.category_btn)
|
||||
|
||||
# Ajouter catégorie
|
||||
self.add_cat_btn = discord.ui.Button(
|
||||
# Gérer les catégories
|
||||
self.manage_cat_btn = discord.ui.Button(
|
||||
style=discord.ButtonStyle.blurple,
|
||||
label="Ajouter Catégorie",
|
||||
custom_id="config_add_cat"
|
||||
label="📂 Gérer les catégories",
|
||||
custom_id="config_manage_cat"
|
||||
)
|
||||
self.add_cat_btn.callback = self._add_cat_callback
|
||||
self.add_item(self.add_cat_btn)
|
||||
self.manage_cat_btn.callback = self._manage_cat_callback
|
||||
self.add_item(self.manage_cat_btn)
|
||||
|
||||
# Staff permissions
|
||||
staff_btn = discord.ui.Button(
|
||||
|
|
@ -1756,9 +1756,9 @@ class ConfigPanelView(discord.ui.View):
|
|||
item.style = discord.ButtonStyle.green if self.config.enabled else discord.ButtonStyle.red
|
||||
await interaction.message.edit(view=self)
|
||||
|
||||
async def _add_cat_callback(self, interaction: discord.Interaction):
|
||||
modal = AddCategoryModal(self.bot, self.storage, self.config)
|
||||
await interaction.response.send_modal(modal)
|
||||
async def _manage_cat_callback(self, interaction: discord.Interaction):
|
||||
view = CategoryManagerView(self.bot, self.storage, self.config)
|
||||
await interaction.response.edit_message(embed=view._get_embed(), view=view)
|
||||
|
||||
async def _staff_perms_callback(self, interaction: discord.Interaction):
|
||||
view = PermissionConfigView(self.bot, self.storage, self.config, interaction.guild, "staff")
|
||||
|
|
@ -1849,6 +1849,251 @@ class AddCategoryModal(discord.ui.Modal):
|
|||
await interaction.response.send_message(f"Catégorie **{self.name.value}** créée!", ephemeral=True)
|
||||
|
||||
|
||||
class EditCategoryModal(discord.ui.Modal):
|
||||
"""Modal pour modifier une catégorie existante"""
|
||||
|
||||
def __init__(self, bot, storage, config, category: TicketCategory, parent_view):
|
||||
super().__init__(title=f"Modifier: {category.name}")
|
||||
self.bot = bot
|
||||
self.storage = storage
|
||||
self.config = config
|
||||
self.category = category
|
||||
self.parent_view = parent_view
|
||||
|
||||
self.name = discord.ui.TextInput(
|
||||
label="Nom",
|
||||
default=category.name,
|
||||
placeholder="Ex: Support",
|
||||
required=True
|
||||
)
|
||||
self.add_item(self.name)
|
||||
|
||||
self.description = discord.ui.TextInput(
|
||||
label="Description",
|
||||
default=category.description,
|
||||
placeholder="Description...",
|
||||
required=False,
|
||||
style=discord.TextStyle.paragraph
|
||||
)
|
||||
self.add_item(self.description)
|
||||
|
||||
self.emoji = discord.ui.TextInput(
|
||||
label="Emoji",
|
||||
default=category.emoji,
|
||||
placeholder="🎫",
|
||||
required=False,
|
||||
max_length=5
|
||||
)
|
||||
self.add_item(self.emoji)
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
# Update category object
|
||||
self.category.name = self.name.value
|
||||
self.category.description = self.description.value or ""
|
||||
self.category.emoji = self.emoji.value or "🎫"
|
||||
|
||||
# Save config
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
# Refresh the parent view's message
|
||||
await interaction.response.edit_message(embed=self.parent_view._get_embed(), view=self.parent_view)
|
||||
await interaction.followup.send(f"✅ Catégorie **{self.category.name}** mise à jour !", ephemeral=True)
|
||||
|
||||
|
||||
class CategoryManagerView(discord.ui.View):
|
||||
"""Vue pour lister et gérer les catégories"""
|
||||
|
||||
def __init__(self, bot, storage, config: GuildTicketConfig):
|
||||
super().__init__(timeout=None)
|
||||
self.bot = bot
|
||||
self.storage = storage
|
||||
self.config = config
|
||||
self._add_category_select()
|
||||
|
||||
def _add_category_select(self):
|
||||
self.clear_items()
|
||||
|
||||
if self.config.categories:
|
||||
options = []
|
||||
for cat in self.config.categories[:25]: # Limite Select menu
|
||||
options.append(discord.SelectOption(
|
||||
label=cat.name,
|
||||
value=cat.id,
|
||||
description=cat.description[:100] if cat.description else "Aucune description",
|
||||
emoji=cat.emoji
|
||||
))
|
||||
|
||||
select = discord.ui.Select(
|
||||
placeholder="Sélectionnez une catégorie à gérer...",
|
||||
options=options,
|
||||
custom_id="manage_cat_select"
|
||||
)
|
||||
select.callback = self._category_select_callback
|
||||
self.add_item(select)
|
||||
|
||||
# Bouton Ajouter
|
||||
add_btn = discord.ui.Button(
|
||||
style=discord.ButtonStyle.success,
|
||||
label="➕ Ajouter une catégorie",
|
||||
custom_id="manage_cat_add"
|
||||
)
|
||||
add_btn.callback = self._add_cat_callback
|
||||
self.add_item(add_btn)
|
||||
|
||||
# Bouton Retour
|
||||
back_btn = discord.ui.Button(
|
||||
style=discord.ButtonStyle.secondary,
|
||||
label="⬅️ Retour",
|
||||
custom_id="manage_cat_back"
|
||||
)
|
||||
back_btn.callback = self._back_callback
|
||||
self.add_item(back_btn)
|
||||
|
||||
def _get_embed(self):
|
||||
embed = discord.Embed(
|
||||
title="📂 Gestion des Catégories",
|
||||
description=f"Il y a actuellement **{len(self.config.categories)}** catégorie(s) configurée(s).\n\n"
|
||||
"Sélectionnez une catégorie dans le menu pour la modifier ou la supprimer.",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
|
||||
if not self.config.categories:
|
||||
embed.description += "\n\n⚠️ **Aucune catégorie configurée.** Commencez par en ajouter une !"
|
||||
|
||||
for cat in self.config.categories[:10]:
|
||||
embed.add_field(
|
||||
name=f"{cat.emoji} {cat.name}",
|
||||
value=cat.description or "Pas de description",
|
||||
inline=False
|
||||
)
|
||||
|
||||
return embed
|
||||
|
||||
async def _category_select_callback(self, interaction: discord.Interaction):
|
||||
# En utilisant interaction.data.get('values') pour obtenir la valeur sélectionnée
|
||||
cat_id = interaction.data.get('values', [None])[0]
|
||||
category = self.config.get_category(cat_id)
|
||||
|
||||
if not category:
|
||||
await interaction.response.send_message("Catégorie introuvable.", ephemeral=True)
|
||||
return
|
||||
|
||||
view = CategoryActionView(self.bot, self.storage, self.config, category, self)
|
||||
await interaction.response.edit_message(embed=view._get_embed(), view=view)
|
||||
|
||||
async def _add_cat_callback(self, interaction: discord.Interaction):
|
||||
# Utilisation de la classe AddCategoryModal existante
|
||||
class AddCategoryManagerModal(AddCategoryModal):
|
||||
def __init__(self, bot, storage, config, parent_view):
|
||||
super().__init__(bot, storage, config)
|
||||
self.parent_view = parent_view
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
import uuid
|
||||
cat_id = str(uuid.uuid4())[:8]
|
||||
category = TicketCategory(
|
||||
id=cat_id,
|
||||
name=self.name.value,
|
||||
description=self.description.value or "",
|
||||
emoji=self.emoji.value or "🎫"
|
||||
)
|
||||
self.config.categories.append(category)
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
# Refresh parent view
|
||||
self.parent_view._add_category_select()
|
||||
# On doit utiliser edit_message sur l'interaction d'origine ou renvoyer un embed
|
||||
await interaction.response.edit_message(
|
||||
embed=self.parent_view._get_embed(),
|
||||
view=self.parent_view
|
||||
)
|
||||
await interaction.followup.send(f"Catégorie **{self.name.value}** créée!", ephemeral=True)
|
||||
|
||||
modal = AddCategoryManagerModal(self.bot, self.storage, self.config, self)
|
||||
await interaction.response.send_modal(modal)
|
||||
|
||||
async def _back_callback(self, interaction: discord.Interaction):
|
||||
view = ConfigPanelView(self.bot, self.storage, self.config)
|
||||
embed = discord.Embed(
|
||||
title="Configuration des Tickets",
|
||||
description="Gérez la configuration du système de tickets",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
await interaction.response.edit_message(embed=embed, view=view)
|
||||
|
||||
|
||||
class CategoryActionView(discord.ui.View):
|
||||
"""Actions pour une catégorie spécifique"""
|
||||
|
||||
def __init__(self, bot, storage, config, category, parent_view):
|
||||
super().__init__(timeout=None)
|
||||
self.bot = bot
|
||||
self.storage = storage
|
||||
self.config = config
|
||||
self.category = category
|
||||
self.parent_view = parent_view
|
||||
|
||||
def _get_embed(self):
|
||||
embed = discord.Embed(
|
||||
title=f"Gestion: {self.category.name}",
|
||||
description=f"**ID:** `{self.category.id}`\n"
|
||||
f"**Emoji:** {self.category.emoji}\n"
|
||||
f"**Description:** {self.category.description or 'Aucune'}\n"
|
||||
f"**Couleur:** `{self.category.color}`",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
return embed
|
||||
|
||||
@discord.ui.button(label="📝 Modifier", style=discord.ButtonStyle.primary)
|
||||
async def edit_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
modal = EditCategoryModal(self.bot, self.storage, self.config, self.category, self)
|
||||
await interaction.response.send_modal(modal)
|
||||
|
||||
@discord.ui.button(label="🗑️ Supprimer", style=discord.ButtonStyle.danger)
|
||||
async def delete_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
view = DeleteCategoryConfirmationView(self.bot, self.storage, self.config, self.category, self.parent_view)
|
||||
embed = discord.Embed(
|
||||
title="⚠️ Confirmer la suppression",
|
||||
description=f"Êtes-vous sûr de vouloir supprimer la catégorie **{self.category.name}** ?\n"
|
||||
"Cette action est irréversible.",
|
||||
color=discord.Color.red()
|
||||
)
|
||||
await interaction.response.edit_message(embed=embed, view=view)
|
||||
|
||||
@discord.ui.button(label="⬅️ Retour", style=discord.ButtonStyle.secondary)
|
||||
async def back_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
self.parent_view._add_category_select()
|
||||
await interaction.response.edit_message(embed=self.parent_view._get_embed(), view=self.parent_view)
|
||||
|
||||
|
||||
class DeleteCategoryConfirmationView(discord.ui.View):
|
||||
def __init__(self, bot, storage, config, category, parent_view):
|
||||
super().__init__(timeout=None)
|
||||
self.bot = bot
|
||||
self.storage = storage
|
||||
self.config = config
|
||||
self.category = category
|
||||
self.parent_view = parent_view
|
||||
|
||||
@discord.ui.button(label="✅ Confirmer", style=discord.ButtonStyle.danger)
|
||||
async def confirm_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
if self.category in self.config.categories:
|
||||
self.config.categories.remove(self.category)
|
||||
self.storage.save_config(interaction.guild_id, self.config)
|
||||
|
||||
self.parent_view._add_category_select()
|
||||
await interaction.response.edit_message(
|
||||
embed=self.parent_view._get_embed(),
|
||||
view=self.parent_view
|
||||
)
|
||||
await interaction.followup.send(f"✅ Catégorie **{self.category.name}** supprimée.", ephemeral=True)
|
||||
|
||||
@discord.ui.button(label="❌ Annuler", style=discord.ButtonStyle.secondary)
|
||||
async def cancel_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
view = CategoryActionView(self.bot, self.storage, self.config, self.category, self.parent_view)
|
||||
await interaction.response.edit_message(embed=view._get_embed(), view=view)
|
||||
|
||||
|
||||
class SetChannelModal(discord.ui.Modal):
|
||||
"""Modal pour définir le canal de logs"""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,40 @@
|
|||
import discord
|
||||
import re
|
||||
from discord.ext import commands
|
||||
from discord import app_commands, ui
|
||||
import json
|
||||
import os
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
from src.logger import kuby_logger
|
||||
import time
|
||||
|
||||
# Dictionnaire global pour suivre les renommages de salons
|
||||
# Format: {channel_id: [timestamp1, timestamp2, ...]}
|
||||
channel_rename_timestamps = {}
|
||||
|
||||
def check_channel_rename_rate_limit(channel_id: int) -> int:
|
||||
"""Vérifie si le renommage va atteindre la limite de Discord (2 edits / 10 min)."""
|
||||
now = time.time()
|
||||
if channel_id not in channel_rename_timestamps:
|
||||
channel_rename_timestamps[channel_id] = []
|
||||
|
||||
timestamps = [ts for ts in channel_rename_timestamps[channel_id] if now - ts < 600]
|
||||
channel_rename_timestamps[channel_id] = timestamps
|
||||
|
||||
if len(timestamps) >= 2:
|
||||
return max(0, int(600 - (now - timestamps[0])))
|
||||
return 0
|
||||
|
||||
def log_channel_rename(channel_id: int):
|
||||
"""Enregistre un renommage de salon."""
|
||||
now = time.time()
|
||||
if channel_id not in channel_rename_timestamps:
|
||||
channel_rename_timestamps[channel_id] = []
|
||||
|
||||
timestamps = [ts for ts in channel_rename_timestamps[channel_id] if now - ts < 600]
|
||||
timestamps.append(now)
|
||||
channel_rename_timestamps[channel_id] = timestamps
|
||||
|
||||
TICKET_WHITELIST_SETTINGS_FILE = "data/ticket_whitelist_settings.json"
|
||||
|
||||
|
|
@ -32,6 +63,31 @@ def save_settings(guild_id: int, settings: dict) -> None:
|
|||
with open(TICKET_WHITELIST_SETTINGS_FILE, "w", encoding='utf-8') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
|
||||
async def get_ticket_user_id(channel: discord.TextChannel) -> Optional[int]:
|
||||
"""Récupère l'ID du propriétaire du ticket de manière robuste (gère le lag de cache)"""
|
||||
import re
|
||||
topic = getattr(channel, "topic", None)
|
||||
|
||||
# Tentative d'utilisation du cache d.py (plus rapide)
|
||||
if topic:
|
||||
match = re.search(r"(\d{17,20})", topic)
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
|
||||
# Si le topic est vide ou ID introuvable, on tente de forcer un refresh via l'API
|
||||
try:
|
||||
# On utilise fetch_channel pour avoir un objet tout neuf avec le topic à jour
|
||||
refreshed_channel = await channel.guild.fetch_channel(channel.id)
|
||||
topic = getattr(refreshed_channel, "topic", None)
|
||||
if topic:
|
||||
match = re.search(r"(\d{17,20})", topic)
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
class TicketWhitelistConfigView(ui.View):
|
||||
def __init__(self, guild_id: int):
|
||||
super().__init__(timeout=60)
|
||||
|
|
@ -43,12 +99,6 @@ class TicketWhitelistConfigView(ui.View):
|
|||
def check(m):
|
||||
return m.author == interaction.user and m.channel == interaction.channel
|
||||
|
||||
try:
|
||||
# We use an explicit import here to avoid clashing if __import__ syntax is weird, but using standard asyncio module is fine if we import it at top. Let's add import asyncio at the top instead!
|
||||
pass
|
||||
except __import__("asyncio").TimeoutError:
|
||||
pass
|
||||
|
||||
try:
|
||||
msg = await interaction.client.wait_for('message', check=check, timeout=30)
|
||||
target = None
|
||||
|
|
@ -323,52 +373,73 @@ class TicketManagementView(discord.ui.View):
|
|||
def __init__(self):
|
||||
super().__init__(timeout=None)
|
||||
|
||||
async def get_ticket_owner(self, interaction: discord.Interaction):
|
||||
"""Récupère le propriétaire du ticket via le helper robuste"""
|
||||
owner_id = await get_ticket_user_id(interaction.channel)
|
||||
if owner_id:
|
||||
try:
|
||||
member = interaction.guild.get_member(owner_id)
|
||||
if not member:
|
||||
member = await interaction.guild.fetch_member(owner_id)
|
||||
return member
|
||||
except:
|
||||
return None
|
||||
return None
|
||||
|
||||
@discord.ui.button(label="🔒 Fermer le Ticket", style=discord.ButtonStyle.red, custom_id="close_ticket")
|
||||
async def close_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
"""Ferme le ticket en désactivant l'envoi de messages pour le membre"""
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
|
||||
settings = load_settings(interaction.guild.id)
|
||||
staff_role_id = settings.get("staff_role_id")
|
||||
|
||||
if not discord.utils.get(interaction.user.roles, id=int(staff_role_id) if staff_role_id else 0) and not interaction.user.guild_permissions.administrator:
|
||||
return await interaction.response.send_message("❌ Seuls les staffs peuvent fermer un ticket.", ephemeral=True)
|
||||
is_staff = any(r.id == int(staff_role_id) for r in interaction.user.roles) if staff_role_id else False
|
||||
if not is_staff and not interaction.user.guild_permissions.administrator:
|
||||
return await interaction.followup.send("❌ Seuls les staffs peuvent fermer un ticket.", ephemeral=True)
|
||||
|
||||
owner = await self.get_ticket_owner(interaction)
|
||||
if not owner:
|
||||
return await interaction.followup.send("❌ Impossible de trouver le propriétaire du ticket à fermer.", ephemeral=True)
|
||||
|
||||
topic = interaction.channel.topic or ""
|
||||
if not topic.startswith("Ticket de "):
|
||||
return await interaction.response.send_message("❌ Impossible de trouver le propriétaire du ticket à fermer.", ephemeral=True)
|
||||
|
||||
try:
|
||||
owner_id = int(topic.split("Ticket de ")[1])
|
||||
ticket_owner = interaction.guild.get_member(owner_id)
|
||||
if not ticket_owner:
|
||||
ticket_owner = await interaction.guild.fetch_member(owner_id)
|
||||
except (IndexError, ValueError, discord.NotFound):
|
||||
return await interaction.response.send_message("❌ Membre introuvable.", ephemeral=True)
|
||||
await interaction.channel.set_permissions(owner, read_messages=False, send_messages=False)
|
||||
log_channel_rename(interaction.channel.id)
|
||||
asyncio.create_task(interaction.channel.edit(name=f"fermé-{owner.display_name}".replace(" ", "-").lower()[:100]))
|
||||
|
||||
# Envoi du message de fermeture dans le salon
|
||||
new_view = ClosedTicketView()
|
||||
await interaction.channel.send(f"🔒 Ce ticket a été fermé par {interaction.user.mention}.", view=new_view)
|
||||
await interaction.followup.send("✅ Ticket fermé avec succès.", ephemeral=True)
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur lors de la fermeture du ticket: {e}")
|
||||
await interaction.followup.send(f"❌ Erreur lors de la fermeture : {e}", ephemeral=True)
|
||||
|
||||
await interaction.channel.set_permissions(ticket_owner, read_messages=False, send_messages=False)
|
||||
await interaction.channel.edit(name="ticket-fermé")
|
||||
await interaction.response.send_message("🔒 Le ticket a été fermé. Vous ne pouvez plus le voir.", ephemeral=True)
|
||||
|
||||
# Mettre à jour la vue pour afficher uniquement les boutons Réouvrir et Supprimer
|
||||
new_view = ClosedTicketView()
|
||||
await interaction.channel.send("Le ticket a été fermé.", view=new_view)
|
||||
|
||||
@discord.ui.button(label="👤 Prendre en charge le Ticket", style=discord.ButtonStyle.blurple, custom_id="claim_ticket")
|
||||
@discord.ui.button(label="👤 Claim le Ticket", style=discord.ButtonStyle.blurple, custom_id="claim_ticket")
|
||||
async def claim_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
"""Un staff prend en charge le ticket"""
|
||||
await interaction.response.defer(ephemeral=False)
|
||||
|
||||
settings = load_settings(interaction.guild.id)
|
||||
staff_role_id = settings.get("staff_role_id")
|
||||
|
||||
if not discord.utils.get(interaction.user.roles, id=int(staff_role_id) if staff_role_id else 0) and not interaction.user.guild_permissions.administrator:
|
||||
return await interaction.response.send_message("❌ Seuls les staffs peuvent claim un ticket.", ephemeral=True)
|
||||
|
||||
staff_role = discord.utils.get(interaction.guild.roles, id=int(staff_role_id)) if staff_role_id else None
|
||||
|
||||
claimed_by = interaction.user
|
||||
if staff_role:
|
||||
await interaction.channel.set_permissions(staff_role, send_messages=False, read_messages=True)
|
||||
|
||||
await interaction.channel.set_permissions(claimed_by, read_messages=True, send_messages=True)
|
||||
await interaction.response.send_message(f"👤 {claimed_by.mention} a claim ce ticket.", ephemeral=False)
|
||||
is_staff = any(r.id == int(staff_role_id) for r in interaction.user.roles) if staff_role_id else False
|
||||
if not is_staff and not interaction.user.guild_permissions.administrator:
|
||||
return await interaction.followup.send("❌ Seuls les staffs peuvent claim un ticket.")
|
||||
|
||||
try:
|
||||
staff_role = interaction.guild.get_role(int(staff_role_id)) if staff_role_id else None
|
||||
|
||||
# Retrait des permissions du rôle staff pour forcer le claimer à parler seul
|
||||
if staff_role:
|
||||
await interaction.channel.set_permissions(staff_role, send_messages=False, read_messages=True)
|
||||
|
||||
# Donner les permissions au claimer
|
||||
await interaction.channel.set_permissions(interaction.user, read_messages=True, send_messages=True)
|
||||
await interaction.followup.send(f"👥 {interaction.user.mention} a pris en charge ce ticket.")
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur lors du claim du ticket: {e}")
|
||||
await interaction.followup.send(f"❌ Erreur lors du claim : {e}")
|
||||
|
||||
class ClosedTicketView(discord.ui.View):
|
||||
"""Vue pour les tickets fermés avec les boutons Réouvrir et Supprimer"""
|
||||
|
|
@ -376,45 +447,133 @@ class ClosedTicketView(discord.ui.View):
|
|||
def __init__(self):
|
||||
super().__init__(timeout=None)
|
||||
|
||||
async def get_ticket_owner(self, interaction: discord.Interaction):
|
||||
"""Récupère le propriétaire du ticket via le helper robuste"""
|
||||
owner_id = await get_ticket_user_id(interaction.channel)
|
||||
if owner_id:
|
||||
try:
|
||||
member = interaction.guild.get_member(owner_id)
|
||||
if not member:
|
||||
member = await interaction.guild.fetch_member(owner_id)
|
||||
return member
|
||||
except:
|
||||
return None
|
||||
return None
|
||||
|
||||
@discord.ui.button(label="♻ Réouvrir le Ticket", style=discord.ButtonStyle.green, custom_id="reopen_ticket")
|
||||
async def reopen_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
"""Réouvre le ticket pour le membre"""
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
|
||||
settings = load_settings(interaction.guild.id)
|
||||
staff_role_id = settings.get("staff_role_id")
|
||||
|
||||
if not discord.utils.get(interaction.user.roles, id=int(staff_role_id) if staff_role_id else 0) and not interaction.user.guild_permissions.administrator:
|
||||
return await interaction.response.send_message("❌ Seuls les staffs peuvent réouvrir un ticket.", ephemeral=True)
|
||||
is_staff = any(r.id == int(staff_role_id) for r in interaction.user.roles) if staff_role_id else False
|
||||
if not is_staff and not interaction.user.guild_permissions.administrator:
|
||||
return await interaction.followup.send("❌ Seuls les staffs peuvent réouvrir un ticket.", ephemeral=True)
|
||||
|
||||
topic = interaction.channel.topic or ""
|
||||
if not topic.startswith("Ticket de "):
|
||||
return await interaction.response.send_message("❌ Impossible de trouver le propriétaire du ticket à réouvrir.", ephemeral=True)
|
||||
owner = await self.get_ticket_owner(interaction)
|
||||
if not owner:
|
||||
return await interaction.followup.send("❌ Impossible de trouver le propriétaire du ticket à réouvrir.", ephemeral=True)
|
||||
|
||||
try:
|
||||
owner_id = int(topic.split("Ticket de ")[1])
|
||||
ticket_owner = interaction.guild.get_member(owner_id)
|
||||
if not ticket_owner:
|
||||
ticket_owner = await interaction.guild.fetch_member(owner_id)
|
||||
except (IndexError, ValueError, discord.NotFound):
|
||||
return await interaction.response.send_message("❌ Membre introuvable.", ephemeral=True)
|
||||
|
||||
await interaction.channel.set_permissions(ticket_owner, read_messages=True, send_messages=True)
|
||||
await interaction.response.send_message("✅ Le ticket a été réouvert.", ephemeral=True)
|
||||
# On demande au staff quel statut remettre
|
||||
embed = discord.Embed(
|
||||
title="♻️ Réouverture du Ticket",
|
||||
description=f"Choisissez le statut à appliquer pour **{owner.display_name}**.",
|
||||
color=discord.Color.blue()
|
||||
)
|
||||
view = ReopenStatusView(owner)
|
||||
await interaction.channel.send(embed=embed, view=view)
|
||||
await interaction.followup.send("✅ Choisissez le statut ci-dessous.", ephemeral=True)
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur lors de la préparation de réouverture: {e}")
|
||||
await interaction.followup.send(f"❌ Erreur : {e}", ephemeral=True)
|
||||
|
||||
# Mettre à jour la vue pour afficher tous les boutons
|
||||
new_view = TicketManagementView()
|
||||
await interaction.channel.send("Le ticket a été réouvert.", view=new_view)
|
||||
class ReopenStatusView(discord.ui.View):
|
||||
"""Vue pour choisir le statut lors d'une réouverture"""
|
||||
def __init__(self, owner: discord.Member):
|
||||
super().__init__(timeout=180)
|
||||
self.owner = owner
|
||||
|
||||
@discord.ui.button(label="Écrit (Ouvert)", style=discord.ButtonStyle.secondary)
|
||||
async def set_written(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
await self.apply_status(interaction, "ouvert")
|
||||
|
||||
@discord.ui.button(label="Oral (À faire)", style=discord.ButtonStyle.primary)
|
||||
async def set_oral(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
await self.apply_status(interaction, "oral-à-faire")
|
||||
|
||||
@discord.ui.button(label="Accepté", style=discord.ButtonStyle.success)
|
||||
async def set_accepted(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
await self.apply_status(interaction, "accepté")
|
||||
|
||||
async def apply_status(self, interaction: discord.Interaction, prefix: str):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
try:
|
||||
settings = load_settings(interaction.guild.id)
|
||||
candidature_a_faire_role_id = settings.get("candidature_a_faire_role_id")
|
||||
attente_oral_role_id = settings.get("attente_oral_role_id")
|
||||
citoyen_role_id = settings.get("citoyen_role_id")
|
||||
|
||||
# On récupère les objets rôles
|
||||
role_écrit = interaction.guild.get_role(int(candidature_a_faire_role_id)) if candidature_a_faire_role_id else None
|
||||
role_oral = interaction.guild.get_role(int(attente_oral_role_id)) if attente_oral_role_id else None
|
||||
role_citoyen = interaction.guild.get_role(int(citoyen_role_id)) if citoyen_role_id else None
|
||||
|
||||
# Synchronisation des RÔLES en fonction du statut choisi
|
||||
roles_to_remove = []
|
||||
role_to_add = None
|
||||
|
||||
if prefix == "ouvert":
|
||||
role_to_add = role_écrit
|
||||
roles_to_remove = [r for r in [role_oral, role_citoyen] if r]
|
||||
elif prefix == "oral-à-faire":
|
||||
role_to_add = role_oral
|
||||
roles_to_remove = [r for r in [role_écrit, role_citoyen] if r]
|
||||
elif prefix == "accepté":
|
||||
role_to_add = role_citoyen
|
||||
roles_to_remove = [r for r in [role_écrit, role_oral] if r]
|
||||
|
||||
# Mise à jour des rôles sur le membre
|
||||
if roles_to_remove:
|
||||
await self.owner.remove_roles(*roles_to_remove, reason="Réouverture du ticket - Maj Statut")
|
||||
if role_to_add:
|
||||
await self.owner.add_roles(role_to_add, reason="Réouverture du ticket - Maj Statut")
|
||||
|
||||
# Mise à jour du SALON
|
||||
await interaction.channel.set_permissions(self.owner, read_messages=True, send_messages=True)
|
||||
new_name = f"{prefix}-{self.owner.display_name}".replace(" ", "-").lower()[:100]
|
||||
log_channel_rename(interaction.channel.id)
|
||||
asyncio.create_task(interaction.channel.edit(name=new_name, topic=f"Ticket de {self.owner.id}"))
|
||||
|
||||
new_view = TicketManagementView()
|
||||
await interaction.channel.send(f"✅ Ticket réouvert par {interaction.user.mention} (Statut: **{prefix}**).", view=new_view)
|
||||
await interaction.followup.send(f"✅ Statut **{prefix}** appliqué et rôles synchronisés.", ephemeral=True)
|
||||
self.stop()
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur lors de la réouverture/synchro: {e}")
|
||||
await interaction.followup.send(f"❌ Erreur système : {e}", ephemeral=True)
|
||||
|
||||
@discord.ui.button(label="❌ Supprimer le Ticket", style=discord.ButtonStyle.danger, custom_id="delete_ticket")
|
||||
async def delete_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||
"""Supprime le salon du ticket"""
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
|
||||
settings = load_settings(interaction.guild.id)
|
||||
staff_role_id = settings.get("staff_role_id")
|
||||
|
||||
if not discord.utils.get(interaction.user.roles, id=int(staff_role_id) if staff_role_id else 0) and not interaction.user.guild_permissions.administrator:
|
||||
return await interaction.response.send_message("❌ Seuls les staffs peuvent supprimer un ticket.", ephemeral=True)
|
||||
is_staff = any(r.id == int(staff_role_id) for r in interaction.user.roles) if staff_role_id else False
|
||||
if not is_staff and not interaction.user.guild_permissions.administrator:
|
||||
return await interaction.followup.send("❌ Seuls les staffs peuvent supprimer un ticket.", ephemeral=True)
|
||||
|
||||
await interaction.response.send_message("❌ Suppression du ticket...", ephemeral=True)
|
||||
await interaction.channel.delete()
|
||||
try:
|
||||
await interaction.followup.send("❌ Suppression du ticket...", ephemeral=True)
|
||||
await interaction.channel.delete()
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur lors de la suppression du ticket: {e}")
|
||||
try: await interaction.followup.send(f"❌ Erreur lors de la suppression : {e}", ephemeral=True)
|
||||
except: pass
|
||||
|
||||
class TicketView(discord.ui.View):
|
||||
"""Vue avec le bouton pour ouvrir le ticket"""
|
||||
|
|
@ -433,6 +592,12 @@ class Ticket(commands.Cog):
|
|||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
async def cog_load(self):
|
||||
"""Enregistre les vues persistantes"""
|
||||
self.bot.add_view(TicketView())
|
||||
self.bot.add_view(TicketManagementView())
|
||||
self.bot.add_view(ClosedTicketView())
|
||||
|
||||
@app_commands.command(name="ticket_whitelist", description="Envoie l'embed pour ouvrir un ticket de whitelist.")
|
||||
@app_commands.checks.has_permissions(administrator=True)
|
||||
async def ticket_whitelist(self, interaction: discord.Interaction):
|
||||
|
|
@ -476,50 +641,134 @@ class Ticket(commands.Cog):
|
|||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
"""Surveille les messages des staffs dans les tickets"""
|
||||
"""Surveille les messages des staffs dans les tickets pour validation automatique"""
|
||||
if message.guild is None or message.author.bot:
|
||||
return
|
||||
if not message.channel.topic or not message.channel.topic.startswith("Ticket de"):
|
||||
|
||||
# On ne traite que si le message contient "validé"
|
||||
if "validé" not in message.content.lower():
|
||||
return
|
||||
|
||||
# Détection du format du topic du ticket via helper (robuste)
|
||||
user_id = await get_ticket_user_id(message.channel)
|
||||
if not user_id:
|
||||
await message.channel.send("❌ Debug: Impossible de récupérer l'ID utilisateur via le topic (même après refresh API).")
|
||||
return
|
||||
|
||||
settings = load_settings(message.guild.id)
|
||||
staff_role_id = settings.get("staff_role_id")
|
||||
attente_oral_role_id = settings.get("attente_oral_role_id")
|
||||
candidature_a_faire_role_id = settings.get("candidature_a_faire_role_id")
|
||||
citoyen_role_id = settings.get("citoyen_role_id")
|
||||
|
||||
if not staff_role_id:
|
||||
# Vérification si l'auteur est staff ou admin
|
||||
is_staff = False
|
||||
if staff_role_id:
|
||||
is_staff = any(r.id == int(staff_role_id) for r in message.author.roles)
|
||||
|
||||
if not is_staff and not message.author.guild_permissions.administrator:
|
||||
if "validé" in message.content.lower():
|
||||
await message.channel.send("❌ Debug: Permission refusée. Vous n'êtes ni Staff ni Admin.")
|
||||
return
|
||||
|
||||
staff_role = discord.utils.get(message.guild.roles, id=int(staff_role_id))
|
||||
|
||||
if staff_role in message.author.roles and "validé" in message.content.lower():
|
||||
try:
|
||||
# L'ID est déjà trouvé par le helper ci-dessus
|
||||
user_id = user_id
|
||||
try:
|
||||
user_id = message.channel.topic.split("Ticket de ")[1]
|
||||
user = await message.guild.fetch_member(int(user_id))
|
||||
user = await message.guild.fetch_member(user_id)
|
||||
except (discord.NotFound, discord.HTTPException):
|
||||
await message.channel.send("❌ Utilisateur introuvable. A-t-il quitté le serveur ?", delete_after=10)
|
||||
return
|
||||
|
||||
if not attente_oral_role_id or not candidature_a_faire_role_id or not citoyen_role_id:
|
||||
await message.channel.send("❌ Erreur de configuration : Impossible d'attribuer les rôles, ils ne sont pas tous définis dans `/ticket_whitelist_config`.", delete_after=10)
|
||||
return
|
||||
attente_oral_role_id = settings.get("attente_oral_role_id")
|
||||
candidature_a_faire_role_id = settings.get("candidature_a_faire_role_id")
|
||||
citoyen_role_id = settings.get("citoyen_role_id")
|
||||
|
||||
# Vérifier si le rôle "attente oral" est déjà attribué
|
||||
attente_oral_role = discord.utils.get(message.guild.roles, id=int(attente_oral_role_id))
|
||||
candidature_a_faire_role = discord.utils.get(message.guild.roles, id=int(candidature_a_faire_role_id))
|
||||
citoyen_role = discord.utils.get(message.guild.roles, id=int(citoyen_role_id))
|
||||
if not attente_oral_role_id or not candidature_a_faire_role_id or not citoyen_role_id:
|
||||
await message.channel.send("❌ Erreur de configuration : Impossible d'attribuer les rôles, ils ne sont pas tous définis dans `/ticket_whitelist_config`.", delete_after=10)
|
||||
return
|
||||
|
||||
if attente_oral_role in user.roles:
|
||||
# Deuxième "validé" détecté
|
||||
if attente_oral_role: await user.remove_roles(attente_oral_role)
|
||||
if citoyen_role: await user.add_roles(citoyen_role)
|
||||
await message.channel.edit(name=f"{user.name}-citoyen")
|
||||
else:
|
||||
# Premier "validé" détecté
|
||||
if candidature_a_faire_role: await user.remove_roles(candidature_a_faire_role)
|
||||
if attente_oral_role: await user.add_roles(attente_oral_role)
|
||||
await message.channel.edit(name=f"{user.name}-oral")
|
||||
attente_oral_role = message.guild.get_role(int(attente_oral_role_id))
|
||||
candidature_a_faire_role = message.guild.get_role(int(candidature_a_faire_role_id))
|
||||
citoyen_role = message.guild.get_role(int(citoyen_role_id))
|
||||
|
||||
except Exception as e:
|
||||
print(f"Erreur lors du traitement du ticket : {e}")
|
||||
if (attente_oral_role and attente_oral_role in user.roles) or "oral-à-faire" in message.channel.name.lower():
|
||||
# DEUXIÈME VALIDATION -> ACCEPTÉ / CITOYEN
|
||||
if attente_oral_role: await user.remove_roles(attente_oral_role)
|
||||
if citoyen_role: await user.add_roles(citoyen_role)
|
||||
|
||||
# Mise à jour du nom du salon
|
||||
new_name = f"accepté-{user.display_name}".replace(" ", "-").lower()[:100]
|
||||
wait_time = check_channel_rename_rate_limit(message.channel.id)
|
||||
log_channel_rename(message.channel.id)
|
||||
asyncio.create_task(message.channel.edit(name=new_name))
|
||||
|
||||
# Confirmation dans le salon (Feedback visuel)
|
||||
embed_val = discord.Embed(
|
||||
title="🎉 Whitelist Validée !",
|
||||
description=f"Félicitations {user.mention}, ton entretien oral a été validé par {message.author.mention} !\nTu es désormais **Citoyen**.",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
await message.channel.send(embed=embed_val)
|
||||
|
||||
# DM au joueur (RESTAURATION DESIGN CAPTURE)
|
||||
try:
|
||||
embed_dm = discord.Embed(
|
||||
title="🎉 Félicitations - Citoyenneté Validée !",
|
||||
description=f"Nous avons le plaisir de t'annoncer que ton passage sur **{message.guild.name}** a été validé avec succès !",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
embed_dm.add_field(name="🏙️ Nouveau Statut", value="Citoyen", inline=True)
|
||||
embed_dm.add_field(name="📍 Serveur", value=message.guild.name, inline=True)
|
||||
embed_dm.add_field(name="📋 Prochaine étape", value="Tu peux désormais te connecter au serveur et commencer ton aventure RP. N'oublie pas de consulter les salons d'informations !", inline=False)
|
||||
if wait_time > 0:
|
||||
m, s = divmod(wait_time, 60)
|
||||
embed_dm.add_field(name="⏳ Nom du ticket", value=f"Le nom de ton ticket sera actualisé d'ici {m}m et {s}s environ (limite de sécurité Discord).", inline=False)
|
||||
embed_dm.add_field(name="🔗 Lien vers ton ticket", value=f"[Clique ici pour voir ton ticket]({message.channel.jump_url})", inline=False)
|
||||
embed_dm.set_footer(text=f"L'équipe {message.guild.name}")
|
||||
if message.guild.icon: embed_dm.set_thumbnail(url=message.guild.icon.url)
|
||||
|
||||
await user.send(embed=embed_dm)
|
||||
except: pass
|
||||
|
||||
else:
|
||||
# PREMIÈRE VALIDATION -> ORAL À FAIRE
|
||||
if candidature_a_faire_role: await user.remove_roles(candidature_a_faire_role)
|
||||
if attente_oral_role: await user.add_roles(attente_oral_role)
|
||||
|
||||
# Mise à jour du nom du salon
|
||||
new_name = f"oral-à-faire-{user.display_name}".replace(" ", "-").lower()[:100]
|
||||
wait_time = check_channel_rename_rate_limit(message.channel.id)
|
||||
log_channel_rename(message.channel.id)
|
||||
asyncio.create_task(message.channel.edit(name=new_name))
|
||||
|
||||
# Confirmation dans le salon
|
||||
embed_val = discord.Embed(
|
||||
title="📝 Étape Écrite Validée !",
|
||||
description=f"Ta candidature écrite a été validée par {message.author.mention}.\nTu passes désormais en **Attente Oral**.",
|
||||
color=discord.Color.orange()
|
||||
)
|
||||
await message.channel.send(embed=embed_val)
|
||||
|
||||
# DM au joueur (RESTAURATION DESIGN CAPTURE)
|
||||
try:
|
||||
embed_dm = discord.Embed(
|
||||
title="📝 Validation Étape Écrite",
|
||||
description=f"Ta candidature écrite sur **{message.guild.name}** a été examinée et validée par notre équipe !",
|
||||
color=discord.Color.orange()
|
||||
)
|
||||
embed_dm.add_field(name="🎤 Statut Actuel", value="Attente Oral", inline=True)
|
||||
embed_dm.add_field(name="🛠️ Action Requise", value="Merci de te rendre dans le salon vocal 'Attente Oral' dès que tu es disponible pour passer ton entretien.", inline=False)
|
||||
if wait_time > 0:
|
||||
m, s = divmod(wait_time, 60)
|
||||
embed_dm.add_field(name="⏳ Nom du ticket", value=f"Le nom de ton ticket sera actualisé d'ici {m}m et {s}s environ (limite de sécurité Discord).", inline=False)
|
||||
embed_dm.add_field(name="🔗 Lien vers ton ticket", value=f"[Clique ici pour voir ton ticket]({message.channel.jump_url})", inline=False)
|
||||
embed_dm.set_footer(text=f"L'équipe {message.guild.name}")
|
||||
if message.guild.icon: embed_dm.set_thumbnail(url=message.guild.icon.url)
|
||||
|
||||
await user.send(embed=embed_dm)
|
||||
except: pass
|
||||
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur lors de la validation du ticket: {e}", exc_info=True)
|
||||
await message.channel.send(f"❌ Une erreur système est survenue : {e}")
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Ticket(bot))
|
||||
|
|
|
|||
|
|
@ -64,11 +64,11 @@ class WebsiteSync(commands.Cog, name="Website Sync"):
|
|||
def cog_unload(self):
|
||||
self.daily_export.cancel()
|
||||
|
||||
# ── Tâche de fond : génération (30s pour test) ────────────────────────────
|
||||
@tasks.loop(seconds=30)
|
||||
# ── Tâche de fond : génération (1 heure) ────────────────────────────
|
||||
@tasks.loop(hours=1)
|
||||
async def daily_export(self):
|
||||
"""Génère les JSON toutes les 30 secondes (Mode Test)."""
|
||||
logger.info("[JSON Export] Génération automatique (toutes les 30s) déclenchée.")
|
||||
"""Génère les JSON toutes les heures."""
|
||||
logger.info("[JSON Export] Génération automatique déclenchée.")
|
||||
await generate_all(self.bot)
|
||||
|
||||
@daily_export.before_loop
|
||||
|
|
|
|||
|
|
@ -141,11 +141,17 @@ class Welcome(commands.Cog):
|
|||
servername=member.guild.name,
|
||||
member_count=member.guild.member_count
|
||||
)
|
||||
await member.send(formatted_message)
|
||||
await member.send("https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExNXV1NW02NTk0bGF2ZHcyMGFna2F6amRrbGpobGpsMHowOW5xa2E5eCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/ZtFuW4rsUbfrRzPauJ/giphy.gif")
|
||||
kuby_logger.info(f"✅ [Welcome] DM envoyé avec succès à {member.name}")
|
||||
# On combine le texte et le GIF dans un SEUL envoi pour réduire les requêtes API (limite de débit)
|
||||
gif_url = "https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExNXV1NW02NTk0bGF2ZHcyMGFna2F6amRrbGpobGpsMHowOW5xa2E5eCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/ZtFuW4rsUbfrRzPauJ/giphy.gif"
|
||||
await member.send(f"{formatted_message}\n\n{gif_url}")
|
||||
kuby_logger.info(f"✅ [Welcome] DM envoyé avec succès à {member.name} (envoi groupé)")
|
||||
except discord.Forbidden:
|
||||
kuby_logger.warning(f"🚫 [Welcome] Impossible d'envoyer le DM à {member.name} (DMs fermés)")
|
||||
except discord.HTTPException as e:
|
||||
if e.code == 40003: # Rate limited (Opening DMs too fast)
|
||||
kuby_logger.warning(f"⏳ [Welcome] Limite de débit Discord atteinte pour les DMs : {member.name} n'a pas reçu son message.")
|
||||
else:
|
||||
kuby_logger.error(f"❌ [Welcome] Erreur HTTP lors de l'envoi du DM à {member.name}: {e}")
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"❌ [Welcome] Erreur lors de l'envoi du DM à {member.name}: {e}", exc_info=True)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,180 +1,180 @@
|
|||
[
|
||||
{
|
||||
"date": "2026-03-14T14:26:12.694595+00:00",
|
||||
"date": "2026-03-31T20:07:49.786458+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:25:42.467679+00:00",
|
||||
"date": "2026-03-31T20:06:47.718241+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:25:11.992208+00:00",
|
||||
"date": "2026-03-31T20:06:07.381254+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:24:42.190744+00:00",
|
||||
"date": "2026-03-31T20:00:43.918120+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:24:12.614886+00:00",
|
||||
"date": "2026-03-29T20:16:08.626593+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:23:42.012764+00:00",
|
||||
"date": "2026-03-29T19:16:08.300074+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:23:12.416066+00:00",
|
||||
"date": "2026-03-29T18:16:08.376405+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:22:42.200744+00:00",
|
||||
"date": "2026-03-29T17:16:08.514497+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:22:12.128982+00:00",
|
||||
"date": "2026-03-29T17:15:42.635599+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:21:41.879828+00:00",
|
||||
"date": "2026-03-29T17:15:41.574258+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:21:25.894956+00:00",
|
||||
"date": "2026-03-29T14:18:49.697634+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:20:56.179577+00:00",
|
||||
"date": "2026-03-29T14:16:08.163385+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:20:25.382325+00:00",
|
||||
"date": "2026-03-29T14:09:18.074641+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:19:55.416432+00:00",
|
||||
"date": "2026-03-29T13:56:24.990061+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:19:25.281242+00:00",
|
||||
"date": "2026-03-29T13:54:43.766970+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:18:55.315861+00:00",
|
||||
"date": "2026-03-29T13:48:39.075696+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:18:25.672058+00:00",
|
||||
"date": "2026-03-29T13:48:08.960324+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:17:55.409042+00:00",
|
||||
"date": "2026-03-29T13:47:39.191350+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:17:25.447376+00:00",
|
||||
"date": "2026-03-29T13:47:09.059722+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
},
|
||||
{
|
||||
"date": "2026-03-14T14:16:55.368379+00:00",
|
||||
"date": "2026-03-29T13:46:39.263054+00:00",
|
||||
"trigger": "auto",
|
||||
"serversCount": 1,
|
||||
"membersCount": 13,
|
||||
"membersCount": 12,
|
||||
"guildName": "Omega Kube Bêta Test",
|
||||
"errors": [],
|
||||
"success": true
|
||||
|
|
|
|||
|
|
@ -1,100 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-19T14:50:31.191194",
|
||||
"event_type": "member_join",
|
||||
"member_id": 318312854816161792,
|
||||
"member_name": "DraftBot#0535",
|
||||
"member_discriminator": "0535",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/318312854816161792/f1d4dc93441273f3f8985a07e0bad164.png?size=1024"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T14:51:48.780957",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 828239898975666216,
|
||||
"member_name": "docteur_w.d_axolotl",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/828239898975666216/1835a7eaede10e9dbb78649beeed070c.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-05-09T18:36:32.808000+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T14:58:16.673562",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 318312854816161792,
|
||||
"member_name": "DraftBot#0535",
|
||||
"member_discriminator": "0535",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/318312854816161792/f1d4dc93441273f3f8985a07e0bad164.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1403041729330024508
|
||||
],
|
||||
"role_names": [
|
||||
"🗝️"
|
||||
],
|
||||
"permissions": [
|
||||
8
|
||||
]
|
||||
},
|
||||
"joined_at": "2025-08-19T12:50:31.007000+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T14:59:06.458094",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 353942721997832195,
|
||||
"member_name": "mg_studios_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/353942721997832195/99c6b7514ce56e19cf87b2c8f0d41316.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1396130252144508939,
|
||||
1369669999366770724,
|
||||
1369669999366770726
|
||||
],
|
||||
"role_names": [
|
||||
"mg_studios_",
|
||||
"👔 | Co-Directeur",
|
||||
"🔑"
|
||||
],
|
||||
"permissions": [
|
||||
0,
|
||||
0,
|
||||
8
|
||||
]
|
||||
},
|
||||
"joined_at": "2025-05-07T13:41:48.145000+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T14:59:19.218122",
|
||||
"event_type": "member_join",
|
||||
"member_id": 353942721997832195,
|
||||
"member_name": "mg_studios_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/353942721997832195/99c6b7514ce56e19cf87b2c8f0d41316.png?size=1024"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T21:41:25.723957",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1407448905817391215,
|
||||
"member_name": "test_33878",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T23:48:12.347482",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1407448905817391215,
|
||||
"member_name": "test_33878",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-08-19T19:41:25.391607+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-20T00:40:57.820048",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1407448905817391215,
|
||||
"member_name": "test_33878",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-20T00:42:00.543535",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1407448905817391215,
|
||||
"member_name": "test_33878",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-08-19T22:40:57.711576+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-20T00:47:10.265057",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1407448905817391215,
|
||||
"member_name": "test_33878",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-20T00:47:23.923297",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1407448905817391215,
|
||||
"member_name": "test_33878",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-08-19T22:47:10.020304+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-20T12:24:08.056140",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1407670411164127242,
|
||||
"member_name": "test_109375",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-08-20T10:21:05.730620+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-20T12:27:27.999521",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1407670411164127242,
|
||||
"member_name": "test_109375",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
}
|
||||
]
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-22T19:06:00.143653",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 872192738920108074,
|
||||
"member_name": "titis_zfr_7007",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/872192738920108074/986a18e279578123ec855f63defcc23f.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1369769836028231730
|
||||
],
|
||||
"role_names": [
|
||||
"⚒️ | Bêta Testeurs"
|
||||
],
|
||||
"permissions": [
|
||||
1032
|
||||
]
|
||||
},
|
||||
"joined_at": "2025-07-18T21:59:11.510000+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-12-30T01:03:48.950150",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:04:52.974501",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1013376581458210986,
|
||||
"member_name": "kayrixtv",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1013376581458210986/42d93e13065339ae40c50bcbf7a7b667.png?size=1024"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:05:11.496294",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-12-30T00:03:48.810667+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:05:38.027616",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:06:16.615009",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-12-30T00:05:37.900874+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:06:36.640980",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:09:36.950883",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-12-30T00:06:36.510813+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:13:30.386228",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:13:47.629282",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-12-30T00:13:30.252167+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:15:07.364595",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-01T22:00:26.255907",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1456390746167967932,
|
||||
"member_name": "juibu_66388",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
}
|
||||
]
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-03T21:25:17.730927",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1456390746167967932,
|
||||
"member_name": "juibu_66388",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1369669999366770721
|
||||
],
|
||||
"role_names": [
|
||||
"Faux banquier"
|
||||
],
|
||||
"permissions": [
|
||||
8192
|
||||
]
|
||||
},
|
||||
"joined_at": "2026-01-01T21:00:26.074000+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-03T21:25:28.894683",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1456390746167967932,
|
||||
"member_name": "juibu_66388",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-03T21:49:33.975462",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1456390746167967932,
|
||||
"member_name": "juibu_66388",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1369669999366770721
|
||||
],
|
||||
"role_names": [
|
||||
"Faux banquier"
|
||||
],
|
||||
"permissions": [
|
||||
8192
|
||||
]
|
||||
},
|
||||
"joined_at": "2026-01-03T20:25:28.737000+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-03T21:49:55.375389",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1456390746167967932,
|
||||
"member_name": "juibu_66388",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
}
|
||||
]
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-10T16:19:17.701722",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1459567012031234198,
|
||||
"member_name": "fequjifenq_85720",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
}
|
||||
]
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-24T15:13:01.488356",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1038035891450556507,
|
||||
"member_name": "celness",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1038035891450556507/e57596b7be5db3a5f3baf75f5fd4720b.png?size=1024"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-02-08T11:49:12.200722",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1470008249322438678,
|
||||
"member_name": "truc_19275",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-08T12:38:12.823655",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1470008249322438678,
|
||||
"member_name": "truc_19275",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2026-02-08T10:49:12.106083+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-15T17:03:39.778010",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405929928641351842,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "test",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:04:15.541259",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405930092764336172,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "bl",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:04:26.128394",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405930138096635996,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 353942721997832195,
|
||||
"author_name": "mg_studios_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396130252144508939,
|
||||
1369669999366770724,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "fe",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:04:26.581875",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405930139358859386,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 353942721997832195,
|
||||
"author_name": "mg_studios_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396130252144508939,
|
||||
1369669999366770724,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "fe",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:04:27.110643",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405930141888282686,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 353942721997832195,
|
||||
"author_name": "mg_studios_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396130252144508939,
|
||||
1369669999366770724,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "fe",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:04:27.420456",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405930143549100153,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 353942721997832195,
|
||||
"author_name": "mg_studios_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396130252144508939,
|
||||
1369669999366770724,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "fef",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:04:27.895168",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405930145155514388,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 353942721997832195,
|
||||
"author_name": "mg_studios_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396130252144508939,
|
||||
1369669999366770724,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "ef",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:04:55.151271",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405930245793517729,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "carré pour ça",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:07:29.586201",
|
||||
"event_type": "edited",
|
||||
"message_id": 1405930871201988708,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 353942721997832195,
|
||||
"author_name": "mg_studios_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396130252144508939,
|
||||
1369669999366770724,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "il est pas kick du serv juste il peux plus écrire",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "il est pas kick du serv juste il peux plus écrire",
|
||||
"after_content": "il est pas kick du serv juste il peut plus écrire"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:08:24.314935",
|
||||
"event_type": "edited",
|
||||
"message_id": 1405931135254528171,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "[fae](https://cdn.discordapp.com/emojis/1377581019649151077.webp?size=48&name=fae)",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "[fae](https://cdn.discordapp.com/emojis/1377581019649151077.webp?size=48&name=fae)",
|
||||
"after_content": "[fae](https://cdn.discordapp.com/emojis/1377581019649151077.webp?size=48&name=fae)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:51:19.548967",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405941938007314614,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "k",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:51:20.415679",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405941942227046552,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "k",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-15T17:52:26.716628",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1405942220049219737,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "<@353942721997832195> il me faut qqn de pas op pour tester le spam",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-16T17:11:20.495657",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1406294262861140100,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "ou @here",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-16T17:22:10.841132",
|
||||
"event_type": "edited",
|
||||
"message_id": 1406296949967290461,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "je dois yalelr en plus",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "je dois yalelr en plus",
|
||||
"after_content": "je dois y aller en plus"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-17T13:14:10.888477",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1406596967433244725,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "h",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-17T13:14:11.627298",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1406596971757568060,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "h",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-17T13:14:11.996001",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1406596972982308935,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "h",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-17T13:14:12.397997",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1406596974714818569,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "h",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-17T13:15:46.771221",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1406597370661310564,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 1324439906046574693,
|
||||
"author_name": "_radio_demon77_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1403041729330024508
|
||||
],
|
||||
"content": "h",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,303 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-19T14:31:07.894788",
|
||||
"event_type": "edited",
|
||||
"message_id": 1407341109302267986,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://music.youtube.com/watch?v=ZjHjIvlokkg&list=RDAMVMZjHjIvlokkg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "https://music.youtube.com/watch?v=ZjHjIvlokkg&list=RDAMVMZjHjIvlokkg",
|
||||
"after_content": "https://music.youtube.com/watch?v=ZjHjIvlokkg&list=RDAMVMZjHjIvlokkg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T14:31:07.908824",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1407341109302267986,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://music.youtube.com/watch?v=ZjHjIvlokkg&list=RDAMVMZjHjIvlokkg",
|
||||
"attachments": [],
|
||||
"embeds": [
|
||||
{
|
||||
"thumbnail": {
|
||||
"width": 1280,
|
||||
"url": "https://i.ytimg.com/vi/ZjHjIvlokkg/maxresdefault.jpg",
|
||||
"proxy_url": "https://images-ext-1.discordapp.net/external/rqEye0Kbh537345_yiwGFQmGsNDfxFg10JHdnuiizrI/https/i.ytimg.com/vi/ZjHjIvlokkg/maxresdefault.jpg",
|
||||
"placeholder_version": 1,
|
||||
"placeholder": "BQgGDIIIplqHd3h4iIUIfHXzJw==",
|
||||
"height": 720,
|
||||
"flags": 0,
|
||||
"content_type": "image/jpeg"
|
||||
},
|
||||
"video": {
|
||||
"width": 1280,
|
||||
"url": "https://www.youtube.com/embed/ZjHjIvlokkg",
|
||||
"placeholder_version": 1,
|
||||
"placeholder": "BQgGDIIIplqHd3h4iIUIfHXzJw==",
|
||||
"height": 720,
|
||||
"flags": 0
|
||||
},
|
||||
"provider": {
|
||||
"url": "https://www.youtube.com",
|
||||
"name": "YouTube"
|
||||
},
|
||||
"author": {
|
||||
"url": "https://www.youtube.com/channel/UCQgovvTTLPxAazVQE6X2ivQ",
|
||||
"name": "Fredz"
|
||||
},
|
||||
"color": 16711680,
|
||||
"type": "video",
|
||||
"description": "Les belles filles - Fredz ft. Leslie Medina\nlive au Badaboum à PARIS le 16/12/22\nJ'espère que ça vous plaira ! Merci pour tout\n\nRéalisation: Noémie Fray (@nomzoa)\nÉtalonnage: Stéphane Martins (@smartins_dop)\n\nRetrouvez Fredz sur :\nInstagram : https://www.instagram.com/fredz_musicc/\nTik Tok : https://vm.tiktok.com/ZSv9b5US/\nFacebook : http...",
|
||||
"url": "https://www.youtube.com/watch?v=ZjHjIvlokkg",
|
||||
"title": "FREDZ feat. Leslie Medina - Les belles filles (Live à Paris)"
|
||||
}
|
||||
],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T14:31:25.362973",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1407341171679826030,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://music.youtube.com/watch?v=ZjHjIvlokkg&list=RDAMVMZjHjIvlokkg",
|
||||
"attachments": [],
|
||||
"embeds": [
|
||||
{
|
||||
"thumbnail": {
|
||||
"width": 1280,
|
||||
"url": "https://i.ytimg.com/vi/ZjHjIvlokkg/maxresdefault.jpg",
|
||||
"proxy_url": "https://images-ext-1.discordapp.net/external/rqEye0Kbh537345_yiwGFQmGsNDfxFg10JHdnuiizrI/https/i.ytimg.com/vi/ZjHjIvlokkg/maxresdefault.jpg",
|
||||
"placeholder_version": 1,
|
||||
"placeholder": "BQgGDIIIplqHd3h4iIUIfHXzJw==",
|
||||
"height": 720,
|
||||
"flags": 0,
|
||||
"content_type": "image/jpeg"
|
||||
},
|
||||
"video": {
|
||||
"width": 1280,
|
||||
"url": "https://www.youtube.com/embed/ZjHjIvlokkg",
|
||||
"placeholder_version": 1,
|
||||
"placeholder": "BQgGDIIIplqHd3h4iIUIfHXzJw==",
|
||||
"height": 720,
|
||||
"flags": 0
|
||||
},
|
||||
"provider": {
|
||||
"url": "https://www.youtube.com",
|
||||
"name": "YouTube"
|
||||
},
|
||||
"author": {
|
||||
"url": "https://www.youtube.com/channel/UCQgovvTTLPxAazVQE6X2ivQ",
|
||||
"name": "Fredz"
|
||||
},
|
||||
"color": 16711680,
|
||||
"type": "video",
|
||||
"description": "Les belles filles - Fredz ft. Leslie Medina\nlive au Badaboum à PARIS le 16/12/22\nJ'espère que ça vous plaira ! Merci pour tout\n\nRéalisation: Noémie Fray (@nomzoa)\nÉtalonnage: Stéphane Martins (@smartins_dop)\n\nRetrouvez Fredz sur :\nInstagram : https://www.instagram.com/fredz_musicc/\nTik Tok : https://vm.tiktok.com/ZSv9b5US/\nFacebook : http...",
|
||||
"url": "https://www.youtube.com/watch?v=ZjHjIvlokkg",
|
||||
"title": "FREDZ feat. Leslie Medina - Les belles filles (Live à Paris)"
|
||||
}
|
||||
],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T14:31:30.378149",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1407341203208278036,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://music.youtube.com/watch?v=ZjHjIvlokkg&list=RDAMVMZjHjIvlokkg",
|
||||
"attachments": [],
|
||||
"embeds": [
|
||||
{
|
||||
"thumbnail": {
|
||||
"width": 1280,
|
||||
"url": "https://i.ytimg.com/vi/ZjHjIvlokkg/maxresdefault.jpg",
|
||||
"proxy_url": "https://images-ext-1.discordapp.net/external/rqEye0Kbh537345_yiwGFQmGsNDfxFg10JHdnuiizrI/https/i.ytimg.com/vi/ZjHjIvlokkg/maxresdefault.jpg",
|
||||
"placeholder_version": 1,
|
||||
"placeholder": "BQgGDIIIplqHd3h4iIUIfHXzJw==",
|
||||
"height": 720,
|
||||
"flags": 0,
|
||||
"content_type": "image/jpeg"
|
||||
},
|
||||
"video": {
|
||||
"width": 1280,
|
||||
"url": "https://www.youtube.com/embed/ZjHjIvlokkg",
|
||||
"placeholder_version": 1,
|
||||
"placeholder": "BQgGDIIIplqHd3h4iIUIfHXzJw==",
|
||||
"height": 720,
|
||||
"flags": 0
|
||||
},
|
||||
"provider": {
|
||||
"url": "https://www.youtube.com",
|
||||
"name": "YouTube"
|
||||
},
|
||||
"author": {
|
||||
"url": "https://www.youtube.com/channel/UCQgovvTTLPxAazVQE6X2ivQ",
|
||||
"name": "Fredz"
|
||||
},
|
||||
"color": 16711680,
|
||||
"type": "video",
|
||||
"description": "Les belles filles - Fredz ft. Leslie Medina\nlive au Badaboum à PARIS le 16/12/22\nJ'espère que ça vous plaira ! Merci pour tout\n\nRéalisation: Noémie Fray (@nomzoa)\nÉtalonnage: Stéphane Martins (@smartins_dop)\n\nRetrouvez Fredz sur :\nInstagram : https://www.instagram.com/fredz_musicc/\nTik Tok : https://vm.tiktok.com/ZSv9b5US/\nFacebook : http...",
|
||||
"url": "https://www.youtube.com/watch?v=ZjHjIvlokkg",
|
||||
"title": "FREDZ feat. Leslie Medina - Les belles filles (Live à Paris)"
|
||||
}
|
||||
],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T20:00:33.051055",
|
||||
"event_type": "edited",
|
||||
"message_id": 1407423989206356008,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770723,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "Viens ici mo cobay préférer",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "Viens ici mo cobay préférer",
|
||||
"after_content": "Viens ici mon cobay préférer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T20:09:09.967269",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1407426178486374564,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770723,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "@everyone qui veut faire le cobay avec moi",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:19:00.115805",
|
||||
"event_type": "edited",
|
||||
"message_id": 1407458853196529705,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 353942721997832195,
|
||||
"author_name": "mg_studios_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396130252144508939,
|
||||
1369669999366770724
|
||||
],
|
||||
"content": "https://tenor.com/view/14th-doctor-doctor-who-david-tennant-wild-blue-yonder-rage-gif-12474509552290072827",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "https://tenor.com/view/14th-doctor-doctor-who-david-tennant-wild-blue-yonder-rage-gif-12474509552290072827",
|
||||
"after_content": "https://tenor.com/view/14th-doctor-doctor-who-david-tennant-wild-blue-yonder-rage-gif-12474509552290072827"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:19:14.095772",
|
||||
"event_type": "edited",
|
||||
"message_id": 1407458911929503875,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 353942721997832195,
|
||||
"author_name": "mg_studios_",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396130252144508939,
|
||||
1369669999366770724
|
||||
],
|
||||
"content": "https://tenor.com/view/dr-who-doctor-who-david-tennant-sad-annoyed-gif-4879151",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "https://tenor.com/view/dr-who-doctor-who-david-tennant-sad-annoyed-gif-4879151",
|
||||
"after_content": "https://tenor.com/view/dr-who-doctor-who-david-tennant-sad-annoyed-gif-4879151"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:24:31.079905",
|
||||
"event_type": "edited",
|
||||
"message_id": 1407460213409452235,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770723,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "OUi",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "OUi",
|
||||
"after_content": "Oui"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:50:46.776609",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1407466849981038592,
|
||||
"channel_id": 1369669999677145101,
|
||||
"channel_name": "┇🔧・salon-de-tests",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770723,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://www.perplexity.ai",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-20T00:42:00.965568",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1407494580709883994,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 1407448905817391215,
|
||||
"author_name": "test_33878",
|
||||
"author_roles": [
|
||||
1369669999345537145
|
||||
],
|
||||
"content": "",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-20T00:47:24.265760",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1407496141343559791,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 1407448905817391215,
|
||||
"author_name": "test_33878",
|
||||
"author_roles": [
|
||||
1369669999345537145
|
||||
],
|
||||
"content": "",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-23T20:54:00.125408",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1408887012731129877,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770723,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "G",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-23T20:54:00.775382",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1408887015570804787,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1396112611292090368,
|
||||
1369669999366770723,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "G",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,705 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:01.432517",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559052359631046,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:01.860802",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559053878235177,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:02.287326",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559055304167619,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:02.656882",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559057019633797,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:13.025829",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559100954837196,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:13.582926",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559103081353248,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:13.780030",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559104306217063,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:14.165698",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559105845395639,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:14.612894",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559107791556762,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:14.798228",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559108798185593,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:15.528887",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559111071629509,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:16.499969",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559109825790114,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g\ng",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:17.142340",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559112875049105,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:18.196550",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559117165826120,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:19.152467",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559114519482421,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:21.275434",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559116280828005,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T14:52:21.407804",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455559118264729792,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:00:35.602064",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455561207493955786,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:00:35.638746",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455561208953442438,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:00:36.363545",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455561211679604820,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:00:36.826764",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455561214045454437,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:00:37.001960",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455561215060480071,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:00:37.594651",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455561215970644102,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g\ng",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:00:37.727681",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455561217610612777,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:00:40.753645",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455561219493728380,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:04:21.499784",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455562138142642443,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:04:23.080095",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455562136209199266,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:04:24.026167",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455562134749581559,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:04:25.951553",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455562133088637020,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:04:27.294471",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455562131473961092,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:04:28.245179",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455562129750102081,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:04:29.191484",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455562128076312689,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:04:30.278917",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455562127220801537,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:36:52.387291",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455570313935847598,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:37:05.116440",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455570329702367242,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:42:16.699177",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455571624299462862,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://www.ecoledirecte.com/login?cameFrom=%2FE%2F5835%2FEmploiDuTemps",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T15:42:24.379846",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1455571718037962854,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://www.ecoledirecte.com/login?cameFrom=%2FE%2F5835%2FEmploiDuTemps",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,284 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-01T21:05:28.276062",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456377795595730994,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:12:06.156108",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456379476211531970,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:12:06.462625",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456379478606348421,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:12:12.104726",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456379484264595700,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:35:44.759055",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456385391564296297,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:35:51.064634",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456385392482844682,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:40:18.016792",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456386513947463855,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:40:21.147093",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456386515096703242,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:40:24.322926",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456386516439007288,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:43:53.352930",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456387431472435231,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:44:15.896248",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456387423477956670,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:44:32.743792",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456387525080776788,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://github.com/Omega-Kube/Kuby",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:44:43.533530",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456387651883237437,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://github.com/Omega-Kube/Kuby",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:51:23.069501",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456389356301582459,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "[DEBUG] anti_link_enabled: True, settings: {'anti_spam': True, 'anti_perm': True, 'anti_salon': True, 'anti_raid': True, 'anti_nuke': True, 'anti_link': True, 'anti_mention': True, 'verification_enabled': True, 'spam_threshold': 5, 'raid_threshold': 3, 'nuke_threshold': 3, 'log_channel_id': 1396088860412346428, 'lockdown_enabled': False, 'auto_ban': True, 'webhook_protection': True, 'mass_delete_protection': True, 'invite_filter': True, 'file_scanning': True, 'ai_moderation': True, 'channel_block_enabled': False, 'server_logs': True, 'anti_channel_delete': True, 'anti_role_create': True}",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T22:01:31.237385",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456391913694433361,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 1456390746167967932,
|
||||
"author_name": "juibu_66388",
|
||||
"author_roles": [
|
||||
1369669999345537145
|
||||
],
|
||||
"content": "https://github.com/Omega-Kube/Kuby",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-02T13:30:27.725564",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456625676537823243,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-02T13:30:27.754495",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456625676537823243,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-02T13:30:37.215876",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456625680153444448,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-10T00:57:48.563188",
|
||||
"event_type": "edited",
|
||||
"message_id": 1459335326660300935,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369769836028231730,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "Non c'est gentil t'inqiutes",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "Non c'est gentil t'inqiutes",
|
||||
"after_content": "Non c'est gentil t’inquiètes"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-24T15:05:23.725825",
|
||||
"event_type": "edited",
|
||||
"message_id": 1464622068598575155,
|
||||
"channel_id": 1464621977376522291,
|
||||
"channel_name": "gameurpro12-écrit",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1366461904976871565,
|
||||
1453708383235473459,
|
||||
1454035592391299234,
|
||||
1454034686979346495,
|
||||
1453708344526246071,
|
||||
1454034988080038040,
|
||||
1366876636259024946
|
||||
],
|
||||
"content": "Les tickets prendront cette forme",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "Les tickets prendront cette forme",
|
||||
"after_content": "Les tickets whitelist prendront cette forme"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:05:52.316927",
|
||||
"event_type": "edited",
|
||||
"message_id": 1464622206439919658,
|
||||
"channel_id": 1460048825665454344,
|
||||
"channel_name": "🔢・nombres-infinis",
|
||||
"author_id": 1355564506754973767,
|
||||
"author_name": "alto1500",
|
||||
"author_roles": [
|
||||
1366461904976871565,
|
||||
1453708383235473459,
|
||||
1454042474141192316,
|
||||
1453708358417912075
|
||||
],
|
||||
"content": "24",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "24",
|
||||
"after_content": "240"
|
||||
}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:23:49.868209",
|
||||
"event_type": "edited",
|
||||
"message_id": 1464626575415705761,
|
||||
"channel_id": 1453386193311105188,
|
||||
"channel_name": "📡・annonces",
|
||||
"author_id": 983747660265693258,
|
||||
"author_name": "mr_reiko_",
|
||||
"author_roles": [
|
||||
1366461904976871565,
|
||||
1453708383235473459,
|
||||
1454035592391299234,
|
||||
1454033803998920769,
|
||||
1454034686979346495,
|
||||
1464424459393040667,
|
||||
1454034988080038040,
|
||||
1453395626128707656,
|
||||
1369003041927200858,
|
||||
1366876636259024946
|
||||
],
|
||||
"content": "> # **__Annonce – Ouverture officielle des Whitelist__** <:emoji_1:1458776441041850430> \n> \n> **Nous vous informons que les Whitelist sont officiellement ouvertes.** <a:56125loading:1413178655038902482> \n> \n> - Pour effectuer votre WL,** il vous suffit de créer un ticket dans le salon** <#1450002116537090149> / <#1463081283679817822> prévu à cet effet.\n> Une fois le ticket ouvert, **un membre du staff prendra votre demande en charge,** vous expliquera l’ensemble de la procédure et **vous accompagnera tout au long du processus.** \n> \n> - __**Rôles disponibles en semi FA**__\n> **Les rôles suivants sont actuellement disponibles en semi FA pour les joueurs WL ecrite effectuée :**\n> \n> <@&1453708467700502561> \n> \n> <@&1453708401933553849> \n> \n> <@&1453708560511926273> \n> \n> <@&1453708517302337695> \n> \n> <@&1453708475132674070> \n> \n> <@&1453708562474860617> \n> \n> - **Merci de respecter les consignes et de faire preuve de sérieux lors de votre démarche.**\n> **Nous restons à votre disposition via les tickets pour toute question.** <:50773approvedids:1464433520301572096> £\n> \n> **Cordialement <@&1458084692803981354> / <@&1453708378336399392> /** <t:1769264525:S> \n> \n> ||@everyone ||",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {
|
||||
"before_content": "> # **__Annonce – Ouverture officielle des Whitelist__** <:emoji_1:1458776441041850430> \n> \n> **Nous vous informons que les Whitelist sont officiellement ouvertes.** <a:56125loading:1413178655038902482> \n> \n> - Pour effectuer votre WL,** il vous suffit de créer un ticket dans le salon** <#1450002116537090149> / <#1463081283679817822> prévu à cet effet.\n> Une fois le ticket ouvert, **un membre du staff prendra votre demande en charge,** vous expliquera l’ensemble de la procédure et **vous accompagnera tout au long du processus.** \n> \n> - __**Rôles disponibles en semi FA**__\n> **Les rôles suivants sont actuellement disponibles en semi FA pour les joueurs WL ecrite effectuée :**\n> \n> <@&1453708467700502561> \n> \n> <@&1453708401933553849> \n> \n> <@&1453708560511926273> \n> \n> <@&1453708517302337695> \n> \n> <@&1453708475132674070> \n> \n> <@&1453708562474860617> \n> \n> - **Merci de respecter les consignes et de faire preuve de sérieux lors de votre démarche.**\n> **Nous restons à votre disposition via les tickets pour toute question.** <:50773approvedids:1464433520301572096> £\n> \n> **Cordialement <@&1458084692803981354> / <@&1453708378336399392> /** <t:1769264525:S> \n> \n> ||@everyone ||",
|
||||
"after_content": "> # **__Annonce – Ouverture officielle des Whitelist__** <:emoji_1:1458776441041850430> \n> \n> **Nous vous informons que les Whitelist sont officiellement ouvertes.** <a:56125loading:1413178655038902482> \n> \n> - Pour effectuer votre WL,** il vous suffit de créer un ticket dans le salon** <#1450002116537090149> / <#1463081283679817822> prévu à cet effet.\n> Une fois le ticket ouvert, **un membre du staff prendra votre demande en charge,** vous expliquera l’ensemble de la procédure et **vous accompagnera tout au long du processus.** \n> \n> - __**Rôles disponibles en semi FA**__\n> **Les rôles suivants sont actuellement disponibles en semi FA pour les joueurs WL ecrite effectuée :**\n> \n> <@&1453708467700502561> \n> \n> <@&1453708401933553849> \n> \n> <@&1453708560511926273> \n> \n> <@&1453708517302337695> \n> \n> <@&1453708475132674070> \n> \n> <@&1453708562474860617> \n> \n> - **Merci de respecter les consignes et de faire preuve de sérieux lors de votre démarche.**\n> **Nous restons à votre disposition via les tickets pour toute question.** <:50773approvedids:1464433520301572096> \n> \n> **Cordialement <@&1458084692803981354> / <@&1453708378336399392> /** <t:1769264525:S> \n> \n> ||@everyone ||"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-02-27T16:51:53.636507",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1476970101038125148,
|
||||
"channel_id": 1369669999677145103,
|
||||
"channel_name": "╰📂・rapports",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369769836028231730,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "1369669999677145103",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-27T16:52:08.494696",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1476970163726188639,
|
||||
"channel_id": 1369669999677145103,
|
||||
"channel_name": "╰📂・rapports",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369769836028231730,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "<@&1369669999345537154>",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-19T20:20:09.529504",
|
||||
"event_type": "joined",
|
||||
"member_id": 353942721997832195,
|
||||
"member_name": "mg_studios_",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T20:20:10.360577",
|
||||
"event_type": "joined",
|
||||
"member_id": 971446412690722826,
|
||||
"member_name": "gameurpro12",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T20:20:16.614354",
|
||||
"event_type": "joined",
|
||||
"member_id": 872192738920108074,
|
||||
"member_name": "titis_zfr_7007",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T20:53:27.763722",
|
||||
"event_type": "left",
|
||||
"member_id": 872192738920108074,
|
||||
"member_name": "titis_zfr_7007",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T21:22:53.512388",
|
||||
"event_type": "joined",
|
||||
"member_id": 768915179995004988,
|
||||
"member_name": "fantom_arn",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T21:23:56.602997",
|
||||
"event_type": "left",
|
||||
"member_id": 768915179995004988,
|
||||
"member_name": "fantom_arn",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T21:39:13.888020",
|
||||
"event_type": "joined",
|
||||
"member_id": 768915179995004988,
|
||||
"member_name": "fantom_arn",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T21:40:19.180475",
|
||||
"event_type": "left",
|
||||
"member_id": 768915179995004988,
|
||||
"member_name": "fantom_arn",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T21:44:18.819339",
|
||||
"event_type": "joined",
|
||||
"member_id": 1108087282692522105,
|
||||
"member_name": "tricks_zz",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T21:54:19.095370",
|
||||
"event_type": "joined",
|
||||
"member_id": 1069386396764221450,
|
||||
"member_name": "matlo13",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:12:16.991281",
|
||||
"event_type": "left",
|
||||
"member_id": 1108087282692522105,
|
||||
"member_name": "tricks_zz",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:14:16.428151",
|
||||
"event_type": "joined",
|
||||
"member_id": 768915179995004988,
|
||||
"member_name": "fantom_arn",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:21:48.361355",
|
||||
"event_type": "left",
|
||||
"member_id": 971446412690722826,
|
||||
"member_name": "gameurpro12",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:21:50.542994",
|
||||
"event_type": "left",
|
||||
"member_id": 353942721997832195,
|
||||
"member_name": "mg_studios_",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:23:14.826669",
|
||||
"event_type": "left",
|
||||
"member_id": 768915179995004988,
|
||||
"member_name": "fantom_arn",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-19T22:23:15.993478",
|
||||
"event_type": "left",
|
||||
"member_id": 1069386396764221450,
|
||||
"member_name": "matlo13",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-20T12:28:09.674559",
|
||||
"event_type": "joined",
|
||||
"member_id": 1407670411164127242,
|
||||
"member_name": "test_109375",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-20T12:28:17.126525",
|
||||
"event_type": "left",
|
||||
"member_id": 1407670411164127242,
|
||||
"member_name": "test_109375",
|
||||
"channel_id": 1369669999677145105,
|
||||
"channel_name": "╭🎤・Général",
|
||||
"channel_type": "voice"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-24T15:04:34.353302",
|
||||
"event_type": "left",
|
||||
"member_id": 1453734314088075306,
|
||||
"member_name": "patalhuile",
|
||||
"channel_id": 1407722372588376084,
|
||||
"channel_name": "〚🌟〛𝐊𝐀𝐘𝐑𝐈𝐗",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:06:06.060691",
|
||||
"event_type": "joined",
|
||||
"member_id": 971446412690722826,
|
||||
"member_name": "gameurpro12",
|
||||
"channel_id": 1457073413616046080,
|
||||
"channel_name": "👑・Bureau Fondation",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:06:12.905500",
|
||||
"event_type": "left",
|
||||
"member_id": 971446412690722826,
|
||||
"member_name": "gameurpro12",
|
||||
"channel_id": 1457073413616046080,
|
||||
"channel_name": "👑・Bureau Fondation",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:12:23.224137",
|
||||
"event_type": "joined",
|
||||
"member_id": 983747660265693258,
|
||||
"member_name": "mr_reiko_",
|
||||
"channel_id": 1453397135234957442,
|
||||
"channel_name": "📓・Bureaux 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:12:25.430175",
|
||||
"event_type": "left",
|
||||
"member_id": 983747660265693258,
|
||||
"member_name": "mr_reiko_",
|
||||
"channel_id": 1453397135234957442,
|
||||
"channel_name": "📓・Bureaux 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:12:30.909163",
|
||||
"event_type": "left",
|
||||
"member_id": 1263573205268828231,
|
||||
"member_name": "arthena_931",
|
||||
"channel_id": 1457073413616046080,
|
||||
"channel_name": "👑・Bureau Fondation",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:13:02.024297",
|
||||
"event_type": "left",
|
||||
"member_id": 353942721997832195,
|
||||
"member_name": "mg_studios_",
|
||||
"channel_id": 1457073413616046080,
|
||||
"channel_name": "👑・Bureau Fondation",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:13:17.531634",
|
||||
"event_type": "joined",
|
||||
"member_id": 1263573205268828231,
|
||||
"member_name": "arthena_931",
|
||||
"channel_id": 1447649079952802055,
|
||||
"channel_name": "🔊・Publique 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:13:26.906602",
|
||||
"event_type": "left",
|
||||
"member_id": 1263573205268828231,
|
||||
"member_name": "arthena_931",
|
||||
"channel_id": 1447649079952802055,
|
||||
"channel_name": "🔊・Publique 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:15:50.817844",
|
||||
"event_type": "joined",
|
||||
"member_id": 1453734314088075306,
|
||||
"member_name": "patalhuile",
|
||||
"channel_id": 1407722372588376084,
|
||||
"channel_name": "〚🌟〛𝐊𝐀𝐘𝐑𝐈𝐗",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:18:40.775427",
|
||||
"event_type": "left",
|
||||
"member_id": 945580436732641320,
|
||||
"member_name": "melhoan",
|
||||
"channel_id": 1407722372588376084,
|
||||
"channel_name": "〚🌟〛𝐊𝐀𝐘𝐑𝐈𝐗",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:18:44.516024",
|
||||
"event_type": "joined",
|
||||
"member_id": 945580436732641320,
|
||||
"member_name": "melhoan",
|
||||
"channel_id": 1407722372588376084,
|
||||
"channel_name": "〚🌟〛𝐊𝐀𝐘𝐑𝐈𝐗",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:20:36.058676",
|
||||
"event_type": "left",
|
||||
"member_id": 1453734314088075306,
|
||||
"member_name": "patalhuile",
|
||||
"channel_id": 1407722372588376084,
|
||||
"channel_name": "〚🌟〛𝐊𝐀𝐘𝐑𝐈𝐗",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:27:14.017625",
|
||||
"event_type": "left",
|
||||
"member_id": 945580436732641320,
|
||||
"member_name": "melhoan",
|
||||
"channel_id": 1407722372588376084,
|
||||
"channel_name": "〚🌟〛𝐊𝐀𝐘𝐑𝐈𝐗",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:29:52.855600",
|
||||
"event_type": "joined",
|
||||
"member_id": 1263573205268828231,
|
||||
"member_name": "arthena_931",
|
||||
"channel_id": 1407780201462497522,
|
||||
"channel_name": "〚🔈〛𝐀𝐓𝐓𝐄𝐍𝐓𝐄 𝐌𝐎𝐎𝐕",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:31:33.895832",
|
||||
"event_type": "joined",
|
||||
"member_id": 1296914730669183066,
|
||||
"member_name": "iikileur_02378",
|
||||
"channel_id": 1447649079952802055,
|
||||
"channel_name": "🔊・Publique 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:31:44.051002",
|
||||
"event_type": "moved_from",
|
||||
"member_id": 534003230435442690,
|
||||
"member_name": "nixfix06",
|
||||
"channel_id": 1457073413616046080,
|
||||
"channel_name": "👑・Bureau Fondation",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:31:44.051366",
|
||||
"event_type": "moved_to",
|
||||
"member_id": 534003230435442690,
|
||||
"member_name": "nixfix06",
|
||||
"channel_id": 1447649079952802055,
|
||||
"channel_name": "🔊・Publique 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:33:48.580429",
|
||||
"event_type": "joined",
|
||||
"member_id": 1320118755090759711,
|
||||
"member_name": "jl_xixo",
|
||||
"channel_id": 1447649079952802055,
|
||||
"channel_name": "🔊・Publique 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:33:51.104140",
|
||||
"event_type": "joined",
|
||||
"member_id": 1389671060902777056,
|
||||
"member_name": "elite_v.2_70323",
|
||||
"channel_id": 1407780201462497522,
|
||||
"channel_name": "〚🔈〛𝐀𝐓𝐓𝐄𝐍𝐓𝐄 𝐌𝐎𝐎𝐕",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:35:01.627777",
|
||||
"event_type": "left",
|
||||
"member_id": 1389671060902777056,
|
||||
"member_name": "elite_v.2_70323",
|
||||
"channel_id": 1407780201462497522,
|
||||
"channel_name": "〚🔈〛𝐀𝐓𝐓𝐄𝐍𝐓𝐄 𝐌𝐎𝐎𝐕",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:35:02.783293",
|
||||
"event_type": "left",
|
||||
"member_id": 1296914730669183066,
|
||||
"member_name": "iikileur_02378",
|
||||
"channel_id": 1447649079952802055,
|
||||
"channel_name": "🔊・Publique 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:35:09.067327",
|
||||
"event_type": "left",
|
||||
"member_id": 1263573205268828231,
|
||||
"member_name": "arthena_931",
|
||||
"channel_id": 1407780201462497522,
|
||||
"channel_name": "〚🔈〛𝐀𝐓𝐓𝐄𝐍𝐓𝐄 𝐌𝐎𝐎𝐕",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:35:15.317831",
|
||||
"event_type": "moved_from",
|
||||
"member_id": 534003230435442690,
|
||||
"member_name": "nixfix06",
|
||||
"channel_id": 1447649079952802055,
|
||||
"channel_name": "🔊・Publique 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:35:15.318377",
|
||||
"event_type": "moved_to",
|
||||
"member_id": 534003230435442690,
|
||||
"member_name": "nixfix06",
|
||||
"channel_id": 1457073756764639355,
|
||||
"channel_name": "👔・Bureau Direction",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:35:20.522454",
|
||||
"event_type": "left",
|
||||
"member_id": 1320118755090759711,
|
||||
"member_name": "jl_xixo",
|
||||
"channel_id": 1447649079952802055,
|
||||
"channel_name": "🔊・Publique 1",
|
||||
"channel_type": "voice"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-24T15:37:06.015710",
|
||||
"event_type": "joined",
|
||||
"member_id": 1433834565042180149,
|
||||
"member_name": "alexandre07_08_13804",
|
||||
"channel_id": 1447649079952802055,
|
||||
"channel_name": "🔊・Publique 1",
|
||||
"channel_type": "voice"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-12-30T01:05:11.496294",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-12-30T00:03:48.810667+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:06:16.615009",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-12-30T00:05:37.900874+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:09:36.950883",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-12-30T00:06:36.510813+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-12-30T01:13:47.629282",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1003956683040624672,
|
||||
"member_name": "eva56_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/1003956683040624672/c364667c914a821cd24212d32f7762b8.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-12-30T00:13:30.252167+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-19T23:48:12.347482",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1407448905817391215,
|
||||
"member_name": "test_33878",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-08-19T19:41:25.391607+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-20T00:42:00.543535",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1407448905817391215,
|
||||
"member_name": "test_33878",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-08-19T22:40:57.711576+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2025-08-20T00:47:23.923297",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1407448905817391215,
|
||||
"member_name": "test_33878",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-08-19T22:47:10.020304+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-20T12:24:08.056140",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1407670411164127242,
|
||||
"member_name": "test_109375",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-08-20T10:21:05.730620+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-03T21:25:17.730927",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1456390746167967932,
|
||||
"member_name": "juibu_66388",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1369669999366770721
|
||||
],
|
||||
"role_names": [
|
||||
"Faux banquier"
|
||||
],
|
||||
"permissions": [
|
||||
8192
|
||||
]
|
||||
},
|
||||
"joined_at": "2026-01-01T21:00:26.074000+00:00"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-03T21:49:33.975462",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1456390746167967932,
|
||||
"member_name": "juibu_66388",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1369669999366770721
|
||||
],
|
||||
"role_names": [
|
||||
"Faux banquier"
|
||||
],
|
||||
"permissions": [
|
||||
8192
|
||||
]
|
||||
},
|
||||
"joined_at": "2026-01-03T20:25:28.737000+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-02-08T12:38:12.823655",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 1470008249322438678,
|
||||
"member_name": "truc_19275",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null,
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2026-02-08T10:49:12.106083+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-19T14:58:16.673562",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 318312854816161792,
|
||||
"member_name": "DraftBot#0535",
|
||||
"member_discriminator": "0535",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/318312854816161792/f1d4dc93441273f3f8985a07e0bad164.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1403041729330024508
|
||||
],
|
||||
"role_names": [
|
||||
"🗝️"
|
||||
],
|
||||
"permissions": [
|
||||
8
|
||||
]
|
||||
},
|
||||
"joined_at": "2025-08-19T12:50:31.007000+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-19T14:59:06.458094",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 353942721997832195,
|
||||
"member_name": "mg_studios_",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/353942721997832195/99c6b7514ce56e19cf87b2c8f0d41316.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1396130252144508939,
|
||||
1369669999366770724,
|
||||
1369669999366770726
|
||||
],
|
||||
"role_names": [
|
||||
"mg_studios_",
|
||||
"👔 | Co-Directeur",
|
||||
"🔑"
|
||||
],
|
||||
"permissions": [
|
||||
0,
|
||||
0,
|
||||
8
|
||||
]
|
||||
},
|
||||
"joined_at": "2025-05-07T13:41:48.145000+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-19T14:51:48.780957",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 828239898975666216,
|
||||
"member_name": "docteur_w.d_axolotl",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/828239898975666216/1835a7eaede10e9dbb78649beeed070c.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [],
|
||||
"role_names": [],
|
||||
"permissions": []
|
||||
},
|
||||
"joined_at": "2025-05-09T18:36:32.808000+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2025-08-22T19:06:00.143653",
|
||||
"event_type": "member_leave",
|
||||
"member_id": 872192738920108074,
|
||||
"member_name": "titis_zfr_7007",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": "https://cdn.discordapp.com/avatars/872192738920108074/986a18e279578123ec855f63defcc23f.png?size=1024",
|
||||
"roles": {
|
||||
"role_ids": [
|
||||
1369769836028231730
|
||||
],
|
||||
"role_names": [
|
||||
"⚒️ | Bêta Testeurs"
|
||||
],
|
||||
"permissions": [
|
||||
1032
|
||||
]
|
||||
},
|
||||
"joined_at": "2025-07-18T21:59:11.510000+00:00"
|
||||
}
|
||||
]
|
||||
|
|
@ -33,16 +33,16 @@ def send_discord_log(status, message, color, author=None, commit_msg=None):
|
|||
except Exception as e:
|
||||
print(f"[!] Erreur envoi Discord : {e}")
|
||||
|
||||
def run_mep_logic(author, commit_msg):
|
||||
def run_mep_logic(author, commit_msg, branch="main"):
|
||||
start_time = datetime.now()
|
||||
send_discord_log("EN COURS", "Déploiement lancé sur la machine de guerre...", 3447003, author, commit_msg)
|
||||
send_discord_log("EN COURS", f"Déploiement branch **{branch}** lancé sur la machine de guerre...", 3447003, author, commit_msg)
|
||||
|
||||
try:
|
||||
os.chdir(PROJECT_PATH)
|
||||
|
||||
# 1. GIT
|
||||
subprocess.run(["git", "fetch", "origin"], check=True)
|
||||
subprocess.run(["git", "reset", "--hard", "origin/main"], check=True)
|
||||
subprocess.run(["git", "reset", "--hard", f"origin/{branch}"], check=True)
|
||||
|
||||
duration = (datetime.now() - start_time).total_seconds()
|
||||
msg = f"✅ **Déploiement réussi en {duration:.2f}s**\nLe bot est à jour et redémarré."
|
||||
|
|
@ -70,8 +70,12 @@ def deploy():
|
|||
author = data['commits'][0].get('author', {}).get('name', 'Inconnu')
|
||||
commit_msg = data['commits'][0].get('message', 'Pas de message')
|
||||
|
||||
# Extraction de la branche
|
||||
ref = data.get('ref', 'refs/heads/main')
|
||||
branch = ref.split('/')[-1] if ref else 'main'
|
||||
|
||||
# Threading pour répondre vite à GitLab
|
||||
threading.Thread(target=run_mep_logic, args=(author, commit_msg)).start()
|
||||
threading.Thread(target=run_mep_logic, args=(author, commit_msg, branch)).start()
|
||||
|
||||
return {"status": "accepted"}, 202
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class AdvancedLogger:
|
|||
"details": details or {}
|
||||
}
|
||||
|
||||
self._write_log("messages", log_data)
|
||||
asyncio.create_task(self._write_log_async("messages", log_data))
|
||||
|
||||
def log_role_event(self, member: discord.Member, role: discord.Role, event_type: str):
|
||||
"""Log role changes (added/removed)"""
|
||||
|
|
@ -49,7 +49,7 @@ class AdvancedLogger:
|
|||
"role_permissions": role.permissions.value
|
||||
}
|
||||
|
||||
self._write_log("roles", log_data)
|
||||
asyncio.create_task(self._write_log_async("roles", log_data))
|
||||
|
||||
def log_voice_event(self, member: discord.Member, channel: discord.VoiceChannel, event_type: str):
|
||||
"""Log voice channel events (join/leave)"""
|
||||
|
|
@ -63,7 +63,7 @@ class AdvancedLogger:
|
|||
"channel_type": str(channel.type)
|
||||
}
|
||||
|
||||
self._write_log("voice", log_data)
|
||||
asyncio.create_task(self._write_log_async("voice", log_data))
|
||||
|
||||
def log_member_leave(self, member: discord.Member):
|
||||
"""Log when a member leaves the server"""
|
||||
|
|
@ -85,10 +85,10 @@ class AdvancedLogger:
|
|||
}
|
||||
|
||||
# Save to member-specific log
|
||||
self._write_member_log(member.id, log_data)
|
||||
asyncio.create_task(self._write_member_log_async(member.id, log_data))
|
||||
|
||||
# Also save to general logs
|
||||
self._write_log("member_events", log_data)
|
||||
asyncio.create_task(self._write_log_async("member_events", log_data))
|
||||
|
||||
def log_member_join(self, member: discord.Member):
|
||||
"""Log when a member joins the server"""
|
||||
|
|
@ -101,10 +101,13 @@ class AdvancedLogger:
|
|||
"member_avatar": str(member.avatar.url) if member.avatar else None
|
||||
}
|
||||
|
||||
self._write_log("member_events", log_data)
|
||||
asyncio.create_task(self._write_log_async("member_events", log_data))
|
||||
|
||||
def check_previous_roles(self, member_id: int) -> Optional[Dict]:
|
||||
"""Check if member has previous role data when rejoining"""
|
||||
# This one stays synchronous for now as it's called in on_member_join and needs immediate result
|
||||
# but since it only reads ONE file, it's less problematic than writing to cumulative logs.
|
||||
# Format update: it now needs to read NDJSON.
|
||||
member_log_file = f"{self.member_logs_dir}/{member_id}.json"
|
||||
|
||||
if not os.path.exists(member_log_file):
|
||||
|
|
@ -112,7 +115,8 @@ class AdvancedLogger:
|
|||
|
||||
try:
|
||||
with open(member_log_file, 'r', encoding='utf-8') as f:
|
||||
logs = json.load(f)
|
||||
# Read line by line for NDJSON
|
||||
logs = [json.loads(line) for line in f if line.strip()]
|
||||
|
||||
# Find the most recent leave event
|
||||
leave_events = [log for log in logs if log.get("event_type") == "member_leave"]
|
||||
|
|
@ -123,47 +127,39 @@ class AdvancedLogger:
|
|||
kuby_logger.error(f"Error checking previous roles for {member_id}: {e}")
|
||||
|
||||
return None
|
||||
|
||||
def _write_log(self, log_type: str, data: Dict):
|
||||
"""Write log data to appropriate file"""
|
||||
date_str = datetime.now().strftime("%Y-%m-%d")
|
||||
log_file = f"{self.logs_dir}/{log_type}_{date_str}.json"
|
||||
|
||||
|
||||
async def _write_log_async(self, log_type: str, data: Dict):
|
||||
"""Asynchronous wrapper for log writing"""
|
||||
return await asyncio.to_thread(self._write_log_sync, log_type, data)
|
||||
|
||||
async def _write_member_log_async(self, member_id: int, data: Dict):
|
||||
"""Asynchronous wrapper for member log writing"""
|
||||
return await asyncio.to_thread(self._write_member_log_sync, member_id, data)
|
||||
|
||||
def _write_log_sync(self, log_type: str, data: Dict):
|
||||
"""Write log data to appropriate file using NDJSON (Append-only)"""
|
||||
try:
|
||||
# Append to existing file or create new
|
||||
if os.path.exists(log_file):
|
||||
with open(log_file, 'r', encoding='utf-8') as f:
|
||||
existing_logs = json.load(f)
|
||||
else:
|
||||
existing_logs = []
|
||||
|
||||
existing_logs.append(data)
|
||||
date_str = datetime.now().strftime("%Y-%m-%d")
|
||||
log_file = f"{self.logs_dir}/{log_type}_{date_str}.json"
|
||||
|
||||
with open(log_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(existing_logs, f, indent=2, ensure_ascii=False)
|
||||
# Simple append in NDJSON format
|
||||
with open(log_file, 'a', encoding='utf-8') as f:
|
||||
f.write(json.dumps(data, ensure_ascii=False) + "\n")
|
||||
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Error writing log for {log_type}: {e}")
|
||||
# We don't use kuby_logger here to avoid infinite recursion if nested
|
||||
print(f"CRITICAL ERROR in AdvancedLogger._write_log_sync: {e}")
|
||||
|
||||
def _write_member_log(self, member_id: int, data: Dict):
|
||||
"""Write member-specific log"""
|
||||
member_log_file = f"{self.member_logs_dir}/{member_id}.json"
|
||||
|
||||
def _write_member_log_sync(self, member_id: int, data: Dict):
|
||||
"""Write member-specific log using NDJSON (Append-only)"""
|
||||
try:
|
||||
# Append to existing file or create new
|
||||
if os.path.exists(member_log_file):
|
||||
with open(member_log_file, 'r', encoding='utf-8') as f:
|
||||
existing_logs = json.load(f)
|
||||
else:
|
||||
existing_logs = []
|
||||
|
||||
existing_logs.append(data)
|
||||
member_log_file = f"{self.member_logs_dir}/{member_id}.json"
|
||||
|
||||
with open(member_log_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(existing_logs, f, indent=2, ensure_ascii=False)
|
||||
with open(member_log_file, 'a', encoding='utf-8') as f:
|
||||
f.write(json.dumps(data, ensure_ascii=False) + "\n")
|
||||
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Error writing member log for {member_id}: {e}")
|
||||
print(f"CRITICAL ERROR in AdvancedLogger._write_member_log_sync: {e}")
|
||||
|
||||
async def send_leave_notification(self, member: discord.Member, channel: discord.TextChannel):
|
||||
"""Send notification when member leaves"""
|
||||
|
|
|
|||
|
|
@ -188,10 +188,10 @@ async def generate_servers_json(bot: discord.Client) -> dict:
|
|||
entry["verificationLevel"] = str(guild.verification_level)
|
||||
|
||||
if fields.get("memberCount"):
|
||||
try:
|
||||
members = [m async for m in guild.fetch_members(limit=None)]
|
||||
entry["memberCount"] = sum(1 for m in members if not m.bot)
|
||||
except Exception:
|
||||
# Use cache if available (intents.members is True), otherwise fallback to count
|
||||
if guild.members:
|
||||
entry["memberCount"] = sum(1 for m in guild.members if not m.bot)
|
||||
else:
|
||||
entry["memberCount"] = guild.member_count
|
||||
|
||||
if fields.get("owner"):
|
||||
|
|
@ -209,22 +209,27 @@ async def generate_servers_json(bot: discord.Client) -> dict:
|
|||
pass
|
||||
|
||||
# Membres avec un rôle dont le nom correspond à founderRoles
|
||||
try:
|
||||
async for member in guild.fetch_members(limit=None):
|
||||
if member.bot or member.id == guild.owner_id:
|
||||
continue
|
||||
for role in member.roles:
|
||||
if any(key in role.name.lower() for key in founder_keys):
|
||||
founders.append({
|
||||
"id": str(member.id),
|
||||
"username": member.name,
|
||||
"displayName": member.display_name,
|
||||
"avatar": str(member.display_avatar.url),
|
||||
"isOwner": False,
|
||||
})
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
# Use cache if possible
|
||||
members_to_check = guild.members if guild.members else []
|
||||
if not members_to_check:
|
||||
try:
|
||||
members_to_check = [m async for m in guild.fetch_members(limit=None)]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for member in members_to_check:
|
||||
if member.bot or member.id == guild.owner_id:
|
||||
continue
|
||||
for role in member.roles:
|
||||
if any(key in role.name.lower() for key in founder_keys):
|
||||
founders.append({
|
||||
"id": str(member.id),
|
||||
"username": member.name,
|
||||
"displayName": member.display_name,
|
||||
"avatar": str(member.display_avatar.url),
|
||||
"isOwner": False,
|
||||
})
|
||||
break
|
||||
|
||||
entry["founders"] = founders
|
||||
|
||||
|
|
@ -259,7 +264,14 @@ async def generate_members_json(bot: discord.Client, guild_id: Optional[int] = N
|
|||
raise ValueError(f"Serveur introuvable : {target_id}")
|
||||
|
||||
members_list = []
|
||||
async for member in guild.fetch_members(limit=None):
|
||||
# Use cached members if available, or fetch if not
|
||||
source = guild.members if guild.members else []
|
||||
if not source:
|
||||
async for m in guild.fetch_members(limit=None):
|
||||
if not m.bot:
|
||||
source.append(m)
|
||||
|
||||
for member in source:
|
||||
if member.bot:
|
||||
continue
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,14 @@ import sys
|
|||
import time
|
||||
import functools
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import Any, Callable
|
||||
import traceback
|
||||
|
||||
REPORTED_ERRORS_FILE = "data/automated_reports.json"
|
||||
|
||||
class KubyLogger:
|
||||
def __init__(self, name="KubyBot"):
|
||||
self.logger = logging.getLogger(name)
|
||||
|
|
@ -53,37 +57,69 @@ class KubyLogger:
|
|||
def __init__(self, client):
|
||||
super().__init__()
|
||||
self.client = client
|
||||
self.last_errors = {}
|
||||
self.cooldown = 3600 # 1 hour cooldown per unique error
|
||||
self.last_errors = self._load_reported_errors()
|
||||
|
||||
def _load_reported_errors(self):
|
||||
if os.path.exists(REPORTED_ERRORS_FILE):
|
||||
try:
|
||||
with open(REPORTED_ERRORS_FILE, "r") as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
print(f"Error loading reported errors: {e}")
|
||||
return {}
|
||||
|
||||
def _save_reported_errors(self):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(REPORTED_ERRORS_FILE), exist_ok=True)
|
||||
with open(REPORTED_ERRORS_FILE, "w") as f:
|
||||
json.dump(self.last_errors, f, indent=4)
|
||||
except Exception as e:
|
||||
print(f"Error saving reported errors: {e}")
|
||||
|
||||
def emit(self, record):
|
||||
if record.levelno >= logging.ERROR:
|
||||
# Extract message and first line of traceback if available
|
||||
msg = record.getMessage()
|
||||
error_key = msg
|
||||
if record.exc_info:
|
||||
error_key += str(record.exc_info[1])
|
||||
# Use message + location + simplified traceback for unique key
|
||||
# This key is used for the local cooldown
|
||||
error_key = f"{record.name}.{record.funcName}:{record.lineno} - {msg}"
|
||||
|
||||
current_time = time.time()
|
||||
if error_key in self.last_errors and current_time - self.last_errors[error_key] < self.cooldown:
|
||||
return # Skip if same error within cooldown
|
||||
last_time = self.last_errors.get(error_key, 0)
|
||||
|
||||
if current_time - last_time < self.cooldown:
|
||||
return
|
||||
|
||||
self.last_errors[error_key] = current_time
|
||||
self._save_reported_errors()
|
||||
|
||||
# Create issue (Fire and forget, we don't want to block logging)
|
||||
# Prepare issue data
|
||||
description = f"**Type:** {record.levelname}\n"
|
||||
description += f"**Message:** {msg}\n"
|
||||
description += f"**Source:** {record.name}.{record.funcName}:{record.lineno}\n\n"
|
||||
if record.exc_info:
|
||||
description += f"**Traceback:**\n```python\n{traceback.format_exc()}\n```"
|
||||
|
||||
title = f"[AUTO] Error: {msg[:50]}..."
|
||||
title = f"[AUTO] Error: {msg[:100]}..."
|
||||
labels = ["bug", "auto-report"]
|
||||
|
||||
# Async reporting flow
|
||||
async def report_flow(client, t, d, l):
|
||||
try:
|
||||
# Check if an open issue with the SAME title already exists on GitLab
|
||||
existing = await client.find_issue_by_title(t, state="opened")
|
||||
if existing:
|
||||
# If it exists, we don't create a new one to avoid clutter
|
||||
return
|
||||
|
||||
# Otherwise, create it
|
||||
await client.create_issue(t, d, l)
|
||||
except Exception as e:
|
||||
print(f"Error in automated reporting flow: {e}")
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
if loop.is_running():
|
||||
loop.create_task(self.client.create_issue(title, description, labels=["bug", "auto-report"]))
|
||||
else:
|
||||
# Fallback if loop is not running (rare for this bot)
|
||||
pass
|
||||
loop.create_task(report_flow(self.client, title, description, labels))
|
||||
|
||||
gitlab_handler = GitLabHandler(gitlab_client)
|
||||
gitlab_handler.setLevel(logging.ERROR)
|
||||
|
|
|
|||
|
|
@ -63,6 +63,35 @@ class GitLabClient:
|
|||
gitlab_internal_logger.error(f"❌ Error connecting to GitLab API: {e}")
|
||||
return None
|
||||
|
||||
async def find_issue_by_title(self, title: str, state: str = "opened") -> Optional[dict]:
|
||||
"""
|
||||
Searches for an issue by its exact title and state.
|
||||
"""
|
||||
if not self.token or not self.project_id:
|
||||
return None
|
||||
|
||||
headers = {"PRIVATE-TOKEN": self.token}
|
||||
params = {
|
||||
"search": title,
|
||||
"state": state
|
||||
}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
# search param is fuzzy on GitLab, so we must double-check for exact match
|
||||
async with session.get(self.api_url, headers=headers, params=params) as response:
|
||||
if response.status == 200:
|
||||
issues = await response.json()
|
||||
for issue in issues:
|
||||
if issue.get("title") == title:
|
||||
return issue
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
except Exception as e:
|
||||
gitlab_internal_logger.error(f"❌ Error searching GitLab issues: {e}")
|
||||
return None
|
||||
|
||||
async def get_closed_issues(self) -> List[dict]:
|
||||
"""
|
||||
Fetches recently closed issues.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue