Skip to content

Commit

Permalink
Add reaction role functionality
Browse files Browse the repository at this point in the history
Fixes #11

Add functionality for role assignment based on reactions.

- Add `addreactionrole` and `removereactionrole` commands in `bot/botcommands/member.py` to link and unlink reactions to roles.
- Update `bot/management/logging.py` to handle role assignment and removal based on reactions.
- Add utility functions `add_reaction_role` and `remove_reaction_role` in `bot/util.py` for managing reaction roles.
- Add `ReactionRole` model in `bot/db/models/reaction_role.py` to define the structure for reaction roles.
- Add `ReactionRoleService` class in `bot/db/services/reaction_role_service.py` to handle database operations for reaction roles.

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/ADEPT-Informatique/adeptbot/issues/11?shareId=XXXX-XXXX-XXXX-XXXX).
  • Loading branch information
DeveloperAnonymous committed Dec 9, 2024
1 parent 53f07e3 commit 8508532
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 0 deletions.
39 changes: 39 additions & 0 deletions bot/botcommands/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from bot.botcommands.utils.validators import has_at_least_role
from bot.db.models.user import AdeptMember
from bot.db.services.user_service import UserService
from bot.db.services.reaction_role_service import ReactionRoleService
from bot.interactions import TicketOpeningInteraction
from bot.interactions import ticket as ticket_interactions
from bot.util import AdeptBotException
Expand All @@ -19,6 +20,7 @@ class MemberCog(commands.Cog):

def __init__(self) -> None:
self.user_service = UserService()
self.reaction_role_service = ReactionRoleService()

@commands.command()
async def ticket(self, ctx: Context, ticket: tickets.TicketConverter):
Expand Down Expand Up @@ -122,3 +124,40 @@ async def count_students_in_computer_science(self, ctx: Context):
+ f" - ``{decbac_students_count}`` en **DEC-BAC**\n\n"
+ f" - ``{former_student_count}`` anciens étudiants"
)

@commands.command()
@has_at_least_role(configs.ADMIN_ROLE)
async def addreactionrole(self, ctx: Context, message_id: int, emoji: str, role_id: int):
"""
Cette commande permet d'ajouter une réaction à un message et de la lier à un rôle.
Utilisation:
!addreactionrole <message_id> <emoji> <role_id>
"""
message = await ctx.fetch_message(message_id)
role = ctx.guild.get_role(role_id)

if not message or not role:
raise AdeptBotException("Message ou rôle invalide!")

await message.add_reaction(emoji)
await self.reaction_role_service.add_reaction_role(message_id, emoji, role_id)
await ctx.send(f"Réaction {emoji} ajoutée au message {message_id} et liée au rôle {role.name}.")

@commands.command()
@has_at_least_role(configs.ADMIN_ROLE)
async def removereactionrole(self, ctx: Context, message_id: int, emoji: str):
"""
Cette commande permet de retirer une réaction d'un message et de supprimer le lien avec un rôle.
Utilisation:
!removereactionrole <message_id> <emoji>
"""
message = await ctx.fetch_message(message_id)

if not message:
raise AdeptBotException("Message invalide!")

await message.clear_reaction(emoji)
await self.reaction_role_service.remove_reaction_role(message_id, emoji)
await ctx.send(f"Réaction {emoji} retirée du message {message_id}.")
37 changes: 37 additions & 0 deletions bot/db/models/reaction_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""ReactionRole model for linking reactions to roles."""

from bot.db.models.entity import Entity


class ReactionRole(Entity):
"""
ReactionRole model for linking reactions to roles.
Attributes
----------
`message_id` : int
The ID of the message.
`emoji` : str
The emoji used for the reaction.
`role_id` : int
The ID of the role to assign.
"""

__slots__ = ("message_id", "emoji", "role_id")

def __init__(self, _id: int, message_id: int, emoji: str, role_id: int):
super().__init__(_id)
self.message_id = message_id
self.emoji = emoji
self.role_id = role_id

def __getstate__(self):
state = super().__getstate__()
state.update(
{
"message_id": self.message_id,
"emoji": self.emoji,
"role_id": self.role_id,
}
)
return state
73 changes: 73 additions & 0 deletions bot/db/services/reaction_role_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Service class for ReactionRole model."""

