Ajout de la monétisation V0.1

This commit is contained in:
Mathis 2026-07-06 16:08:14 +02:00
parent cd0fc4c488
commit 879355f792
29 changed files with 698 additions and 72 deletions

View file

@ -9,6 +9,7 @@ try:
except ImportError:
from backports.zoneinfo import ZoneInfo
from typing import Optional, Dict, Any
from utils.premium import check_premium_tier
PARIS_TZ = ZoneInfo("Europe/Paris")
DATE_FORMAT = "%d/%m/%Y %H:%M"
@ -259,12 +260,14 @@ class Absence(commands.Cog):
self.check_absences.start()
@commands.slash_command(name="absence", description="Déclarer une absence staff")
@check_premium_tier()
async def absence(self, interaction: disnake.ApplicationCommandInteraction,
superieur: Optional[disnake.Member] = commands.Param(None, description="Le supérieur hiérarchique à prévenir")):
"""Déclare une absence via un formulaire"""
await interaction.response.send_modal(AbsenceModal(superieur))
@commands.slash_command(name="absence_config", description="Configurer le système d'absence (Admin)")
@check_premium_tier()
@commands.has_permissions(administrator=True)
async def absence_config(self, interaction: disnake.ApplicationCommandInteraction):
"""Ouvre le panneau de configuration des absences"""
@ -350,6 +353,7 @@ class Absence(commands.Cog):
print(f"Erreur lors du barrage du message d'absence: {e}")
@commands.slash_command(name="fin_absence", description="Terminer son absence staff")
@check_premium_tier()
async def fin_absence(self, interaction: disnake.ApplicationCommandInteraction):
"""Met fin à l'absence en cours"""
all_abs = await load_absences()
@ -382,6 +386,7 @@ class Absence(commands.Cog):
await interaction.response.send_message("✅ Ton absence a été retirée.", ephemeral=True)
@commands.slash_command(name="liste_absences", description="Afficher la liste des absences staff en cours")
@check_premium_tier()
async def liste_absences(self, interaction: disnake.ApplicationCommandInteraction):
"""Affiche les absences en cours sur le serveur"""
all_abs = await load_absences()

View file

@ -9,6 +9,7 @@ from typing import Dict, Any, List
import disnake
from disnake.ext import commands
from utils.premium import check_premium_tier
BACKUPS_ROOT = "data/security_backups" # dossier de sortie des sauvegardes
@ -64,6 +65,7 @@ class Backup(commands.Cog):
self.bot = bot
@commands.slash_command(name="backup", description="Outils de sauvegarde du serveur")
@check_premium_tier()
async def backup_group(self, interaction: disnake.ApplicationCommandInteraction):
pass

View file

@ -7,6 +7,7 @@ import shutil
from typing import List
import disnake
from disnake.ext import commands
from utils.premium import check_premium_tier
BACKUPS_ROOT = "data/security_backups"
@ -133,6 +134,7 @@ class BackupRestore(commands.Cog):
await channel.send(msg["content"])
@commands.slash_command(name="granulaire", description="Restaure un élément précis d'une sauvegarde")
@check_premium_tier()
async def restore_granulaire(
self,
interaction: disnake.ApplicationCommandInteraction,

View file

@ -4,6 +4,7 @@ import json
import os
import asyncio
from datetime import datetime, timedelta
from utils.premium import check_premium_tier
BLACKLIST_FILE = "data/blacklist.json"
AGENTS_FILE = "data/agents.json"
@ -57,6 +58,7 @@ class Blacklist(commands.Cog):
return str(user_id) in agents["agents"]
@commands.slash_command(name="blacklist", description="Blacklist un utilisateur")
@check_premium_tier()
async def blacklist(self, interaction: disnake.ApplicationCommandInteraction, user: disnake.User, reason: str = "Aucune raison fournie"):
if not self.is_agent(interaction.user.id):
return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True)
@ -122,6 +124,7 @@ class Blacklist(commands.Cog):
)
@commands.slash_command(name="unblacklist", description="Retirer un utilisateur de la blacklist")
@check_premium_tier()
async def unblacklist(self, interaction: disnake.ApplicationCommandInteraction, user: disnake.User):
if not self.is_agent(interaction.user.id):
return await interaction.response.send_message("⛔ Tu nas pas la permission.", ephemeral=True)

