diff --git a/robocop_ng/cogs/ryujinx_reactionroles.py b/robocop_ng/cogs/ryujinx_reactionroles.py new file mode 100644 index 0000000..cfe2b99 --- /dev/null +++ b/robocop_ng/cogs/ryujinx_reactionroles.py @@ -0,0 +1,153 @@ +import json +import config +import os + +import discord +from discord.ext.commands import Cog + + +class RyujinxReactionRoles(Cog): + def __init__(self, bot): + self.bot = bot + self.channel_id = ( + config.reaction_roles_channel_id + ) # The channel to send the reaction role message. (self-roles channel) + + self.emoji_map = { + "🦑": "Looking for LDN game (Splatoon 2)", + "👹": "Looking for LDN game (Monster Hunter Generations Ultimate)", + "👺": "Looking for LDN game (Monster Hunter Rise)", + "🧩": "Looking for LDN game (Mario Party Superstars)", + "🐉": "Looking for LDN game (Pokémon Sword/Shield)", + "⚔️": "Looking for LDN game (Super Smash Bros. Ultimate)", + "🏎️": "Looking for LDN game (Mario Kart 8)", + "🪨": "Looking for LDN game (Pokémon Brilliant Diamond/Shining Pearl)", + "🍃": "Looking for LDN game (Animal Crossing: New Horizons)", + "➡": "Looking for LDN game (Others)", + "🚩": "Testers", + # LDN roles should be placed *before* testers role, because of embed generating. + # LDN roles ought to be in the format "Looking for LDN game ()". + } # The mapping of emoji ids to the role. + + self.file = "data/reactionroles.json" # the file to store the required reaction role data. (message id of the RR message.) + + self.msg_id = None + self.m = None # the msg object + + self.get_role = lambda emoji_name: discord.utils.get( + self.bot.guilds[0].roles, + name=self.emoji_map.get(str(emoji_name)), + ) + + async def generate_embed(self): + emojis = list(self.emoji_map.keys()) + description = "React to this message with the emojis given below to get your 'Looking for LDN game' roles. \n\n" + + for x in emojis: + if self.emoji_map.get(x) == "Testers": + description += f'\nReact {x} to get the "{self.emoji_map.get(x)}" role.' + else: + description += ( + f"{x} for __{self.emoji_map.get(x).split('(')[1].split(')')[0]}__ \n" + ) + + embed = discord.Embed( + title="**Select your roles**", description=description, color=420420 + ) + embed.set_footer( + text="To remove a role, simply remove the corresponding reaction." + ) + + return embed + + async def handle_offline_reaction_add(self): + for reaction in self.m.reactions: + for user in await reaction.users().flatten(): + if self.emoji_map.get(reaction.emoji) is not None: + role = self.get_role(reaction.emoji) + if not user in role.members and not user.bot: + await user.add_roles(role) + else: + await self.m.clear_reaction(reaction.emoji) + + async def handle_offline_reaction_remove(self): + for emoji in self.emoji_map: + for reaction in self.m.reactions: + role = self.get_role(reaction.emoji) + for user in role.members: + if user not in await reaction.users().flatten(): + await self.m.guild.get_member(user.id).remove_roles(role) + + @Cog.listener() + async def on_ready(self): + + guild = self.bot.guilds[0] # The ryu guild in which the bot is. + channel = guild.get_channel(self.channel_id) + + if not os.path.exists(self.file): + with open(self.file, "w") as f: + f.write("{}") + + with open(self.file, "r") as f: + id = json.load(f).get("id") + + m = discord.utils.get(await channel.history().flatten(), id=id) + if m is None: + os.remove(self.file) + + embed = await self.generate_embed() + self.m = await channel.send(embed=embed) + self.msg_id = self.m.id + + for x in self.emoji_map: + await self.m.add_reaction(x) + + with open(self.file, "w") as f: + json.dump({"id": self.m.id}, f) + + await self.handle_offline_reaction_remove() + + else: + self.m = discord.utils.get(await channel.history().flatten(), id=id) + self.msg_id = self.m.id + + await self.m.edit(embed=await self.generate_embed()) + for x in self.emoji_map: + if not x in self.m.reactions: + await self.m.add_reaction(x) + + await self.handle_offline_reaction_add() + await self.handle_offline_reaction_remove() + + @Cog.listener() + async def on_raw_reaction_add(self, payload): + if payload.member.bot: + pass + else: + if payload.message_id == self.msg_id: + if self.emoji_map.get(payload.emoji.name) is not None: + if self.get_role(payload.emoji.name) is not None: + await payload.member.add_roles( + self.get_role(payload.emoji.name) + ) + else: + print(f"Role {self.emoji_map[payload.emoji.name]} not found.") + else: + await self.m.clear_reaction(payload.emoji.name) + + @Cog.listener() + async def on_raw_reaction_remove(self, payload): + if payload.message_id == self.msg_id: + if self.emoji_map.get(str(payload.emoji.name)) is not None: + + guild = discord.utils.find( + lambda guild: guild.id == payload.guild_id, self.bot.guilds + ) + + await guild.get_member(payload.user_id).remove_roles( + self.get_role(payload.emoji.name) + ) # payload.member.remove_roles will throw error + + +async def setup(bot): + await bot.add_cog(RyujinxReactionRoles(bot)) diff --git a/robocop_ng/cogs/ryujinx_verification.py b/robocop_ng/cogs/ryujinx_verification.py index d114d6d..14ed6e4 100644 --- a/robocop_ng/cogs/ryujinx_verification.py +++ b/robocop_ng/cogs/ryujinx_verification.py @@ -24,7 +24,9 @@ class RyujinxVerification(Cog): join_channel = self.bot.get_channel(config.welcome_channel) if join_channel is not None: - await join_channel.send('Hello {0.mention}! Welcome to Ryujinx! Please read the <#411271165429022730>, and then type the verifying command here to gain access to the rest of the channels.\n\nIf you need help with basic common questions, visit the <#585288848704143371> channel after joining.\n\nIf you need help with Animal Crossing visit the <#692104087889641472> channel for common issues and solutions. If you need help that is not Animal Crossing related, please visit the <#410208610455519243> channel after verifying.'.format(member)) + await join_channel.send( + 'Hello {0.mention}! Welcome to Ryujinx! Please read the <#411271165429022730>, and then type the verifying command here to gain access to the rest of the channels.\n\nIf you need help with basic common questions, visit the <#585288848704143371> channel after joining.\n\nIf you need help with Animal Crossing visit the <#692104087889641472> channel for common issues and solutions. If you need help that is not Animal Crossing related, please visit the <#410208610455519243> channel after verifying.'.format( + member)) async def process_message(self, message): """Process the verification process""" @@ -90,5 +92,6 @@ class RyujinxVerification(Cog): # We only auto clear the channel daily await self.do_reset(channel, author) -def setup(bot): - bot.add_cog(RyujinxVerification(bot)) + +async def setup(bot): + await bot.add_cog(RyujinxVerification(bot))