Beispiel #1
0
async def send_reminder(client, timer: Timer):
    handles.pop(timer.id, None)
    del data['timers'][timer.id]
    storage.save()

    channel = client.get_channel(timer.channel_id)
    if not channel:
        logging.error(f"Cannot find channel for {timer}")
        return

    text = timer.text or "I am visiting from the past to remind you of something."
    text = f"<@{timer.user_id}> {text}"
    now = datetime.now()
    if now > timer.timestamp + timedelta(seconds=5):
        text = f"{text} ({format_timedelta(now - timer.timestamp)} late)"
    reference = discord.MessageReference(
        message_id=timer.message_id,
        channel_id=timer.channel_id,
        guild_id=timer.guild_id,
        fail_if_not_exists=False,
    )
    await channel.send(
        text,
        reference=reference,
        # Generally we want to allow mentions,
        # but no power abuse through the bot's permissions
        allowed_mentions=NO_EVERYONE_MENTIONS,
        mention_author=True,
    )
Beispiel #2
0
async def test(ctx):
    try:
        jopa = discord.MessageReference('34')
        await ctx.send(jopa)
    except Exception as e:
        await ctx.send(e)
        return
Beispiel #3
0
async def send_reminder(user_id: int, reminder: Reminder) -> None:
    guild = discord_client.client.get_guild(reminder["guild"])
    if guild is None:
        logger.info(
            "Reminder {} for user {} silently removed (guild no longer exists)"
            .format(str(reminder), user_id))
        return
    channel = guild.get_channel_or_thread(reminder["channel"])
    if not isinstance(channel, (discord.TextChannel, discord.Thread)):
        logger.info(
            "Reminder {} for user {} silently removed (channel no longer exists)"
            .format(str(reminder), user_id))
        return
    try:
        creation_time = discord.utils.snowflake_time(
            reminder["msg"]).replace(tzinfo=timezone.utc)
        await channel.send(
            util.discord.format("{!m} asked to be reminded <t:{}:R>: {}",
                                user_id, int(creation_time.timestamp()),
                                reminder["contents"])[:2000],
            reference=discord.MessageReference(message_id=reminder["msg"],
                                               channel_id=reminder["channel"],
                                               fail_if_not_exists=False),
            allowed_mentions=discord.AllowedMentions(
                everyone=False, users=[discord.Object(user_id)], roles=False))
    except discord.Forbidden:
        logger.info(
            "Reminder {} for user {} silently removed (permission error)".
            format(str(reminder), user_id))
Beispiel #4
0
async def run(ctx: commands.Context):
    l1 = await ctx.send(content="test test test", )
    l2 = await ctx.send(content="test test test", )
    last_at1 = {"incr": 0, "timestamp": 0}
    last_at2 = {"incr": 0, "timestamp": 1}

    while True:
        od = snowflake_to_dict(l1.id)
        nd = snowflake_to_dict(l2.id)
        diff = {
            "timestamp": nd["timestamp"] - od["timestamp"],
            "iw": nd["iw"] - od["iw"],
            "ip": nd["ip"] - od["ip"],
            "incr": nd["incr"] - od["incr"],
        }
        # print("l1/l2: " + str(diff))
        pd = {
            "timestamp": nd["timestamp"] + diff["timestamp"],
            "iw": 2,
            "ip": nd["ip"] + diff["ip"],
            "incr": nd["incr"] + diff["incr"],
        }
        pd["incr"] = round((last_at2["incr"] /
                            (last_at2["timestamp"] - last_at1["timestamp"])) *
                           (pd["timestamp"] - last_at2["timestamp"]))
        # print("l2: " + str(snowflake_to_dict(l2.id)))
        # print("pd: " + str(pd))
        pred_id = dict_to_snowflake(pd)
        l1 = l2
        l2 = await ctx.send(
            content=
            f"https://discord.com/channels/{ctx.guild.id}/{ctx.channel.id}/{pred_id}"
        )
        if snowflake_to_dict(l2.id)["iw"] == 2:
            last_at1 = last_at2
            last_at2 = {
                "incr": snowflake_to_dict(l2.id)["incr"],
                "timestamp": snowflake_to_dict(l2.id)["timestamp"],
            }
            if l2.id == pred_id:
                l2 = await ctx.send(
                    reference=discord.MessageReference(
                        message_id=ctx.message.id, channel_id=ctx.channel.id),
                    content=
                    "IT WORKS THE PREVIOUS UNEDITED MESSAGE LINKS TO ITSELF <@234020040830091265>",
                )
                break
            else:
                nd = snowflake_to_dict(l2.id)
                od = snowflake_to_dict(pred_id)
                print(l2.id)
                print(pred_id)
                print("l2/pred: " +
                      str({
                          "timestamp": nd["timestamp"] - od["timestamp"],
                          "iw": nd["iw"] - od["iw"],
                          "ip": nd["ip"] - od["ip"],
                          "incr": nd["incr"] - od["incr"],
                      }))
