diff --git a/.gitignore b/.gitignore index 553ad321..f06391dd 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ __pycache__/ # Other *.out + +# Environment +env diff --git a/.version b/.version index 75a22a26..b0f2dcb3 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -3.0.3 +3.0.4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 97646b87..e42d94f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ # Reaction Light - Changelog +### 3.0.4 +- Rework reactions storage ([#105](https://github.com/eibex/reaction-light/pull/105) by [Edwinexd](https://github.com/Edwinexd)) +- Bump timeout for message contents from 2 to 5 minutes ([cad818b](https://github.com/eibex/reaction-light/commit/cad818ba231a63acddb0dffc606abf7959d4fb11) by [eibex](https://github.com/eibex)) + ### 3.0.3 - Allow (once again) new lines via modals ([#101](https://github.com/eibex/reaction-light/issues/101) closed by [#103](https://github.com/eibex/reaction-light/pull/103) by [eibex](https://github.com/eibex)) - Bump disnake requirement to v2.4.0 (necessary to update disnake manually) - ### 3.0.2 - Fix `/bot version` - Bump disnake requirement to v2.3.2 (necessary to update disnake manually) diff --git a/README.md b/README.md index 919b35c8..3998f616 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Reaction Light - Discord Role Bot [![Reaction Light Discord Server](https://img.shields.io/discord/914952998109716531?color=5865f2&logo=discord&logoColor=ffffff)](https://discord.gg/cqxZQkhhHm) -[![Reaction Light 3.0.3](https://img.shields.io/badge/Reaction%20Light-3.0.3-yellow.svg)](https://github.com/eibex/reaction-light/blob/master/CHANGELOG.md) +[![Reaction Light 3.0.4](https://img.shields.io/badge/Reaction%20Light-3.0.4-yellow.svg)](https://github.com/eibex/reaction-light/blob/master/CHANGELOG.md) [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](#) [![disnake 2.4.0+](https://img.shields.io/badge/disnake-2.4.0+-blue.svg)](#) diff --git a/bot.py b/bot.py index 5cab05ec..94870022 100644 --- a/bot.py +++ b/bot.py @@ -98,6 +98,9 @@ async def database_updates(self): if handler.version == 2: handler.two_to_three() + if handler.version == 3: + handler.three_to_four() + async def report(self, text, guild_id=None, embed=None): # Send a message to the system channel (if set) if guild_id: diff --git a/cogs/message.py b/cogs/message.py index 8f9f80cc..3b9cafcf 100644 --- a/cogs/message.py +++ b/cogs/message.py @@ -29,6 +29,7 @@ from disnake.ext import commands from cogs.utils.i18n import response from cogs.utils import database +from cogs.utils.sanitizing import sanitize_emoji class Message(commands.Cog): @@ -104,6 +105,9 @@ def check(message): error_messages.append((await inter.channel.send(response.get("new-reactionrole-emoji-403")))) continue else: + rl_object["reactions"] = dict( + (sanitize_emoji(reaction), role_id) for reaction, role_id in (rl_object["reactions"].items()) + ) break except asyncio.TimeoutError: await inter.author.send(response.get("new-reactionrole-timeout")) @@ -533,7 +537,7 @@ async def edit_reaction( return try: - react = self.bot.db.add_reaction(message_to_edit.id, role.id, reaction) + react = self.bot.db.add_reaction(message_to_edit.id, role.id, sanitize_emoji(reaction)) except DatabaseError as error: await self.bot.report( response.get("db-error-add-reaction").format( @@ -557,7 +561,7 @@ async def edit_reaction( return try: - react = self.bot.db.remove_reaction(message_to_edit.id, reaction) + react = self.bot.db.remove_reaction(message_to_edit.id, sanitize_emoji(reaction)) except DatabaseError as error: await self.bot.report( response.get("db-error-remove-reaction").format( diff --git a/cogs/roles.py b/cogs/roles.py index 2ab6be44..91df8be7 100644 --- a/cogs/roles.py +++ b/cogs/roles.py @@ -25,6 +25,7 @@ from sqlite3 import Error as DatabaseError import disnake from disnake.ext import commands + from cogs.utils.i18n import response from cogs.utils.locks import lock_manager @@ -34,8 +35,9 @@ def __init__(self, bot): self.bot = bot @commands.Cog.listener() - async def on_raw_reaction_add(self, payload): + async def on_raw_reaction_add(self, payload: disnake.RawReactionActionEvent): reaction = str(payload.emoji) + sanitized_reaction = str(payload.emoji.id) if payload.emoji.is_custom_emoji() else payload.emoji.name msg_id = payload.message_id ch_id = payload.channel_id user_id = payload.user_id @@ -58,12 +60,12 @@ async def on_raw_reaction_add(self, payload): ch = await self.bot.getchannel(ch_id) msg = await ch.fetch_message(msg_id) user = await self.bot.getuser(user_id) - if reaction not in reactions: + if sanitized_reaction not in reactions: # Removes reactions added to the reaction-role message that are not connected to any role await msg.remove_reaction(reaction, user) else: # Gives role if it has permissions, else 403 error is raised - role_id = reactions[reaction] + role_id = reactions[sanitized_reaction] guild = await self.bot.getguild(guild_id) member = await self.bot.getmember(guild, user_id) role = disnake.utils.get(guild.roles, id=role_id) @@ -97,8 +99,8 @@ async def on_raw_reaction_add(self, payload): await self.bot.report(guild_id, response.get("permission-error-add")) @commands.Cog.listener() - async def on_raw_reaction_remove(self, payload): - reaction = str(payload.emoji) + async def on_raw_reaction_remove(self, payload: disnake.RawReactionActionEvent): + sanitized_reaction = str(payload.emoji.id) if payload.emoji.is_custom_emoji() else payload.emoji.name msg_id = payload.message_id user_id = payload.user_id guild_id = payload.guild_id @@ -114,8 +116,8 @@ async def on_raw_reaction_remove(self, payload): except DatabaseError as error: await self.bot.report(guild_id, response.get("db-error-reaction-get").format(exception=error)) return - if reaction in reactions: - role_id = reactions[reaction] + if sanitized_reaction in reactions: + role_id = reactions[sanitized_reaction] # Removes role if it has permissions, else 403 error is raised guild = await self.bot.getguild(guild_id) member = await self.bot.getmember(guild, user_id) diff --git a/cogs/utils/sanitizing.py b/cogs/utils/sanitizing.py new file mode 100644 index 00000000..d7448a81 --- /dev/null +++ b/cogs/utils/sanitizing.py @@ -0,0 +1,33 @@ +""" +MIT License + +Copyright (c) 2019-present eibex + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + + +def sanitize_emoji(emoji: str): + if "<" in emoji: + # Store the custom emojis ID + try: + emoji = emoji.split(":")[-1].split(">")[0] + except KeyError: + pass + return emoji diff --git a/cogs/utils/schema.py b/cogs/utils/schema.py index 1ea598d0..96a7fa96 100644 --- a/cogs/utils/schema.py +++ b/cogs/utils/schema.py @@ -26,6 +26,8 @@ import sqlite3 import disnake +from cogs.utils.sanitizing import sanitize_emoji + class SchemaHandler: def __init__(self, database, client): @@ -139,3 +141,31 @@ def two_to_three(self): cursor.close() conn.close() self.set_version(3) + + def three_to_four(self): + conn = sqlite3.connect(self.database) + cursor = conn.cursor() + + cursor.execute("SELECT reactionrole_id, reaction, role_id FROM reactionroles;") + result = cursor.fetchall() + + targets = [] + for reaction_role in result: + reaction: str = reaction_role[1] + sanitized_reaction = sanitize_emoji(reaction) + if reaction != sanitized_reaction: + reaction_role = list(reaction_role) + reaction_role[1] = sanitized_reaction + targets.append(reaction_role) + + if targets: + # Repack targets for query + # reactionrole_id, reaction, role_id -> reaction, reactionrole_id, role_id + targets = [(i[1], i[0], i[2]) for i in targets] + cursor.executemany("UPDATE reactionroles SET reaction = ? WHERE reactionrole_id = ? AND role_id = ?", targets) + conn.commit() + + cursor.close() + conn.close() + + self.set_version(4)