Merge branch 'dev' into 'main'
Nettoyage du repository See merge request Omega_Kube/kuby!2
This commit is contained in:
commit
d41339f196
22 changed files with 285 additions and 49268 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,10 +1,11 @@
|
|||
# Fichiers d'environnement (contiennent des tokens/clés sensibles)
|
||||
.env
|
||||
|
||||
# Fichiers de configuration générés
|
||||
config.json
|
||||
whitelist.json
|
||||
bridges.json
|
||||
config.db
|
||||
malware.json
|
||||
|
||||
# Cache Python
|
||||
__pycache__/
|
||||
|
|
@ -23,4 +24,5 @@ env/
|
|||
|
||||
# Logs
|
||||
*.Logs
|
||||
*.log
|
||||
.data
|
||||
|
|
|
|||
7
bot.py
7
bot.py
|
|
@ -132,6 +132,13 @@ class MyBot(commands.Bot):
|
|||
async def on_ready(self):
|
||||
kuby_logger.info(f"🤖 Bot connecté : {self.user} (ID : {self.user.id})")
|
||||
kuby_logger.info(f"📊 Serveurs : {len(self.guilds)}")
|
||||
|
||||
# Log intents status
|
||||
kuby_logger.info(f"🔍 Intents Status - Members: {self.intents.members}, Presences: {self.intents.presences}, Core: {self.intents.message_content}")
|
||||
|
||||
if not self.intents.members:
|
||||
kuby_logger.warning("⚠️ L'intent MEMBERS est désactivé ! Les événements de join/leave et les DMs pourraient ne pas fonctionner correctement.")
|
||||
|
||||
for guild in self.guilds:
|
||||
kuby_logger.debug(f"Guild: {guild.name} (ID: {guild.id}) - Members: {guild.member_count}")
|
||||
|
||||
|
|
|
|||
18
check_cols.py
Normal file
18
check_cols.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import sqlite3
|
||||
import os
|
||||
|
||||
db_path = "/home/gameurpro12/Documents/Mes_projets/Discord_bot/backup_kuby/config.db"
|
||||
if os.path.exists(db_path):
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
try:
|
||||
cursor.execute("SELECT * FROM server_configs LIMIT 1")
|
||||
col_names = [description[0] for description in cursor.description]
|
||||
print(f"Columns: {col_names}")
|
||||
row = cursor.fetchone()
|
||||
print(f"Data: {row}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
conn.close()
|
||||
else:
|
||||
print("Database not found")
|
||||
18
check_db.py
Normal file
18
check_db.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import sqlite3
|
||||
import os
|
||||
|
||||
db_path = "/home/gameurpro12/Documents/Mes_projets/Discord_bot/backup_kuby/config.db"
|
||||
if os.path.exists(db_path):
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
try:
|
||||
cursor.execute("SELECT * FROM server_configs")
|
||||
rows = cursor.fetchall()
|
||||
print(f"Server Configs ({len(rows)} rows):")
|
||||
for row in rows:
|
||||
print(row)
|
||||
except Exception as e:
|
||||
print(f"Error reading database: {e}")
|
||||
conn.close()
|
||||
else:
|
||||
print("Database not found")
|
||||
18
check_schema.py
Normal file
18
check_schema.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import sqlite3
|
||||
import os
|
||||
|
||||
db_path = "/home/gameurpro12/Documents/Mes_projets/Discord_bot/backup_kuby/config.db"
|
||||
if os.path.exists(db_path):
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
try:
|
||||
cursor.execute("PRAGMA table_info(server_configs)")
|
||||
rows = cursor.fetchall()
|
||||
print("Table Schema (server_configs):")
|
||||
for row in rows:
|
||||
print(row)
|
||||
except Exception as e:
|
||||
print(f"Error reading schema: {e}")
|
||||
conn.close()
|
||||
else:
|
||||
print("Database not found")
|
||||
|
|
@ -69,6 +69,43 @@ class BugReportModal(discord.ui.Modal, title="Signaler un Bug"):
|
|||
else:
|
||||
await interaction.edit_original_response(content="❌ Une erreur est survenue lors de l'envoi du rapport à GitLab. Veuillez contacter un administrateur.")
|
||||
|
||||
class FeatureSuggestionModal(discord.ui.Modal, title="Suggérer une fonctionnalité"):
|
||||
suggestion_title = discord.ui.TextInput(
|
||||
label="Titre de la suggestion",
|
||||
placeholder="Que voulez-vous ajouter ?",
|
||||
required=True,
|
||||
max_length=100
|
||||
)
|
||||
|
||||
description = discord.ui.TextInput(
|
||||
label="Détails de la fonctionnalité",
|
||||
style=discord.TextStyle.paragraph,
|
||||
placeholder="Décrivez comment cela devrait fonctionner...",
|
||||
required=True,
|
||||
max_length=1000
|
||||
)
|
||||
|
||||
async def on_submit(self, interaction: discord.Interaction):
|
||||
await interaction.response.send_message("Envoi de votre suggestion à GitLab...", ephemeral=True)
|
||||
|
||||
description_text = f"**Suggéré par:** {interaction.user} ({interaction.user.id})\n\n"
|
||||
description_text += f"**Description:**\n{self.description.value}"
|
||||
|
||||
labels = ["enhancement", "manual-suggestion"]
|
||||
|
||||
result = await gitlab_client.create_issue(
|
||||
title=f"[SUGGESTION] {self.suggestion_title.value}",
|
||||
description=description_text,
|
||||
labels=labels
|
||||
)
|
||||
|
||||
if result:
|
||||
issue_iid = result.get("iid")
|
||||
save_report(issue_iid, interaction.user.id)
|
||||
await interaction.edit_original_response(content=f"✅ Votre suggestion a été envoyée avec succès ! Merci de contribuer à l'amélioration du bot. [Voir l'issue]({result.get('web_url')})")
|
||||
else:
|
||||
await interaction.edit_original_response(content="❌ Une erreur est survenue lors de l'envoi de la suggestion à GitLab.")
|
||||
|
||||
class BugReport(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
|
@ -98,12 +135,17 @@ class BugReport(commands.Cog):
|
|||
user = self.bot.get_user(user_id)
|
||||
if user:
|
||||
try:
|
||||
is_suggestion = "[SUGGESTION]" in issue.get('title', '')
|
||||
title_type = "Suggestion Implémentée !" if is_suggestion else "🛠️ Bug Résolu !"
|
||||
msg_type = "suggestion" if is_suggestion else "bug"
|
||||
status_val = "Implémenté / Terminé" if is_suggestion else "Terminé / Résolu"
|
||||
|
||||
embed = discord.Embed(
|
||||
title="🛠️ Bug Résolu !",
|
||||
description=f"Bonne nouvelle ! Le bug que vous avez signalé (**{issue.get('title')}**) a été marqué comme terminé sur GitLab.",
|
||||
title=title_type,
|
||||
description=f"Bonne nouvelle ! Votre {msg_type} (**{issue.get('title')}**) a été marqué comme terminé sur GitLab.",
|
||||
color=discord.Color.green()
|
||||
)
|
||||
embed.add_field(name="Statut", value="Terminé / Résolu")
|
||||
embed.add_field(name="Statut", value=status_val)
|
||||
embed.add_field(name="Prochaine étape", value="La mise à jour arrive prochainement !")
|
||||
embed.set_footer(text="Merci de votre aide pour améliorer le bot.")
|
||||
await user.send(embed=embed)
|
||||
|
|
@ -133,5 +175,9 @@ class BugReport(commands.Cog):
|
|||
async def signaler_bug(self, interaction: discord.Interaction, priority: app_commands.Choice[str]):
|
||||
await interaction.response.send_modal(BugReportModal(priority))
|
||||
|
||||
@app_commands.command(name="suggerer_fonctionnalite", description="Proposer une nouvelle fonctionnalité pour le bot")
|
||||
async def suggerer_fonctionnalite(self, interaction: discord.Interaction):
|
||||
await interaction.response.send_modal(FeatureSuggestionModal())
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(BugReport(bot))
|
||||
|
|
|
|||
|
|
@ -12,6 +12,38 @@ class Goodbye(commands.Cog):
|
|||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.db_path = os.path.join(os.path.dirname(__file__), "..", "config.db")
|
||||
self._init_db()
|
||||
|
||||
def _init_db(self):
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
# On s'assure que la table existe au cas où (normalement gérée par welcome.py)
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS server_configs (
|
||||
server_id INTEGER PRIMARY KEY,
|
||||
welcome_channel INTEGER,
|
||||
goodbye_channel INTEGER,
|
||||
welcome_dm_message TEXT,
|
||||
welcome_server_name TEXT,
|
||||
welcome_banner_background TEXT,
|
||||
welcome_channel_message TEXT,
|
||||
goodbye_server_name TEXT,
|
||||
goodbye_message TEXT
|
||||
)
|
||||
''')
|
||||
|
||||
# Migration pour ajouter les colonnes si elles n'existent pas
|
||||
cursor.execute("PRAGMA table_info(server_configs)")
|
||||
columns = [col[1] for col in cursor.fetchall()]
|
||||
|
||||
if 'goodbye_server_name' not in columns:
|
||||
cursor.execute('ALTER TABLE server_configs ADD COLUMN goodbye_server_name TEXT')
|
||||
|
||||
if 'goodbye_message' not in columns:
|
||||
cursor.execute('ALTER TABLE server_configs ADD COLUMN goodbye_message TEXT')
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def humanize_time_delta(self, date):
|
||||
if date is None: return "date inconnue"
|
||||
|
|
@ -41,7 +73,7 @@ class Goodbye(commands.Cog):
|
|||
seconds = delta.seconds % 60
|
||||
return f"il y a {seconds} {'seconde' if seconds <= 1 else 'secondes'}"
|
||||
|
||||
async def create_goodbye_image(self, username, avatar_url):
|
||||
async def create_goodbye_image(self, username, avatar_url, server_name=None):
|
||||
current_dir = os.path.dirname(__file__)
|
||||
base_dir = os.path.abspath(os.path.join(current_dir, ".."))
|
||||
|
||||
|
|
@ -58,7 +90,10 @@ class Goodbye(commands.Cog):
|
|||
|
||||
draw.text((325, 70), "A Bientot", font=font_large, fill=(255,255,255))
|
||||
draw.text((325, 135), f"{username} chez", font=font_small, fill=(255,255,255))
|
||||
draw.text((325, 195), "OMEGA KUBE", font=font_large_omega, fill=(255,255,255))
|
||||
|
||||
# Afficher le nom du serveur personnalisé s'il existe, sinon OMEGA KUBE
|
||||
display_name = server_name if server_name else "OMEGA KUBE"
|
||||
draw.text((325, 195), display_name, font=font_large_omega, fill=(255,255,255))
|
||||
|
||||
avatar = Image.open(io.BytesIO(avatar_bytes)).convert("RGBA").resize((224, 224), Image.LANCZOS)
|
||||
mask = Image.new('L', avatar.size, 0)
|
||||
|
|
@ -75,35 +110,53 @@ class Goodbye(commands.Cog):
|
|||
async def on_member_remove(self, member):
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('SELECT goodbye_channel FROM server_configs WHERE server_id = ?', (member.guild.id,))
|
||||
cursor.execute('SELECT goodbye_channel, goodbye_server_name, goodbye_message FROM server_configs WHERE server_id = ?', (member.guild.id,))
|
||||
result = cursor.fetchone()
|
||||
conn.close()
|
||||
|
||||
if result and result[0]:
|
||||
channel = member.guild.get_channel(result[0])
|
||||
goodbye_channel = result[0]
|
||||
server_name = result[1]
|
||||
custom_message = result[2]
|
||||
|
||||
channel = member.guild.get_channel(goodbye_channel)
|
||||
if channel:
|
||||
img = await self.create_goodbye_image(member.name, member.avatar.url if member.avatar else member.default_avatar.url)
|
||||
img = await self.create_goodbye_image(
|
||||
member.name,
|
||||
member.avatar.url if member.avatar else member.default_avatar.url,
|
||||
server_name=server_name
|
||||
)
|
||||
joined_message = self.humanize_time_delta(member.joined_at)
|
||||
|
||||
# Utiliser le message personnalisé ou un par défaut
|
||||
description = custom_message if custom_message else "Nous espérons vous revoir bientôt <a:rain:1317973615714504806>"
|
||||
|
||||
embed = discord.Embed(title=f"{member} viens de nous quitter.",
|
||||
description="Nous espérons vous revoir bientôt <a:rain:1317973615714504806>",
|
||||
description=description,
|
||||
color=discord.Color.dark_magenta())
|
||||
embed.set_footer(text=f"Avait rejoint {joined_message}")
|
||||
embed.set_image(url="attachment://goodbye.png")
|
||||
await channel.send(embed=embed, file=discord.File(img, filename="goodbye.png"))
|
||||
|
||||
@app_commands.command(name="setgoodbye", description="Définit le salon d'aurevoir")
|
||||
@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)
|
||||
async def set_goodbye(self, interaction: discord.Interaction, channel: discord.TextChannel):
|
||||
async def set_goodbye(self, interaction: discord.Interaction, channel: discord.TextChannel, server_name: str = None, message: str = None):
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('''INSERT INTO server_configs (server_id, goodbye_channel)
|
||||
VALUES (?, ?) ON CONFLICT(server_id)
|
||||
DO UPDATE SET goodbye_channel=excluded.goodbye_channel''',
|
||||
(interaction.guild_id, channel.id))
|
||||
cursor.execute('''INSERT INTO server_configs (server_id, goodbye_channel, goodbye_server_name, goodbye_message)
|
||||
VALUES (?, ?, ?, ?) ON CONFLICT(server_id)
|
||||
DO UPDATE SET goodbye_channel=excluded.goodbye_channel,
|
||||
goodbye_server_name=COALESCE(excluded.goodbye_server_name, goodbye_server_name),
|
||||
goodbye_message=COALESCE(excluded.goodbye_message, goodbye_message)''',
|
||||
(interaction.guild_id, channel.id, server_name, message))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
await interaction.response.send_message(f"Salon d'aurevoir défini sur {channel.mention}", ephemeral=True)
|
||||
|
||||
msg = f"✅ Salon d'aurevoir défini sur {channel.mention}"
|
||||
if server_name: msg += f"\nNom du serveur: {server_name}"
|
||||
if message: msg += f"\nMessage: {message}"
|
||||
|
||||
await interaction.response.send_message(msg, ephemeral=True)
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(Goodbye(bot))
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
# Fix Plan: Missing _config_roles_callback method
|
||||
|
||||
## Problem
|
||||
The `TicketSetupView` class has a button that references `_config_roles_callback`, but this method doesn't exist. This causes an `AttributeError` when the `/ticketconfig` command is used.
|
||||
|
||||
## Solution
|
||||
1. Add `_config_roles_callback` method to `TicketSetupView` class
|
||||
2. Create `ConfigRolesSetupView` class to handle config roles selection
|
||||
|
||||
## Files to modify
|
||||
- `commandes/ticket/__init__.py`
|
||||
|
||||
## Changes
|
||||
1. Add `_config_roles_callback` method in `TicketSetupView` (after `_categories_callback`)
|
||||
2. Add `ConfigRolesSetupView` class (after `StaffRolesSetupView`)
|
||||
|
||||
## Status
|
||||
- [x] Add `_config_roles_callback` method
|
||||
- [x] Add `ConfigRolesSetupView` class
|
||||
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
# Ticket System Fixes - Implementation Status
|
||||
|
||||
## ✅ Completed Fixes
|
||||
|
||||
### 1. UI Synchronization Issue
|
||||
- **Problem**: TicketManagementView._claim_callback didn't update Discord UI after removing claim button
|
||||
- **Fix**: Added `await interaction.response.edit_message(view=self)` after view modification
|
||||
- **Status**: ✅ FIXED
|
||||
|
||||
### 2. Resource Leak and API Overload
|
||||
- **Problem**: @tasks.loop(seconds=30) on _register_views caused rate limits and memory consumption
|
||||
- **Fix**: Moved view registration to cog_load() method, removed looped task
|
||||
- **Status**: ✅ FIXED
|
||||
|
||||
### 3. Permission Logic in _reopen_callback
|
||||
- **Problem**: Loop overwrote permissions for all members instead of targeting ticket.user_id
|
||||
- **Fix**: Modified logic to specifically restore send_messages permission for ticket.user_id only
|
||||
- **Status**: ✅ FIXED
|
||||
|
||||
### 4. Missing Error Handling in Modals
|
||||
- **Problem**: TicketPriorityModal and CloseTicketModal lacked on_error methods
|
||||
- **Fix**: Added try/except blocks in on_submit and implemented on_error methods
|
||||
- **Status**: ✅ FIXED
|
||||
|
||||
### 5. Input Validation in StaffRolesModal
|
||||
- **Problem**: Regex (\d{17,20}) was too permissive, didn't validate role existence
|
||||
- **Fix**: Added validation to check if extracted role IDs correspond to existing guild roles
|
||||
- **Status**: ✅ FIXED
|
||||
|
||||
### 6. Circular Import Risk
|
||||
- **Problem**: Local imports suggested potential circular dependencies
|
||||
- **Fix**: Verified models.py doesn't import from __init__.py - no circular import exists
|
||||
- **Status**: ✅ VERIFIED (No fix needed)
|
||||
|
||||
## 🧪 Testing Recommendations
|
||||
|
||||
1. **UI Updates**: Test ticket claiming - UI should update immediately after claiming
|
||||
2. **Performance**: Monitor API usage - should be significantly reduced
|
||||
3. **Permissions**: Test ticket reopening - only ticket creator should regain send_messages
|
||||
4. **Error Handling**: Trigger errors in modals to verify graceful failure
|
||||
5. **Role Validation**: Try invalid role IDs in staff configuration
|
||||
6. **Import Safety**: Verify no import errors on bot startup
|
||||
|
||||
## 📋 Files Modified
|
||||
- `commandes/ticket/__init__.py`: All fixes applied
|
||||
- `commandes/ticket/data/models.py`: Verified for circular imports (none found)
|
||||
|
||||
## 🎯 Impact
|
||||
- Improved user experience with immediate UI updates
|
||||
- Reduced API load and memory usage
|
||||
- Enhanced security with proper permission handling
|
||||
- Better error resilience
|
||||
- More robust input validation
|
||||
- Maintained clean architecture
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
# Ticket Close Confirmation and Delay - Implementation Plan
|
||||
|
||||
## Objective
|
||||
Add confirmation dialog and waiting delay before ticket closure.
|
||||
|
||||
## Changes to make
|
||||
|
||||
### 1. Create `CloseConfirmationView` class
|
||||
- Yes/No confirmation buttons
|
||||
- Cancel option
|
||||
- Shows before closing
|
||||
|
||||
### 2. Create `CloseDelayView` class
|
||||
- Countdown display (5 seconds)
|
||||
- Progress steps:
|
||||
- 📄 Génération du transcript...
|
||||
- 📝 Sauvegarde des données...
|
||||
- 🗑️ Suppression du canal...
|
||||
- Cancel option during delay
|
||||
|
||||
### 3. Modify `TicketManagementView._close_callback`
|
||||
- Show confirmation view first
|
||||
- After Yes, show delay view with countdown
|
||||
- After delay completes, proceed with closing
|
||||
|
||||
## Files to modify
|
||||
- `commandes/ticket/__init__.py`
|
||||
|
||||
## Status
|
||||
- [x] Add CloseConfirmationView class ✅
|
||||
- [x] Add CloseDelayView class ✅
|
||||
- [x] Modify TicketManagementView._close_callback ✅
|
||||
- [x] Add cancel button to CloseDelayView ✅
|
||||
- [x] Test the flow ✅
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### CloseConfirmationView
|
||||
```python
|
||||
class CloseConfirmationView(discord.ui.View):
|
||||
"""Confirmation dialog before closing ticket"""
|
||||
|
||||
def __init__(self, bot, storage, config, ticket):
|
||||
super().__init__(timeout=60)
|
||||
# Yes button (green)
|
||||
# No button (red) - cancels and removes message
|
||||
```
|
||||
|
||||
### CloseDelayView
|
||||
```python
|
||||
class CloseDelayView(discord.ui.View):
|
||||
"""Countdown and progress before ticket deletion"""
|
||||
|
||||
def __init__(self, bot, storage, config, ticket, close_reason):
|
||||
super().__init__(timeout=None)
|
||||
# Disable all buttons during countdown
|
||||
# Update embed with countdown
|
||||
# After delay, call actual close function
|
||||
```
|
||||
|
||||
## Flow
|
||||
1. User clicks "Fermer"
|
||||
2. Show confirmation embed with Yes/No buttons
|
||||
3. If Yes → Show delay view with countdown
|
||||
4. After delay → Close ticket and delete channel
|
||||
5. If No or timeout → Remove confirmation message
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
# TODO - Correction du système de tickets pour les rôles staff/config
|
||||
|
||||
## Problème
|
||||
Les utilisateurs avec les rôles staff et config ne peuvent pas interagir avec le système de tickets.
|
||||
|
||||
## Cause
|
||||
La méthode `_is_whitelisted` retourne `False` quand le cog WhitelistMonitor n'est pas disponible, les utilisateurs bloquant même staff/config.
|
||||
|
||||
## Plan de correction
|
||||
|
||||
### Étape 1: Corriger TicketPanelView._is_whitelisted()
|
||||
- [ ] Modifier pour que les rôles staff/config soient toujours autorisés
|
||||
|
||||
### Étape 2: Corriger CategorySelectionView._is_whitelisted()
|
||||
- [ ] Modifier pour que les rôles staff/config soient toujours autorisés
|
||||
|
||||
### Étape 3: Vérifier les autres vues
|
||||
- [ ] Vérifier TicketManagementView._is_staff()
|
||||
|
||||
## État d'avancement
|
||||
- [x] TicketPanelView._is_whitelisted() corrigé
|
||||
- [x] CategorySelectionView._is_whitelisted() corrigé
|
||||
- [x] Tests de vérification
|
||||
|
|
@ -8,6 +8,8 @@ import os
|
|||
import logging
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
kuby_logger = logging.getLogger("KubyBot")
|
||||
|
||||
class Welcome(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
|
@ -42,6 +44,15 @@ class Welcome(commands.Cog):
|
|||
if 'welcome_channel_message' not in columns:
|
||||
cursor.execute('ALTER TABLE server_configs ADD COLUMN welcome_channel_message TEXT')
|
||||
|
||||
# Migration: Conversion des chemins absolus en chemins relatifs pour les bannières
|
||||
cursor.execute("SELECT server_id, welcome_banner_background FROM server_configs WHERE welcome_banner_background IS NOT NULL")
|
||||
for server_id, path in cursor.fetchall():
|
||||
if path and os.path.isabs(path):
|
||||
filename = os.path.basename(path)
|
||||
# Vérifier si c'est bien une bannière dans le dossier banners
|
||||
if "banner_" in filename:
|
||||
cursor.execute("UPDATE server_configs SET welcome_banner_background = ? WHERE server_id = ?", (filename, server_id))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
|
@ -55,8 +66,19 @@ class Welcome(commands.Cog):
|
|||
avatar_bytes = await resp.read()
|
||||
|
||||
# Utiliser le fond personnalisé ou celui par défaut
|
||||
if banner_background and os.path.exists(banner_background):
|
||||
background = Image.open(banner_background)
|
||||
bg_path = None
|
||||
if banner_background:
|
||||
# Si c'est un chemin absolu (pour compatibilité temporaire)
|
||||
if os.path.isabs(banner_background) and os.path.exists(banner_background):
|
||||
bg_path = banner_background
|
||||
else:
|
||||
# Sinon 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.png'))
|
||||
|
||||
|
|
@ -89,30 +111,47 @@ class Welcome(commands.Cog):
|
|||
|
||||
@commands.Cog.listener()
|
||||
async def on_member_join(self, member):
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('SELECT welcome_channel, welcome_dm_message, welcome_server_name, welcome_banner_background, welcome_channel_message FROM server_configs WHERE server_id = ?', (member.guild.id,))
|
||||
result = cursor.fetchone()
|
||||
conn.close()
|
||||
kuby_logger.info(f"📥 [Welcome] Événement on_member_join reçu pour {member.name} (ID: {member.id}) sur {member.guild.name}")
|
||||
|
||||
welcome_channel = result[0] if result else None
|
||||
welcome_dm_text = result[1] if result and result[1] else None
|
||||
server_name = result[2] if result and result[2] else None
|
||||
banner_background = result[3] if result and result[3] else None
|
||||
welcome_channel_message = result[4] if result and result[4] else None
|
||||
try:
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('SELECT welcome_channel, welcome_dm_message, welcome_server_name, welcome_banner_background, welcome_channel_message FROM server_configs WHERE server_id = ?', (member.guild.id,))
|
||||
result = cursor.fetchone()
|
||||
conn.close()
|
||||
|
||||
# 1. Gestion du DM
|
||||
if welcome_dm_text:
|
||||
try:
|
||||
formatted_message = welcome_dm_text.format(
|
||||
username=member.name,
|
||||
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")
|
||||
except Exception as e:
|
||||
logging.warning(f"Impossible d'envoyer le DM à {member.name}: {e}")
|
||||
if not result:
|
||||
kuby_logger.warning(f"⚠️ [Welcome] Aucune configuration trouvée dans la base de données pour le serveur {member.guild.id}")
|
||||
return
|
||||
|
||||
welcome_channel = result[0]
|
||||
welcome_dm_text = result[1]
|
||||
server_name = result[2]
|
||||
banner_background = result[3]
|
||||
welcome_channel_message = result[4]
|
||||
|
||||
kuby_logger.debug(f"🔍 [Welcome] Config récupérée: DM={bool(welcome_dm_text)}, Channel={welcome_channel}")
|
||||
|
||||
# 1. Gestion du DM
|
||||
if welcome_dm_text:
|
||||
kuby_logger.info(f"✉️ [Welcome] Tentative d'envoi de DM à {member.name}")
|
||||
try:
|
||||
formatted_message = welcome_dm_text.format(
|
||||
username=member.name,
|
||||
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}")
|
||||
except discord.Forbidden:
|
||||
kuby_logger.warning(f"🚫 [Welcome] Impossible d'envoyer le DM à {member.name} (DMs fermés)")
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"❌ [Welcome] Erreur lors de l'envoi du DM à {member.name}: {e}", exc_info=True)
|
||||
else:
|
||||
kuby_logger.info(f"ℹ️ [Welcome] Aucun message de DM configuré pour le serveur {member.guild.id}")
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"❌ [Welcome] Erreur critique dans on_member_join: {e}", exc_info=True)
|
||||
|
||||
# 2. Gestion du salon de bienvenue
|
||||
if welcome_channel:
|
||||
|
|
@ -168,7 +207,7 @@ class Welcome(commands.Cog):
|
|||
with open(banner_path, 'wb') as f:
|
||||
f.write(img_data)
|
||||
|
||||
return banner_path
|
||||
return os.path.basename(banner_path)
|
||||
|
||||
@app_commands.command(name="setwelcome", description="Définit le salon, les messages de bienvenue et le fond de la bannière")
|
||||
@app_commands.checks.has_permissions(administrator=True)
|
||||
|
|
|
|||
BIN
config.db
BIN
config.db
Binary file not shown.
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"4": 971446412690722826,
|
||||
"5": 971446412690722826,
|
||||
"11": 971446412690722826
|
||||
"15": 971446412690722826
|
||||
}
|
||||
24
data/logs/member_events_2026-02-08.json
Normal file
24
data/logs/member_events_2026-02-08.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
16
data/member_logs/1470008249322438678.json
Normal file
16
data/member_logs/1470008249322438678.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
44
debug.log
44
debug.log
|
|
@ -1,44 +0,0 @@
|
|||
nohup: les entrées sont ignorées
|
||||
[2026-01-16 18:41:19] [DEBUG] [KubyBot] [debug:50] Raw APPLICATION_ID: 1390778748097527808
|
||||
[2026-01-16 18:41:19] [INFO] [KubyBot] [info:53] ✅ APPLICATION_ID loaded successfully: 1390778748097527808
|
||||
[2026-01-16 18:41:19] [DEBUG] [KubyBot] [debug:50] Discord intents configured: <Intents value=53608191>
|
||||
[2026-01-16 18:41:19] [DEBUG] [KubyBot] [debug:50] Initializing MyBot class
|
||||
[2026-01-16 18:41:19] [INFO] [KubyBot] [info:53] MyBot instance created successfully
|
||||
[2026-01-16 18:41:19] [INFO] [KubyBot] [info:53] 🚀 Lancement du bot Kuby...
|
||||
[2026-01-16 18:41:19] [DEBUG] [KubyBot] [debug:50] Starting __main__.py execution
|
||||
[2026-01-16 18:41:19] [INFO] [KubyBot] [info:53] 📋 Chargement des variables d'environnement...
|
||||
[2026-01-16 18:41:19] [DEBUG] [KubyBot] [debug:50] Environment variables loaded
|
||||
[2026-01-16 18:41:19] [DEBUG] [KubyBot] [debug:50] Token retrieved from environment: ***
|
||||
[2026-01-16 18:41:19] [INFO] [KubyBot] [info:53] ✅ Token Discord chargé avec succès
|
||||
[2026-01-16 18:41:19] [INFO] [KubyBot] [info:53] 🚀 Lancement du bot Kuby...
|
||||
[2026-01-16 18:41:19] [DEBUG] [KubyBot] [debug:50] Entering main with args: (), kwargs: {}
|
||||
[2026-01-16 18:41:19] [INFO] [KubyBot] [info:53] 🔄 Démarrage de la connexion Discord...
|
||||
[2026-01-16 18:41:19] [DEBUG] [KubyBot] [debug:50] Starting async context manager
|
||||
[2026-01-16 18:41:19] [INFO] [KubyBot] [info:53] 🔗 Connexion établie avec Discord...
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] 🚀 Démarrage du bot Kuby...
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Advanced logger initialized
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.whitelist
|
||||
[WhitelistMonitor] Persistent view registered
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.whitelist_monitor
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.sendbotmessages
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.goodbye
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.welcome
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.security
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.snipe
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.scan
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.no_link
|
||||
[Blacklist] 0 vues de tickets enregistrées
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.blacklist
|
||||
[Ticket] Views registered for guild 1369669999345537145
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.ticket
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.modules_security.antispam
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.modules_security.antiraid
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.modules_security.logs_manager
|
||||
[Rules] View registered for guild 1369669999345537145
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Extension chargée : commandes.modules_security.rules
|
||||
[2026-01-16 18:41:20] [INFO] [KubyBot] [info:53] ✅ Commandes slash synchronisées avec Discord
|
||||
[2026-01-16 18:41:22] [INFO] [KubyBot] [info:53] 🤖 Bot connecté : Kuby Alpha#6731 (ID : 1390778748097527808)
|
||||
[2026-01-16 18:41:22] [INFO] [KubyBot] [info:53] 📊 Serveurs : 1
|
||||
[2026-01-16 18:41:22] [DEBUG] [KubyBot] [debug:50] Guild: Omega Kube Bêta Test (ID: 1369669999345537145) - Members: 19
|
||||
[2026-01-16 18:41:22] [INFO] [KubyBot] [info:53] 📊 Total members across all guilds: 19
|
||||
[2026-01-16 18:41:22] [INFO] [KubyBot] [info:53] ✅ Bot prêt et opérationnel !
|
||||
17745
kuby_audit.log
17745
kuby_audit.log
File diff suppressed because it is too large
Load diff
9708
kuby_errors.log
9708
kuby_errors.log
File diff suppressed because it is too large
Load diff
21562
kuby_logs.log
21562
kuby_logs.log
File diff suppressed because it is too large
Load diff
|
|
@ -1 +0,0 @@
|
|||
[]
|
||||
Loading…
Add table
Add a link
Reference in a new issue