Exemple #1
0
 async def restart_cmd(self, inter):
     if platform != "win32":
         self.restart()
         await inter.response.defer()
         await inter.edit_original_message(content=response.get("restart"))
         await self.bot.close()
     else:
         await inter.send(response.get("windows-error"))
Exemple #2
0
    async def toggle_notify(self, inter):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            return

        await inter.response.defer()
        notify = self.bot.db.toggle_notify(inter.guild.id)
        if notify:
            await inter.edit_original_message(
                content=response.get("notifications-on"))
        else:
            await inter.edit_original_message(
                content=response.get("notifications-off"))
Exemple #3
0
 async def set_language(
     self,
     inter,
     language: str = commands.Param(
         description=response.get("settings-language-option-language"),
         choices=response.languages(),
     ),
 ):
     await inter.response.defer()
     self.bot.config.update("server", "language", language)
     response.language = language
     await inter.edit_original_message(
         content=response.get("language-success"))
Exemple #4
0
    async def on_raw_reaction_remove(self, payload):
        reaction = str(payload.emoji)
        msg_id = payload.message_id
        user_id = payload.user_id
        guild_id = payload.guild_id
        exists = self.bot.db.exists(msg_id)

        if isinstance(exists, Exception):
            await self.bot.system_notification(
                guild_id,
                response.get("db-error-reaction-remove").format(
                    exception=exists),
            )
        elif exists:
            # Checks that the message that was unreacted to is a reaction-role message managed by the bot
            reactions = self.bot.db.get_reactions(msg_id)

            if isinstance(reactions, Exception):
                await self.bot.system_notification(
                    guild_id,
                    response.get("db-error-reaction-get").format(
                        exception=reactions),
                )
            elif reaction in reactions:
                role_id = reactions[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)

                role = disnake.utils.get(guild.roles, id=role_id)
                try:
                    await member.remove_roles(role)
                    notify = self.bot.db.notify(guild_id)
                    if isinstance(notify, Exception):
                        await self.bot.system_notification(
                            guild_id,
                            response.get("db-error-notification-check").format(
                                exception=notify),
                        )
                        return

                    if notify:
                        await member.send(
                            response.get("removed-role-dm").format(
                                role_name=role.name))
                except disnake.Forbidden:
                    await self.bot.system_notification(
                        guild_id, response.get("permission-error-remove"))
