mirror of
https://github.com/skylanix/MamieHenriette.git
synced 2026-02-06 06:40:35 +01:00
Ajout de la gestion des messages de bienvenue et de départ pour les membres. Mise à jour des configurations pour activer ces fonctionnalités dans le panneau d'administration.
This commit is contained in:
@@ -6,9 +6,10 @@ import random
|
|||||||
from database import db
|
from database import db
|
||||||
from database.helpers import ConfigurationHelper
|
from database.helpers import ConfigurationHelper
|
||||||
from database.models import Configuration, Humeur, Commande
|
from database.models import Configuration, Humeur, Commande
|
||||||
from discord import Message, TextChannel
|
from discord import Message, TextChannel, Member
|
||||||
from discordbot.humblebundle import checkHumbleBundleAndNotify
|
from discordbot.humblebundle import checkHumbleBundleAndNotify
|
||||||
from discordbot.command import handle_warning_command, handle_remove_warning_command, handle_list_warnings_command, handle_ban_command, handle_kick_command, handle_unban_command
|
from discordbot.command import handle_warning_command, handle_remove_warning_command, handle_list_warnings_command, handle_ban_command, handle_kick_command, handle_unban_command
|
||||||
|
from discordbot.welcome import sendWelcomeMessage, sendLeaveMessage, updateInviteCache
|
||||||
from protondb import searhProtonDb
|
from protondb import searhProtonDb
|
||||||
|
|
||||||
class DiscordBot(discord.Client):
|
class DiscordBot(discord.Client):
|
||||||
@@ -17,6 +18,9 @@ class DiscordBot(discord.Client):
|
|||||||
for c in self.get_all_channels() :
|
for c in self.get_all_channels() :
|
||||||
logging.info(f'{c.id} {c.name}')
|
logging.info(f'{c.id} {c.name}')
|
||||||
|
|
||||||
|
for guild in self.guilds:
|
||||||
|
await updateInviteCache(guild)
|
||||||
|
|
||||||
self.loop.create_task(self.updateStatus())
|
self.loop.create_task(self.updateStatus())
|
||||||
self.loop.create_task(self.updateHumbleBundle())
|
self.loop.create_task(self.updateHumbleBundle())
|
||||||
|
|
||||||
@@ -54,6 +58,8 @@ class DiscordBot(discord.Client):
|
|||||||
|
|
||||||
intents = discord.Intents.default()
|
intents = discord.Intents.default()
|
||||||
intents.message_content = True
|
intents.message_content = True
|
||||||
|
intents.members = True
|
||||||
|
intents.invites = True
|
||||||
bot = DiscordBot(intents=intents)
|
bot = DiscordBot(intents=intents)
|
||||||
|
|
||||||
# https://discordpy.readthedocs.io/en/stable/quickstart.html
|
# https://discordpy.readthedocs.io/en/stable/quickstart.html
|
||||||
@@ -121,4 +127,20 @@ async def on_message(message: Message):
|
|||||||
await message.channel.send(msg, suppress_embeds=True)
|
await message.channel.send(msg, suppress_embeds=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f'Échec de l\'envoi du message ProtonDB : {e}')
|
logging.error(f'Échec de l\'envoi du message ProtonDB : {e}')
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_member_join(member: Member):
|
||||||
|
await sendWelcomeMessage(bot, member)
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_member_remove(member: Member):
|
||||||
|
await sendLeaveMessage(bot, member)
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_invite_create(invite):
|
||||||
|
await updateInviteCache(invite.guild)
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_invite_delete(invite):
|
||||||
|
await updateInviteCache(invite.guild)
|
||||||
|
|
||||||
|
|||||||
147
discordbot/welcome.py
Normal file
147
discordbot/welcome.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import discord
|
||||||
|
import logging
|
||||||
|
from database.helpers import ConfigurationHelper
|
||||||
|
from discord import Member, TextChannel
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
invite_cache = {}
|
||||||
|
|
||||||
|
async def updateInviteCache(guild):
|
||||||
|
try:
|
||||||
|
invites = await guild.invites()
|
||||||
|
invite_cache[guild.id] = {invite.code: invite.uses for invite in invites}
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def getUsedInvite(guild) -> str:
|
||||||
|
try:
|
||||||
|
new_invites = await guild.invites()
|
||||||
|
for invite in new_invites:
|
||||||
|
old_uses = invite_cache.get(guild.id, {}).get(invite.code, 0)
|
||||||
|
if invite.uses > old_uses:
|
||||||
|
await updateInviteCache(guild)
|
||||||
|
inviter = f' (créée par {invite.inviter.name})' if invite.inviter else ''
|
||||||
|
return f'`{invite.code}`{inviter}'
|
||||||
|
await updateInviteCache(guild)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return 'Inconnue'
|
||||||
|
|
||||||
|
async def sendWelcomeMessage(bot: discord.Client, member: Member):
|
||||||
|
config = ConfigurationHelper()
|
||||||
|
|
||||||
|
if not config.getValue('welcome_enable'):
|
||||||
|
return
|
||||||
|
|
||||||
|
channel_id = config.getIntValue('welcome_channel_id')
|
||||||
|
if not channel_id:
|
||||||
|
logging.warning('Canal de bienvenue non configuré')
|
||||||
|
return
|
||||||
|
|
||||||
|
channel = bot.get_channel(channel_id)
|
||||||
|
if not channel or not isinstance(channel, TextChannel):
|
||||||
|
logging.error(f'Canal de bienvenue {channel_id} introuvable')
|
||||||
|
return
|
||||||
|
|
||||||
|
welcome_message = config.getValue('welcome_message')
|
||||||
|
if not welcome_message:
|
||||||
|
welcome_message = 'Bienvenue sur le serveur !'
|
||||||
|
|
||||||
|
invite_used = await getUsedInvite(member.guild)
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title='🎉 Nouveau membre !',
|
||||||
|
description=welcome_message,
|
||||||
|
color=discord.Color.green()
|
||||||
|
)
|
||||||
|
|
||||||
|
embed.set_thumbnail(url=member.display_avatar.url)
|
||||||
|
embed.add_field(name='Membre', value=member.mention, inline=True)
|
||||||
|
embed.add_field(name='Nombre de membres', value=str(member.guild.member_count), inline=True)
|
||||||
|
embed.add_field(name='Invitation utilisée', value=invite_used, inline=False)
|
||||||
|
embed.set_footer(text=f'ID: {member.id}')
|
||||||
|
|
||||||
|
try:
|
||||||
|
await channel.send(embed=embed)
|
||||||
|
logging.info(f'Message de bienvenue envoyé pour {member.name}')
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f'Échec de l\'envoi du message de bienvenue : {e}')
|
||||||
|
|
||||||
|
def formatDuration(seconds: int) -> str:
|
||||||
|
days = seconds // 86400
|
||||||
|
hours = (seconds % 86400) // 3600
|
||||||
|
minutes = (seconds % 3600) // 60
|
||||||
|
|
||||||
|
parts = []
|
||||||
|
if days > 0:
|
||||||
|
parts.append(f'{days} jour{"s" if days > 1 else ""}')
|
||||||
|
if hours > 0:
|
||||||
|
parts.append(f'{hours} heure{"s" if hours > 1 else ""}')
|
||||||
|
if minutes > 0:
|
||||||
|
parts.append(f'{minutes} minute{"s" if minutes > 1 else ""}')
|
||||||
|
|
||||||
|
if not parts:
|
||||||
|
return 'moins d\'une minute'
|
||||||
|
|
||||||
|
return ' et '.join(parts)
|
||||||
|
|
||||||
|
async def sendLeaveMessage(bot: discord.Client, member: Member):
|
||||||
|
config = ConfigurationHelper()
|
||||||
|
|
||||||
|
if not config.getValue('leave_enable'):
|
||||||
|
return
|
||||||
|
|
||||||
|
channel_id = config.getIntValue('leave_channel_id')
|
||||||
|
if not channel_id:
|
||||||
|
logging.warning('Canal de départ non configuré')
|
||||||
|
return
|
||||||
|
|
||||||
|
channel = bot.get_channel(channel_id)
|
||||||
|
if not channel or not isinstance(channel, TextChannel):
|
||||||
|
logging.error(f'Canal de départ {channel_id} introuvable')
|
||||||
|
return
|
||||||
|
|
||||||
|
leave_message = config.getValue('leave_message')
|
||||||
|
if not leave_message:
|
||||||
|
leave_message = 'Un membre a quitté le serveur.'
|
||||||
|
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
duration_seconds = int((now - member.joined_at).total_seconds()) if member.joined_at else 0
|
||||||
|
duration_text = formatDuration(duration_seconds)
|
||||||
|
|
||||||
|
reason = 'Départ volontaire'
|
||||||
|
try:
|
||||||
|
async for entry in member.guild.audit_logs(limit=5):
|
||||||
|
if entry.target and entry.target.id == member.id:
|
||||||
|
if entry.action == discord.AuditLogAction.kick:
|
||||||
|
reason = f'Expulsé par {entry.user.mention}'
|
||||||
|
if entry.reason:
|
||||||
|
reason += f' - Raison: {entry.reason}'
|
||||||
|
break
|
||||||
|
elif entry.action == discord.AuditLogAction.ban:
|
||||||
|
reason = f'Banni par {entry.user.mention}'
|
||||||
|
if entry.reason:
|
||||||
|
reason += f' - Raison: {entry.reason}'
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title='👋 Membre parti',
|
||||||
|
description=leave_message,
|
||||||
|
color=discord.Color.red()
|
||||||
|
)
|
||||||
|
|
||||||
|
embed.set_thumbnail(url=member.display_avatar.url)
|
||||||
|
embed.add_field(name='Membre', value=f'{member.mention} ({member.name})', inline=True)
|
||||||
|
embed.add_field(name='Nombre de membres', value=str(member.guild.member_count), inline=True)
|
||||||
|
embed.add_field(name='Temps sur le serveur', value=duration_text, inline=False)
|
||||||
|
embed.add_field(name='Raison', value=reason, inline=False)
|
||||||
|
embed.set_footer(text=f'ID: {member.id}')
|
||||||
|
|
||||||
|
try:
|
||||||
|
await channel.send(embed=embed)
|
||||||
|
logging.info(f'Message de départ envoyé pour {member.name}')
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f'Échec de l\'envoi du message de départ : {e}')
|
||||||
|
|
||||||
@@ -23,6 +23,10 @@ def updateConfiguration():
|
|||||||
ConfigurationHelper().createOrUpdate('moderation_ban_enable', False)
|
ConfigurationHelper().createOrUpdate('moderation_ban_enable', False)
|
||||||
if (request.form.get("moderation_staff_role_id") != None and request.form.get("moderation_kick_enable") == None) :
|
if (request.form.get("moderation_staff_role_id") != None and request.form.get("moderation_kick_enable") == None) :
|
||||||
ConfigurationHelper().createOrUpdate('moderation_kick_enable', False)
|
ConfigurationHelper().createOrUpdate('moderation_kick_enable', False)
|
||||||
|
if (request.form.get("welcome_channel_id") != None and request.form.get("welcome_enable") == None) :
|
||||||
|
ConfigurationHelper().createOrUpdate('welcome_enable', False)
|
||||||
|
if (request.form.get("leave_channel_id") != None and request.form.get("leave_enable") == None) :
|
||||||
|
ConfigurationHelper().createOrUpdate('leave_enable', False)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return redirect(request.referrer)
|
return redirect(request.referrer)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
<h1>Configuration de Mamie</h1>
|
<h1>Configuration de Mamie</h1>
|
||||||
<p>Configurez les tokens Discord, les notifications Humble Bundle et l'API ProtonDB pour la commande !protondb.</p>
|
<p>Configurez les tokens Discord, les notifications Humble Bundle et l'API ProtonDB pour la commande !protondb.</p>
|
||||||
|
|
||||||
<h2>API Discord</h2>
|
<h2>Discord</h2>
|
||||||
|
|
||||||
|
<h3>API Discord</h3>
|
||||||
<form action="{{ url_for('updateConfiguration') }}" method="POST">
|
<form action="{{ url_for('updateConfiguration') }}" method="POST">
|
||||||
<label for="discord_token">API Discord (cachée)</label>
|
<label for="discord_token">API Discord (cachée)</label>
|
||||||
<input name="discord_token" type="password" />
|
<input name="discord_token" type="password" />
|
||||||
@@ -12,6 +14,72 @@
|
|||||||
<p>Nécessite un redémarrage</p>
|
<p>Nécessite un redémarrage</p>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<h3>Message de bienvenue Discord</h3>
|
||||||
|
<form action="{{ url_for('updateConfiguration') }}" method="POST">
|
||||||
|
<label for="welcome_enable">Activer</label>
|
||||||
|
<input type="checkbox" name="welcome_enable" {% if configuration.getValue('welcome_enable') %}
|
||||||
|
checked="checked" {% endif %}>
|
||||||
|
<label>Activer le message de bienvenue pour les nouveaux membres</label>
|
||||||
|
<label for="welcome_channel_id">Canal de bienvenue</label>
|
||||||
|
<select name="welcome_channel_id">
|
||||||
|
{% for channel in channels %}
|
||||||
|
<option value="{{channel.id}}" {% if configuration.getIntValue('welcome_channel_id')==channel.id %}
|
||||||
|
selected="selected" {% endif %}>
|
||||||
|
{{channel.name}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<label for="welcome_message">Message personnalisé</label>
|
||||||
|
<textarea name="welcome_message" rows="4" placeholder="Bienvenue sur le serveur !">{{ configuration.getValue('welcome_message') }}</textarea>
|
||||||
|
<input type="Submit" value="Définir">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h3>Message de départ Discord</h3>
|
||||||
|
<form action="{{ url_for('updateConfiguration') }}" method="POST">
|
||||||
|
<label for="leave_enable">Activer</label>
|
||||||
|
<input type="checkbox" name="leave_enable" {% if configuration.getValue('leave_enable') %}
|
||||||
|
checked="checked" {% endif %}>
|
||||||
|
<label>Activer le message de départ quand un membre quitte le serveur</label>
|
||||||
|
<label for="leave_channel_id">Canal de départ</label>
|
||||||
|
<select name="leave_channel_id">
|
||||||
|
{% for channel in channels %}
|
||||||
|
<option value="{{channel.id}}" {% if configuration.getIntValue('leave_channel_id')==channel.id %}
|
||||||
|
selected="selected" {% endif %}>
|
||||||
|
{{channel.name}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<label for="leave_message">Message personnalisé</label>
|
||||||
|
<textarea name="leave_message" rows="4" placeholder="Un membre a quitté le serveur.">{{ configuration.getValue('leave_message') }}</textarea>
|
||||||
|
<input type="Submit" value="Définir">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h3>Modération Discord</h3>
|
||||||
|
<form action="{{ url_for('updateConfiguration') }}" method="POST">
|
||||||
|
<label for="moderation_enable">Activer les avertissements</label>
|
||||||
|
<input type="checkbox" name="moderation_enable" {% if configuration.getValue('moderation_enable') %}
|
||||||
|
checked="checked" {% endif %}>
|
||||||
|
<label>Activer les commandes d'avertissement (!averto, !delaverto, !listaverto)</label>
|
||||||
|
|
||||||
|
<label for="moderation_ban_enable">Activer le ban</label>
|
||||||
|
<input type="checkbox" name="moderation_ban_enable" {% if configuration.getValue('moderation_ban_enable') %}
|
||||||
|
checked="checked" {% endif %}>
|
||||||
|
<label>Activer les commandes de bannissement (!ban, !unban)</label>
|
||||||
|
|
||||||
|
<label for="moderation_kick_enable">Activer le kick</label>
|
||||||
|
<input type="checkbox" name="moderation_kick_enable" {% if configuration.getValue('moderation_kick_enable') %}
|
||||||
|
checked="checked" {% endif %}>
|
||||||
|
<label>Activer la commande d'expulsion (!kick)</label>
|
||||||
|
|
||||||
|
<label for="moderation_staff_role_id">ID du rôle Staff</label>
|
||||||
|
<input name="moderation_staff_role_id" type="text" value="{{ configuration.getValue('moderation_staff_role_id') }}"
|
||||||
|
placeholder="581990740431732738" />
|
||||||
|
|
||||||
|
<label for="moderation_embed_delete_delay">Délai de suppression des embeds (en secondes, 0 = ne pas supprimer)</label>
|
||||||
|
<input name="moderation_embed_delete_delay" type="number" value="{{ configuration.getValue('moderation_embed_delete_delay') or '0' }}"
|
||||||
|
placeholder="0" min="0" />
|
||||||
|
|
||||||
|
<input type="Submit" value="Définir">
|
||||||
|
</form>
|
||||||
|
|
||||||
<h2>API Twitch</h2>
|
<h2>API Twitch</h2>
|
||||||
<form action="{{ url_for('updateConfiguration') }}" method="POST">
|
<form action="{{ url_for('updateConfiguration') }}" method="POST">
|
||||||
<label for="twitch_client_id">Client ID</label>
|
<label for="twitch_client_id">Client ID</label>
|
||||||
@@ -55,32 +123,4 @@
|
|||||||
</select>
|
</select>
|
||||||
<input type="Submit" value="Définir">
|
<input type="Submit" value="Définir">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<h2>Modération Discord</h2>
|
|
||||||
<form action="{{ url_for('updateConfiguration') }}" method="POST">
|
|
||||||
<label for="moderation_enable">Activer les avertissements</label>
|
|
||||||
<input type="checkbox" name="moderation_enable" {% if configuration.getValue('moderation_enable') %}
|
|
||||||
checked="checked" {% endif %}>
|
|
||||||
<label>Activer les commandes d'avertissement (!averto, !delaverto, !listaverto)</label>
|
|
||||||
|
|
||||||
<label for="moderation_ban_enable">Activer le ban</label>
|
|
||||||
<input type="checkbox" name="moderation_ban_enable" {% if configuration.getValue('moderation_ban_enable') %}
|
|
||||||
checked="checked" {% endif %}>
|
|
||||||
<label>Activer les commandes de bannissement (!ban, !unban)</label>
|
|
||||||
|
|
||||||
<label for="moderation_kick_enable">Activer le kick</label>
|
|
||||||
<input type="checkbox" name="moderation_kick_enable" {% if configuration.getValue('moderation_kick_enable') %}
|
|
||||||
checked="checked" {% endif %}>
|
|
||||||
<label>Activer la commande d'expulsion (!kick)</label>
|
|
||||||
|
|
||||||
<label for="moderation_staff_role_id">ID du rôle Staff</label>
|
|
||||||
<input name="moderation_staff_role_id" type="text" value="{{ configuration.getValue('moderation_staff_role_id') }}"
|
|
||||||
placeholder="581990740431732738" />
|
|
||||||
|
|
||||||
<label for="moderation_embed_delete_delay">Délai de suppression des embeds (en secondes, 0 = ne pas supprimer)</label>
|
|
||||||
<input name="moderation_embed_delete_delay" type="number" value="{{ configuration.getValue('moderation_embed_delete_delay') or '0' }}"
|
|
||||||
placeholder="0" min="0" />
|
|
||||||
|
|
||||||
<input type="Submit" value="Définir">
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user