from bot.db.services.base_service import BaseService
from bot.db.models.reaction_role import ReactionRole


class ReactionRoleService(BaseService):
"""
Service class for ReactionRole model.
Methods
-------
`add_reaction_role` : None
Add a reaction role to the database.
`remove_reaction_role` : None
Remove a reaction role from the database.
`get_reaction_role` : ReactionRole
Get a reaction role from the database.
"""

@property
def collection_name(self):
return "reaction_roles"

async def add_reaction_role(self, message_id: int, emoji: str, role_id: int):
"""
Add a reaction role to the database.
Parameters
----------
`message_id` : int
The ID of the message.
`emoji` : str
The emoji used for the reaction.
`role_id` : int
The ID of the role to assign.
"""
reaction_role = ReactionRole(None, message_id, emoji, role_id)
await self.insert_one(reaction_role.__getstate__())

async def remove_reaction_role(self, message_id: int, emoji: str):
"""
Remove a reaction role from the database.
Parameters
----------
`message_id` : int
The ID of the message.
`emoji` : str
The emoji used for the reaction.
"""
await self.delete_one({"message_id": message_id, "emoji": emoji})

async def get_reaction_role(self, message_id: int, emoji: str) -> ReactionRole:
"""
Get a reaction role from the database.
Parameters
----------
`message_id` : int
The ID of the message.
`emoji` : str
The emoji used for the reaction.
Returns
-------
ReactionRole
The reaction role.
"""
result = await self.find_one({"message_id": message_id, "emoji": emoji})
if result:
return ReactionRole(result["_id"], result["message_id"], result["emoji"], result["role_id"])
return None
29 changes: 29 additions & 0 deletions bot/management/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@

import configs
from bot import util
from bot.db.services.reaction_role_service import ReactionRoleService


class LoggingCog(commands.Cog):
"""This class contains the events related to logging."""

def __init__(self):
self.reaction_role_service = ReactionRoleService()

@commands.Cog.listener()
async def on_message_edit(self, before: discord.Message, after: discord.Message):
"""This event is called when a message is edited."""
Expand Down Expand Up @@ -135,3 +139,28 @@ async def on_guild_channel_update(self, before: discord.abc.GuildChannel, after:
embed.description = f"**``#{before}`` a été renommé pour {after.mention}**"

await util.say(configs.LOGS_CHANNEL, embed=embed)

@commands.Cog.listener()
async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent):
"""This event is called when a reaction is added to a message."""
if payload.member.bot:
return

reaction_role = await self.reaction_role_service.get_reaction_role(payload.message_id, str(payload.emoji))
if reaction_role:
guild = self.bot.get_guild(payload.guild_id)
role = guild.get_role(reaction_role.role_id)
await payload.member.add_roles(role)

@commands.Cog.listener()
async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent):
"""This event is called when a reaction is removed from a message."""
guild = self.bot.get_guild(payload.guild_id)
member = guild.get_member(payload.user_id)
if member.bot:
return

reaction_role = await self.reaction_role_service.get_reaction_role(payload.message_id, str(payload.emoji))
if reaction_role:
role = guild.get_role(reaction_role.role_id)
await member.remove_roles(role)
32 changes: 32 additions & 0 deletions bot/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,35 @@ def load(loaded_client):
"""
global CLIENT
CLIENT = loaded_client


async def add_reaction_role(message_id: int, emoji: str, role_id: int):
"""
Add a reaction role.
Parameters
----------
`message_id` : int
The id of the message to add the reaction to.
`emoji` : str
The emoji to add as a reaction.
`role_id` : int
The id of the role to assign when the reaction is added.
"""
reaction_role_service = ReactionRoleService()
await reaction_role_service.add_reaction_role(message_id, emoji, role_id)


async def remove_reaction_role(message_id: int, emoji: str):
"""
Remove a reaction role.
Parameters
----------
`message_id` : int
The id of the message to remove the reaction from.
`emoji` : str
The emoji to remove as a reaction.
"""
reaction_role_service = ReactionRoleService()
await reaction_role_service.remove_reaction_role(message_id, emoji)

0 comments on commit 8508532

Please sign in to comment.