Beispiel #5
0
 async def process_reference(
     self,
     reference: Optional[discord.MessageReference],
     channel: UnionChannel,
 ) -> Optional[discord.MessageReference]:
     if not reference:
         return None
     # discord.py-stubs has a bad typehint for MessageReference.__init__
     async for de, to in AsyncIter(self.messages.vectors(), steps=100):
         if de == (reference.channel_id, reference.message_id) and to[0] == channel.id:
             return discord.MessageReference(  # type: ignore
                 channel_id=channel.id, message_id=to[1]
             )
         elif to == (reference.channel_id, reference.message_id) and de[0] == channel.id:
             return discord.MessageReference(  # type: ignore
                 channel_id=channel.id, message_id=de[1]
             )
     return None
Beispiel #6
0
 async def on_message(self, msg: discord.Message) -> None:
     if not msg.guild and self.user is not None and msg.author.id != self.user.id:
         try:
             guild = discord_client.client.get_guild(int(conf.guild))
             if guild is None: return
             channel = guild.get_channel(int(conf.channel))
             if not isinstance(channel,
                               (discord.TextChannel, discord.Thread)):
                 return
             role = guild.get_role(int(conf.role))
             if role is None: return
         except (ValueError, AttributeError):
             return
         thread_id = await update_thread(msg.author.id)
         header = util.discord.format("**From {}#{}** {} {!m} on {}:\n\n",
                                      msg.author.name,
                                      msg.author.discriminator,
                                      msg.author.id, msg.author,
                                      msg.created_at)
         footer = "".join(
             "\n**Attachment:** {} {}".format(att.filename, att.url)
             for att in msg.attachments)
         if thread_id is None:
             footer += util.discord.format("\n{!m}", role)
         if footer:
             footer = "\n" + footer
         text = msg.content
         mentions = discord.AllowedMentions.none()
         mentions.roles = [role]
         reference = None
         if thread_id is not None:
             reference = discord.MessageReference(message_id=thread_id,
                                                  channel_id=channel.id,
                                                  fail_if_not_exists=False)
         copy_first = None
         sent_footer = False
         for i in range(0, len(header) + len(text), 2000):
             part = (header + text)[i:i + 2000]
             if len(part) + len(footer) <= 2000:
                 part += footer
                 sent_footer = True
             copy = await channel.send(
                 part,
                 allowed_mentions=mentions,
                 reference=reference if copy_first is None else None)
             await add_modmail(msg, copy)
             if copy_first is None:
                 copy_first = copy
         if not sent_footer:
             copy = await channel.send(footer, allowed_mentions=mentions)
             await add_modmail(msg, copy)
         if thread_id is None and copy_first is not None:
             await create_thread(msg.author.id, copy_first.id)
         await msg.add_reaction("\u2709")
Beispiel #7
0
async def bind_channel_envoi(msg):
    if msg.content.startswith(BLANK): return

    if msg.channel.id in BINDED_CHANNELS:
        auteur, texte, files = msg.author, msg.content, [
            resendFile(x.url, x.filename) for x in msg.attachments
        ]
        embeds = msg.embeds
        reference = msg.reference

        embed = None if embeds == [] else embeds[0]

        texteRenvoye = BLANK + "**@{} :**\n{}".format(
            auteur.nick or auteur.name, texte)

        MSG_RETRANSMIS[msg.id] = (auteur, dict(), msg)

        for serveurCible, salonCible in BINDED_CHANNELS[msg.channel.id]:
            serveur = bot.get_guild(serveurCible)
            channel = serveur.get_channel(salonCible)

            if reference:
                refId = reference.message_id
                #il y a deux cas
                #1. soit on fait référence à un "vrai" message qui a été retransmis
                #2. soit on fait référence à un écho

                #1.
                if refId in MSG_RETRANSMIS:
                    refEcho = MSG_RETRANSMIS[refId][1][salonCible].id
                    chanRef = channel.id
                #2.
                elif refId in ECHO2MSG:
                    refEcho, _ = ECHO2MSG[refId]
                    chanRef = channel.id

                objRef = discord.MessageReference(message_id=refEcho,
                                                  channel_id=chanRef)
                retransmis = await channel.send(texteRenvoye,
                                                reference=objRef,
                                                files=files,
                                                embed=embed)
            else:
                retransmis = await channel.send(texteRenvoye,
                                                files=files,
                                                embed=embed)

            MSG_RETRANSMIS[msg.id][1][salonCible] = retransmis
            ECHO2MSG[retransmis.id] = (msg.id, msg.channel.id)
            sleep(0.5)

            for x in files:
                supprFichier(x)
