Fix des derniers détails
This commit is contained in:
parent
07198c20b7
commit
00446c5fb8
3 changed files with 130 additions and 21 deletions
|
|
@ -28,7 +28,8 @@ class Goodbye(commands.Cog):
|
||||||
welcome_banner_background TEXT,
|
welcome_banner_background TEXT,
|
||||||
welcome_channel_message TEXT,
|
welcome_channel_message TEXT,
|
||||||
goodbye_server_name TEXT,
|
goodbye_server_name TEXT,
|
||||||
goodbye_message TEXT
|
goodbye_message TEXT,
|
||||||
|
goodbye_banner_background TEXT
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
|
@ -42,6 +43,9 @@ class Goodbye(commands.Cog):
|
||||||
if 'goodbye_message' not in columns:
|
if 'goodbye_message' not in columns:
|
||||||
cursor.execute('ALTER TABLE server_configs ADD COLUMN goodbye_message TEXT')
|
cursor.execute('ALTER TABLE server_configs ADD COLUMN goodbye_message TEXT')
|
||||||
|
|
||||||
|
if 'goodbye_banner_background' not in columns:
|
||||||
|
cursor.execute('ALTER TABLE server_configs ADD COLUMN goodbye_banner_background TEXT')
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
@ -73,7 +77,7 @@ class Goodbye(commands.Cog):
|
||||||
seconds = delta.seconds % 60
|
seconds = delta.seconds % 60
|
||||||
return f"il y a {seconds} {'seconde' if seconds <= 1 else 'secondes'}"
|
return f"il y a {seconds} {'seconde' if seconds <= 1 else 'secondes'}"
|
||||||
|
|
||||||
async def create_goodbye_image(self, username, avatar_url, server_name=None):
|
async def create_goodbye_image(self, username, avatar_url, server_name=None, banner_background=None):
|
||||||
current_dir = os.path.dirname(__file__)
|
current_dir = os.path.dirname(__file__)
|
||||||
base_dir = os.path.abspath(os.path.join(current_dir, ".."))
|
base_dir = os.path.abspath(os.path.join(current_dir, ".."))
|
||||||
|
|
||||||
|
|
@ -81,7 +85,18 @@ class Goodbye(commands.Cog):
|
||||||
async with session.get(avatar_url) as resp:
|
async with session.get(avatar_url) as resp:
|
||||||
avatar_bytes = await resp.read()
|
avatar_bytes = await resp.read()
|
||||||
|
|
||||||
background = Image.open(os.path.join(base_dir, 'background_template_goodbye.png'))
|
# Utiliser le fond personnalisé ou celui par défaut
|
||||||
|
bg_path = None
|
||||||
|
if banner_background:
|
||||||
|
# On cherche dans le dossier banners/
|
||||||
|
potential_path = os.path.join(base_dir, "banners", banner_background)
|
||||||
|
if os.path.exists(potential_path):
|
||||||
|
bg_path = potential_path
|
||||||
|
|
||||||
|
if bg_path:
|
||||||
|
background = Image.open(bg_path)
|
||||||
|
else:
|
||||||
|
background = Image.open(os.path.join(base_dir, 'background_template_goodbye.png'))
|
||||||
draw = ImageDraw.Draw(background)
|
draw = ImageDraw.Draw(background)
|
||||||
|
|
||||||
font_large = ImageFont.truetype(os.path.join(base_dir, 'custom_font_large.otf'), 70)
|
font_large = ImageFont.truetype(os.path.join(base_dir, 'custom_font_large.otf'), 70)
|
||||||
|
|
@ -110,7 +125,7 @@ class Goodbye(commands.Cog):
|
||||||
async def on_member_remove(self, member):
|
async def on_member_remove(self, member):
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute('SELECT goodbye_channel, goodbye_server_name, goodbye_message FROM server_configs WHERE server_id = ?', (member.guild.id,))
|
cursor.execute('SELECT goodbye_channel, goodbye_server_name, goodbye_message, goodbye_banner_background FROM server_configs WHERE server_id = ?', (member.guild.id,))
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
@ -118,13 +133,15 @@ class Goodbye(commands.Cog):
|
||||||
goodbye_channel = result[0]
|
goodbye_channel = result[0]
|
||||||
server_name = result[1]
|
server_name = result[1]
|
||||||
custom_message = result[2]
|
custom_message = result[2]
|
||||||
|
banner_background = result[3]
|
||||||
|
|
||||||
channel = member.guild.get_channel(goodbye_channel)
|
channel = member.guild.get_channel(goodbye_channel)
|
||||||
if channel:
|
if channel:
|
||||||
img = await self.create_goodbye_image(
|
img = await self.create_goodbye_image(
|
||||||
member.name,
|
member.name,
|
||||||
member.avatar.url if member.avatar else member.default_avatar.url,
|
member.avatar.url if member.avatar else member.default_avatar.url,
|
||||||
server_name=server_name
|
server_name=server_name,
|
||||||
|
banner_background=banner_background
|
||||||
)
|
)
|
||||||
joined_message = self.humanize_time_delta(member.joined_at)
|
joined_message = self.humanize_time_delta(member.joined_at)
|
||||||
|
|
||||||
|
|
@ -138,23 +155,67 @@ class Goodbye(commands.Cog):
|
||||||
embed.set_image(url="attachment://goodbye.png")
|
embed.set_image(url="attachment://goodbye.png")
|
||||||
await channel.send(embed=embed, file=discord.File(img, filename="goodbye.png"))
|
await channel.send(embed=embed, file=discord.File(img, filename="goodbye.png"))
|
||||||
|
|
||||||
|
async def save_banner_attachment(self, attachment: discord.Attachment, guild_id: int) -> str:
|
||||||
|
"""Sauvegarde l'attachment et retourne le chemin du fichier"""
|
||||||
|
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "banners"))
|
||||||
|
os.makedirs(base_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Vérifier que c'est une image
|
||||||
|
if not attachment.content_type or not attachment.content_type.startswith('image/'):
|
||||||
|
raise ValueError("Le fichier doit être une image.")
|
||||||
|
|
||||||
|
# Vérifier le format PNG
|
||||||
|
if not attachment.filename.lower().endswith('.png'):
|
||||||
|
raise ValueError("Le fichier doit être au format PNG.")
|
||||||
|
|
||||||
|
# Vérifier les dimensions
|
||||||
|
banner_path = os.path.join(base_dir, f"banner_goodbye_{guild_id}.png")
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.get(attachment.url) as resp:
|
||||||
|
if resp.status == 200:
|
||||||
|
# Vérifier les dimensions avant de sauvegarder
|
||||||
|
img_data = await resp.read()
|
||||||
|
from io import BytesIO
|
||||||
|
with Image.open(BytesIO(img_data)) as img:
|
||||||
|
width, height = img.size
|
||||||
|
if width != 1000 or height != 300:
|
||||||
|
raise ValueError(f"Les dimensions doivent être 1000x300 pixels (votre image: {width}x{height})")
|
||||||
|
|
||||||
|
with open(banner_path, 'wb') as f:
|
||||||
|
f.write(img_data)
|
||||||
|
|
||||||
|
return os.path.basename(banner_path)
|
||||||
|
|
||||||
@app_commands.command(name="setgoodbye", description="Définit le salon d'aurevoir et les paramètres personnalisés")
|
@app_commands.command(name="setgoodbye", description="Définit le salon d'aurevoir et les paramètres personnalisés")
|
||||||
@app_commands.checks.has_permissions(administrator=True)
|
@app_commands.checks.has_permissions(administrator=True)
|
||||||
async def set_goodbye(self, interaction: discord.Interaction, channel: discord.TextChannel, server_name: str = None, message: str = None):
|
async def set_goodbye(self, interaction: discord.Interaction, channel: discord.TextChannel, server_name: str = None, message: str = None, banner_file: discord.Attachment = None):
|
||||||
|
banner_path = None
|
||||||
|
|
||||||
|
# Si un fichier est uploadé, le sauvegarder
|
||||||
|
if banner_file:
|
||||||
|
try:
|
||||||
|
banner_path = await self.save_banner_attachment(banner_file, interaction.guild_id)
|
||||||
|
except Exception as e:
|
||||||
|
await interaction.response.send_message(f"❌ Erreur avec le fichier: {e}", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute('''INSERT INTO server_configs (server_id, goodbye_channel, goodbye_server_name, goodbye_message)
|
cursor.execute('''INSERT INTO server_configs (server_id, goodbye_channel, goodbye_server_name, goodbye_message, goodbye_banner_background)
|
||||||
VALUES (?, ?, ?, ?) ON CONFLICT(server_id)
|
VALUES (?, ?, ?, ?, ?) ON CONFLICT(server_id)
|
||||||
DO UPDATE SET goodbye_channel=excluded.goodbye_channel,
|
DO UPDATE SET goodbye_channel=excluded.goodbye_channel,
|
||||||
goodbye_server_name=COALESCE(excluded.goodbye_server_name, goodbye_server_name),
|
goodbye_server_name=COALESCE(excluded.goodbye_server_name, goodbye_server_name),
|
||||||
goodbye_message=COALESCE(excluded.goodbye_message, goodbye_message)''',
|
goodbye_message=COALESCE(excluded.goodbye_message, goodbye_message),
|
||||||
(interaction.guild_id, channel.id, server_name, message))
|
goodbye_banner_background=COALESCE(excluded.goodbye_banner_background, goodbye_banner_background)''',
|
||||||
|
(interaction.guild_id, channel.id, server_name, message, banner_path))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
msg = f"✅ Salon d'aurevoir défini sur {channel.mention}"
|
msg = f"✅ Salon d'aurevoir défini sur {channel.mention}"
|
||||||
if server_name: msg += f"\nNom du serveur: {server_name}"
|
if server_name: msg += f"\nNom du serveur: {server_name}"
|
||||||
if message: msg += f"\nMessage: {message}"
|
if message: msg += f"\nMessage: {message}"
|
||||||
|
if banner_path: msg += f"\nBannière personnalisée activée."
|
||||||
|
|
||||||
await interaction.response.send_message(msg, ephemeral=True)
|
await interaction.response.send_message(msg, ephemeral=True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -567,7 +567,16 @@ class TicketPriorityModal(discord.ui.Modal):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
category_channel = None
|
category_channel = None
|
||||||
if self.config.default_category:
|
|
||||||
|
# Check if category has a specific Discord category
|
||||||
|
if self.category.discord_category_id:
|
||||||
|
try:
|
||||||
|
category_channel = guild.get_channel(int(self.category.discord_category_id))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Fallback to default config category if not found or not set
|
||||||
|
if not category_channel and self.config.default_category:
|
||||||
try:
|
try:
|
||||||
category_channel = guild.get_channel(int(self.config.default_category))
|
category_channel = guild.get_channel(int(self.config.default_category))
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
|
|
@ -2214,7 +2223,8 @@ class CategoryActionView(discord.ui.View):
|
||||||
f"**Emoji:** {self.category.emoji}\n"
|
f"**Emoji:** {self.category.emoji}\n"
|
||||||
f"**Description:** {self.category.description or 'Aucune'}\n"
|
f"**Description:** {self.category.description or 'Aucune'}\n"
|
||||||
f"**Couleur:** `{self.category.color}`\n"
|
f"**Couleur:** `{self.category.color}`\n"
|
||||||
f"**Staff Spécifique:** {', '.join([f'<@&{r}>' for r in self.category.staff_roles]) if self.category.staff_roles else 'Global (Tous les staffs)'}",
|
f"**Staff Spécifique:** {', '.join([f'<@&{r}>' for r in self.category.staff_roles]) if self.category.staff_roles else 'Global (Tous les staffs)'}\n"
|
||||||
|
f"**Catégorie Discord:** {f'<#{self.category.discord_category_id}>' if self.category.discord_category_id else 'Par défaut'}",
|
||||||
color=discord.Color.blue()
|
color=discord.Color.blue()
|
||||||
)
|
)
|
||||||
return embed
|
return embed
|
||||||
|
|
@ -2236,6 +2246,17 @@ class CategoryActionView(discord.ui.View):
|
||||||
)
|
)
|
||||||
await interaction.response.edit_message(embed=embed, view=view)
|
await interaction.response.edit_message(embed=embed, view=view)
|
||||||
|
|
||||||
|
@discord.ui.button(label="📁 Catégorie Discord", style=discord.ButtonStyle.secondary)
|
||||||
|
async def discord_category_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
view = CategoryDiscordCategoryView(self.bot, self.storage, self.config, self.category, self)
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"Catégorie Discord: {self.category.name}",
|
||||||
|
description="Choisissez la catégorie Discord (dossier) dans laquelle les tickets de ce type seront créés.\n\n"
|
||||||
|
"Si aucune n'est sélectionnée, la catégorie par défaut du serveur sera utilisée.",
|
||||||
|
color=discord.Color.blue()
|
||||||
|
)
|
||||||
|
await interaction.response.edit_message(embed=embed, view=view)
|
||||||
|
|
||||||
@discord.ui.button(label="🗑️ Supprimer", style=discord.ButtonStyle.danger)
|
@discord.ui.button(label="🗑️ Supprimer", style=discord.ButtonStyle.danger)
|
||||||
async def delete_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
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)
|
view = DeleteCategoryConfirmationView(self.bot, self.storage, self.config, self.category, self.parent_view)
|
||||||
|
|
@ -2276,6 +2297,33 @@ class CategoryPermissionsView(discord.ui.View):
|
||||||
async def back_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
async def back_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
await interaction.response.edit_message(embed=self.parent_view._get_embed(), view=self.parent_view)
|
await interaction.response.edit_message(embed=self.parent_view._get_embed(), view=self.parent_view)
|
||||||
|
|
||||||
|
class CategoryDiscordCategoryView(discord.ui.View):
|
||||||
|
"""Vue pour configurer la catégorie Discord d'une catégorie de ticket"""
|
||||||
|
|
||||||
|
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.select(cls=discord.ui.ChannelSelect, channel_types=[discord.ChannelType.category], placeholder="Sélectionner la catégorie Discord")
|
||||||
|
async def select_callback(self, interaction: discord.Interaction, select: discord.ui.ChannelSelect):
|
||||||
|
self.category.discord_category_id = select.values[0].id
|
||||||
|
self.storage.save_config(interaction.guild_id, self.config)
|
||||||
|
await interaction.response.edit_message(embed=self.parent_view._get_embed(), view=self.parent_view)
|
||||||
|
|
||||||
|
@discord.ui.button(label="❌ Réinitialiser", style=discord.ButtonStyle.danger)
|
||||||
|
async def reset_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
self.category.discord_category_id = None
|
||||||
|
self.storage.save_config(interaction.guild_id, self.config)
|
||||||
|
await interaction.response.edit_message(embed=self.parent_view._get_embed(), view=self.parent_view)
|
||||||
|
|
||||||
|
@discord.ui.button(label="⬅️ Retour", style=discord.ButtonStyle.secondary)
|
||||||
|
async def back_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
await interaction.response.edit_message(embed=self.parent_view._get_embed(), view=self.parent_view)
|
||||||
|
|
||||||
|
|
||||||
class DeleteCategoryConfirmationView(discord.ui.View):
|
class DeleteCategoryConfirmationView(discord.ui.View):
|
||||||
def __init__(self, bot, storage, config, category, parent_view):
|
def __init__(self, bot, storage, config, category, parent_view):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,13 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"date": "2026-05-01T14:11:08.947818+00:00",
|
||||||
|
"trigger": "auto",
|
||||||
|
"serversCount": 1,
|
||||||
|
"membersCount": 12,
|
||||||
|
"guildName": "Omega Kube Bêta Test",
|
||||||
|
"errors": [],
|
||||||
|
"success": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"date": "2026-05-01T13:48:18.180388+00:00",
|
"date": "2026-05-01T13:48:18.180388+00:00",
|
||||||
"trigger": "auto",
|
"trigger": "auto",
|
||||||
|
|
@ -169,14 +178,5 @@
|
||||||
"guildName": "Omega Kube Bêta Test",
|
"guildName": "Omega Kube Bêta Test",
|
||||||
"errors": [],
|
"errors": [],
|
||||||
"success": true
|
"success": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"date": "2026-04-01T09:07:49.861748+00:00",
|
|
||||||
"trigger": "auto",
|
|
||||||
"serversCount": 1,
|
|
||||||
"membersCount": 12,
|
|
||||||
"guildName": "Omega Kube Bêta Test",
|
|
||||||
"errors": [],
|
|
||||||
"success": true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
Loading…
Add table
Add a link
Reference in a new issue