Exemple #5
0
class Help(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.bot.remove_command("help")

    @commands.slash_command(name="help",
                            description=response.get("brief-help"))
    async def hlp(self, inter):
        if self.bot.isadmin(inter.author, inter.guild.id):
            await inter.response.defer()
            await inter.edit_original_message(
                content=response.get("help-messages-title") +
                response.get("help-new") + response.get("help-edit") +
                response.get("help-reaction") +
                response.get("help-settings-title") +
                response.get("help-notify") + response.get("help-colour") +
                response.get("help-activity") +
                response.get("help-systemchannel") +
                response.get("help-language") +
                response.get("help-admins-title") +
                response.get("help-admin") +
                response.get("help-bot-control-title") +
                response.get("help-kill") + response.get("help-restart") +
                response.get("help-update") + response.get("help-version") +
                response.get("help-footer").format(version=self.bot.version))
        else:
            await inter.send(content=response.get("not-admin"))
Exemple #6
0
    async def formatted_channel_list(self, channel):
        # Returns a formatted numbered list of reaction roles message present in a given channel
        all_messages = self.bot.db.fetch_messages(channel.id)
        if isinstance(all_messages, Exception):
            await self.bot.system_notification(
                channel.guild.id,
                response.get("db-error-fetching-messages").format(
                    exception=all_messages),
            )
            return

        formatted_list = []
        counter = 1
        for msg_id in all_messages:
            try:
                old_msg = await channel.fetch_message(int(msg_id))

            except disnake.NotFound:
                # Skipping reaction-role messages that might have been deleted without updating CSVs
                continue

            entry = (
                f"`{counter}`"
                f" {old_msg.embeds[0].title if old_msg.embeds else old_msg.content}"
            )
            formatted_list.append(entry)
            counter += 1

        return formatted_list
Exemple #7
0
    async def system_notification(self, guild_id, text, embed=None):
        # Send a message to the system channel (if set)
        if guild_id:
            server_channel = self.db.fetch_systemchannel(guild_id)

            if isinstance(server_channel, Exception):
                await self.system_notification(
                    None,
                    response.get(
                        "db-error-fetching-systemchannels-server").format(
                            exception=server_channel, text=text),
                )
                return

            if server_channel:
                server_channel = server_channel[0][0]

            if server_channel:
                try:
                    target_channel = await self.getchannel(server_channel)
                    if embed:
                        await target_channel.send(text, embed=embed)
                    else:
                        await target_channel.send(text)
                except disnake.Forbidden:
                    await self.system_notification(None, text)
            else:
                if embed:
                    await self.system_notification(None, text, embed=embed)
                else:
                    await self.system_notification(None, text)
        elif self.config.system_channel:
            try:
                target_channel = await self.getchannel(
                    self.config.system_channel)
                if embed:
                    await target_channel.send(text, embed=embed)
                else:
                    await target_channel.send(text)
            except disnake.NotFound:
                print(response.get("systemchannel-404"))
            except disnake.Forbidden:
                print(response.get("systemchannel-403"))
        else:
            print(text)
Exemple #8
0
 async def update(self, inter):
     if platform != "win32":
         await inter.response.defer()
         await inter.edit_original_message(
             content=response.get("attempting-update"))
         os.chdir(self.bot.directory)
         cmd = os.popen("git fetch")
         cmd.close()
         cmd = os.popen("git pull")
         cmd.close()
         await inter.channel.send(response.get("database-backup"))
         copy(
             f"{self.directory}/files/reactionlight.db",
             f"{self.directory}/files/reactionlight.db.bak",
         )
         self.restart()
         await inter.channel.send(response.get("restart"))
         await self.bot.close()
     else:
         await inter.send(response.get("windows-error"))
Exemple #9
0
    async def set_colour(
        self,
        inter,
        colour: str = commands.Param(
            description=response.get("settings-colour-option-colour")),
    ):
        await inter.response.defer()
        try:
            self.bot.config.botcolour = disnake.Colour(int(colour, 16))
            self.bot.config.update("server", "colour", colour)
            example = disnake.Embed(
                title=response.get("example-embed"),
                description=response.get("example-embed-new-colour"),
                colour=self.bot.config.botcolour,
            )
            await inter.edit_original_message(
                content=response.get("colour-changed"), embed=example)

        except ValueError:
            await inter.edit_original_message(
                content=response.get("colour-hex-error"))
Exemple #10
0
    async def print_version(self, inter):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.edit_original_message(content=response.get("not-admin")
                                              )
            return

        await inter.response.defer()
        latest = await github.get_latest()
        changelog = await github.latest_changelog()
        em = disnake.Embed(
            title=f"Reaction Light v{latest} - Changes",
            description=changelog,
            colour=self.bot.config.botcolour,
        )
        em.set_footer(text=f"{self.bot.config.botname}",
                      icon_url=self.bot.config.logo)
        await inter.edit_original_message(
            content=response.get("version").format(version=self.bot.version,
                                                   latest_version=latest),
            embed=em,
        )
Exemple #11
0
    async def change_activity(
        self,
        inter,
        action: str = commands.Param(
            description=response.get("settings-activity-option-action"),
            choices=("add", "remove", "list"),
        ),
        activity: str = commands.Param(
            description=response.get("settings-activity-option-activity"),
            default=None),
    ):
        await inter.response.defer()
        if action == "add" and activity:
            if "," in activity:
                await inter.send(response.get("activity-no-commas"))

            else:
                self.bot.activities.add(activity)
                await inter.send(
                    response.get("activity-success").format(
                        new_activity=activity))
        elif action == "list":
            if self.bot.activities.activity_list:
                formatted_list = []
                for item in self.bot.activities.activity_list:
                    formatted_list.append(f"`{item}`")

                await inter.send(
                    response.get("current-activities").format(
                        activity_list="\n- ".join(formatted_list)))

            else:
                await inter.send(response.get("no-current-activities"))
        elif action == "remove" and activity:
            removed = self.bot.activities.remove(activity)
            if removed:
                await inter.send(
                    response.get("rm-activity-success").format(
                        activity_to_delete=activity))
            else:
                await inter.send(response.get("rm-activity-not-exists"))
        else:
            await inter.send(response.get("activity-add-list-remove"))
Exemple #12
0
    def isadmin(self, member, guild_id):
        # Checks if command author has an admin role that was added with rl!admin
        admins = self.db.get_admins(guild_id)

        if isinstance(admins, Exception):
            print(
                response.get("db-error-admin-check").format(exception=admins))
            return False

        try:
            member_roles = [role.id for role in member.roles]
            return [
                admin_role for admin_role in admins
                if admin_role in member_roles
            ]

        except AttributeError:
            # Error raised from 'fake' users, such as webhooks
            return False
Exemple #13
0
    async def updates(self):
        await self.bot.wait_until_ready()
        # Sends a reminder once a day if there are updates available
        new_version = await github.check_for_updates(self.bot.version)

        if new_version:
            changelog = await github.latest_changelog()
            em = disnake.Embed(
                title=f"Reaction Light v{new_version} - Changes",
                description=changelog,
                colour=self.bot.config.botcolour,
            )
            em.set_footer(text=f"{self.bot.config.botname}",
                          icon_url=self.bot.config.logo)
            await self.bot.system_notification(
                None,
                response.get("update-notification").format(
                    new_version=new_version),
                embed=em,
            )
Exemple #14
0
        if not guild:
            guild = await self.fetch_guild(guild_id)

        return guild

    async def getuser(self, user_id):
        user = self.get_user(user_id)

        if not user:
            user = await self.fetch_user(user_id)

        return user

    async def getmember(self, guild, user_id):
        member = guild.get_member(user_id)

        if not member:
            member = await guild.fetch_member(user_id)

        return member


rl = ReactionLight()

try:
    rl.run(rl.config.token, reconnect=True)
except disnake.PrivilegedIntentsRequired:
    print(response.get("login-failure-intents"))
except disnake.errors.LoginFailure:
    print(response.get("login-failure-token"))
Exemple #15
0
 async def kill(self, inter):
     await inter.response.defer()
     await inter.edit_original_message(content=response.get("shutdown"))
     await self.bot.close()
Exemple #16
0
class Control(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.updates.start()

    def restart(self):
        # Create a new python process of bot.py and stops the current one
        os.chdir(self.bot.directory)
        python = "python" if platform == "win32" else "python3"
        cmd = os.popen(f"nohup {python} bot.py &")
        cmd.close()

    @tasks.loop(hours=24)
    async def updates(self):
        await self.bot.wait_until_ready()
        # Sends a reminder once a day if there are updates available
        new_version = await github.check_for_updates(self.bot.version)

        if new_version:
            changelog = await github.latest_changelog()
            em = disnake.Embed(
                title=f"Reaction Light v{new_version} - Changes",
                description=changelog,
                colour=self.bot.config.botcolour,
            )
            em.set_footer(text=f"{self.bot.config.botname}",
                          icon_url=self.bot.config.logo)
            await self.bot.system_notification(
                None,
                response.get("update-notification").format(
                    new_version=new_version),
                embed=em,
            )

    @commands.slash_command(name="bot")
    async def controlbot_group(self, inter):
        pass

    @controlbot_group.sub_command(name="version",
                                  description=response.get("brief-version"))
    async def print_version(self, inter):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.edit_original_message(content=response.get("not-admin")
                                              )
            return

        await inter.response.defer()
        latest = await github.get_latest()
        changelog = await github.latest_changelog()
        em = disnake.Embed(
            title=f"Reaction Light v{latest} - Changes",
            description=changelog,
            colour=self.bot.config.botcolour,
        )
        em.set_footer(text=f"{self.bot.config.botname}",
                      icon_url=self.bot.config.logo)
        await inter.edit_original_message(
            content=response.get("version").format(version=self.bot.version,
                                                   latest_version=latest),
            embed=em,
        )

    @commands.is_owner()
    @controlbot_group.sub_command(name="kill",
                                  description=response.get("brief-kill"))
    async def kill(self, inter):
        await inter.response.defer()
        await inter.edit_original_message(content=response.get("shutdown"))
        await self.bot.close()

    @commands.is_owner()
    @controlbot_group.sub_command(name="restart",
                                  description=response.get("brief-restart"))
    async def restart_cmd(self, inter):
        if platform != "win32":
            self.restart()
            await inter.response.defer()
            await inter.edit_original_message(content=response.get("restart"))
            await self.bot.close()
        else:
            await inter.send(response.get("windows-error"))

    @commands.is_owner()
    @controlbot_group.sub_command(name="update",
                                  description=response.get("brief-update"))
    async def update(self, inter):
        if platform != "win32":
            await inter.response.defer()
            await inter.edit_original_message(
                content=response.get("attempting-update"))
            os.chdir(self.bot.directory)
            cmd = os.popen("git fetch")
            cmd.close()
            cmd = os.popen("git pull")
            cmd.close()
            await inter.channel.send(response.get("database-backup"))
            copy(
                f"{self.directory}/files/reactionlight.db",
                f"{self.directory}/files/reactionlight.db.bak",
            )
            self.restart()
            await inter.channel.send(response.get("restart"))
            await self.bot.close()
        else:
            await inter.send(response.get("windows-error"))
Exemple #17
0
    async def edit_selector(
        self,
        inter,
        channel: disnake.TextChannel = commands.Param(
            description=response.get("message-edit-option-channel")),
        number: int = commands.Param(
            description=response.get("message-edit-option-number")),
        message: str = commands.Param(
            description=response.get("message-edit-option-message"),
            default="none"),
        title: str = commands.Param(
            description=response.get("message-edit-option-title"),
            default="none"),
        description: str = commands.Param(
            description=response.get("message-edit-option-description"),
            default="none"),
    ):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.send(response.get("not-admin"))
            return

        await inter.response.defer()
        all_messages = await self.formatted_channel_list(channel)
        if number == 0:
            if len(all_messages) == 1:
                await inter.edit_original_message(
                    content=response.get("edit-reactionrole-one").format(
                        channel_name=channel.name))
            elif len(all_messages) > 1:
                await inter.edit_original_message(content=response.get(
                    "edit-reactionrole-instructions").format(
                        num_messages=len(all_messages),
                        channel_name=channel.name,
                        message_list="\n".join(all_messages),
                    ))
            else:
                await inter.edit_original_message(
                    content=response.get("no-reactionrole-messages"))
        else:
            try:
                # Tries to edit the reaction-role message
                # Raises errors if the channel sent was invalid or if the bot cannot edit the message
                all_messages = self.bot.db.fetch_messages(channel.id)
                message = message if message.lower() != "none" else None
                title = title if title.lower() != "none" else None
                description = description if description.lower(
                ) != "none" else None

                if isinstance(all_messages, Exception):
                    await self.bot.system_notification(
                        inter.guild.id,
                        response.get("db-error-fetching-messages").format(
                            message_ids=all_messages),
                    )
                    return

                counter = 1
                if all_messages:
                    message_to_edit_id = None
                    for msg_id in all_messages:
                        # Loop through all msg_ids and stops when the counter matches the user input
                        if counter == number:
                            message_to_edit_id = msg_id
                            break

                        counter += 1
                else:
                    await inter.send(response.get("reactionrole-not-exists"))
                    return

                if message_to_edit_id:
                    old_msg = await channel.fetch_message(
                        int(message_to_edit_id))
                else:
                    await inter.send(response.get("select-valid-reactionrole"))
                    return
                await old_msg.edit(suppress=False)
                selector_msg_new_body = message
                selector_embed = disnake.Embed()

                if title:
                    selector_embed.title = title
                    selector_embed.colour = self.bot.config.botcolour
                    selector_embed.set_footer(
                        text=f"{self.bot.config.botname}",
                        icon_url=self.bot.config.logo,
                    )

                if description:
                    selector_embed.description = description
                    selector_embed.colour = self.bot.config.botcolour
                    selector_embed.set_footer(
                        text=f"{self.bot.config.botname}",
                        icon_url=self.bot.config.logo,
                    )

                try:

                    if selector_embed.title or selector_embed.description:
                        await old_msg.edit(content=selector_msg_new_body,
                                           embed=selector_embed)
                    else:
                        await old_msg.edit(content=selector_msg_new_body,
                                           embed=None)

                    await inter.edit_original_message(
                        content=response.get("message-edited"))
                except disnake.Forbidden:
                    await inter.edit_original_message(
                        content=response.get("other-author-error"))
                    return
                except disnake.HTTPException as e:
                    if e.code == 50006:
                        await inter.edit_original_message(
                            content=response.get("empty-message-error"))
                    else:
                        guild_id = inter.guild.id
                        await self.bot.system_notification(guild_id, str(e))
            except IndexError:
                await inter.edit_original_message(
                    content=response.get("invalid-target-channel"))
            except disnake.Forbidden:
                await inter.edit_original_message(
                    content=response.get("edit-permission-error"))
Exemple #18
0
    async def on_raw_reaction_add(self, payload):
        reaction = str(payload.emoji)
        msg_id = payload.message_id
        ch_id = payload.channel_id
        user_id = payload.user_id
        guild_id = payload.guild_id
        exists = self.bot.db.exists(msg_id)

        async with (await lock_manager.get_lock(user_id)):
            if isinstance(exists, Exception):
                await self.bot.system_notification(
                    guild_id,
                    response.get("db-error-reaction-add").format(
                        exception=exists),
                )
            elif exists:
                # Checks that the message that was reacted to is a reaction-role message managed by the bot
                reactions = self.bot.db.get_reactions(msg_id)

                if isinstance(reactions, Exception):
                    await self.bot.system_notification(
                        guild_id,
                        response.get("db-error-reaction-get").format(
                            exception=reactions),
                    )
                    return

                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:
                    # 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]
                    guild = await self.bot.getguild(guild_id)
                    member = await self.bot.getmember(guild, user_id)
                    role = disnake.utils.get(guild.roles, id=role_id)
                    if user_id != self.bot.user.id:
                        unique = self.bot.db.isunique(msg_id)
                        if unique:
                            for existing_reaction in msg.reactions:
                                if str(existing_reaction.emoji) == reaction:
                                    continue
                                async for reaction_user in existing_reaction.users(
                                ):
                                    if reaction_user.id == user_id:
                                        await msg.remove_reaction(
                                            existing_reaction, user)
                                        # We can safely break since a user can only have one reaction at once
                                        break

                        try:
                            await member.add_roles(role)
                            notify = self.bot.db.notify(guild_id)
                            if isinstance(notify, Exception):
                                await self.bot.system_notification(
                                    guild_id,
                                    response.get("db-error-notification-check"
                                                 ).format(exception=notify),
                                )
                                return

                            if notify:
                                await user.send(
                                    response.get("new-role-dm").format(
                                        role_name=role.name))
                        except disnake.Forbidden:
                            await self.bot.system_notification(
                                guild_id, response.get("permission-error-add"))
Exemple #19
0
 async def on_command_error(self, inter, error):
     if isinstance(error, commands.NotOwner):
         await inter.send(response.get("not-owner"))
     else:
         traceback.print_tb(error.__traceback__)
         print(error)
Exemple #20
0
    async def set_systemchannel(
        self,
        inter,
        channel_type: str = commands.Param(
            description=response.get("settings-systemchannel-option-type"),
            choices=("main", "server", "explanation"),
        ),
        channel: disnake.TextChannel = commands.Param(
            description=response.get("settings-systemchannel-option-channel"),
            default=None,
        ),
    ):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.send(content=response.get("not-admin"))
            return

        await inter.response.defer()
        if not channel or channel_type not in ("main", "server"):
            server_channel = self.bot.db.fetch_systemchannel(inter.guild.id)
            if isinstance(server_channel, Exception):
                await self.bot.system_notification(
                    None,
                    response.get("db-error-fetching-systemchannels").format(
                        exception=server_channel),
                )
                return

            if server_channel:
                server_channel = server_channel[0][0]

            main_text = ((await self.bot.getchannel(
                self.bot.config.system_channel)).mention
                         if self.bot.config.system_channel else "none")
            server_text = ((await self.bot.getchannel(server_channel)).mention
                           if server_channel else "none")
            await inter.edit_original_message(
                content=response.get("systemchannels-info").format(
                    main_channel=main_text, server_channel=server_text))
            return

        bot_user = inter.guild.get_member(self.bot.user.id)
        bot_permissions = channel.permissions_for(bot_user)
        writable = bot_permissions.read_messages
        readable = bot_permissions.view_channel
        if not writable or not readable:
            await inter.edit_original_message(
                content=response.get("permission-error-channel"))
            return

        if channel_type == "main":
            self.bot.config.update("server", "system_channel", str(channel.id))
        elif channel_type == "server":
            add_channel = self.bot.db.add_systemchannel(
                inter.guild.id, channel.id)

            if isinstance(add_channel, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-adding-systemchannels").format(
                        exception=add_channel),
                )
                return

        await inter.edit_original_message(
            content=response.get("systemchannels-success"))
Exemple #21
0
class Settings(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.maintain_presence.start()

    @tasks.loop(seconds=30)
    async def maintain_presence(self):
        await self.bot.wait_until_ready()
        # Loops through the activities specified in activities.csv
        current_activity = self.bot.activities.get()
        await self.bot.change_presence(activity=disnake.Game(
            name=current_activity))

    @commands.slash_command(name="settings")
    async def settings_group(self, inter):
        pass

    @settings_group.sub_command(
        name="systemchannel",
        description=response.get("brief-settings-systemchannel"))
    async def set_systemchannel(
        self,
        inter,
        channel_type: str = commands.Param(
            description=response.get("settings-systemchannel-option-type"),
            choices=("main", "server", "explanation"),
        ),
        channel: disnake.TextChannel = commands.Param(
            description=response.get("settings-systemchannel-option-channel"),
            default=None,
        ),
    ):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.send(content=response.get("not-admin"))
            return

        await inter.response.defer()
        if not channel or channel_type not in ("main", "server"):
            server_channel = self.bot.db.fetch_systemchannel(inter.guild.id)
            if isinstance(server_channel, Exception):
                await self.bot.system_notification(
                    None,
                    response.get("db-error-fetching-systemchannels").format(
                        exception=server_channel),
                )
                return

            if server_channel:
                server_channel = server_channel[0][0]

            main_text = ((await self.bot.getchannel(
                self.bot.config.system_channel)).mention
                         if self.bot.config.system_channel else "none")
            server_text = ((await self.bot.getchannel(server_channel)).mention
                           if server_channel else "none")
            await inter.edit_original_message(
                content=response.get("systemchannels-info").format(
                    main_channel=main_text, server_channel=server_text))
            return

        bot_user = inter.guild.get_member(self.bot.user.id)
        bot_permissions = channel.permissions_for(bot_user)
        writable = bot_permissions.read_messages
        readable = bot_permissions.view_channel
        if not writable or not readable:
            await inter.edit_original_message(
                content=response.get("permission-error-channel"))
            return

        if channel_type == "main":
            self.bot.config.update("server", "system_channel", str(channel.id))
        elif channel_type == "server":
            add_channel = self.bot.db.add_systemchannel(
                inter.guild.id, channel.id)

            if isinstance(add_channel, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-adding-systemchannels").format(
                        exception=add_channel),
                )
                return

        await inter.edit_original_message(
            content=response.get("systemchannels-success"))

    @settings_group.sub_command(
        name="notify", description=response.get("brief-settings-notify"))
    async def toggle_notify(self, inter):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            return

        await inter.response.defer()
        notify = self.bot.db.toggle_notify(inter.guild.id)
        if notify:
            await inter.edit_original_message(
                content=response.get("notifications-on"))
        else:
            await inter.edit_original_message(
                content=response.get("notifications-off"))

    @commands.is_owner()
    @settings_group.sub_command(
        name="language", description=response.get("brief-settings-language"))
    async def set_language(
        self,
        inter,
        language: str = commands.Param(
            description=response.get("settings-language-option-language"),
            choices=response.languages(),
        ),
    ):
        await inter.response.defer()
        self.bot.config.update("server", "language", language)
        response.language = language
        await inter.edit_original_message(
            content=response.get("language-success"))

    @commands.is_owner()
    @settings_group.sub_command(
        name="colour", description=response.get("brief-settings-colour"))
    async def set_colour(
        self,
        inter,
        colour: str = commands.Param(
            description=response.get("settings-colour-option-colour")),
    ):
        await inter.response.defer()
        try:
            self.bot.config.botcolour = disnake.Colour(int(colour, 16))
            self.bot.config.update("server", "colour", colour)
            example = disnake.Embed(
                title=response.get("example-embed"),
                description=response.get("example-embed-new-colour"),
                colour=self.bot.config.botcolour,
            )
            await inter.edit_original_message(
                content=response.get("colour-changed"), embed=example)

        except ValueError:
            await inter.edit_original_message(
                content=response.get("colour-hex-error"))

    @commands.is_owner()
    @settings_group.sub_command(
        name="activity", description=response.get("brief-settings-activity"))
    async def change_activity(
        self,
        inter,
        action: str = commands.Param(
            description=response.get("settings-activity-option-action"),
            choices=("add", "remove", "list"),
        ),
        activity: str = commands.Param(
            description=response.get("settings-activity-option-activity"),
            default=None),
    ):
        await inter.response.defer()
        if action == "add" and activity:
            if "," in activity:
                await inter.send(response.get("activity-no-commas"))

            else:
                self.bot.activities.add(activity)
                await inter.send(
                    response.get("activity-success").format(
                        new_activity=activity))
        elif action == "list":
            if self.bot.activities.activity_list:
                formatted_list = []
                for item in self.bot.activities.activity_list:
                    formatted_list.append(f"`{item}`")

                await inter.send(
                    response.get("current-activities").format(
                        activity_list="\n- ".join(formatted_list)))

            else:
                await inter.send(response.get("no-current-activities"))
        elif action == "remove" and activity:
            removed = self.bot.activities.remove(activity)
            if removed:
                await inter.send(
                    response.get("rm-activity-success").format(
                        activity_to_delete=activity))
            else:
                await inter.send(response.get("rm-activity-not-exists"))
        else:
            await inter.send(response.get("activity-add-list-remove"))
Exemple #22
0
    async def new(self, inter):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.send(response.get("new-reactionrole-noadmin"))
            return

        await inter.send(response.get("new-reactionrole-init"))
        rl_object = {}
        cancelled = False

        def check(message):
            return message.author.id == inter.author.id and message.content != "" and message.channel.id == inter.channel.id

        if not cancelled:
            error_messages = []
            user_messages = []
            sent_reactions_message = await inter.channel.send(
                response.get("new-reactionrole-roles-emojis"))
            rl_object["reactions"] = {}
            try:
                while True:
                    reactions_message = await self.bot.wait_for("message",
                                                                timeout=120,
                                                                check=check)
                    user_messages.append(reactions_message)
                    if reactions_message.content.lower() != "done":
                        reaction = (reactions_message.content.split())[0]
                        try:
                            role = reactions_message.role_mentions[0].id
                        except IndexError:
                            error_messages.append((await inter.channel.send(
                                response.get("new-reactionrole-error"))))
                            continue

                        if reaction in rl_object["reactions"]:
                            error_messages.append((await inter.channel.send(
                                response.get("new-reactionrole-already-used")
                            )))
                            continue
                        else:
                            try:
                                await reactions_message.add_reaction(reaction)
                                rl_object["reactions"][reaction] = role
                            except disnake.HTTPException:
                                error_messages.append(
                                    (await inter.channel.send(
                                        response.get(
                                            "new-reactionrole-emoji-403"))))
                                continue
                    else:
                        break
            except asyncio.TimeoutError:
                await inter.author.send(
                    response.get("new-reactionrole-timeout"))
                cancelled = True
            finally:
                await sent_reactions_message.delete()
                for message in error_messages + user_messages:
                    await message.delete()

        if not cancelled:
            sent_limited_message = await inter.channel.send(
                response.get("new-reactionrole-limit"))

            def reaction_check(payload):
                return (payload.member.id == inter.author.id
                        and payload.message_id == sent_limited_message.id
                        and (str(payload.emoji) == "🔒"
                             or str(payload.emoji) == "♾️"))

            try:
                await sent_limited_message.add_reaction("🔒")
                await sent_limited_message.add_reaction("♾️")
                limited_message_response_payload = await self.bot.wait_for(
                    "raw_reaction_add", timeout=120, check=reaction_check)

                if str(limited_message_response_payload.emoji) == "🔒":
                    rl_object["limit_to_one"] = 1
                else:
                    rl_object["limit_to_one"] = 0
            except asyncio.TimeoutError:
                await inter.author.send(
                    response.get("new-reactionrole-timeout"))
                cancelled = True
            finally:
                await sent_limited_message.delete()

        if not cancelled:
            sent_oldmessagequestion_message = await inter.channel.send(
                response.get("new-reactionrole-old-or-new").format(
                    bot_mention=self.bot.user.mention))

            def reaction_check2(payload):
                return (payload.member.id == inter.author.id
                        and payload.message_id
                        == sent_oldmessagequestion_message.id
                        and (str(payload.emoji) == "🗨️"
                             or str(payload.emoji) == "🤖"))

            try:
                await sent_oldmessagequestion_message.add_reaction("🗨️")
                await sent_oldmessagequestion_message.add_reaction("🤖")
                oldmessagequestion_response_payload = await self.bot.wait_for(
                    "raw_reaction_add", timeout=120, check=reaction_check2)

                if str(oldmessagequestion_response_payload.emoji) == "🗨️":
                    rl_object["old_message"] = True
                else:
                    rl_object["old_message"] = False
            except asyncio.TimeoutError:
                await inter.author.send(
                    response.get("new-reactionrole-timeout"))
                cancelled = True
            finally:
                await sent_oldmessagequestion_message.delete()

        if not cancelled:
            error_messages = []
            user_messages = []
            if rl_object["old_message"]:
                sent_oldmessage_message = await inter.channel.send(
                    response.get("new-reactionrole-which-message").format(
                        bot_mention=self.bot.user.mention))

                def reaction_check3(payload):
                    return (payload.user_id == inter.author.id
                            and payload.guild_id == inter.guild.id
                            and str(payload.emoji) == "🔧")

                try:
                    while True:
                        oldmessage_response_payload = await self.bot.wait_for(
                            "raw_reaction_add",
                            timeout=120,
                            check=reaction_check3)
                        try:
                            try:
                                channel = await self.bot.getchannel(
                                    oldmessage_response_payload.channel_id)
                            except disnake.InvalidData:
                                channel = None
                            except disnake.HTTPException:
                                channel = None

                            if channel is None:
                                raise disnake.NotFound
                            try:
                                message = await channel.fetch_message(
                                    oldmessage_response_payload.message_id)
                            except disnake.HTTPException:
                                raise disnake.NotFound
                            try:
                                await message.add_reaction("👌")
                                await message.remove_reaction(
                                    "👌", message.guild.me)
                                await message.remove_reaction(
                                    "🔧", inter.author)
                            except disnake.HTTPException:
                                raise disnake.NotFound
                            if self.bot.db.exists(message.id):
                                raise ValueError
                            rl_object["message"] = dict(
                                message_id=message.id,
                                channel_id=message.channel.id,
                                guild_id=message.guild.id,
                            )
                            final_message = message
                            break
                        except disnake.NotFound:
                            error_messages.append((await inter.channel.send(
                                response.get(
                                    "new-reactionrole-permission-error").
                                format(bot_mention=self.bot.user.mention))))
                        except ValueError:
                            error_messages.append((await inter.channel.send(
                                response.get("new-reactionrole-already-exists")
                            )))
                except asyncio.TimeoutError:
                    await inter.author.send(
                        response.get("new-reactionrole-timeout"))
                    cancelled = True
                finally:
                    await sent_oldmessage_message.delete()
                    for message in error_messages:
                        await message.delete()
            else:
                sent_channel_message = await inter.channel.send(
                    response.get("new-reactionrole-target-channel"))
                try:
                    while True:
                        channel_message = await self.bot.wait_for("message",
                                                                  timeout=120,
                                                                  check=check)
                        user_messages.append(channel_message)
                        if channel_message.channel_mentions:
                            rl_object[
                                "target_channel"] = channel_message.channel_mentions[
                                    0]
                            break
                        else:
                            error_messages.append((await message.channel.send(
                                response.get("invalid-target-channel"))))
                except asyncio.TimeoutError:
                    await inter.author.send(
                        response.get("new-reactionrole-timeout"))
                    cancelled = True
                finally:
                    await sent_channel_message.delete()
                    for message in error_messages + user_messages:
                        await message.delete()

        if not cancelled and "target_channel" in rl_object:
            error_messages = []
            user_messages = []
            selector_embed = disnake.Embed(
                title="Embed_title",
                description="Embed_content",
                colour=self.bot.config.botcolour,
            )
            selector_embed.set_footer(text=f"{self.bot.config.botname}",
                                      icon_url=self.bot.config.logo)

            sent_message_message = await message.channel.send(
                response.get("new-reactionrole-message-contents"),
                embed=selector_embed,
            )
            try:
                while True:
                    message_message = await self.bot.wait_for("message",
                                                              timeout=120,
                                                              check=check)
                    user_messages.append(message_message)
                    msg_values = message_message.content.split(" // ")
                    # This whole system could also be re-done using wait_for to make the syntax easier for the user
                    # But it would be a breaking change that would be annoying for thoose who have saved their message commands
                    # for editing.
                    selector_msg_body = (msg_values[0]
                                         if msg_values[0].lower() != "none"
                                         else None)
                    selector_embed = disnake.Embed(
                        colour=self.bot.config.botcolour)
                    selector_embed.set_footer(
                        text=f"{self.bot.config.botname}",
                        icon_url=self.bot.config.logo,
                    )

                    if len(msg_values) > 1:
                        if msg_values[1].lower() != "none":
                            selector_embed.title = msg_values[1]
                        if len(msg_values) > 2 and msg_values[2].lower(
                        ) != "none":
                            selector_embed.description = msg_values[2]

                    # Prevent sending an empty embed instead of removing it
                    selector_embed = (selector_embed if selector_embed.title
                                      or selector_embed.description else None)

                    if selector_msg_body or selector_embed:
                        target_channel = rl_object["target_channel"]
                        sent_final_message = None
                        try:
                            sent_final_message = await target_channel.send(
                                content=selector_msg_body,
                                embed=selector_embed)
                            rl_object["message"] = dict(
                                message_id=sent_final_message.id,
                                channel_id=sent_final_message.channel.id,
                                guild_id=sent_final_message.guild.id,
                            )
                            final_message = sent_final_message
                            break
                        except disnake.Forbidden:
                            error_messages.append((await message.channel.send(
                                response.get(
                                    "new-reactionrole-message-send-permission-error"
                                ).format(
                                    channel_mention=target_channel.mention))))
            except asyncio.TimeoutError:
                await inter.author.send(
                    response.get("new-reactionrole-timeout"))
                cancelled = True
            finally:
                await sent_message_message.delete()
                for message in error_messages + user_messages:
                    await message.delete()

        if not cancelled:
            # Ait we are (almost) all done, now we just need to insert that into the database and add the reactions 💪
            try:
                r = self.bot.db.add_reaction_role(rl_object)
            except database.DuplicateInstance:
                await inter.channel.send(
                    response.get("new-reactionrole-already-exists"))
                return

            if isinstance(r, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-new-reactionrole").format(
                        exception=r),
                )
                return

            for reaction, _ in rl_object["reactions"].items():
                await final_message.add_reaction(reaction)

        await inter.delete_original_message()

        if cancelled:
            await inter.channel.send(response.get("new-reactionrole-cancelled")
                                     )