Beispiel #8
0
 async def process_reference(
     self,
     reference: Optional[discord.MessageReference],
     channel: UnionChannel,
 ) -> Optional[discord.MessageReference]:
     if not reference:
         return None
     async for de, to in AsyncIter(self.messages.vectors(), steps=100):
         if (de == (reference.guild_id, reference.channel_id,
                    reference.message_id) and to[1] == channel.id):
             return discord.MessageReference(
                 guild_id=to[0],
                 channel_id=to[1],
                 message_id=to[2],
                 fail_if_not_exists=False,
             )
         elif (to == (reference.guild_id, reference.channel_id,
                      reference.message_id) and de[1] == channel.id):
             return discord.MessageReference(guild_id=de[0],
                                             channel_id=de[1],
                                             message_id=de[2],
                                             fail_if_not_exists=False)
     return None
Beispiel #9
0
    async def modmail_reply(self, msg: discord.Message) -> None:
        if msg.reference and msg.reference.message_id in message_map and not msg.author.bot:
            modmail = message_map[msg.reference.message_id]

            anon_react = "\U0001F574"
            named_react = "\U0001F9CD"
            cancel_react = "\u274C"

            try:
                query = await msg.channel.send(
                    "Reply anonymously {}, personally {}, or cancel {}".format(
                        anon_react, named_react, cancel_react))
            except (discord.NotFound, discord.Forbidden):
                return

            result = await plugins.reactions.get_reaction(
                query,
                msg.author, {
                    anon_react: "anon",
                    named_react: "named",
                    cancel_react: None
                },
                timeout=120,
                unreact=False)

            await query.delete()
            if result is None:
                await msg.channel.send("Cancelled")
            else:
                header = ""
                if result == "named":
                    header = util.discord.format("**From {}** {!m}:\n\n",
                                                 msg.author.display_name,
                                                 msg.author)
                try:
                    chan = await client.fetch_channel(modmail.dm_channel_id)
                    if not isinstance(chan, discord.DMChannel):
                        await msg.channel.send(
                            "Could not deliver DM (DM closed)")
                        return
                    await chan.send(header + msg.content,
                                    reference=discord.MessageReference(
                                        message_id=modmail.dm_message_id,
                                        channel_id=modmail.dm_channel_id,
                                        fail_if_not_exists=False))
                except (discord.NotFound, discord.Forbidden):
                    await msg.channel.send(
                        "Could not deliver DM (User left guild?)")
                else:
                    await msg.channel.send("Message delivered")
Beispiel #10
0
    async def post_slash_command_warning(self, command_name, message):
        channel = message.channel
        guild = message.guild

        embed = discord.Embed(
            title=f"Please use /{command_name} to execute this command!",
            description=
            f"Discord is requiring **all bots** to switch to Slash Commands (which Bloxlink already supports!).\n\nPlease use `/{command_name}` instead to execute this command."
            "\n\n**Don't see Slash Commands?** Get the Server Admins to Re-authorize the bot here (__they don't need to kick it__): https://blox.link/invite and make sure the **Use Application Commands** permission is enabled for members.\n\n[Click here to see the Discord FAQ on Slash Commands](https://support.discord.com/hc/en-us/articles/1500000368501-Slash-Commands-FAQ)"
        )
        embed.set_image(url="https://i.imgur.com/wVo8gt2.png")
        embed.colour = ORANGE_COLOR

        reference = discord.MessageReference(message_id=message and message.id,
                                             channel_id=channel.id,
                                             guild_id=guild and guild.id,
                                             fail_if_not_exists=False)

        try:
            await channel.send(embed=embed, reference=reference)
        except (discord.errors.NotFound, discord.errors.Forbidden):
            pass
