Skip to content

Commit

Permalink
Merge pull request #2 from makcimerrr/feature--helped
Browse files Browse the repository at this point in the history
🚀 Ajout de fonctionnalités : Embeds avec réactions pour sondages et système d'aide contextuel basé sur les rôles 🆘
  • Loading branch information
makcimerrr authored Aug 21, 2024
2 parents c2177ed + d4d50ec commit bc97569
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 24 deletions.
4 changes: 4 additions & 0 deletions .idea/bot-discord-zone01.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 1 addition & 18 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,14 @@

intents = discord.Intents.all()

logging.basicConfig(level=logging.INFO)

bot = commands.Bot(command_prefix="!", intents=intents)

initial_extensions = ['cogs.gestion_ping', 'cogs.gestion_jobs', 'cogs.gestion_cdi', 'cogs.event_cog']
initial_extensions = ['cogs.gestion_ping', 'cogs.gestion_jobs', 'cogs.gestion_cdi', 'cogs.event_cog', 'cogs.helped_student', 'cogs.embed_cog']

# Flag to check if the bot is loading for the first time
first_ready = True


@tasks.loop(minutes=5.0)
async def keep_alive():
try:
await bot.ws.ping()
logging.info("Sent a ping to keep the connection alive")
except Exception as e:
logging.error(f"Error while sending ping: {e}")


@keep_alive.before_loop
async def before_keep_alive():
await bot.wait_until_ready()


async def load_extensions(bot):
for extension in initial_extensions:
try:
Expand All @@ -48,7 +32,6 @@ async def load_extensions(bot):
async def on_ready():
global first_ready
print('Bot is ready.')
keep_alive.start()

if first_ready:
await load_extensions(bot)
Expand Down
79 changes: 79 additions & 0 deletions cogs/embed_cog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import discord
from discord import app_commands
from discord.ext import commands
from discord.ui import Modal, TextInput, View


class EmbedModal(Modal):
def __init__(self, channel: discord.TextChannel):
super().__init__(title="Créer un Embed")
self.channel = channel

# Champs pour le formulaire
self.add_item(TextInput(label="Titre de l'embed", placeholder="Entrez le titre de l'embed"))
self.add_item(TextInput(label="Description de l'embed", style=discord.TextStyle.long, placeholder="Entrez la description de l'embed"))
self.add_item(TextInput(label="Détails",style=discord.TextStyle.long, placeholder="Entrez les détails de l'embed"))
self.add_item(TextInput(label="Nombre de sessions",style=discord.TextStyle.short, placeholder="Entrez le nombre de sessions"))
self.add_item(TextInput(label="Nombre max de réactions par session",style=discord.TextStyle.short, placeholder="Entrez le nombre max de réactions par session"))

async def on_submit(self, interaction: discord.Interaction):
try:
# Récupère les valeurs des champs
title = self.children[0].value
description = self.children[1].value
details = self.children[2].value
num_responses = int(self.children[3].value)
max_reactions = int(self.children[4].value)

# Crée l'embed avec les informations fournies
embed = discord.Embed(title=title, description=description, color=discord.Color.green())
embed.set_author(name="🚨 - " + interaction.user.display_name)
embed.add_field(name="📜 - Détails:", value=details, inline=False)
embed.timestamp = discord.utils.utcnow()

await self.channel.send(f"@everyone", allowed_mentions=discord.AllowedMentions(everyone=True))

# Envoie l'embed dans le canal spécifié
message = await self.channel.send(embed=embed)

# Ajoute les réactions sous l'embed
emojis = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣', '🔟'] # Liste d'émojis possibles
for i in range(min(num_responses, len(emojis))):
await message.add_reaction(emojis[i])

await interaction.response.send_message(
f"Embed envoyé dans {self.channel.mention} avec {num_responses} sessions et max {max_reactions} réactions par session.",
ephemeral=True
)

except Exception as e:
await interaction.response.send_message(f"Erreur lors de la création de l'embed : {str(e)}", ephemeral=True)


def is_admin():
async def predicate(interaction: discord.Interaction) -> bool:
return interaction.user.guild_permissions.administrator

return app_commands.check(predicate)