Exemple #23
0
    async def cleandb(self):
        await self.bot.wait_until_ready()
        # Cleans the database by deleting rows of reaction role messages that don't exist anymore
        messages = self.bot.db.fetch_all_messages()
        guilds = self.bot.db.fetch_all_guilds()
        # Get the cleanup queued guilds
        cleanup_guild_ids = self.bot.db.fetch_cleanup_guilds(
            guild_ids_only=True)

        if isinstance(messages, Exception):
            await self.bot.system_notification(
                None,
                response.get("db-error-fetching-cleaning").format(
                    exception=messages),
            )
            return

        for message in messages:
            try:
                channel_id = message[1]
                channel = await self.bot.fetch_channel(channel_id)

                await channel.fetch_message(message[0])

            except disnake.NotFound as e:
                # If unknown channel or unknown message
                if e.code == 10003 or e.code == 10008:
                    delete = self.bot.db.delete(message[0])

                    if isinstance(delete, Exception):
                        await self.bot.system_notification(
                            channel.guild.id,
                            response.get("db-error-fetching-cleaning").format(
                                exception=delete),
                        )
                        return

                    await self.bot.system_notification(
                        channel.guild.id,
                        response.get("db-message-delete-success").format(
                            message_id=message, channel=channel.mention),
                    )
            except disnake.Forbidden:
                # If we can't fetch the channel due to the bot not being in the guild or permissions we usually cant mention it or get the guilds id using the channels object
                await self.bot.system_notification(
                    message[3],
                    response.get("db-forbidden-message").format(
                        message_id=message[0], channel_id=message[1]),
                )

        if isinstance(guilds, Exception):
            await self.bot.system_notification(
                None,
                response.get("db-error-fetching-cleaning-guild").format(
                    exception=guilds),
            )
            return

        for guild_id in guilds:
            try:
                await self.bot.fetch_guild(guild_id)
                if guild_id in cleanup_guild_ids:
                    self.bot.db.remove_cleanup_guild(guild_id)
            except disnake.Forbidden:
                # If unknown guild
                if guild_id in cleanup_guild_ids:
                    continue
                else:
                    self.bot.db.add_cleanup_guild(
                        guild_id, round(datetime.utcnow().timestamp()))

        cleanup_guilds = self.bot.db.fetch_cleanup_guilds()

        if isinstance(cleanup_guilds, Exception):
            await self.bot.system_notification(
                None,
                response.get("db-error-fetching-cleanup-guild").format(
                    exception=cleanup_guilds),
            )
            return

        current_timestamp = round(datetime.utcnow().timestamp())

        for guild in cleanup_guilds:
            if int(guild[1]) - current_timestamp <= -86400:
                # The guild has been invalid / unreachable for more than 24 hrs, try one more fetch then give up and purge the guilds database entries
                try:
                    await self.bot.fetch_guild(guild[0])
                    self.bot.db.remove_cleanup_guild(guild[0])
                    continue
                except disnake.Forbidden:
                    delete = self.bot.db.remove_guild(guild[0])
                    delete2 = self.bot.db.remove_cleanup_guild(guild[0])
                    if isinstance(delete, Exception):
                        await self.bot.system_notification(
                            None,
                            response.get("db-error-deleting-cleaning-guild").
                            format(exception=delete),
                        )
                        return
                    elif isinstance(delete2, Exception):
                        await self.bot.system_notification(
                            None,
                            response.get("db-error-deleting-cleaning-guild").
                            format(exception=delete2),
                        )
                        return
