feat: full feature suite — welcome, modmail, security, staff, avis, rules, links, shop, custom
All checks were successful
ci / ci (push) Successful in 1m1s

features/shared.py: per-guild JSON config store
features/welcome.py: on_member_join message + invite tracking + /invites
features/modmail.py: DM-based tickets with staff relay
features/security.py: antiraid (join rate detection), ban protection, join/leave log
features/staff.py: staff ranks, promote/demote, /staff_list
features/avis.py: /avis modal -> embed in configured channel
features/rules.py: /rules_setup with accept button + role assignment
features/links.py: /links panel, /links_setup, /links_remove
features/shop.py: /shop_announce new product embeds
features/custom.py: /botstatus, /custom_send, /embed
This commit is contained in:
Mathis 2026-10-02 19:45:46 +02:00
parent 33b9303948
commit 5d9baee102
12 changed files with 911 additions and 2 deletions

91
features/rules.py Normal file
View file

@ -0,0 +1,91 @@
from __future__ import annotations
import contextlib
import logging
import discord
from discord import app_commands
from discord.ext import commands
from features import shared
logger = logging.getLogger("vision")
DEFAULT_RULES = [
"Respectez tous les membres du serveur.",
"Pas de spam ni de flood.",
"Pas de contenu NSFW ou gore.",
"Pas de publicité sans autorisation.",
"Utilisez les canaux appropriés.",
"Suivez les instructions du staff.",
]
class RulesAcceptButton(discord.ui.Button):
def __init__(self):
super().__init__(
label="J'accepte le règlement",
style=discord.ButtonStyle.success,
custom_id="rules_accept",
)
async def callback(self, interaction: discord.Interaction):
cfg = shared.section(interaction.guild_id, "rules")
role_id = cfg.get("role_id")
if role_id:
role = interaction.guild.get_role(role_id)
if role:
with contextlib.suppress(discord.HTTPException):
await interaction.user.add_roles(role, reason="Règlement accepté")
await interaction.response.send_message("Merci d'avoir accepté le règlement !", ephemeral=True)
class RulesView(discord.ui.LayoutView):
def __init__(self):
super().__init__(timeout=None)
container = discord.ui.Container()
container.add_item(discord.ui.ActionRow(RulesAcceptButton()))
self.add_item(container)
class Rules(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.bot.add_view(RulesView())
@app_commands.command(name="rules_setup", description="Configurer et envoyer le règlement")
@app_commands.describe(channel="Canal du règlement", role="Rôle donné après acceptation")
@app_commands.checks.has_permissions(manage_guild=True)
async def rules_setup(self, interaction: discord.Interaction, channel: discord.TextChannel, role: discord.Role):
cfg = shared.get(interaction.guild_id, "rules")
cfg["channel_id"] = channel.id
cfg["role_id"] = role.id
shared.set(interaction.guild_id, "rules", cfg)
rules = cfg.get("rules", DEFAULT_RULES)
rules_text = "\n".join(f"{i + 1}. {r}" for i, r in enumerate(rules))
container = discord.ui.Container()
container.add_item(discord.ui.TextDisplay(f"## Règlement du serveur\n\n{rules_text}"))
container.add_item(discord.ui.Separator())
container.add_item(discord.ui.ActionRow(RulesAcceptButton()))
view = discord.ui.LayoutView()
view.add_item(container)
await channel.send(view=view)
await interaction.response.send_message(f"Règlement publié dans {channel.mention}", ephemeral=True)
@app_commands.command(name="rules_set", description="Modifier les règles")
@app_commands.describe(rule1="Règle 1", rule2="Règle 2", rule3="Règle 3")
@app_commands.checks.has_permissions(manage_guild=True)
async def rules_set(self, interaction: discord.Interaction, rule1: str, rule2: str = "", rule3: str = ""):
rules = [r for r in [rule1, rule2, rule3] if r]
cfg = shared.get(interaction.guild_id, "rules")
cfg["rules"] = rules
shared.set(interaction.guild_id, "rules", cfg)
await interaction.response.send_message(f"{len(rules)} règles mises à jour.", ephemeral=True)
async def setup(bot: commands.Bot):
await bot.add_cog(Rules(bot))