View file

@ -7,6 +7,7 @@ import json
import os
import asyncio
from typing import Dict, Any, Optional
from utils.premium import check_premium_tier
kuby_logger = logging.getLogger("KubyBot")
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -373,11 +374,13 @@ class BugReport(commands.Cog):
return web.json_response({"status": "error", "message": str(e)}, status=500)
@commands.slash_command(name="signaler_bug", description="Signaler un bug aux développeurs")
@check_premium_tier()
async def signifier_bug(self, interaction: disnake.ApplicationCommandInteraction):
modal = BugReportModal(self)
await interaction.response.send_modal(modal)
@commands.slash_command(name="suggerer_fonctionnalite", description="Proposer une nouvelle fonctionnalité")
@check_premium_tier()
async def suggerer_fonctionnalite(self, interaction: disnake.ApplicationCommandInteraction):
modal = FeatureSuggestionModal(self)
await interaction.response.send_modal(modal)

View file

@ -6,6 +6,7 @@ from typing import List, Optional, Dict
import datetime
import asyncio
import logging
from utils.premium import check_premium_tier
kuby_logger = logging.getLogger("KubyBot")
@ -61,6 +62,7 @@ class Convocation(commands.Cog):
save_json(CONV_BACKUPS_FILE, self.backups)
@commands.slash_command(name="convocation", description="Gère les convocations de membres")
@check_premium_tier()
@commands.has_permissions(manage_roles=True)
async def convocation_group(self, interaction: disnake.ApplicationCommandInteraction):
pass

View file

@ -7,6 +7,7 @@ import os
import logging
from PIL import Image, ImageDraw, ImageFont
from datetime import datetime, timezone
from utils.premium import check_premium_tier
kuby_logger = logging.getLogger("KubyBot")
@ -285,6 +286,7 @@ class Goodbye(commands.Cog):
return os.path.basename(banner_path)
@commands.slash_command(name="setgoodbye", description="Définit le salon d'au revoir et les paramètres personnalisés")
@check_premium_tier()
@commands.has_permissions(administrator=True)
async def set_goodbye(self, interaction: disnake.ApplicationCommandInteraction, channel: disnake.TextChannel, server_name: str = None, message: str = None, banner_file: disnake.Attachment = None):
# ✅ DÉFÉRER LA RÉPONSE (le traitement peut prendre > 3s avec les images)

View file

@ -5,6 +5,7 @@ import os
import logging
from typing import Dict, Optional
import asyncio
from utils.premium import check_premium_tier
kuby_logger = logging.getLogger("KubyBot")
@ -234,6 +235,7 @@ class Invites(commands.Cog):
kuby_logger.error(f"[Invites] Erreur lors de la suppression de l'enregistrement de l'invitation pour {user.name}: {e}")
@commands.slash_command(name="setinvitechannel", description="Définit le salon des logs d'invitations")
@check_premium_tier()
@commands.has_permissions(administrator=True)
async def set_invite_channel(self, interaction: disnake.ApplicationCommandInteraction, channel: disnake.TextChannel):
try:

View file

@ -5,6 +5,7 @@ import os
from datetime import datetime, timedelta
import re
from src.logger import kuby_logger
from utils.premium import check_premium_tier
class ModReasonModal(disnake.ui.Modal):
def __init__(self, cog, action_type, member):
@ -254,6 +255,7 @@ class Moderation(commands.Cog):
await interaction.response.send_message(components=components, ephemeral=True)
@commands.slash_command(name="modpanel", description="Ouvre le panel de modération")
@check_premium_tier()
@commands.has_permissions(moderate_members=True)
async def modpanel(self, interaction: disnake.ApplicationCommandInteraction, member: disnake.Member):
if member.top_role >= interaction.user.top_role and interaction.user.id != interaction.guild.owner_id:
@ -291,6 +293,7 @@ class Moderation(commands.Cog):
await interaction.response.send_message(components=components, ephemeral=True)
@commands.slash_command(name="sanctions", description="Voir l'historique des sanctions d'un membre")
@check_premium_tier()
@commands.has_permissions(moderate_members=True)
async def sanctions(self, interaction: disnake.ApplicationCommandInteraction, member: disnake.Member):
conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
@ -316,6 +319,7 @@ class Moderation(commands.Cog):
await interaction.response.send_message(components=components, ephemeral=True)
@commands.slash_command(name="modconfig", description="Configuration de la modération")
@check_premium_tier()
@commands.has_permissions(administrator=True)
async def modconfig(self, interaction: disnake.ApplicationCommandInteraction):
conn = sqlite3.connect(self.db_path); cursor = conn.cursor()