class EmbedCog(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot

@commands.Cog.listener()
async def on_ready(self):
print("EmbedCog is ready.")

@app_commands.command(name="create_embed", description="Crée un embed avec les détails fournis et l'envoie dans un canal spécifié.")
@is_admin()
async def create_embed(self, interaction: discord.Interaction, channel: discord.TextChannel):
try:
modal = EmbedModal(channel)
await interaction.response.send_modal(modal)
except Exception as e:
await interaction.response.send_message(f"Une erreur s'est produite : {str(e)}", ephemeral=True)


async def setup(bot: commands.Bot):
await bot.add_cog(EmbedCog(bot))
2 changes: 1 addition & 1 deletion cogs/gestion_ping.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class PingCog(commands.Cog):

def __init__(self, bot):
self.bot = bot

@commands.command()
async def ping(self, ctx):
"""Renvoie la latence du bot en millisecondes."""
Expand Down
175 changes: 175 additions & 0 deletions cogs/helped_student.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import discord
from discord import app_commands
from discord.ext import commands
from discord.ui import Modal, TextInput, Button, View
from utils.config_loader import role_help, role_p1_2023, role_p2_2023, role_p1_2024

# Dictionnaire pour les IDs de canal associés aux rôles
role_channel_mapping = {
role_p1_2023: 1045019188927938641, # Remplacez par les IDs de vos canaux
role_p2_2023: 1133380731461193769,
role_p1_2024: 1222587487969611906
}

# Création de la classe pour les boutons
class HelpView(discord.ui.View):
def __init__(self, bot: commands.Bot):
super().__init__(timeout=None)
self.bot = bot # Ajout du bot comme attribut
self.session_open = True # État initial de la session

@discord.ui.button(label="Fermer la session", style=discord.ButtonStyle.danger, emoji="🔒")
async def close_button_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
# Vérifiez si l'utilisateur a les permissions nécessaires
if not interaction.user.guild_permissions.administrator:
await interaction.response.send_message("Vous n'avez pas la permission de faire cela.", ephemeral=True)
return

# Toggle entre fermer et réouvrir la session
if self.session_open:
button.label = "Réouvrir la session"
button.style = discord.ButtonStyle.success
button.emoji = "🔓"
self.session_open = True
await interaction.response.send_message("La session a été fermée.", ephemeral=True)
else:
button.label = "Fermer la session"
button.style = discord.ButtonStyle.danger
button.emoji = "🔒"
self.session_open = False
await interaction.response.send_message("La session a été réouverte.", ephemeral=True)

# Mettre à jour le message avec la vue modifiée
await interaction.message.edit(view=self)

@discord.ui.button(label="Demander de l'aide", style=discord.ButtonStyle.success, emoji="✅")
async def ask_button_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
if not self.session_open:
# Si la session est fermée, désactiver l'interaction
await interaction.response.send_message("La session est actuellement fermée.", ephemeral=True)
return

role = interaction.guild.get_role(role_help)
if role:
# Vérifie si l'utilisateur a déjà le rôle
if role in interaction.user.roles:
await interaction.user.remove_roles(role) # Enlève le rôle
# Ne modifie le pseudo que si le préfixe 🚨 est présent
if interaction.user.nick and interaction.user.nick.startswith("🚨"):
# Supprime le préfixe 🚨 sans toucher au reste du pseudo
original_nick = interaction.user.nick.replace("🚨 ", "", 1)
await interaction.user.edit(nick=original_nick)

# Change le bouton pour revenir à l'état initial
button.label = "Demander de l'aide"
button.style = discord.ButtonStyle.success
button.emoji = "✅"

await interaction.message.edit(view=self)
await interaction.response.send_message("Le rôle vous a été retiré et votre pseudo a été réinitialisé.",
ephemeral=True)
# Supprimer les messages d'aide existants dans le canal du rôle
user_roles = [role.id for role in interaction.user.roles]
channel_id = None

# Vérifier les rôles et sélectionner le canal approprié
for role_id, target_channel_id in role_channel_mapping.items():
if role_id in user_roles:
channel_id = target_channel_id
break

if channel_id:
channel = interaction.guild.get_channel(channel_id)
if channel:
# Recherche des messages dans le canal correspondant
async for message in channel.history(limit=100):
if message.author == self.bot.user and "a besoin d'aide" in message.content and interaction.user.mention in message.content:
try:
await message.delete()
#print(f"Deleted message: {message.id}") # Debugging
except discord.Forbidden:
print("Bot lacks permission to delete messages.") # Debugging
except discord.HTTPException as e:
print(f"Failed to delete message: {e}") # Debugging
else:
await interaction.followup.send("Le canal pour envoyer le message d'aide est introuvable.", ephemeral=True)
else:
await interaction.followup.send("Aucun canal correspondant aux rôles de l'utilisateur n'a été trouvé.", ephemeral=True)

else:
await interaction.user.add_roles(role) # Ajoute le rôle
# Ajoute le préfixe 🚨 uniquement si le pseudo actuel n'a pas déjà ce préfixe
if interaction.user.nick is None or not interaction.user.nick.startswith("🚨"):
new_nickname = f"🚨 {interaction.user.nick or interaction.user.name}"
await interaction.user.edit(nick=new_nickname)

# Change l'aspect du bouton une fois le rôle attribué
button.label = "Rôle attribué"
button.style = discord.ButtonStyle.danger # Change la couleur du bouton
button.emoji = "❌"

await interaction.message.edit(view=self)
await interaction.response.send_message("Vous avez été attribué le rôle et votre pseudo a été modifié.",
ephemeral=True)

# Determine the appropriate channel based on the user's roles
channel_id = None
user_roles = [role.id for role in interaction.user.roles] # Get the list of role IDs of the user

#print("User Roles:", user_roles) # Debugging line
#print("Role Channel Mapping:", role_channel_mapping) # Debugging line

for role_id, target_channel_id in role_channel_mapping.items():
if role_id in user_roles:
channel_id = target_channel_id
break

if channel_id:
channel = interaction.guild.get_channel(channel_id)
if channel:
await channel.send(f"{interaction.user.mention} a besoin d'aide !")
else:
await interaction.followup.send(
"Le canal pour envoyer le message d'aide est introuvable.", ephemeral=True)
else:
await interaction.followup.send(
"Aucun canal correspondant aux rôles de l'utilisateur n'a été trouvé.", ephemeral=True)
else:
await interaction.followup.send("Le rôle pour la demande d'aide n'existe pas.", ephemeral=True)

def is_admin():
async def predicate(interaction: discord.Interaction) -> bool:
return interaction.user.guild_permissions.administrator

return app_commands.check(predicate)

# Création de la commande slash
class HelpCommand(commands.Cog):
def __init__(self, bot):
self.bot = bot

@commands.Cog.listener()
async def on_ready(self):
print("EventCog is ready.")

@app_commands.command(name="send_help_embed", description="Envoie un embed d'aide dans le canal spécifié.")
@is_admin()
async def send_help_embed(self, interaction: discord.Interaction, channel: discord.TextChannel):
embed_description = (
"Pour demander de l'aide auprès d'autres apprenants de ta promo, clique sur le bouton ci-dessous\n\n> Une fois ta demande effectuée, tu te verras attribuer un rôle et un pseudo. Des apprenants viendront sous peu t'apporter de l'aide !"
)

embed = discord.Embed(title="Besoin d'aide ?", description=embed_description, colour=0x002e7a,
timestamp=discord.utils.utcnow())
embed.set_author(name="Info")
embed.set_footer(text="Zone01",
icon_url="https://zone01rouennormandie.org/wp-content/uploads/2024/03/01talent-profil-400x400-1.jpg")

view = HelpView(self.bot)

# Envoyer l'embed dans le canal spécifié
await channel.send(embed=embed, view=view)
await interaction.response.send_message(f"L'embed d'aide a été envoyé dans {channel.mention}.", ephemeral=True)

async def setup(bot):
await bot.add_cog(HelpCommand(bot))
6 changes: 5 additions & 1 deletion data/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
"forum_channel_id_cdi": 1265685577496395907,
"role_ping": 1045009211211387063,
"role_ping_cdi": 1257311029797326868,
"guild_id": 905002122309951538
"guild_id": 905002122309951538,
"role_p1_2023": 1045009211211387063,
"role_p2_2023": 1133378674255745085,
"role_p1_2024": 1222586722077114409,
"role_help": 1245022473364176975
}
4 changes: 2 additions & 2 deletions utils/cdi_fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
async def fetch_api_fulltime():
url = "https://jsearch.p.rapidapi.com/search"

