Modularisation du système de ticket & ajout des boutons persistant système WL

This commit is contained in:
Mathis 2026-03-14 15:40:19 +01:00
parent be8bf3fa5c
commit fd9251fc6e
2 changed files with 340 additions and 87 deletions

View file

@ -1,13 +1,138 @@
import discord
from discord.ext import commands
from discord import app_commands
from discord import app_commands, ui
import json
import os
from typing import Optional
TICKET_WHITELIST_SETTINGS_FILE = "data/ticket_whitelist_settings.json"
def load_settings(guild_id: int) -> dict:
"""Charge les paramètres de ticket pour un serveur"""
if not os.path.exists(TICKET_WHITELIST_SETTINGS_FILE):
return {}
try:
with open(TICKET_WHITELIST_SETTINGS_FILE, "r", encoding='utf-8') as f:
return json.load(f).get(str(guild_id), {})
except (json.JSONDecodeError, FileNotFoundError):
return {}
def save_settings(guild_id: int, settings: dict) -> None:
"""Sauvegarde les paramètres de ticket"""
data = {}
if os.path.exists(TICKET_WHITELIST_SETTINGS_FILE):
try:
with open(TICKET_WHITELIST_SETTINGS_FILE, "r", encoding='utf-8') as f:
data = json.load(f)
except (json.JSONDecodeError, FileNotFoundError):
pass
data[str(guild_id)] = settings
os.makedirs(os.path.dirname(TICKET_WHITELIST_SETTINGS_FILE), exist_ok=True)
with open(TICKET_WHITELIST_SETTINGS_FILE, "w", encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
class TicketWhitelistConfigView(ui.View):
def __init__(self, guild_id: int):
super().__init__(timeout=60)
self.guild_id = guild_id
async def prompt_for_id(self, interaction: discord.Interaction, prompt_text: str, is_category: bool = False):
await interaction.response.send_message(prompt_text, ephemeral=True)
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
if is_category:
if msg.content.isdigit():
target = discord.utils.get(interaction.guild.categories, id=int(msg.content))
if not target:
await interaction.followup.send("❌ Catégorie introuvable avec cet ID.", ephemeral=True)
return None
else:
await interaction.followup.send("❌ Veuillez envoyer l'ID (les chiffres) de la catégorie.", ephemeral=True)
return None
else:
if msg.role_mentions:
target = msg.role_mentions[0]
elif msg.content.isdigit():
target = interaction.guild.get_role(int(msg.content))
if not target:
await interaction.followup.send("❌ ID ou mention invalide.", ephemeral=True)
return None
try: await msg.delete()
except: pass
return target
except __import__("asyncio").TimeoutError:
await interaction.followup.send("❌ Temps écoulé.", ephemeral=True)
return None
@ui.button(label="Catégorie Tickets", style=discord.ButtonStyle.primary, row=0, emoji="📁")
async def set_category(self, interaction: discord.Interaction, button: ui.Button):
category = await self.prompt_for_id(interaction, "Envoie l'ID de la **catégorie** où créer les tickets :", is_category=True)
if category:
settings = load_settings(self.guild_id)
settings["ticket_category_id"] = category.id
save_settings(self.guild_id, settings)
await interaction.followup.send(f"✅ Catégorie configurée sur **{category.name}**", ephemeral=True)
@ui.button(label="Rôle Staff", style=discord.ButtonStyle.primary, row=0, emoji="🛡️")
async def set_staff_role(self, interaction: discord.Interaction, button: ui.Button):
role = await self.prompt_for_id(interaction, "Mentionne le **rôle Staff** ou envoie son ID :")
if role:
settings = load_settings(self.guild_id)
settings["staff_role_id"] = role.id
save_settings(self.guild_id, settings)
await interaction.followup.send(f"✅ Rôle Staff configuré sur **{role.name}**", ephemeral=True)
@ui.button(label="Rôle Équipe Staff", style=discord.ButtonStyle.primary, row=0, emoji="👥")
async def set_team_staff_role(self, interaction: discord.Interaction, button: ui.Button):
role = await self.prompt_for_id(interaction, "Mentionne le **rôle Équipe Staff** (à ping pour les nouveaux tickets) ou envoie son ID :")
if role:
settings = load_settings(self.guild_id)
settings["team_staff_role_id"] = role.id
save_settings(self.guild_id, settings)
await interaction.followup.send(f"✅ Rôle Équipe Staff configuré sur **{role.name}**", ephemeral=True)
@ui.button(label="Rôle Attente Oral", style=discord.ButtonStyle.secondary, row=1, emoji="🎤")
async def set_attente_oral_role(self, interaction: discord.Interaction, button: ui.Button):
role = await self.prompt_for_id(interaction, "Mentionne le rôle **Attente Oral** ou envoie son ID :")
if role:
settings = load_settings(self.guild_id)
settings["attente_oral_role_id"] = role.id
save_settings(self.guild_id, settings)
await interaction.followup.send(f"✅ Rôle Attente Oral configuré sur **{role.name}**", ephemeral=True)
@ui.button(label="Rôle Candidature à faire", style=discord.ButtonStyle.secondary, row=1, emoji="📝")
async def set_candidature_a_faire_role(self, interaction: discord.Interaction, button: ui.Button):
role = await self.prompt_for_id(interaction, "Mentionne le rôle **Candidature à faire** ou envoie son ID :")
if role:
settings = load_settings(self.guild_id)
settings["candidature_a_faire_role_id"] = role.id
save_settings(self.guild_id, settings)
await interaction.followup.send(f"✅ Rôle Candidature à faire configuré sur **{role.name}**", ephemeral=True)
@ui.button(label="Rôle Citoyen", style=discord.ButtonStyle.success, row=1, emoji="🏙️")
async def set_citoyen_role(self, interaction: discord.Interaction, button: ui.Button):
role = await self.prompt_for_id(interaction, "Mentionne le rôle **Citoyen** ou envoie son ID :")
if role:
settings = load_settings(self.guild_id)
settings["citoyen_role_id"] = role.id
save_settings(self.guild_id, settings)
await interaction.followup.send(f"✅ Rôle Citoyen configuré sur **{role.name}**", ephemeral=True)
TICKET_CATEGORY_ID = 1450001640127205388 # ID de la catégorie des tickets
STAFF_ROLE_ID = 1454042474141192316 # ID du rôle staff
TEAM_STAFF_ROLE_ID = 1454042474141192316 # ID du rôle équipe staff
ATTENTE_ORAL_ROLE_ID = 11464424211442307279 # ID du rôle "attente oral"
CANDIDATURE_A_FAIRE_ROLE_ID = 1464428034906919038 # ID du rôle "candidature à faire"
CITOYEN_ROLE_ID = 1453708386674806835 # ID du rôle "citoyen"
class ContinueFormView(discord.ui.View):
"""Vue avec un bouton pour continuer à l'étape suivante"""
@ -108,43 +233,45 @@ class TicketStep3(discord.ui.Modal, title="📋 Développement du Personnage"):
"""Création du ticket après validation"""
guild = interaction.guild
user = interaction.user
category = discord.utils.get(guild.categories, id=TICKET_CATEGORY_ID)
settings = load_settings(guild.id)
category_id = settings.get("ticket_category_id")
staff_role_id = settings.get("staff_role_id")
team_staff_role_id = settings.get("team_staff_role_id")
# Vérifier si la catégorie existe
if not category_id or not staff_role_id or not team_staff_role_id:
return await interaction.response.send_message("❌ Erreur : Le système de tickets n'est pas entièrement configuré sur ce serveur (Catégorie, Rôle Staff ou Rôle Équipe Staff manquant).", ephemeral=True)
category = discord.utils.get(guild.categories, id=int(category_id))
if category is None:
await interaction.response.send_message("❌ Erreur : La catégorie des tickets n'existe pas !", ephemeral=True)
return
return await interaction.response.send_message("❌ Erreur : La catégorie des tickets configurée n'existe plus !", ephemeral=True)
# Vérifier si le rôle staff existe
staff_role = discord.utils.get(guild.roles, id=STAFF_ROLE_ID)
if staff_role is None:
await interaction.response.send_message("❌ Erreur : Le rôle staff n'existe pas !", ephemeral=True)
return
staff_role = discord.utils.get(guild.roles, id=int(staff_role_id))
team_staff_role = discord.utils.get(guild.roles, id=int(team_staff_role_id))
if staff_role is None or team_staff_role is None:
return await interaction.response.send_message("❌ Erreur : L'un des rôles staff configurés n'existe plus !", ephemeral=True)
# Vérifier si l'utilisateur a déjà un ticket ouvert
for channel in category.text_channels:
if channel.topic == f"Ticket de {user.id}":
await interaction.response.send_message(f"❌ Vous avez déjà un ticket ouvert : {channel.mention}", ephemeral=True)
return
return await interaction.response.send_message(f"❌ Vous avez déjà un ticket ouvert : {channel.mention}", ephemeral=True)
# Définir les permissions du salon du ticket
overwrites = {
guild.default_role: discord.PermissionOverwrite(read_messages=False),
user: discord.PermissionOverwrite(read_messages=True, send_messages=True),
staff_role: discord.PermissionOverwrite(read_messages=True, send_messages=True),
discord.utils.get(guild.roles, id=TEAM_STAFF_ROLE_ID): discord.PermissionOverwrite(read_messages=True, send_messages=False)
team_staff_role: discord.PermissionOverwrite(read_messages=True, send_messages=False)
}
# Créer un salon de ticket avec le nom [pseudo_du_membre]-écrit
# Créer un salon de ticket avec le nom [pseudo]-écrit
ticket_channel = await category.create_text_channel(
name=f"{user.name}-écrit",
topic=f"Ticket de {user.id}",
overwrites=overwrites
)
# Récupérer le rôle "équipe staff"
team_staff_role = discord.utils.get(guild.roles, id=TEAM_STAFF_ROLE_ID)
# Création de l'embed avec les infos du formulaire
embed = discord.Embed(title="📩 Ticket Whitelist", color=0x00ff00)
embed.add_field(name="📋 - Informations Personnelles", value=(
@ -171,7 +298,7 @@ class TicketStep3(discord.ui.Modal, title="📋 Développement du Personnage"):
), inline=False)
# Envoyer l'embed avec les boutons d'actions pour les staff
await ticket_channel.send(embed=embed, view=TicketManagementView(user))
await ticket_channel.send(embed=embed, view=TicketManagementView())
# Envoyer un message pour mentionner l'équipe staff
await ticket_channel.send(f"{team_staff_role.mention} - Nouveau ticket créé !")
@ -181,10 +308,9 @@ class TicketStep3(discord.ui.Modal, title="📋 Développement du Personnage"):
new_nickname = f"{self.step2_part1_data.prenom.value} {self.step2_part1_data.nom.value} | {self.step1_data.pseudo.value}"
if len(new_nickname) > 32:
new_nickname = new_nickname[:32]
await user.edit(nick=new_nickname)
else:
await interaction.followup.send("❌ Le bot n'a pas les permissions nécessaires pour modifier le pseudo.", ephemeral=True)
try: await user.edit(nick=new_nickname)
except discord.Forbidden: pass
# Envoyer un message de confirmation
try:
await interaction.response.send_message(f"✅ Ticket ouvert : {ticket_channel.mention}", ephemeral=True)
@ -194,63 +320,99 @@ class TicketStep3(discord.ui.Modal, title="📋 Développement du Personnage"):
class TicketManagementView(discord.ui.View):
"""Vue pour gérer le ticket avec les boutons Fermer, Réouvrir, Claim et Supprimer"""
def __init__(self, ticket_owner):
def __init__(self):
super().__init__(timeout=None)
self.ticket_owner = ticket_owner
self.claimed_by = None # Stocke le staff qui claim le ticket
@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"""
if not discord.utils.get(interaction.user.roles, id=STAFF_ROLE_ID):
await interaction.response.send_message("❌ Seuls les staffs peuvent fermer un ticket.", ephemeral=True)
return
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)
await interaction.channel.set_permissions(self.ticket_owner, read_messages=False, send_messages=False)
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(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(self.ticket_owner)
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")
async def claim_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
"""Un staff prend en charge le ticket"""
if not discord.utils.get(interaction.user.roles, id=STAFF_ROLE_ID):
await interaction.response.send_message("❌ Seuls les staffs peuvent claim un ticket.", ephemeral=True)
return
self.claimed_by = interaction.user
await interaction.channel.set_permissions(discord.utils.get(interaction.guild.roles, id=STAFF_ROLE_ID), send_messages=False, read_messages=True)
await interaction.channel.set_permissions(self.claimed_by, read_messages=True, send_messages=True)
await interaction.response.send_message(f"👤 {self.claimed_by.mention} a claim ce ticket.", 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)
class ClosedTicketView(discord.ui.View):
"""Vue pour les tickets fermés avec les boutons Réouvrir et Supprimer"""
def __init__(self, ticket_owner):
def __init__(self):
super().__init__(timeout=None)
self.ticket_owner = ticket_owner
@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"""
if not discord.utils.get(interaction.user.roles, id=STAFF_ROLE_ID):
await interaction.response.send_message("❌ Seuls les staffs peuvent réouvrir un ticket.", ephemeral=True)
return
await interaction.channel.set_permissions(self.ticket_owner, read_messages=True, send_messages=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)
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)
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)
# Mettre à jour la vue pour afficher tous les boutons
new_view = TicketManagementView(self.ticket_owner)
new_view = TicketManagementView()
await interaction.channel.send("Le ticket a été réouvert.", view=new_view)
@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"""
if not discord.utils.get(interaction.user.roles, id=STAFF_ROLE_ID):
await interaction.response.send_message("❌ Seuls les staffs peuvent supprimer un ticket.", ephemeral=True)
return
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)
await interaction.response.send_message("❌ Suppression du ticket...", ephemeral=True)
await interaction.channel.delete()
@ -272,6 +434,7 @@ class Ticket(commands.Cog):
self.bot = bot
@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):
"""Envoie l'embed avec le bouton d'ouverture de ticket"""
embed = discord.Embed(
@ -283,6 +446,34 @@ class Ticket(commands.Cog):
await interaction.channel.send(embed=embed, view=view)
await interaction.response.send_message("✅ Embed des tickets envoyé.", ephemeral=True)
@app_commands.command(name="ticket_whitelist_config", description="Configurer le système de tickets whitelist (Admin)")
@app_commands.checks.has_permissions(administrator=True)
async def ticket_whitelist_config(self, interaction: discord.Interaction):
"""Interface de configuration des tickets"""
settings = load_settings(interaction.guild.id)
embed = discord.Embed(
title="⚙️ Configuration Tickets Whitelist",
description="Utilisez les boutons ci-dessous pour lier la catégorie et les rôles.",
color=discord.Color.blue()
)
cat_id = settings.get("ticket_category_id")
s_role_id = settings.get("staff_role_id")
ts_role_id = settings.get("team_staff_role_id")
ao_role_id = settings.get("attente_oral_role_id")
caf_role_id = settings.get("candidature_a_faire_role_id")
c_role_id = settings.get("citoyen_role_id")
embed.add_field(name="📁 Catégorie Tickets", value=f"Id: {cat_id}" if cat_id else "❌ Non configuré", inline=True)
embed.add_field(name="🛡️ Staff", value=f"<@&{s_role_id}>" if s_role_id else "❌ Non configuré", inline=True)
embed.add_field(name="👥 Équipe Staff", value=f"<@&{ts_role_id}>" if ts_role_id else "❌ Non configuré", inline=True)
embed.add_field(name="🎤 Attente Oral", value=f"<@&{ao_role_id}>" if ao_role_id else "❌ Non configuré", inline=True)
embed.add_field(name="📝 Candidature à faire", value=f"<@&{caf_role_id}>" if caf_role_id else "❌ Non configuré", inline=True)
embed.add_field(name="🏙️ Citoyen", value=f"<@&{c_role_id}>" if c_role_id else "❌ Non configuré", inline=True)
await interaction.response.send_message(embed=embed, view=TicketWhitelistConfigView(interaction.guild.id), ephemeral=True)
@commands.Cog.listener()
async def on_message(self, message):
"""Surveille les messages des staffs dans les tickets"""
@ -291,39 +482,47 @@ class Ticket(commands.Cog):
if not message.channel.topic or not message.channel.topic.startswith("Ticket de"):
return
staff_role = discord.utils.get(message.guild.roles, id=STAFF_ROLE_ID)
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:
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:
user_id = message.channel.topic.split("Ticket de ")[1]
user = await message.guild.fetch_member(user_id)
user = await message.guild.fetch_member(int(user_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
# Vérifier si le rôle "attente oral" est déjà attribué
attente_oral_role = discord.utils.get(message.guild.roles, id=ATTENTE_ORAL_ROLE_ID)
candidature_a_faire_role = discord.utils.get(message.guild.roles, id=CANDIDATURE_A_FAIRE_ROLE_ID)
citoyen_role = discord.utils.get(message.guild.roles, id=CITOYEN_ROLE_ID)
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 attente_oral_role in user.roles:
# Deuxième "validé" détecté
await user.remove_roles(attente_oral_role)
await user.add_roles(citoyen_role)
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é
await user.remove_roles(candidature_a_faire_role)
await user.add_roles(attente_oral_role)
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")
# Mettre à jour le pseudo du joueur si le bot a les permissions nécessaires
if message.guild.me.guild_permissions.manage_nicknames:
new_nickname = f"{self.step2_part1_data.prenom.value} {self.step2_part1_data.nom.value} | {self.step1_data.pseudo.value}"
if len(new_nickname) > 32:
new_nickname = new_nickname[:32]
await user.edit(nick=new_nickname)
else:
await message.channel.send("❌ Le bot n'a pas les permissions nécessaires pour modifier le pseudo.", delete_after=10)
except Exception as e:
print(f"Erreur lors du renommage du ticket: {e}")
print(f"Erreur lors du traitement du ticket : {e}")
async def setup(bot):
await bot.add_cog(Ticket(bot))
await bot.add_cog(Ticket(bot))
bot.add_view(TicketView())
bot.add_view(TicketManagementView())
bot.add_view(ClosedTicketView())

View file

@ -1,6 +1,6 @@
[
{
"date": "2026-03-01T00:26:14.746054+00:00",
"date": "2026-03-14T14:26:12.694595+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -9,7 +9,7 @@
"success": true
},
{
"date": "2026-03-01T00:25:45.072770+00:00",
"date": "2026-03-14T14:25:42.467679+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -18,7 +18,7 @@
"success": true
},
{
"date": "2026-03-01T00:25:15.071380+00:00",
"date": "2026-03-14T14:25:11.992208+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -27,7 +27,7 @@
"success": true
},
{
"date": "2026-03-01T00:24:45.388984+00:00",
"date": "2026-03-14T14:24:42.190744+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -36,7 +36,7 @@
"success": true
},
{
"date": "2026-03-01T00:24:14.975026+00:00",
"date": "2026-03-14T14:24:12.614886+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -45,7 +45,7 @@
"success": true
},
{
"date": "2026-03-01T00:23:44.713904+00:00",
"date": "2026-03-14T14:23:42.012764+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -54,7 +54,7 @@
"success": true
},
{
"date": "2026-03-01T00:23:16.510199+00:00",
"date": "2026-03-14T14:23:12.416066+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -63,7 +63,7 @@
"success": true
},
{
"date": "2026-03-01T00:22:44.966638+00:00",
"date": "2026-03-14T14:22:42.200744+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -72,7 +72,7 @@
"success": true
},
{
"date": "2026-03-01T00:22:14.857332+00:00",
"date": "2026-03-14T14:22:12.128982+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -81,7 +81,7 @@
"success": true
},
{
"date": "2026-03-01T00:21:44.958489+00:00",
"date": "2026-03-14T14:21:41.879828+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -90,7 +90,7 @@
"success": true
},
{
"date": "2026-03-01T00:21:14.844468+00:00",
"date": "2026-03-14T14:21:25.894956+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -99,7 +99,7 @@
"success": true
},
{
"date": "2026-03-01T00:20:44.959093+00:00",
"date": "2026-03-14T14:20:56.179577+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -108,7 +108,7 @@
"success": true
},
{
"date": "2026-03-01T00:20:14.948095+00:00",
"date": "2026-03-14T14:20:25.382325+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
@ -117,7 +117,61 @@
"success": true
},
{
"date": "2026-03-01T00:19:44.835750+00:00",
"date": "2026-03-14T14:19:55.416432+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
"guildName": "Omega Kube Bêta Test",
"errors": [],
"success": true
},
{
"date": "2026-03-14T14:19:25.281242+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
"guildName": "Omega Kube Bêta Test",
"errors": [],
"success": true
},
{
"date": "2026-03-14T14:18:55.315861+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
"guildName": "Omega Kube Bêta Test",
"errors": [],
"success": true
},
{
"date": "2026-03-14T14:18:25.672058+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
"guildName": "Omega Kube Bêta Test",
"errors": [],
"success": true
},
{
"date": "2026-03-14T14:17:55.409042+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
"guildName": "Omega Kube Bêta Test",
"errors": [],
"success": true
},
{
"date": "2026-03-14T14:17:25.447376+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,
"guildName": "Omega Kube Bêta Test",
"errors": [],
"success": true
},
{
"date": "2026-03-14T14:16:55.368379+00:00",
"trigger": "auto",
"serversCount": 1,
"membersCount": 13,