View file

@ -10,6 +10,7 @@ except ImportError:
import disnake
from disnake.ext import commands, tasks
from utils.premium import check_premium_tier
kuby_logger = logging.getLogger("KubyBot")
PARIS_TZ = ZoneInfo("Europe/Paris")
@ -906,6 +907,7 @@ class Rapports(commands.Cog):
await self.bot.wait_until_ready()
@commands.slash_command(name="config-system", description="Configuration du module de rapports (Admin uniquement)")
@check_premium_tier()
@commands.has_permissions(administrator=True)
async def config_system(self, interaction: disnake.ApplicationCommandInteraction, role_viewer: disnake.Role = None):
guild_id = interaction.guild.id
@ -938,10 +940,12 @@ class Rapports(commands.Cog):
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
@commands.slash_command(name="rapport", description="Ouvrir le formulaire de saisie de rapport")
@check_premium_tier()
async def rapport(self, interaction: disnake.ApplicationCommandInteraction):
await interaction.response.send_modal(ReportModal(self))
@commands.slash_command(name="consulter_rapport", description="Consulter les rapports du serveur via une interface interactive")
@check_premium_tier()
async def consulter_rapport(
self,
interaction: disnake.ApplicationCommandInteraction,

View file

@ -5,6 +5,7 @@ import hashlib
import os
import json
import re
from utils.premium import check_premium_tier
MALWARE_DB = "malware.json"
SUSPICIOUS_EXTENSIONS = [".exe", ".scr", ".bat", ".js", ".vbs", ".cmd"]
@ -59,6 +60,7 @@ class Scan(commands.Cog):
self.bot = bot
@commands.slash_command(name="scan", description="Scanner un fichier pour détecter un malware.")
@check_premium_tier()
async def scan(self, interaction: disnake.ApplicationCommandInteraction, file: disnake.Attachment):
await interaction.response.defer() # Permet de prendre un peu de temps pour le scan

View file

@ -3,6 +3,7 @@ from disnake.ext import commands
import json
import os
from typing import Optional
from utils.premium import check_premium_tier
# Chemins ABSOLUS des fichiers (basés sur le fichier courant)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@ -1029,6 +1030,7 @@ class Security(commands.Cog):
name="security",
description="🛡️ Ouvrir le panneau de sécurité Kuby"
)
@check_premium_tier()
async def security(self, interaction: disnake.ApplicationCommandInteraction):
"""
Commande principale pour ouvrir l'interface de sécurité.

View file

@ -1,5 +1,6 @@
import disnake
from disnake.ext import commands
from utils.premium import check_premium_tier
OWNER_ID = 971446412690722826
@ -124,6 +125,7 @@ class SentBotMessages(commands.Cog):
name="sentbotmessages",
description="Le bot envoie un message dans un salon choisi."
)
@check_premium_tier()
async def sentbotmessages(
self,
interaction: disnake.ApplicationCommandInteraction,
@ -154,6 +156,7 @@ class SentBotMessages(commands.Cog):
name="annonce_proprietaires",
description="Ouvrir le formulaire d'annonce pour les propriétaires."
)
@check_premium_tier()
@commands.check(is_authorized)
async def annonce_proprietaires(
self,

View file

@ -2,6 +2,7 @@ import disnake
from disnake.ext import commands
from datetime import datetime
from collections import deque
from utils.premium import check_premium_tier
class SnipeCommands(commands.Cog):
def __init__(self, bot):
@ -34,6 +35,7 @@ class SnipeCommands(commands.Cog):
self.deleted_messages[channel_id].appendleft(message_data)
@commands.slash_command(name="snipe", description="Voir les derniers messages supprimés d'un salon")
@check_premium_tier()
async def snipe(self, interaction: disnake.ApplicationCommandInteraction,
nombre: int = commands.Param(1, description="Nombre de messages à afficher (1-10, par défaut: 1)")):
"""Retrieve deleted messages from the current channel"""
@ -93,6 +95,7 @@ class SnipeCommands(commands.Cog):
await interaction.response.send_message(embed=embed)
@commands.slash_command(name="snipeclear", description="Effacer l'historique des messages supprimés pour ce salon")
@check_premium_tier()
async def snipeclear(self, interaction: disnake.ApplicationCommandInteraction):
"""Clear the deleted messages history for the current channel"""
channel_id = interaction.channel.id

View file

@ -4,6 +4,7 @@ from datetime import datetime
from commandes.ticket.data.storage import get_storage
from commandes.ticket.staff_analytics import StaffAnalytics
from utils.premium import check_premium_tier
class StaffLeaderboard(commands.Cog):
@ -11,6 +12,7 @@ class StaffLeaderboard(commands.Cog):
self.bot = bot
@commands.slash_command(name="staff-leaderboard", description="Affiche le classement du staff")
@check_premium_tier()
async def staff_leaderboard(self, interaction: disnake.ApplicationCommandInteraction):
"""Commande pour afficher le classement du staff"""
await interaction.response.defer(ephemeral=False)

View file

@ -12,6 +12,7 @@ from collections import defaultdict
from commandes.ticket.data.storage import get_storage
from commandes.ticket.data.models import TicketStatus
from commandes.ticket.staff_analytics import StaffAnalytics
from utils.premium import check_premium_tier
class StaffRatings(commands.Cog):
@ -19,6 +20,7 @@ class StaffRatings(commands.Cog):
self.bot = bot
@commands.slash_command(name="staff-ratings", description="Affiche les évaluations du staff")
@check_premium_tier()
async def staff_ratings(self, interaction: disnake.ApplicationCommandInteraction,
team: str = commands.Param(None, description="Filtrer par équipe (optionnel)")):
"""Commande pour afficher les évaluations du staff"""

View file

@ -18,6 +18,7 @@ from utils.gestion_taches import (
PRIORITES, STATUTS
)
from src.logger import kuby_logger
from utils.premium import check_premium_tier
# ============================================================================
@ -655,6 +656,7 @@ class TachesCog(commands.Cog):
# ==========================================================================
@commands.slash_command(name="taches", description="Ouvrir le menu de gestion des tâches")
@check_premium_tier()
async def taches_command(self, inter: disnake.ApplicationCommandInteraction):
"""Commande principale pour accéder au menu des tâches."""
settings = await get_taches_settings(inter.guild.id)

View file

@ -162,6 +162,7 @@ class TeamJSON(commands.Cog):
name="generate_team_json",
description="Génère le JSON de l'équipe (admin only)"
)
@check_premium_tier()
@commands.has_permissions(administrator=True)
async def generate_team_json(self, inter: disnake.ApplicationCommandInteraction):
"""Commande manuelle pour (re)générer le JSON et les avatars."""

View file

@ -38,6 +38,7 @@ from .utils.formatters import TicketEmbedFormatter
from .staff_analytics import StaffAnalytics, StaffStatsView
from .utils.permissions import is_staff, is_whitelisted, can_access_config
from src.logger import kuby_logger
from utils.premium import check_premium_tier
# V2 RICH COMPONENTS LOADED - 14:10
kuby_logger.info("🎫 [TicketSystem] Chargement de la version V2 Rich Components...")
@ -3951,15 +3952,18 @@ class TicketCommands(commands.Cog):
await inter.followup.send("❌ Erreur lors de la decision de recrutement.", ephemeral=True)
# === COMMANDES ===
@commands.slash_command(name="ticket", description="Ouvre le panel des tickets")
@check_premium_tier()
async def ticket_main(self, inter: disnake.ApplicationCommandInteraction):
"""Ouvre le panel des tickets"""
config = self.storage.load_config(inter.guild.id)
view = TicketPanelView(self.bot, config, self.storage)
await inter.response.send_message(components=view.get_components_v2(), ephemeral=True)
@commands.slash_command(name="ticketpanel", description="Envoie le panel de création de tickets dans un canal")
@check_premium_tier()
@commands.has_permissions(administrator=True)
async def ticket_panel(self, inter: disnake.ApplicationCommandInteraction, channel: disnake.TextChannel = None):
"""Envoie le panel de création de tickets dans un canal"""
@ -3983,6 +3987,7 @@ class TicketCommands(commands.Cog):
await inter.edit_original_response(content=f"Panel envoyé dans {target.mention}")
@commands.slash_command(name="ticketconfig", description="Ouvre le panel de configuration complet du système de tickets")
@check_premium_tier()
async def ticket_config(self, inter: disnake.ApplicationCommandInteraction):
"""Ouvre le panel de configuration complet du système de tickets"""
await inter.response.defer(ephemeral=True)

View file

@ -9,6 +9,7 @@ from typing import Optional
from src.logger import kuby_logger
import time
from datetime import datetime, timezone
from utils.premium import check_premium_tier
# Dictionnaire global pour suivre les renommages de salons
# Format: {channel_id: [timestamp1, timestamp2, ...]}
@ -1586,6 +1587,7 @@ class Ticket(commands.Cog):
self.bot.add_view(ClosedTicketView())
@commands.slash_command(name="ticket_whitelist", description="Envoie l'embed pour ouvrir un ticket de whitelist.")
@check_premium_tier()
async def ticket_whitelist(self, interaction: disnake.ApplicationCommandInteraction):
"""Envoie l'embed avec le bouton d'ouverture de ticket"""
if not is_staff_or_admin(interaction.user, interaction.guild):
@ -1601,6 +1603,7 @@ class Ticket(commands.Cog):
await interaction.response.send_message("✅ Embed des tickets envoyé.", ephemeral=True)
@commands.slash_command(name="ticket_whitelist_config", description="Configurer le système de tickets whitelist (Staff/Admin)")
@check_premium_tier()
async def ticket_whitelist_config(self, interaction: disnake.ApplicationCommandInteraction):
"""Interface de configuration des tickets en Containers V2"""
if not is_staff_or_admin(interaction.user, interaction.guild):

View file

@ -7,6 +7,7 @@ import os
import logging
import asyncio
from PIL import Image, ImageDraw, ImageFont
from utils.premium import check_premium_tier
kuby_logger = logging.getLogger("KubyBot")
@ -345,6 +346,7 @@ class Welcome(commands.Cog):
return os.path.basename(banner_path)
@commands.slash_command(name="setwelcome", description="Définit le salon, les messages de bienvenue et le fond de la bannière")
@check_premium_tier()
@commands.has_permissions(administrator=True)
async def set_welcome(self, interaction: disnake.ApplicationCommandInteraction, channel: disnake.TextChannel, message_dm: str, message_salon: str, server_name: str, banner_file: disnake.Attachment = None):
# ✅ DÉFÉRER LA RÉPONSE (le traitement peut prendre > 3s avec les images)
@ -385,6 +387,7 @@ class Welcome(commands.Cog):
await interaction.followup.send(error_message, ephemeral=True)
@commands.slash_command(name="invitations", description="Affiche vos statistiques d'invitations")
@check_premium_tier()
async def invitations_stats(self, interaction: disnake.ApplicationCommandInteraction, user: disnake.Member = None):
user = user or interaction.author
await self._send_invitation_stats(interaction, user)

View file

@ -3,6 +3,7 @@ from disnake.ext import commands
import json
import os
from typing import List
from utils.premium import check_premium_tier
# Chemins ABSOLUS des fichiers
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@ -38,6 +39,7 @@ class Whitelist(commands.Cog):
self.save_whitelist()
@commands.slash_command(name="whitelist", description="Gère la whitelist du serveur")
@check_premium_tier()
async def whitelist_group(self, interaction: disnake.ApplicationCommandInteraction):
"""Groupe de commandes pour gérer la whitelist"""
pass