querystring = {"query": "Full Stack Developer Rouen France", "page": "1", "num_pages": "1", "date_posted": "today",
"employment_types": "FULLTIME", "radius": "120"}
querystring = {"query": "full stack developer in rouen, france", "page": "1", "num_pages": "1", "date_posted": "today",
"employment_types": "FULLTIME", "radius": "70"}

headers = {
"x-rapidapi-key": os.getenv('RAPIDAPI_KEY'),
Expand Down
4 changes: 4 additions & 0 deletions utils/config_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ def load_config():
forum_channel_id = config["forum_channel_id"]
forum_channel_id_cdi = config["forum_channel_id_cdi"]
guild_id = config["guild_id"]
role_p1_2023 = config["role_p1_2023"]
role_p2_2023 = config["role_p2_2023"]
role_p1_2024 = config["role_p1_2024"]
role_help = config["role_help"]
discord_token = os.getenv("TOKEN")
4 changes: 2 additions & 2 deletions utils/intern_fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
async def fetch_api_intern():
url = "https://jsearch.p.rapidapi.com/search"

querystring = {"query": "Full Stack Developer Alternant Rouen France", "page": "1", "num_pages": "1", "date_posted": "today",
"employment_types": "INTERN", "radius": "120"}
querystring = {"query": "full stack developer alternant in rouen, france", "page": "1", "num_pages": "1", "date_posted": "today",
"employment_types": "INTERN", "radius": "70"}

headers = {
"x-rapidapi-key": os.getenv('RAPIDAPI_KEY'),
Expand Down

0 comments on commit bc97569

Please sign in to comment.