예제 #1
0
def setup_module():
    global SESSION, BASE_SERVER, BASE_USER
    SESSION = manager.get_session(botconfig, db_config="TestDatabase")
    BASE_USER = models.User(discord_id=randint(10, 10000))
    SESSION.add(BASE_USER)
    BASE_SERVER = models.Server(discord_id=randint(10, 10000))
    SESSION.add(BASE_SERVER)
    SESSION.commit()
예제 #2
0
def test_positive_create_user():
    """Create a user and verify it exists in the database"""
    discord_id = randint(10, 10000)
    new_user = models.User(discord_id=discord_id)
    SESSION.add(new_user)
    SESSION.commit()
    user = SESSION.query(
        models.User).filter(models.User.discord_id == discord_id).one()
    assert user.discord_id == discord_id
    assert user.created
예제 #3
0
def test_positive_create_alias():
    """Create a user and alias, assigning the latter to the former"""
    discord_id = randint(10, 10000)
    new_user = models.User(discord_id=discord_id)
    SESSION.add(new_user)
    alias_text = "my cool alias#0000"
    new_alias = models.Alias(name=alias_text, user=new_user)
    SESSION.add(new_alias)
    SESSION.commit()
    assert (SESSION.query(models.Alias.name).filter(
        models.Alias.user == new_user).one()[0] == alias_text)
예제 #4
0
파일: helpers.py 프로젝트: glanyx/segachan
 async def db_get_user(self, session, discord_id):
     try:
         # Try and get record from database
         db_user = (session.query(models.User).filter(
             models.User.discord_id == discord_id).first())
         # If no DB record for the user then create one
         if not db_user:
             db_user = models.User(discord_id=discord_id)
             session.add(db_user)
             session.commit()
             self.bot.log.debug(f"Added new user to DB: {discord_id}")
         return db_user
     except Exception as err:
         self.bot.log.exception(
             f"Error getting / adding user to database: '{discord_id}'. {sys.exc_info()[0].__name__}: {err}"
         )
예제 #5
0
def test_positive_action_warn():
    """This test also covers Note, Mute, and Ban"""
    discord_id, warn_text = randint(10, 10000), "this is a test warning"
    logged_action = models.Action(mod=BASE_USER, server=BASE_SERVER)
    new_warn = models.Warn(
        text=warn_text,
        user=models.User(discord_id=discord_id),
        server=BASE_SERVER,
        action=logged_action,
    )
    SESSION.add(new_warn)
    SESSION.commit()
    user = SESSION.query(
        models.User).filter(models.User.discord_id == discord_id).one()
    assert new_warn in user.warn
    warn = SESSION.query(models.Warn).filter(models.Warn.user == user).first()
    assert warn.text == warn_text
    assert warn.action == logged_action