Exemple #24
0
    async def admin(
        self,
        inter,
        action: str = commands.Param(
            description=response.get("admin-option-action"),
            choices=("add", "remove", "list"),
        ),
        role: disnake.Role = commands.Param(
            description=response.get("admin-option-role"), default=None),
    ):
        await inter.response.defer()
        if role is None or action == "list":
            # Lists all admin IDs in the database, mentioning them if possible
            admin_ids = self.bot.db.get_admins(inter.guild.id)

            if isinstance(admin_ids, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-fetching-admins").format(
                        exception=admin_ids),
                )
                return

            adminrole_objects = []
            for admin_id in admin_ids:
                adminrole_objects.append(
                    disnake.utils.get(inter.guild.roles, id=admin_id).mention)

            if adminrole_objects:
                await inter.edit_original_message(
                    content=response.get("adminlist-local").format(
                        admin_list="\n- ".join(adminrole_objects)))
            else:
                await inter.edit_original_message(
                    content=response.get("adminlist-local-empty"))

        elif action == "add":
            # Adds an admin role ID to the database
            add = self.bot.db.add_admin(role.id, inter.guild.id)

            if isinstance(add, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-admin-add").format(exception=add),
                )
                return

            await inter.edit_original_message(
                content=response.get("admin-add-success"))

        elif action == "remove":
            # Removes an admin role ID from the database
            remove = self.bot.db.remove_admin(role.id, inter.guild.id)

            if isinstance(remove, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-admin-remove").format(
                        exception=remove),
                )
                return

            await inter.edit_original_message(
                content=response.get("admin-remove-success"))
