280 lines
12 KiB
Python
280 lines
12 KiB
Python
|
|
import discord
|
|||
|
|
from discord.ext import commands, tasks
|
|||
|
|
from discord import app_commands
|
|||
|
|
import json
|
|||
|
|
import os
|
|||
|
|
import asyncio
|
|||
|
|
from datetime import datetime, timedelta
|
|||
|
|
|
|||
|
|
BLACKLIST_FILE = "data/blacklist.json"
|
|||
|
|
AGENTS_FILE = "data/agents.json"
|
|||
|
|
TICKETS_FILE = "data/tickets_blacklist.json"
|
|||
|
|
MAIN_GUILD_ID = 1369669999345537145 # ID serveur principal
|
|||
|
|
TICKET_CATEGORY_ID = 1369669999677145104 # Catégorie tickets
|
|||
|
|
|
|||
|
|
# --------- Utils JSON ---------
|
|||
|
|
def load_json(path, default):
|
|||
|
|
if not os.path.exists(path):
|
|||
|
|
with open(path, "w") as f:
|
|||
|
|
json.dump(default, f, indent=4)
|
|||
|
|
with open(path, "r") as f:
|
|||
|
|
return json.load(f)
|
|||
|
|
|
|||
|
|
def save_json(path, data):
|
|||
|
|
with open(path, "w") as f:
|
|||
|
|
json.dump(data, f, indent=4)
|
|||
|
|
|
|||
|
|
# --------- Cog ---------
|
|||
|
|
class Blacklist(commands.Cog):
|
|||
|
|
def __init__(self, bot: commands.Bot):
|
|||
|
|
self.bot = bot
|
|||
|
|
self.check_ban_expiry.start() # boucle auto pour bannir après 7j
|
|||
|
|
|
|||
|
|
def cog_unload(self):
|
|||
|
|
self.check_ban_expiry.cancel()
|
|||
|
|
|
|||
|
|
def is_agent(self, user_id: int):
|
|||
|
|
agents = load_json(AGENTS_FILE, {"agents": []})
|
|||
|
|
return str(user_id) in agents["agents"]
|
|||
|
|
|
|||
|
|
@app_commands.command(name="blacklist", description="Blacklist un utilisateur")
|
|||
|
|
async def blacklist(self, interaction: discord.Interaction, user: discord.User, reason: str = "Aucune raison fournie"):
|
|||
|
|
if not self.is_agent(interaction.user.id):
|
|||
|
|
return await interaction.response.send_message("⛔ Tu n’as pas la permission.", ephemeral=True)
|
|||
|
|
|
|||
|
|
blacklist = load_json(BLACKLIST_FILE, {})
|
|||
|
|
blacklist[str(user.id)] = {
|
|||
|
|
"reason": reason,
|
|||
|
|
"timestamp": datetime.utcnow().isoformat()
|
|||
|
|
}
|
|||
|
|
save_json(BLACKLIST_FILE, blacklist)
|
|||
|
|
|
|||
|
|
# Préparer l'embed pro
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="🚫 Mise en blacklist - Réseau Omega Kube",
|
|||
|
|
description=(
|
|||
|
|
f"Bonjour {user.mention},\n\n"
|
|||
|
|
f"Vous avez été **blacklisté** du **Réseau Omega Kube**.\n\n"
|
|||
|
|
f"**Raison :** {reason}\n\n"
|
|||
|
|
"⚠️ Vous êtes banni de tous nos serveurs partenaires. "
|
|||
|
|
"Cependant, vous restez présent sur le **serveur principal**, "
|
|||
|
|
"mais tu ne peux pas interagir avec la communauté.\n\n"
|
|||
|
|
"📩 Vous disposez de **7 jours** pour contester cette décision en ouvrant un ticket via le bouton ci-dessous.\n\n"
|
|||
|
|
"⏳ Passé ce délai, vous serez **définitivement banni de tout le réseau**, sans autre recours possible."
|
|||
|
|
),
|
|||
|
|
color=discord.Color.red()
|
|||
|
|
)
|
|||
|
|
embed.set_footer(text="Omega Kube - Nixfix06 & Mgstudios")
|
|||
|
|
|
|||
|
|
view = TicketButton(user.id)
|
|||
|
|
|
|||
|
|
# Envoyer MP avant action
|
|||
|
|
try:
|
|||
|
|
await user.send(embed=embed, view=view)
|
|||
|
|
await asyncio.sleep(2)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# Bannir de tous les serveurs sauf principal
|
|||
|
|
for guild in self.bot.guilds:
|
|||
|
|
if guild.id == MAIN_GUILD_ID:
|
|||
|
|
member = guild.get_member(user.id)
|
|||
|
|
if member:
|
|||
|
|
try:
|
|||
|
|
# Supprime la permission d'écrire partout
|
|||
|
|
for channel in guild.channels:
|
|||
|
|
overwrite = channel.overwrites_for(member)
|
|||
|
|
overwrite.send_messages = False
|
|||
|
|
overwrite.add_reactions = False
|
|||
|
|
await channel.set_permissions(member, overwrite=overwrite)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
else:
|
|||
|
|
member = guild.get_member(user.id)
|
|||
|
|
if member:
|
|||
|
|
try:
|
|||
|
|
await member.ban(reason=f"Blacklisté : {reason}")
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ {user.mention} blacklisté, banni des partenaires et restreint sur le serveur principal.",
|
|||
|
|
ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
@app_commands.command(name="unblacklist", description="Retirer un utilisateur de la blacklist")
|
|||
|
|
async def unblacklist(self, interaction: discord.Interaction, user: discord.User):
|
|||
|
|
if not self.is_agent(interaction.user.id):
|
|||
|
|
return await interaction.response.send_message("⛔ Tu n’as pas la permission.", ephemeral=True)
|
|||
|
|
|
|||
|
|
blacklist = load_json(BLACKLIST_FILE, {})
|
|||
|
|
if str(user.id) in blacklist:
|
|||
|
|
del blacklist[str(user.id)]
|
|||
|
|
save_json(BLACKLIST_FILE, blacklist)
|
|||
|
|
await interaction.response.send_message(f"✅ {user.mention} retiré de la blacklist.", ephemeral=True)
|
|||
|
|
else:
|
|||
|
|
await interaction.response.send_message("❌ Cet utilisateur n’est pas blacklisté.", ephemeral=True)
|
|||
|
|
|
|||
|
|
@tasks.loop(hours=1)
|
|||
|
|
async def check_ban_expiry(self):
|
|||
|
|
"""Boucle qui vérifie si 7 jours sont écoulés → ban total."""
|
|||
|
|
blacklist = load_json(BLACKLIST_FILE, {})
|
|||
|
|
to_remove = []
|
|||
|
|
for user_id, data in blacklist.items():
|
|||
|
|
try:
|
|||
|
|
ts = datetime.fromisoformat(data["timestamp"])
|
|||
|
|
if datetime.utcnow() > ts + timedelta(days=7):
|
|||
|
|
# Ban définitif partout
|
|||
|
|
user = await self.bot.fetch_user(int(user_id))
|
|||
|
|
for guild in self.bot.guilds:
|
|||
|
|
member = guild.get_member(int(user_id))
|
|||
|
|
if member:
|
|||
|
|
try:
|
|||
|
|
await member.ban(reason="Blacklist définitive (7j écoulés)")
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
to_remove.append(user_id)
|
|||
|
|
except:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
for uid in to_remove:
|
|||
|
|
del blacklist[uid]
|
|||
|
|
|
|||
|
|
save_json(BLACKLIST_FILE, blacklist)
|
|||
|
|
|
|||
|
|
@commands.Cog.listener()
|
|||
|
|
async def on_message(self, message: discord.Message):
|
|||
|
|
if message.author.bot:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
tickets = load_json(TICKETS_FILE, {})
|
|||
|
|
|
|||
|
|
if isinstance(message.channel, discord.DMChannel):
|
|||
|
|
user_id = str(message.author.id)
|
|||
|
|
if user_id in tickets:
|
|||
|
|
guild = self.bot.get_guild(MAIN_GUILD_ID)
|
|||
|
|
ticket_channel = guild.get_channel(tickets[user_id]["channel_id"])
|
|||
|
|
if ticket_channel:
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
description=message.content,
|
|||
|
|
color=discord.Color.blue()
|
|||
|
|
).set_author(name=message.author, icon_url=message.author.display_avatar.url)
|
|||
|
|
await ticket_channel.send(embed=embed)
|
|||
|
|
|
|||
|
|
else:
|
|||
|
|
for user_id, data in tickets.items():
|
|||
|
|
if message.channel.id == data["channel_id"] and self.is_agent(message.author.id):
|
|||
|
|
user = await self.bot.fetch_user(int(user_id))
|
|||
|
|
try:
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
description=message.content,
|
|||
|
|
color=discord.Color.green()
|
|||
|
|
).set_author(name=f"Agent {message.author}", icon_url=message.author.display_avatar.url)
|
|||
|
|
await user.send(embed=embed)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# --------- Boutons ---------
|
|||
|
|
class TicketButton(discord.ui.View):
|
|||
|
|
def __init__(self, user_id: int):
|
|||
|
|
super().__init__(timeout=None)
|
|||
|
|
self.user_id = user_id
|
|||
|
|
|
|||
|
|
@discord.ui.button(label="📩 Ouvrir une demande de révision", style=discord.ButtonStyle.primary)
|
|||
|
|
async def open_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|||
|
|
if interaction.user.id != self.user_id:
|
|||
|
|
return await interaction.response.send_message("❌ Ce bouton ne t’appartient pas.", ephemeral=True)
|
|||
|
|
|
|||
|
|
tickets = load_json(TICKETS_FILE, {})
|
|||
|
|
if str(self.user_id) in tickets:
|
|||
|
|
return await interaction.response.send_message("❌ Tu as déjà un ticket ouvert.", ephemeral=True)
|
|||
|
|
|
|||
|
|
guild = interaction.client.get_guild(MAIN_GUILD_ID)
|
|||
|
|
category = guild.get_channel(TICKET_CATEGORY_ID)
|
|||
|
|
|
|||
|
|
ticket_channel = await guild.create_text_channel(
|
|||
|
|
name=f"ticket-{self.user_id}",
|
|||
|
|
category=category,
|
|||
|
|
topic=f"Ticket de l'utilisateur {self.user_id}"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
tickets[str(self.user_id)] = {"channel_id": ticket_channel.id}
|
|||
|
|
save_json(TICKETS_FILE, tickets)
|
|||
|
|
|
|||
|
|
view_close = CloseTicketView(self.user_id)
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="📩 Ticket ouvert",
|
|||
|
|
description=f"Un utilisateur blacklisté (<@{self.user_id}>) a ouvert une demande de révision.\n\nUn agent Omega Kube prendra en charge ce dossier.",
|
|||
|
|
color=discord.Color.blurple()
|
|||
|
|
)
|
|||
|
|
await ticket_channel.send(embed=embed, view=view_close)
|
|||
|
|
|
|||
|
|
await interaction.response.send_message("✅ Ton ticket a bien été créé.", ephemeral=True)
|
|||
|
|
|
|||
|
|
button.disabled = True
|
|||
|
|
self.stop()
|
|||
|
|
|
|||
|
|
class CloseTicketView(discord.ui.View):
|
|||
|
|
def __init__(self, user_id: int):
|
|||
|
|
super().__init__(timeout=None)
|
|||
|
|
self.user_id = user_id
|
|||
|
|
|
|||
|
|
@discord.ui.button(label="❌ Fermer le ticket", style=discord.ButtonStyle.danger)
|
|||
|
|
async def close_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|||
|
|
if not interaction.client.get_cog("Blacklist").is_agent(interaction.user.id):
|
|||
|
|
return await interaction.response.send_message("⛔ Seuls les agents peuvent fermer ce ticket.", ephemeral=True)
|
|||
|
|
|
|||
|
|
view = ConfirmCloseView(self.user_id)
|
|||
|
|
await interaction.response.send_message("⚠️ Veux-tu vraiment fermer ce ticket ?", view=view, ephemeral=True)
|
|||
|
|
|
|||
|
|
class ConfirmCloseView(discord.ui.View):
|
|||
|
|
def __init__(self, user_id: int):
|
|||
|
|
super().__init__(timeout=30)
|
|||
|
|
self.user_id = user_id
|
|||
|
|
|
|||
|
|
@discord.ui.button(label="✅ Oui", style=discord.ButtonStyle.success)
|
|||
|
|
async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|||
|
|
if not interaction.client.get_cog("Blacklist").is_agent(interaction.user.id):
|
|||
|
|
return await interaction.response.send_message("⛔ Tu n’as pas la permission.", ephemeral=True)
|
|||
|
|
|
|||
|
|
tickets = load_json(TICKETS_FILE, {})
|
|||
|
|
if str(self.user_id) in tickets:
|
|||
|
|
channel_id = tickets[str(self.user_id)]["channel_id"]
|
|||
|
|
guild = interaction.guild
|
|||
|
|
channel = guild.get_channel(channel_id)
|
|||
|
|
if channel:
|
|||
|
|
await channel.delete()
|
|||
|
|
|
|||
|
|
del tickets[str(self.user_id)]
|
|||
|
|
save_json(TICKETS_FILE, tickets)
|
|||
|
|
|
|||
|
|
user = await interaction.client.fetch_user(int(self.user_id))
|
|||
|
|
try:
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="🔒 Ticket fermé",
|
|||
|
|
description="Ton ticket a été examiné et fermé.\n\n⚠️ Après analyse, la sanction est confirmée et tu restes blacklisté de l’ensemble du réseau.",
|
|||
|
|
color=discord.Color.orange()
|
|||
|
|
)
|
|||
|
|
await user.send(embed=embed)
|
|||
|
|
await asyncio.sleep(2)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
for guild in interaction.client.guilds:
|
|||
|
|
member = guild.get_member(self.user_id)
|
|||
|
|
if member:
|
|||
|
|
try:
|
|||
|
|
await member.ban(reason="Ticket blacklist fermé")
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
await interaction.response.send_message("✅ Ticket fermé avec succès.", ephemeral=True)
|
|||
|
|
|
|||
|
|
@discord.ui.button(label="❌ Non", style=discord.ButtonStyle.secondary)
|
|||
|
|
async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button):
|
|||
|
|
await interaction.response.send_message("❌ Fermeture annulée.", ephemeral=True)
|
|||
|
|
|
|||
|
|
# --------- Setup ---------
|
|||
|
|
async def setup(bot: commands.Bot):
|
|||
|
|
await bot.add_cog(Blacklist(bot))
|