예제 #6
0
    async def handle_outgoing_chan_from_mod(self, message):
        user = None
        # Check if we have a user for the mod mail channel the message is being sent in
        user_id = self.redis.get(
            f"user_id:bid:{self.bot.user.id}:mmcid:{message.channel.id}")
        # If no user ID, such as message sent in a non user mod mail channel, just stop processing
        if not user_id:
            return
        # Try to get the user from the bots caching
        else:
            user = self.bot.get_user(int(user_id))
            # Try to get from an API call
            if not user:
                user = await self.bot.fetch_user(int(user_id))
                # If no user, let mods know, stop processing
                if not user:
                    self.bot.log.exception(
                        f"Unable to find a user from the User ID: {user_id}. This could be due to bad Redis cache data.\n\n**Redis Data:** 'user_id:bid:{self.bot.user.id}:mmcid:{message.channel.id}'"
                    )
                    return await message.channel.send(
                        f"Unable to find a user from the User ID: {user_id}. Please validate it's the correct User ID for the user. This has already been reported to my developers."
                    )

        # If the user is blacklisted, exit out (but let's tell the mods first)
        if await self.bot.helpers.check_if_blacklisted(user.id,
                                                       self.modmail_server_id):
            self.bot.log.debug(
                f"User {message.author} ({message.author.id}) Blacklisted, unable to use Mod Mail"
            )
            return await message.channel.send(
                "\N{CROSS MARK} Sorry, unable to send to that user as they are **blacklisted.**"
            )

        # Now that we have the channel, we need to process it
        session = self.bot.helpers.get_db_session()
        try:
            msg_body = f"{message.content[:1900]}\n\n-{message.author}"

            # Step 1: Send the mods message to the user
            if message.attachments:
                all_links = []
                for file in message.attachments:
                    new_file = discord.File(io.BytesIO(await file.read()),
                                            filename=file.filename)
                    all_links.append(new_file)
                # Once we have all files, send to the user
                msg_to_user = await user.send(msg_body, files=all_links)
            else:
                # If no attachments send regular message
                msg_to_user = await user.send(msg_body)

            # Step 2: Send the message to the mod server
            embed = discord.Embed(color=0x551A8B,
                                  timestamp=datetime.utcnow(),
                                  description=msg_body)
            embed.set_author(
                name=f"Member: {message.author} ({message.author.id})",
                icon_url=message.author.avatar_url,
            )
            # Create list of links
            file_links = []
            if msg_to_user.attachments:
                all_links = []
                counter = 0
                for file in msg_to_user.attachments:
                    counter += 1
                    word = num2words(counter)
                    link = f"Link [{word}]({file.proxy_url})"
                    all_links.append(link)
                    file_links.append(file.proxy_url)
                attachments_text = ", ".join(all_links)
                embed.add_field(name="Attachments",
                                value=f"{attachments_text}",
                                inline=False)
            embed.add_field(name="Bot/User Channel ID",
                            value=f"{user.dm_channel.id}",
                            inline=False)
            embed.add_field(name="Bot/User Message ID",
                            value=f"{msg_to_user.id}",
                            inline=False)
            # Set the footer
            embed.set_footer(text=f"Outgoing Mod Mail")

            # Send the message in the channel
            await message.channel.send(embed=embed)
            # If message successfully sends, delete the calling message
            await message.delete()
            # Step 3: Move to the In Progress category, only if it was in unanswered
            if message.channel.category_id == self.modmail_unanswered_cat.id:
                try:
                    await message.channel.edit(
                        category=self.modmail_in_progress_cat)
                except discord.errors.HTTPException as err:
                    if err.code == 50035:
                        self.bot.log.warning(
                            f"Unable to move channel. Error: {err}")

                # Update category counts
                # 2020/06/19 - Disabling Category Count Update due to B9940-121
                # await self.update_cat_count(
                #    self.modmail_unanswered_cat, unanswered=True
                # )
                # await self.update_cat_count(
                #    self.modmail_in_progress_cat, unanswered=False
                # )
            # Step 4: Log to the database
            # Check if there is a user in the database already
            db_user = (session.query(models.User).filter(
                models.User.discord_id == message.author.id).first())
            # If no DB record for the user then create one
            if not db_user:
                db_user = models.User(discord_id=message.author.id)
                session.add(db_user)
            # Get the mod mail guild
            db_mm_guild = (session.query(models.Server).filter(
                models.Server.discord_id == self.mm_guild.id).first())
            # Get the main guild
            db_main_guild = (session.query(models.Server).filter(
                models.Server.discord_id == self.main_guild.id).first())
            # Create the data to inject
            data = {
                "mm_channel_id": message.channel.id,
                "user_channel_id": user.dm_channel.id,
                "message_id": msg_to_user.id,
                "message": msg_body,
                "from_mod": True,
                "file_links": file_links,
            }
            new_message = models.ModMailMessage(
                primary_server=db_main_guild,
                mm_server=db_mm_guild,
                user=db_user,
                **data,
            )
            session.add(new_message)
            session.commit()

        except DBAPIError as err:
            self.bot.log.exception(
                f"Error processing database query for outgoing mod mail. {sys.exc_info()[0].__name__}: {err}"
            )
            session.rollback()
        except discord.Forbidden:
            await message.channel.send(
                f"Unable to send messages to this user. They may have blocked the bot or don't share any servers with the bot anymore."
            )
        except Exception as err:
            self.bot.log.exception(
                f"Unknown exception processing outgoing mod mail. {sys.exc_info()[0].__name__}: {err}"
            )
            await message.channel.send(
                f"There was an error processing the outgoing mod mail. Please wait a few minutes and try again. If you are still having issues, please contact the bot developers."
                f"\n\nThis error has already been reported to my developers. Sorry for the inconvenience."
            )
        finally:
            session.close()