Beispiel #11
0
    async def on_message(self, msg: discord.Message) -> None:
        if msg.author.bot: return
        if not isinstance(msg.channel,
                          (discord.abc.GuildChannel, discord.Thread)):
            return
        if not msg.content.startswith(conf.prefix): return
        if not plugins.locations.in_location("factoids", msg.channel): return
        text = " ".join(msg.content[len(conf.prefix):].split()).lower()
        if not len(text): return
        async with sqlalchemy.ext.asyncio.AsyncSession(engine) as session:
            stmt = (sqlalchemy.select(Alias).where(
                Alias.name == sqlalchemy.func.substring(
                    text, 1, sqlalchemy.func.length(Alias.name))).order_by(
                        sqlalchemy.func.length(Alias.name).desc()).limit(1))
            if (alias := (await session.execute(stmt)).scalar()) is None:
                return
            embed = discord.Embed.from_dict(
                alias.factoid.embed_data
            ) if alias.factoid.embed_data is not None else None
            reference = None
            if msg.reference is not None and msg.reference.message_id is not None:
                reference = discord.MessageReference(
                    guild_id=msg.reference.guild_id,
                    channel_id=msg.reference.channel_id,
                    message_id=msg.reference.message_id,
                    fail_if_not_exists=False)
            await msg.channel.send(
                alias.factoid.message_text,
                embed=embed,
                reference=reference,
                allowed_mentions=discord.AllowedMentions.none())

            alias.factoid.uses += 1
            alias.factoid.used_at = datetime.datetime.utcnow()
            alias.uses += 1
            alias.used_at = datetime.datetime.utcnow()
            await session.commit()
        channel = await messageable._get_channel()
        ref_data = CONFIG_CACHE.setdefault(str(channel.id),
                                           {}).setdefault(emoji, {})

        if (smileysend_force_new_ref
                or (ref_msg_id := ref_data.get("message_id")) is None):
            emoji_count = (2000 + 1) // (len(emoji) + 1)
            ref_msg_content = " ".join(
                itertools.repeat(emoji, min(50, emoji_count)))
            ref_msg = await real_send(messageable, ref_msg_content)

            ref_data["message_id"] = ref_msg_id = ref_msg.id
            scope = CONFIG.custom(MSG_IDS, str(channel.id), emoji).message_id
            await scope.set(ref_msg_id)

        return discord.MessageReference(message_id=ref_msg_id,
                                        channel_id=channel.id)

    async def send_with_msg_ref(
        messageable: Messageable,
        content=None,
        *,
        reference=None,
        smileysend_emoji,
        smileysend_force_new_ref=False,
        **kwargs,
    ) -> discord.Message:
        if reference is None and REPLIES_ENABLED:
            reference = await get_msg_ref(
                messageable,
                smileysend_emoji,
                smileysend_force_new_ref=smileysend_force_new_ref,
Beispiel #13
0
 async def _requests(self, dc_channel, webhook, msg):
     name = image = None
     reply_to = reply_ref = reply_embed = None
     embeds = []
     files = []
     if msg.user:
         name = msg.user.real_name or msg.user.username
         image = msg.user.avatar
     for i, attach in enumerate(msg.attachments or []):
         if isinstance(attach, immp.File):
             if attach.title:
                 title = attach.title
             elif attach.type == immp.File.Type.image:
                 title = "image_{}.png".format(i)
             elif attach.type == immp.File.Type.video:
                 title = "video_{}.mp4".format(i)
             else:
                 title = "file_{}".format(i)
             async with (await
                         attach.get_content(self.session)) as img_content:
                 # discord.py expects a file-like object with a synchronous read() method.
                 # NB. The whole file is read into memory by discord.py anyway.
                 files.append(
                     discord.File(BytesIO(await img_content.read()), title))
         elif isinstance(attach, immp.Location):
             embed = discord.Embed()
             embed.title = attach.name or "Location"
             embed.url = attach.google_map_url
             embed.description = attach.address
             embed.set_thumbnail(url=attach.google_image_url(80))
             embed.set_footer(
                 text="{}, {}".format(attach.latitude, attach.longitude))
             embeds.append((embed, "sent a location"))
         elif isinstance(attach, immp.Message):
             resolved = await self.resolve_message(attach)
             embeds.append(
                 (await
                  DiscordMessage.to_embed(self,
                                          resolved), "sent a message"))
     if msg.reply_to:
         if isinstance(msg.reply_to, immp.Receipt):
             if msg.reply_to.channel.plug.network_id == self.network_id:
                 guild_id = dc_channel.guild.id if dc_channel.guild else None
                 reply_ref = discord.MessageReference(
                     message_id=int(msg.reply_to.id),
                     channel_id=dc_channel.id,
                     guild_id=guild_id)
         if not reply_to:
             reply_to = msg.reply_to
         reply_embed = await DiscordMessage.to_embed(self, reply_to, True)
     if webhook and msg.user:
         # Sending via webhook: multiple embeds and files supported.
         requests = []
         rich = None
         if reply_embed:
             # Webhooks can't reply to other messages, quote the target in an embed instead.
             # https://github.com/discord/discord-api-docs/issues/2251
             embeds.append((reply_embed, None))
         if msg.text:
             rich = msg.text.clone()
             if msg.action:
                 for segment in rich:
                     segment.italic = True
         if msg.edited:
             if rich:
                 rich.append(immp.Segment(" "))
             else:
                 rich = immp.RichText()
             rich.append(immp.Segment("(edited)", italic=True))
         text = None
         if rich:
             mark = DiscordRichText.to_markdown(self, rich, True)
             chunks = immp.RichText.chunked_plain(mark, 2000)
             if len(chunks) > 1:
                 # Multiple messages required to accommodate the text.
                 requests.extend(
                     webhook.send(content=chunk,
                                  wait=True,
                                  username=name,
                                  avatar_url=image) for chunk in chunks)
             else:
                 text = chunks[0]
         if text or embeds or files:
             requests.append(
                 webhook.send(content=text,
                              wait=True,
                              username=name,
                              avatar_url=image,
                              files=files,
                              embeds=[embed[0] for embed in embeds]))
         return requests
     else:
         # Sending via client: only a single embed per message.
         requests = []
         text = embed = desc = None
         chunks = []
         rich = msg.render(link_name=False, edit=msg.edited) or None
         if rich:
             mark = DiscordRichText.to_markdown(self, rich)
             text, *chunks = immp.RichText.chunked_plain(mark, 2000)
         if reply_embed and not reply_ref:
             embeds.append((reply_embed, None))
         if len(embeds) == 1:
             # Attach the only embed to the message text.
             embed, desc = embeds.pop()
         if text or embed or files:
             # Primary message: set reference for reply-to if applicable.
             requests.append(
                 dc_channel.send(content=text or desc,
                                 embed=embed,
                                 files=files,
                                 reference=reply_ref))
         # Send the remaining text if multiple messages were required to accommodate it.
         requests.extend(dc_channel.send(content=chunk) for chunk in chunks)
         for embed, desc in embeds:
             # Send any additional embeds in their own separate messages.
             content = None
             if msg.user and desc:
                 label = immp.Message(user=msg.user,
                                      text="sent {}".format(desc),
                                      action=True)
                 content = DiscordRichText.to_markdown(self, label.render())
             requests.append(dc_channel.send(content=content, embed=embed))
         return requests
Beispiel #14
0
    async def command_checks(self,
                             command,
                             prefix,
                             response,
                             guild_data,
                             author,
                             channel,
                             locale,
                             CommandArgs,
                             message=None,
                             guild=None,
                             subcommand_attrs=None,
                             slash_command=False):
        channel_id = str(channel.id) if channel else None
        donator_profile = None
        dm = not bool(guild)
        subcommand_attrs = subcommand_attrs or {}

        if guild:
            if getattr(command, "addon", False):
                enabled_addons = guild and await get_enabled_addons(guild
                                                                    ) or {}

                if str(command.addon) not in enabled_addons:
                    raise CancelCommand

                if getattr(command.addon, "premium", False):
                    donator_profile, _ = await get_features(
                        discord.Object(id=guild.owner_id), guild=guild)

                    if not donator_profile.features.get("premium"):
                        await response.error(
                            f"This add-on requires premium! You may use `{prefix}donate` for instructions on donating.\n"
                            f"You may also disable this add-on with `{prefix}addon change`.",
                            hidden=True)

                        raise CancelCommand

            if RELEASE == "PRO" and command.name not in (
                    "donate", "transfer", "eval", "status", "prefix",
                    "add-features", "stats"):
                if not donator_profile:
                    donator_profile, _ = await get_features(
                        discord.Object(id=guild.owner_id), guild=guild)

                if not donator_profile.features.get("pro"):
                    await response.error(
                        f"Server not authorized to use Pro. Please use the `{prefix}donate` command to see information on "
                        "how to get Bloxlink Pro.",
                        hidden=True)

                    raise CancelCommand

            if not command.bypass_channel_perms:
                if command.premium_bypass_channel_perms and not donator_profile:
                    donator_profile, _ = await get_features(author,
                                                            guild=guild)

                ignored_channels = guild_data.get("ignoredChannels", {})
                disabled_commands = guild_data.get("disabledCommands", {})

                author_perms = author.guild_permissions

                if guild.owner_id != author.id and not (
                        author_perms.manage_guild
                        or author_perms.administrator or discord.utils.find(
                            lambda r: r.name in MAGIC_ROLES, author.roles) or
                    (command.premium_bypass_channel_perms
                     and donator_profile.features.get("premium"))):
                    premium_upsell = "\n**Pro-tip:** Bloxlink Premium users can use this command in disabled channels! Learn more at https://patreon.com/bloxlink." if command.premium_bypass_channel_perms else ""
                    ignored_channel = ignored_channels.get(channel_id) or (
                        channel.category
                        and ignored_channels.get(str(channel.category.id)))
                    bypass_roles = ignored_channel.get(
                        "bypassRoles", []) if ignored_channel else []

                    if ignored_channel and not discord.utils.find(
                            lambda r: str(r.id) in bypass_roles, author.roles):
                        await response.send(
                            f"The server admins have **disabled** all commands in channel {channel.mention}.{premium_upsell}",
                            dm=True,
                            hidden=True,
                            strict_post=True,
                            no_dm_post=True)

                        if message:
                            try:
                                await message.delete()
                            except (discord.errors.Forbidden,
                                    discord.errors.NotFound):
                                pass

                        raise CancelCommand

                    if command.name in disabled_commands.get("global", []):
                        await response.send(
                            f"The server admins have **disabled** the command `{command.name}` globally.{premium_upsell}",
                            dm=True,
                            hidden=True,
                            strict_post=True,
                            no_dm_post=True)

                        if message:
                            try:
                                await message.delete()
                            except (discord.errors.Forbidden,
                                    discord.errors.NotFound):
                                pass

                        raise CancelCommand

                    elif disabled_commands.get("channels",
                                               {}).get(channel_id,
                                                       {}).get(command.name):
                        await response.send(
                            f"The server admins have **disabled** the command `{command.name}` in channel {channel.mention}.{premium_upsell}",
                            dm=True,
                            hidden=True,
                            strict_post=True,
                            no_dm_post=True)

                        if message:
                            try:
                                await message.delete()
                            except (discord.errors.Forbidden,
                                    discord.errors.NotFound):
                                pass

                        raise CancelCommand

        if not slash_command and getattr(command, "slash_only", False):
            embed = discord.Embed(
                title="Please use this command as a Slash Command!",
                description="This command can only be used "
                f"as a Slash Command. Please use `/{command.name}` instead to execute this command. Non-slash commands will be "
                "disappearing **April of 2022!**\n\nPlease note that **all bots** will be **required** to switch to Slash Commands by next April (which Bloxlink already supports).\n\n"
                "For the technical: [Discord announcement](https://support-dev.discord.com/hc/en-us/articles/4404772028055)"
            )
            embed.set_image(url="https://i.imgur.com/IsrRp5U.png")
            embed.colour = ORANGE_COLOR

            reference = discord.MessageReference(message_id=message
                                                 and message.id,
                                                 channel_id=channel_id,
                                                 guild_id=guild and guild.id,
                                                 fail_if_not_exists=False)

            try:
                await channel.send(embed=embed,
                                   reference=reference,
                                   delete_after=20)
            except (discord.errors.NotFound, discord.errors.Forbidden):
                pass

            raise CancelCommand

        restriction = await get_restriction("users", author.id)

        if restriction:
            restrction_text = isinstance(
                restriction, str
            ) and f"has an active restriction for: `{restriction}`" or "has an active restriction from Bloxlink."

            await response.send(f"{author.mention} {restrction_text}",
                                hidden=True)
            raise CancelCommand

        if command.cooldown and self.cache:
            redis_cooldown_key = f"cooldown_cache:{command.name}:{author.id}"

            if not donator_profile or (
                    donator_profile
                    and not donator_profile.features.get("premium")):
                donator_profile, _ = await get_features(author)

            if not donator_profile.features.get("premium"):
                on_cooldown = await self.cache.get(redis_cooldown_key)

                if on_cooldown:
                    cooldown_time = await self.redis.ttl(redis_cooldown_key)

                    embed = discord.Embed(title="Slow down!")
                    embed.description = "This command has a short cooldown since it's relatively expensive for the bot. " \
                                        f"You'll need to wait **{cooldown_time}** more second(s).\n\nDid you know? " \
                                        "**[Bloxlink Premium](https://www.patreon.com/join/bloxlink?)** subscribers NEVER " \
                                        f"see any cooldowns. Find out more information with `{prefix}donate`."

                    m = await response.send(embed=embed, hidden=True)

                    if m:
                        await asyncio.sleep(10)

                        try:
                            await m.delete()

                            if message:
                                await message.delete()

                        except (discord.errors.NotFound,
                                discord.errors.Forbidden):
                            pass

                    raise CancelCommand

                await self.cache.set(redis_cooldown_key,
                                     True,
                                     expire_time=command.cooldown)

        if not (command.dm_allowed or guild):
            await response.send(
                "This command does not support DM; please run it in a server.",
                hidden=True)
            raise CancelCommand

        try:
            await command.check_permissions(author,
                                            guild,
                                            locale,
                                            dm=dm,
                                            **subcommand_attrs)
        except PermissionError as e:
            if subcommand_attrs.get("allow_bypass"):
                CommandArgs.has_permission = False
            elif command.permissions.allow_bypass:
                CommandArgs.has_permission = False
            else:
                await response.error(e, hidden=True)
                raise CancelCommand

        except Message as e:
            message_type = "send" if e.type == "info" else e.type
            response_fn = getattr(response, message_type, response.send)

            if e.message:
                await response_fn(e, hidden=True)

            if subcommand_attrs.get("allow_bypass"):
                CommandArgs.has_permission = False
            elif command.permissions.allow_bypass:
                CommandArgs.has_permission = False
            else:
                raise CancelCommand

        else:
            CommandArgs.has_permission = True
    async def reminder_finish_handler(self):
        """
        Handles reminders expiring.
        """

        # Grab finished stuff from the database
        db = await vbu.Database.get_connection()
        rows = await db(
            "SELECT * FROM reminders WHERE timestamp < TIMEZONE('UTC', NOW())")
        if not rows:
            await db.disconnect()
            return

        # Go through all finished reminders
        expired_reminders = []
        for reminder in rows:
            channel_id = reminder["channel_id"]
            user_id = reminder["user_id"]
            message_id = reminder["message_id"]
            message = reminder["message"]
            reminder_id = reminder["reminder_id"]

            try:
                channel = self.bot.get_channel(
                    channel_id) or await self.bot.fetch_channel(channel_id)
            except discord.HTTPException:
                channel = None
            sendable = {
                "content":
                f"<@{user_id}> reminder `{reminder_id}` triggered - {message}",
                "allowed_mentions":
                discord.AllowedMentions(users=[discord.Object(user_id)]),
            }
            if message_id:
                sendable.update({
                    "reference":
                    discord.MessageReference(message_id=message_id,
                                             channel_id=channel_id),
                    "mention_author":
                    True,
                })
            try:
                assert channel is not None
                try:
                    await channel.send(**sendable)
                except Exception:
                    sendable.pop("reference")
                    await channel.send(**sendable)
            except (AssertionError, discord.Forbidden):
                try:
                    user = self.bot.get_user(
                        user_id) or await self.bot.fetch_user(user_id)
                    await user.send(**sendable)
                except discord.HTTPException:
                    pass
            except AttributeError:
                pass
            expired_reminders.append(reminder_id)

        # Delete expired reminders
        await db("DELETE FROM reminders WHERE reminder_id=ANY($1::TEXT[])",
                 expired_reminders)
        await db.disconnect()