Exemple #25
0
    async def edit_reaction(
        self,
        inter,
        channel: disnake.TextChannel = commands.Param(
            description=response.get("message-reaction-option-channel")),
        action: str = commands.Param(
            description=response.get("message-reaction-option-action"),
            choices=("add", "remove"),
        ),
        number: int = commands.Param(
            description=response.get("message-reaction-option-number")),
        reaction: str = commands.Param(
            description=response.get("message-reaction-option-reaction"),
            default=None),
        role: disnake.Role = commands.Param(
            description=response.get("message-reaction-option-role"),
            default=None),
    ):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.send(response.get("not-admin"))
            return

        await inter.response.defer()
        if number == 0 or not reaction:
            all_messages = await self.formatted_channel_list(channel)
            if len(all_messages) == 1:
                await inter.edit_original_message(
                    content=response.get("reaction-edit-one").format(
                        channel_name=channel.name))
                return
            elif len(all_messages) > 1:
                await inter.edit_original_message(
                    content=response.get("reaction-edit-multi").format(
                        num_messages=len(all_messages),
                        channel_name=channel.name,
                        message_list="\n".join(all_messages),
                    ))
                return
            else:
                await inter.edit_original_message(
                    content=response.get("no-reactionrole-messages"))
                return

        if action == "add":
            if not role:
                await inter.edit_original_message(
                    content=response.get("no-role-mentioned"))
                return

        all_messages = self.bot.db.fetch_messages(channel.id)
        if isinstance(all_messages, Exception):
            await self.bot.system_notification(
                inter.guild.id,
                response.get("db-error-fetching-messages").format(
                    exception=all_messages),
            )
            return

        counter = 1
        if all_messages:
            message_to_edit_id = None
            for msg_id in all_messages:
                # Loop through all msg_ids and stops when the counter matches the user input
                if counter == number:
                    message_to_edit_id = msg_id
                    break

                counter += 1
        else:
            await inter.edit_original_message(
                content=response.get("reactionrole-not-exists"))
            return

        if message_to_edit_id:
            message_to_edit = await channel.fetch_message(
                int(message_to_edit_id))
        else:
            await inter.edit_original_message(
                content=response.get("select-valid-reactionrole"))
            return

        if action == "add":
            try:
                # Check that the bot can actually use the emoji
                await message_to_edit.add_reaction(reaction)
            except disnake.HTTPException:
                await inter.edit_original_message(
                    content=response.get("new-reactionrole-emoji-403"))
                return

            react = self.bot.db.add_reaction(message_to_edit.id, role.id,
                                             reaction)
            if isinstance(react, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-add-reaction").format(
                        channel_mention=message_to_edit.channel.mention,
                        exception=react,
                    ),
                )
                return

            if not react:
                await inter.edit_original_message(
                    content=response.get("reaction-edit-already-exists"))
                return

            await inter.edit_original_message(
                content=response.get("reaction-edit-add-success"))
        elif action == "remove":
            try:
                await message_to_edit.clear_reaction(reaction)

            except disnake.HTTPException:
                await inter.edit_original_message(
                    content=response.get("reaction-edit-invalid-reaction"))
                return

            react = self.bot.db.remove_reaction(message_to_edit.id, reaction)

            if isinstance(react, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-remove-reaction").format(
                        channel_mention=message_to_edit.channel.mention,
                        exception=react,
                    ),
                )
                return

            await inter.edit_original_message(
                content=response.get("reaction-edit-remove-success"))