예제 #7
0
    async def handle_incoming_dm_from_user(self, ctx, message):
        self.bot.log.debug(
            f"ModMail: New Message From: {message.author} ({message.author.id})"
        )
        # If the user is blacklisted, exit out
        if await self.bot.helpers.check_if_blacklisted(message.author.id,
                                                       self.modmail_server_id):
            self.bot.log.debug(
                f"ModMail: User {message.author} ({message.author.id}) Blacklisted, unable to use Mod Mail"
            )
            return
        # Check if user is on cooldown/rate limited
        # Also check if the antispam modmail quickmsg feature is enabled
        settings = self.bot.guild_settings.get(self.main_guild.id)
        if settings and settings.antispam_quickmsg_modmail:
            bucket = self._cd_modmail_incoming.get_bucket(message)
            retry_after = bucket.update_rate_limit()
            if retry_after:
                # you're rate limited helpful message here
                self.bot.log.debug(
                    f"ModMail: User {message.author} ({message.author.id}) is on cooldown/rate limited, unable to use Mod Mail. Expires: {retry_after:0.2f} seconds"
                )
                await message.channel.send(
                    f"You are currently on cooldown. Please decrease the rate at which you send us messages or you may find yourself blacklisted.\n\nYou may send messages again in {retry_after:0.2f} seconds."
                )
                return
        # you're not rate limited, continue

        new_channel_created = False
        # Check if we have a channel in the mod mail server yet
        mm_channel_id = self.redis.get(
            f"mm_chanid:bid:{self.bot.user.id}:uid:{message.author.id}")
        self.bot.log.debug(
            f"ModMail: Redis mm_channel_id: {mm_channel_id} User: {message.author} ({message.author.id})"
        )
        # Try to get the channel
        mm_channel = None
        if mm_channel_id:
            mm_channel = self.bot.get_channel(int(mm_channel_id))
        # If no channel, create one
        if not mm_channel:
            mm_channel = await self.make_modmail_channel(message.author)
            # Additional check to make sure a mod mail channel exists
            if not mm_channel:
                self.bot.log.exception(
                    f"ModMail: We just made a mod mail channel, why are we saying there isn't one for user: ({message.author.id})"
                )
                return
            # When we get an incoming message we know all 3 parts:
            # 1. The bot ID
            # 2. The mod mail channel ID
            # 3. The users ID
            # We take all this info and store it, so when we get an incoming message we know the mod mail channel
            # to send it to. When we have an outgoing message we can find the user ID as at any given point
            # we know 2 parts and need to find the 3rd.
            #
            # This sets the mod mail channel ID with a key of the bot ID and the author ID
            # TO DO - Could move the redis cache setting into self.make_modmail_channel so it happens upon creation
            self.redis.set(
                f"mm_chanid:bid:{self.bot.user.id}:uid:{message.author.id}",
                f"{mm_channel.id}",
            )
            self.bot.log.debug(
                f"ModMail: Redis SET: 'mm_chanid:bid:{self.bot.user.id}:uid:{message.author.id}' TO '{mm_channel.id}'"
            )
            # This sets the users ID with a key of the bot ID and the mod mail channel ID
            self.redis.set(
                f"user_id:bid:{self.bot.user.id}:mmcid:{mm_channel.id}",
                f"{message.author.id}",
            )
            self.bot.log.debug(
                f"ModMail: Redis SET: 'user_id:bid:{self.bot.user.id}:mmcid:{mm_channel.id}' TO '{message.author.id}'"
            )
            new_channel_created = True

        # Now that we have the channel, we need to process it
        session = self.bot.helpers.get_db_session()
        try:
            # Step 2: Get the users history and send it:
            (
                embed_result_entries,
                footer_text,
            ) = await self.bot.helpers.get_action_history(
                session, message.author, self.main_guild)

            p = FieldPages(
                ctx,
                per_page=8,
                entries=embed_result_entries,
                mm_channel=mm_channel,
            )
            p.embed.color = 0xFF8C00
            p.embed.set_author(
                name=f"Member: {message.author} ({message.author.id})",
                icon_url=message.author.avatar_url,
            )
            p.embed.set_footer(text=footer_text)

            # Step 3: Send the users message to the mod mail channel
            msg_body = message.clean_content[:2000]
            embed = discord.Embed(color=0x19D219,
                                  timestamp=datetime.utcnow(),
                                  description=msg_body)
            embed.set_author(
                name=f"Member: {message.author} ({message.author.id})",
                icon_url=message.author.avatar_url,
            )
            file_links = []
            if message.attachments:
                all_links = []
                counter = 0
                for file in message.attachments:
                    counter += 1
                    word = num2words(counter)
                    link = f"Link [{word}]({file.url})"
                    all_links.append(link)
                    file_links.append(file.url)
                attachments_text = ", ".join(all_links)
                embed.add_field(name="Attachments",
                                value=f"{attachments_text}",
                                inline=False)
            embed.add_field(name="Bot/User Channel ID",
                            value=f"{message.channel.id}",
                            inline=False)
            embed.add_field(name="Bot/User Message ID",
                            value=f"{message.id}",
                            inline=False)
            # Set the footer
            embed.set_footer(text=f"Incoming Mod Mail")
            # If this is a new interaction (defined by having to create a new channel in the mod mail server)
            if new_channel_created:
                # Send the history
                try:
                    await p.paginate(modmail_bypass=True)
                except discord.errors.HTTPException:
                    self.bot.log.error(
                        f"Error sending History in Mod Mail for {message.author.id}"
                    )
                # Let the user know that we will use reactions to signify their message was received
                await message.channel.send(
                    self.bot.constants.modmail_read_receipts)
            # Always send the users message to us
            await mm_channel.send(embed=embed)
            # Step 4: Let the user know we received their message
            await message.add_reaction("✉")
            # Step 5: Log to the database
            # Check if there is a user in the database already
            db_user = (session.query(models.User).filter(
                models.User.discord_id == message.author.id).first())
            # If no DB record for the user then create one
            if not db_user:
                db_user = models.User(discord_id=message.author.id)
                session.add(db_user)
            # Get the mod mail guild
            db_mm_guild = (session.query(models.Server).filter(
                models.Server.discord_id == self.mm_guild.id).first())
            # Get the main guild
            db_main_guild = (session.query(models.Server).filter(
                models.Server.discord_id == self.main_guild.id).first())
            # Create the data to inject
            data = {
                "mm_channel_id": mm_channel.id,
                "user_channel_id": message.channel.id,
                "message_id": message.id,
                "message": msg_body,
                "from_mod": False,
                "file_links": file_links,
            }
            new_message = models.ModMailMessage(
                primary_server=db_main_guild,
                mm_server=db_mm_guild,
                user=db_user,
                **data,
            )
            session.add(new_message)
            session.commit()

        except DBAPIError as err:
            self.bot.log.exception(
                f"Error processing database query for an incoming mod mail. {sys.exc_info()[0].__name__}: {err}"
            )
            session.rollback()
        except Exception as err:
            self.bot.log.exception(
                f"Unknown exception processing incoming mod mail. {sys.exc_info()[0].__name__}: {err}"
            )
            await message.channel.send(
                f"There was an error processing your mod mail. Please wait a few minutes and try again. If you are still having issues, contact a mod directly."
                f"\n\nThis error has already been reported to my developers. Sorry for the inconvenience."
            )
        finally:
            session.close()
예제 #8
0
    async def request(self, ctx, *, request_body):
        """Takes input as a request and reposts it in a dedicated channel and provides voting reactions to show interest. Logs to database for record keeping. Detects duplication.

        Requires Permission
        -------------------
        Send Messages
        """
        session = self.bot.helpers.get_db_session()
        try:
            self.bot.log.info(
                f"CMD {ctx.invoked_with} called by {ctx.message.author} ({ctx.message.author.id})"
            )

            # Check if user is blacklisted, if so, ignore.
            if await self.bot.helpers.check_if_blacklisted(
                    ctx.message.author.id, ctx.message.guild.id):
                self.bot.log.debug(
                    f"User {ctx.message.author} ({ctx.message.author.id}) Blacklisted, unable to use command {ctx.command}"
                )
                return
            # Get channel ID's the command is allowed in
            guild = ctx.message.guild
            settings = self.bot.guild_settings.get(guild.id)

            if settings.request_type == models.RequestType.suggestion:
                footer = f"Usage: '{ctx.prefix}suggestion [your suggestion]"
            else:
                footer = f"Usage: '{ctx.prefix}request Game Title (Release Date)'"

            upvote_emoji = settings.upvote_emoji or self.bot.constants.reactions[
                "upvote"]
            downvote_emoji = settings.downvote_emoji or self.bot.constants.reactions[
                "downvote"]
            question_emoji = settings.question_emoji or self.bot.constants.reactions[
                "question"]
            downvotes_allowed = settings.allow_downvotes
            questions_allowed = settings.allow_questions

            request_channel = settings.request_channel
            request_channel_allowed = settings.request_channel_allowed

            if request_channel_allowed is None:
                return await ctx.send(
                    f"No requests allowed channel found. Please set one on the configuration."
                )
            if request_channel is None:
                return await ctx.send(
                    f"No requests channel found. Please set one on the configuration."
                )

            temp_request_channel_allowed_name = []
            for temp_channel_id in request_channel_allowed:
                temp_channel = self.bot.get_channel(temp_channel_id)
                if temp_channel:
                    temp_request_channel_allowed_name.append(temp_channel)
            request_channel_allowed_name = [
                f"{channel.name}"
                for channel in temp_request_channel_allowed_name
            ]
            request_channel_allowed_clean = ", ".join(
                request_channel_allowed_name)

            if ctx.message.channel.id not in request_channel_allowed:
                # Tries to let user know in DM that cmd not allowed in that channel, if that fails send in channel.
                # Next tries to delete calling command to reduce spam
                try:
                    await ctx.message.author.send(
                        f"This command can only be used in the channels: {request_channel_allowed_clean} \n\n >>> {request_body[:1850]}"
                    )
                except discord.errors.Forbidden:
                    await ctx.send(
                        f"This command can only be used in the channels: {request_channel_allowed_clean}"
                    )
                try:
                    await ctx.message.delete()
                except discord.errors.Forbidden:
                    pass
                # Stop processing command if not done in right channel
                return

            # Check if request exists
            guild_requests = (session.query(models.Requests).join(
                models.Server, models.Server.id == models.Requests.server_id
            ).filter(models.Server.discord_id == ctx.message.guild.id).filter(
                models.Requests.status == models.RequestStatus.open).all())

            # Check for direct duplicates
            if request_body[:1900].lower() in [
                    singleRequest.text.lower()
                    for singleRequest in guild_requests
            ]:
                for singleRequest in guild_requests:
                    title = getattr(singleRequest, "text")

                    if request_body[:1900].lower() == title.lower():

                        dupe_link = getattr(singleRequest, "message_id")
                        await ctx.message.delete()

                        dupe_embed = discord.Embed(
                            color=0x00CC00,
                            title="Found it!",
                            description=
                            f"It looks like a request for this title already exists! You can view the existing request [here](https://discord.com/channels/{ctx.guild.id}/{ctx.channel.id}/{dupe_link}).\nRemember to upvote it!",
                            timestamp=datetime.utcnow(),
                        ).set_footer(
                            text="This message will be removed in 15 seconds.")

                        await (await ctx.channel.send(embed=dupe_embed
                                                      )).delete(delay=15)
                        return

            # Loop through existing requests
            for singleRequest in guild_requests:
                game_title = getattr(singleRequest, "text")
                message_link = getattr(singleRequest, "message_id")

                # Check for substrings in the text
                if (re.sub('[-!$%^&*()_+|~=`{}\[\]:\";\'<>?,.\/\s+]', '',
                           request_body[:1900].lower()) in re.sub(
                               '[-!$%^&*()_+|~=`{}\[\]:\";\'<>?,.\/\s+]', '',
                               game_title.lower())
                        or re.sub('[-!$%^&*()_+|~=`{}\[\]:\";\'<>?,.\/\s+]',
                                  '', game_title.lower())
                        in re.sub('[-!$%^&*()_+|~=`{}\[\]:\";\'<>?,.\/\s+]',
                                  '', request_body[:1900].lower())):

                    # Check function for reactions (yes / no)
                    def check(reaction, user):
                        return user == ctx.author and (
                            reaction.emoji == self.bot.get_emoji(
                                self.bot.constants.reactions["yes"])
                            or reaction.emoji == self.bot.get_emoji(
                                self.bot.constants.reactions["no"]))

                    # Embed to display when a potential duplicate entry is found
                    found_embed = discord.Embed(
                        color=0xFFA500,
                        title=
                        "I've found an existing request quite similar to yours! Is this the title you wanted to request?",
                        description=f">>> {game_title}",
                        timestamp=datetime.utcnow(),
                    ).set_footer(
                        text=
                        "This message will timeout in 60 seconds and your request will be removed without a response."
                    )

                    msg = await ctx.channel.send(embed=found_embed)

                    # Reactions for the user to react on
                    yes = self.bot.get_emoji(
                        self.bot.constants.reactions["yes"])
                    no = self.bot.get_emoji(self.bot.constants.reactions["no"])

                    # Add the reactions
                    for emoji in (yes, no):
                        if emoji:
                            await msg.add_reaction(emoji)

                    try:
                        # Wait for the user to confirm or deny if duplicate
                        reaction, user = await self.bot.wait_for(
                            "reaction_add", check=check, timeout=60.0)
                    except asyncio.TimeoutError:
                        # Delete message on timeout
                        await msg.delete()
                        await ctx.message.delete()
                        return
                    else:
                        # Delete message on reaction
                        await msg.delete()
                        # If user replies yes, link to the existing request
                        if reaction.emoji == self.bot.get_emoji(
                                self.bot.constants.reactions["yes"]):
                            await ctx.message.delete()

                            existing_embed = discord.Embed(
                                color=0x00CC00,
                                title="Found it!",
                                description=
                                f"Great! You can view the existing request [here](https://discord.com/channels/{ctx.guild.id}/{ctx.channel.id}/{message_link}).\nRemember to upvote it!",
                                timestamp=datetime.utcnow(),
                            ).set_footer(
                                text=
                                "This message will be removed in 15 seconds.")

                            await (await ctx.channel.send(embed=existing_embed
                                                          )).delete(delay=15)
                            return

            # Create the embed of info
            embed = discord.Embed(
                color=0x14738E,
                title=
                f"Port Request from {ctx.message.author} ({ctx.message.author.id})",
                description=f">>> {request_body[:1900]}",
                timestamp=datetime.utcnow(),
            )

            embed.set_footer(text=f"{footer}")

            channel = ctx.message.guild.get_channel(request_channel)
            if channel:
                try:
                    msg = await channel.send(embed=embed)

                    upvote = self.bot.get_emoji(upvote_emoji)
                    downvote = self.bot.get_emoji(
                        downvote_emoji) if downvotes_allowed else None
                    question = self.bot.get_emoji(
                        question_emoji) if questions_allowed else None

                    # Add the reactions
                    for emoji in (upvote, downvote, question):
                        if emoji:
                            await msg.add_reaction(emoji)
                    # Now let user know it was posted - but if it's in same channel it's being posted to, no need
                    if ctx.message.channel.id == channel.id:
                        # Delete the request command, no feedback
                        try:
                            await ctx.message.delete()
                        except discord.errors.Forbidden:
                            pass
                    else:
                        await ctx.message.delete()
                        await (await ctx.send(
                            f"Thank you for your request, it has now been posted and is available in {channel.mention}"
                        )).delete(delay=15)
                    # Now let's log it to the database
                    try:
                        # Check if there is a user in the database already
                        db_user = (session.query(
                            models.User).filter(models.User.discord_id ==
                                                ctx.message.author.id).first())
                        # If no DB record for the user then create one
                        if not db_user:
                            db_user = models.User(
                                discord_id=ctx.message.author.id)
                            session.add(db_user)
                        # Check if there is a guild in the database already
                        db_guild = (session.query(models.Server).filter(
                            models.Server.discord_id == msg.guild.id).first())
                        if not db_guild:
                            db_guild = await self.bot.helpers.db_add_new_guild(
                                session, msg.guild.id)

                        new_record = models.Requests(
                            user=db_user,
                            server=db_guild,
                            message_id=msg.id,
                            text=request_body,
                        )
                        session.add(new_record)
                        session.commit()
                    except DBAPIError as err:
                        self.bot.log.exception(
                            f"Error processing database query for '{ctx.command}' command. {sys.exc_info()[0].__name__}: {err}"
                        )
                        session.rollback()
                    except Exception as err:
                        self.bot.log.exception(
                            f"Unknown Error logging to database for to '{ctx.command}' command via Msg ID {ctx.message.id}. {sys.exc_info()[0].__name__}: {err}"
                        )
                    finally:
                        session.close()
                except discord.errors.Forbidden:
                    await ctx.send(
                        f"Sorry, I lack permissions to be able to submit that request"
                    )
                except Exception as err:
                    self.bot.log.exception(
                        f"Error responding to {ctx.command} via Msg ID {ctx.message.id}. {sys.exc_info()[0].__name__}: {err}"
                    )
                    try:
                        await ctx.send(
                            f"Error processing {ctx.command}. Error has already been reported to my developers."
                        )
                    except discord.errors.Forbidden:
                        pass

        except discord.HTTPException as err:
            self.bot.log.exception(
                f"Discord HTTP Error responding to {ctx.command} request via Msg ID {ctx.message.id}. {sys.exc_info()[0].__name__}: {err}"
            )
            await ctx.send(
                f"Error processing {ctx.command}. Error has already been reported to my developers."
            )
        except Exception as err:
            self.bot.log.exception(
                f"Error responding to {ctx.command} via Msg ID {ctx.message.id}. {sys.exc_info()[0].__name__}: {err}"
            )
            await ctx.send(
                f"Error processing {ctx.command}. Error has already been reported to my developers."
            )