Exemple #26
0
class Message(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    async def formatted_channel_list(self, channel):
        # Returns a formatted numbered list of reaction roles message present in a given channel
        all_messages = self.bot.db.fetch_messages(channel.id)
        if isinstance(all_messages, Exception):
            await self.bot.system_notification(
                channel.guild.id,
                response.get("db-error-fetching-messages").format(
                    exception=all_messages),
            )
            return

        formatted_list = []
        counter = 1
        for msg_id in all_messages:
            try:
                old_msg = await channel.fetch_message(int(msg_id))

            except disnake.NotFound:
                # Skipping reaction-role messages that might have been deleted without updating CSVs
                continue

            entry = (
                f"`{counter}`"
                f" {old_msg.embeds[0].title if old_msg.embeds else old_msg.content}"
            )
            formatted_list.append(entry)
            counter += 1

        return formatted_list

    @commands.slash_command(name="message")
    async def message_group(self, inter):
        pass

    @message_group.sub_command(name="new",
                               description=response.get("brief-message-new"))
    async def new(self, inter):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.send(response.get("new-reactionrole-noadmin"))
            return

        await inter.send(response.get("new-reactionrole-init"))
        rl_object = {}
        cancelled = False

        def check(message):
            return message.author.id == inter.author.id and message.content != "" and message.channel.id == inter.channel.id

        if not cancelled:
            error_messages = []
            user_messages = []
            sent_reactions_message = await inter.channel.send(
                response.get("new-reactionrole-roles-emojis"))
            rl_object["reactions"] = {}
            try:
                while True:
                    reactions_message = await self.bot.wait_for("message",
                                                                timeout=120,
                                                                check=check)
                    user_messages.append(reactions_message)
                    if reactions_message.content.lower() != "done":
                        reaction = (reactions_message.content.split())[0]
                        try:
                            role = reactions_message.role_mentions[0].id
                        except IndexError:
                            error_messages.append((await inter.channel.send(
                                response.get("new-reactionrole-error"))))
                            continue

                        if reaction in rl_object["reactions"]:
                            error_messages.append((await inter.channel.send(
                                response.get("new-reactionrole-already-used")
                            )))
                            continue
                        else:
                            try:
                                await reactions_message.add_reaction(reaction)
                                rl_object["reactions"][reaction] = role
                            except disnake.HTTPException:
                                error_messages.append(
                                    (await inter.channel.send(
                                        response.get(
                                            "new-reactionrole-emoji-403"))))
                                continue
                    else:
                        break
            except asyncio.TimeoutError:
                await inter.author.send(
                    response.get("new-reactionrole-timeout"))
                cancelled = True
            finally:
                await sent_reactions_message.delete()
                for message in error_messages + user_messages:
                    await message.delete()

        if not cancelled:
            sent_limited_message = await inter.channel.send(
                response.get("new-reactionrole-limit"))

            def reaction_check(payload):
                return (payload.member.id == inter.author.id
                        and payload.message_id == sent_limited_message.id
                        and (str(payload.emoji) == "🔒"
                             or str(payload.emoji) == "♾️"))

            try:
                await sent_limited_message.add_reaction("🔒")
                await sent_limited_message.add_reaction("♾️")
                limited_message_response_payload = await self.bot.wait_for(
                    "raw_reaction_add", timeout=120, check=reaction_check)

                if str(limited_message_response_payload.emoji) == "🔒":
                    rl_object["limit_to_one"] = 1
                else:
                    rl_object["limit_to_one"] = 0
            except asyncio.TimeoutError:
                await inter.author.send(
                    response.get("new-reactionrole-timeout"))
                cancelled = True
            finally:
                await sent_limited_message.delete()

        if not cancelled:
            sent_oldmessagequestion_message = await inter.channel.send(
                response.get("new-reactionrole-old-or-new").format(
                    bot_mention=self.bot.user.mention))

            def reaction_check2(payload):
                return (payload.member.id == inter.author.id
                        and payload.message_id
                        == sent_oldmessagequestion_message.id
                        and (str(payload.emoji) == "🗨️"
                             or str(payload.emoji) == "🤖"))

            try:
                await sent_oldmessagequestion_message.add_reaction("🗨️")
                await sent_oldmessagequestion_message.add_reaction("🤖")
                oldmessagequestion_response_payload = await self.bot.wait_for(
                    "raw_reaction_add", timeout=120, check=reaction_check2)

                if str(oldmessagequestion_response_payload.emoji) == "🗨️":
                    rl_object["old_message"] = True
                else:
                    rl_object["old_message"] = False
            except asyncio.TimeoutError:
                await inter.author.send(
                    response.get("new-reactionrole-timeout"))
                cancelled = True
            finally:
                await sent_oldmessagequestion_message.delete()

        if not cancelled:
            error_messages = []
            user_messages = []
            if rl_object["old_message"]:
                sent_oldmessage_message = await inter.channel.send(
                    response.get("new-reactionrole-which-message").format(
                        bot_mention=self.bot.user.mention))

                def reaction_check3(payload):
                    return (payload.user_id == inter.author.id
                            and payload.guild_id == inter.guild.id
                            and str(payload.emoji) == "🔧")

                try:
                    while True:
                        oldmessage_response_payload = await self.bot.wait_for(
                            "raw_reaction_add",
                            timeout=120,
                            check=reaction_check3)
                        try:
                            try:
                                channel = await self.bot.getchannel(
                                    oldmessage_response_payload.channel_id)
                            except disnake.InvalidData:
                                channel = None
                            except disnake.HTTPException:
                                channel = None

                            if channel is None:
                                raise disnake.NotFound
                            try:
                                message = await channel.fetch_message(
                                    oldmessage_response_payload.message_id)
                            except disnake.HTTPException:
                                raise disnake.NotFound
                            try:
                                await message.add_reaction("👌")
                                await message.remove_reaction(
                                    "👌", message.guild.me)
                                await message.remove_reaction(
                                    "🔧", inter.author)
                            except disnake.HTTPException:
                                raise disnake.NotFound
                            if self.bot.db.exists(message.id):
                                raise ValueError
                            rl_object["message"] = dict(
                                message_id=message.id,
                                channel_id=message.channel.id,
                                guild_id=message.guild.id,
                            )
                            final_message = message
                            break
                        except disnake.NotFound:
                            error_messages.append((await inter.channel.send(
                                response.get(
                                    "new-reactionrole-permission-error").
                                format(bot_mention=self.bot.user.mention))))
                        except ValueError:
                            error_messages.append((await inter.channel.send(
                                response.get("new-reactionrole-already-exists")
                            )))
                except asyncio.TimeoutError:
                    await inter.author.send(
                        response.get("new-reactionrole-timeout"))
                    cancelled = True
                finally:
                    await sent_oldmessage_message.delete()
                    for message in error_messages:
                        await message.delete()
            else:
                sent_channel_message = await inter.channel.send(
                    response.get("new-reactionrole-target-channel"))
                try:
                    while True:
                        channel_message = await self.bot.wait_for("message",
                                                                  timeout=120,
                                                                  check=check)
                        user_messages.append(channel_message)
                        if channel_message.channel_mentions:
                            rl_object[
                                "target_channel"] = channel_message.channel_mentions[
                                    0]
                            break
                        else:
                            error_messages.append((await message.channel.send(
                                response.get("invalid-target-channel"))))
                except asyncio.TimeoutError:
                    await inter.author.send(
                        response.get("new-reactionrole-timeout"))
                    cancelled = True
                finally:
                    await sent_channel_message.delete()
                    for message in error_messages + user_messages:
                        await message.delete()

        if not cancelled and "target_channel" in rl_object:
            error_messages = []
            user_messages = []
            selector_embed = disnake.Embed(
                title="Embed_title",
                description="Embed_content",
                colour=self.bot.config.botcolour,
            )
            selector_embed.set_footer(text=f"{self.bot.config.botname}",
                                      icon_url=self.bot.config.logo)

            sent_message_message = await message.channel.send(
                response.get("new-reactionrole-message-contents"),
                embed=selector_embed,
            )
            try:
                while True:
                    message_message = await self.bot.wait_for("message",
                                                              timeout=120,
                                                              check=check)
                    user_messages.append(message_message)
                    msg_values = message_message.content.split(" // ")
                    # This whole system could also be re-done using wait_for to make the syntax easier for the user
                    # But it would be a breaking change that would be annoying for thoose who have saved their message commands
                    # for editing.
                    selector_msg_body = (msg_values[0]
                                         if msg_values[0].lower() != "none"
                                         else None)
                    selector_embed = disnake.Embed(
                        colour=self.bot.config.botcolour)
                    selector_embed.set_footer(
                        text=f"{self.bot.config.botname}",
                        icon_url=self.bot.config.logo,
                    )

                    if len(msg_values) > 1:
                        if msg_values[1].lower() != "none":
                            selector_embed.title = msg_values[1]
                        if len(msg_values) > 2 and msg_values[2].lower(
                        ) != "none":
                            selector_embed.description = msg_values[2]

                    # Prevent sending an empty embed instead of removing it
                    selector_embed = (selector_embed if selector_embed.title
                                      or selector_embed.description else None)

                    if selector_msg_body or selector_embed:
                        target_channel = rl_object["target_channel"]
                        sent_final_message = None
                        try:
                            sent_final_message = await target_channel.send(
                                content=selector_msg_body,
                                embed=selector_embed)
                            rl_object["message"] = dict(
                                message_id=sent_final_message.id,
                                channel_id=sent_final_message.channel.id,
                                guild_id=sent_final_message.guild.id,
                            )
                            final_message = sent_final_message
                            break
                        except disnake.Forbidden:
                            error_messages.append((await message.channel.send(
                                response.get(
                                    "new-reactionrole-message-send-permission-error"
                                ).format(
                                    channel_mention=target_channel.mention))))
            except asyncio.TimeoutError:
                await inter.author.send(
                    response.get("new-reactionrole-timeout"))
                cancelled = True
            finally:
                await sent_message_message.delete()
                for message in error_messages + user_messages:
                    await message.delete()

        if not cancelled:
            # Ait we are (almost) all done, now we just need to insert that into the database and add the reactions 💪
            try:
                r = self.bot.db.add_reaction_role(rl_object)
            except database.DuplicateInstance:
                await inter.channel.send(
                    response.get("new-reactionrole-already-exists"))
                return

            if isinstance(r, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-new-reactionrole").format(
                        exception=r),
                )
                return

            for reaction, _ in rl_object["reactions"].items():
                await final_message.add_reaction(reaction)

        await inter.delete_original_message()

        if cancelled:
            await inter.channel.send(response.get("new-reactionrole-cancelled")
                                     )

    @message_group.sub_command(name="edit",
                               description=response.get("brief-message-edit"))
    async def edit_selector(
        self,
        inter,
        channel: disnake.TextChannel = commands.Param(
            description=response.get("message-edit-option-channel")),
        number: int = commands.Param(
            description=response.get("message-edit-option-number")),
        message: str = commands.Param(
            description=response.get("message-edit-option-message"),
            default="none"),
        title: str = commands.Param(
            description=response.get("message-edit-option-title"),
            default="none"),
        description: str = commands.Param(
            description=response.get("message-edit-option-description"),
            default="none"),
    ):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.send(response.get("not-admin"))
            return

        await inter.response.defer()
        all_messages = await self.formatted_channel_list(channel)
        if number == 0:
            if len(all_messages) == 1:
                await inter.edit_original_message(
                    content=response.get("edit-reactionrole-one").format(
                        channel_name=channel.name))
            elif len(all_messages) > 1:
                await inter.edit_original_message(content=response.get(
                    "edit-reactionrole-instructions").format(
                        num_messages=len(all_messages),
                        channel_name=channel.name,
                        message_list="\n".join(all_messages),
                    ))
            else:
                await inter.edit_original_message(
                    content=response.get("no-reactionrole-messages"))
        else:
            try:
                # Tries to edit the reaction-role message
                # Raises errors if the channel sent was invalid or if the bot cannot edit the message
                all_messages = self.bot.db.fetch_messages(channel.id)
                message = message if message.lower() != "none" else None
                title = title if title.lower() != "none" else None
                description = description if description.lower(
                ) != "none" else None

                if isinstance(all_messages, Exception):
                    await self.bot.system_notification(
                        inter.guild.id,
                        response.get("db-error-fetching-messages").format(
                            message_ids=all_messages),
                    )
                    return

                counter = 1
                if all_messages:
                    message_to_edit_id = None
                    for msg_id in all_messages:
                        # Loop through all msg_ids and stops when the counter matches the user input
                        if counter == number:
                            message_to_edit_id = msg_id
                            break

                        counter += 1
                else:
                    await inter.send(response.get("reactionrole-not-exists"))
                    return

                if message_to_edit_id:
                    old_msg = await channel.fetch_message(
                        int(message_to_edit_id))
                else:
                    await inter.send(response.get("select-valid-reactionrole"))
                    return
                await old_msg.edit(suppress=False)
                selector_msg_new_body = message
                selector_embed = disnake.Embed()

                if title:
                    selector_embed.title = title
                    selector_embed.colour = self.bot.config.botcolour
                    selector_embed.set_footer(
                        text=f"{self.bot.config.botname}",
                        icon_url=self.bot.config.logo,
                    )

                if description:
                    selector_embed.description = description
                    selector_embed.colour = self.bot.config.botcolour
                    selector_embed.set_footer(
                        text=f"{self.bot.config.botname}",
                        icon_url=self.bot.config.logo,
                    )

                try:

                    if selector_embed.title or selector_embed.description:
                        await old_msg.edit(content=selector_msg_new_body,
                                           embed=selector_embed)
                    else:
                        await old_msg.edit(content=selector_msg_new_body,
                                           embed=None)

                    await inter.edit_original_message(
                        content=response.get("message-edited"))
                except disnake.Forbidden:
                    await inter.edit_original_message(
                        content=response.get("other-author-error"))
                    return
                except disnake.HTTPException as e:
                    if e.code == 50006:
                        await inter.edit_original_message(
                            content=response.get("empty-message-error"))
                    else:
                        guild_id = inter.guild.id
                        await self.bot.system_notification(guild_id, str(e))
            except IndexError:
                await inter.edit_original_message(
                    content=response.get("invalid-target-channel"))
            except disnake.Forbidden:
                await inter.edit_original_message(
                    content=response.get("edit-permission-error"))

    @message_group.sub_command(
        name="reaction", description=response.get("brief-message-reaction"))
    async def edit_reaction(
        self,
        inter,
        channel: disnake.TextChannel = commands.Param(
            description=response.get("message-reaction-option-channel")),
        action: str = commands.Param(
            description=response.get("message-reaction-option-action"),
            choices=("add", "remove"),
        ),
        number: int = commands.Param(
            description=response.get("message-reaction-option-number")),
        reaction: str = commands.Param(
            description=response.get("message-reaction-option-reaction"),
            default=None),
        role: disnake.Role = commands.Param(
            description=response.get("message-reaction-option-role"),
            default=None),
    ):
        if not self.bot.isadmin(inter.author, inter.guild.id):
            await inter.send(response.get("not-admin"))
            return

        await inter.response.defer()
        if number == 0 or not reaction:
            all_messages = await self.formatted_channel_list(channel)
            if len(all_messages) == 1:
                await inter.edit_original_message(
                    content=response.get("reaction-edit-one").format(
                        channel_name=channel.name))
                return
            elif len(all_messages) > 1:
                await inter.edit_original_message(
                    content=response.get("reaction-edit-multi").format(
                        num_messages=len(all_messages),
                        channel_name=channel.name,
                        message_list="\n".join(all_messages),
                    ))
                return
            else:
                await inter.edit_original_message(
                    content=response.get("no-reactionrole-messages"))
                return

        if action == "add":
            if not role:
                await inter.edit_original_message(
                    content=response.get("no-role-mentioned"))
                return

        all_messages = self.bot.db.fetch_messages(channel.id)
        if isinstance(all_messages, Exception):
            await self.bot.system_notification(
                inter.guild.id,
                response.get("db-error-fetching-messages").format(
                    exception=all_messages),
            )
            return

        counter = 1
        if all_messages:
            message_to_edit_id = None
            for msg_id in all_messages:
                # Loop through all msg_ids and stops when the counter matches the user input
                if counter == number:
                    message_to_edit_id = msg_id
                    break

                counter += 1
        else:
            await inter.edit_original_message(
                content=response.get("reactionrole-not-exists"))
            return

        if message_to_edit_id:
            message_to_edit = await channel.fetch_message(
                int(message_to_edit_id))
        else:
            await inter.edit_original_message(
                content=response.get("select-valid-reactionrole"))
            return

        if action == "add":
            try:
                # Check that the bot can actually use the emoji
                await message_to_edit.add_reaction(reaction)
            except disnake.HTTPException:
                await inter.edit_original_message(
                    content=response.get("new-reactionrole-emoji-403"))
                return

            react = self.bot.db.add_reaction(message_to_edit.id, role.id,
                                             reaction)
            if isinstance(react, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-add-reaction").format(
                        channel_mention=message_to_edit.channel.mention,
                        exception=react,
                    ),
                )
                return

            if not react:
                await inter.edit_original_message(
                    content=response.get("reaction-edit-already-exists"))
                return

            await inter.edit_original_message(
                content=response.get("reaction-edit-add-success"))
        elif action == "remove":
            try:
                await message_to_edit.clear_reaction(reaction)

            except disnake.HTTPException:
                await inter.edit_original_message(
                    content=response.get("reaction-edit-invalid-reaction"))
                return

            react = self.bot.db.remove_reaction(message_to_edit.id, reaction)

            if isinstance(react, Exception):
                await self.bot.system_notification(
                    inter.guild.id,
                    response.get("db-error-remove-reaction").format(
                        channel_mention=message_to_edit.channel.mention,
                        exception=react,
                    ),
                )
                return

            await inter.edit_original_message(
                content=response.get("reaction-edit-remove-success"))
Exemple #27
0
 async def hlp(self, inter):
     if self.bot.isadmin(inter.author, inter.guild.id):
         await inter.response.defer()
         await inter.edit_original_message(
             content=response.get("help-messages-title") +
             response.get("help-new") + response.get("help-edit") +
             response.get("help-reaction") +
             response.get("help-settings-title") +
             response.get("help-notify") + response.get("help-colour") +
             response.get("help-activity") +
             response.get("help-systemchannel") +
             response.get("help-language") +
             response.get("help-admins-title") +
             response.get("help-admin") +
             response.get("help-bot-control-title") +
             response.get("help-kill") + response.get("help-restart") +
             response.get("help-update") + response.get("help-version") +
             response.get("help-footer").format(version=self.bot.version))
     else:
         await inter.send(content=response.get("not-admin"))