diff options
| author | 2025-01-12 17:41:47 -0500 | |
|---|---|---|
| committer | 2025-01-12 17:41:47 -0500 | |
| commit | 7f131172eb72677418303c85c5d892fc11cc963e (patch) | |
| tree | 49548cab7f0d707715d6998b16b87e130eb07a4c | |
| parent | Further abbreviate the "wrong language specifier" message; remove extra "plea... (diff) | |
work-in-progress: when upload a text file attachment, ask for permission to auto-upload to pastebin.
Also DMs the delete URL to the user. This code will very likely be moved elsewhere before/if it is merged.
Diffstat (limited to '')
| -rw-r--r-- | bot/exts/filtering/_filter_lists/extension.py | 92 | ||||
| -rw-r--r-- | bot/exts/filtering/filtering.py | 2 | 
2 files changed, 92 insertions, 2 deletions
diff --git a/bot/exts/filtering/_filter_lists/extension.py b/bot/exts/filtering/_filter_lists/extension.py index d656bc6d2..3e7fa8e75 100644 --- a/bot/exts/filtering/_filter_lists/extension.py +++ b/bot/exts/filtering/_filter_lists/extension.py @@ -1,10 +1,18 @@  from __future__ import annotations +import logging +import re  import typing  from os.path import splitext +import aiohttp +import discord +from discord.ext import commands +from pydis_core.utils import paste_service +  import bot -from bot.constants import Channels +from bot.bot import Bot +from bot.constants import Channels, Emojis  from bot.exts.filtering._filter_context import Event, FilterContext  from bot.exts.filtering._filter_lists.filter_list import FilterList, ListType  from bot.exts.filtering._filters.extension import ExtensionFilter @@ -20,7 +28,7 @@ PY_EMBED_DESCRIPTION = (      f"please use a code-pasting service such as {PASTE_URL}"  ) -TXT_LIKE_FILES = {".txt", ".csv", ".json"} +TXT_LIKE_FILES = {".txt", ".csv", ".json", ".py"}  TXT_EMBED_DESCRIPTION = (      "You either uploaded a `{blocked_extension}` file or entered a message that was too long. "      f"Please use our [paste bin]({PASTE_URL}) instead." @@ -32,6 +40,9 @@ DISALLOWED_EMBED_DESCRIPTION = (      "Feel free to ask in {meta_channel_mention} if you think this is a mistake."  ) +PASTEBIN_UPLOAD_EMOJI = Emojis.check_mark +DELETE_PASTE_EMOJI = Emojis.trashcan +  class ExtensionsList(FilterList[ExtensionFilter]):      """ @@ -116,3 +127,80 @@ class ExtensionsList(FilterList[ExtensionFilter]):          ctx.blocked_exts |= set(not_allowed)          actions = self[ListType.ALLOW].defaults.actions if ctx.event != Event.SNEKBOX else None          return actions, [f"`{ext}`" if ext else "`No Extension`" for ext in not_allowed], {ListType.ALLOW: triggered} + + +class EmbedFileHandler(commands.Cog): + +    def __init__(self, bot: Bot): +        self.bot = bot + +    @staticmethod +    async def _convert_attachment(attachment: discord.Attachment) -> paste_service.PasteFile: +        encoding = re.search(r"charset=(\S+)", attachment.content_type).group(1) +        file_content = (await attachment.read()).decode(encoding) +        return paste_service.PasteFile(content=file_content, name=attachment.filename) + +    @commands.Cog.listener() +    async def on_message(self, message: discord.Message) -> None: +        # Check if the message contains an embedded file and is not sent by a bot +        if message.author.bot or not message.attachments: +            return + +        bot_reply = await message.reply(f"React with {PASTEBIN_UPLOAD_EMOJI} to upload your file to our paste bin") +        await bot_reply.add_reaction(PASTEBIN_UPLOAD_EMOJI) + +        def wait_for_upload_permission(reaction: discord.Reaction, user: discord.User) -> bool: +            return ( +                reaction.message.id == bot_reply.id +                and str(reaction.emoji) == PASTEBIN_UPLOAD_EMOJI +                and user == message.author +            ) + +        try: +            # Wait for the reaction with a timeout of 60 seconds +            await self.bot.wait_for("reaction_add", timeout=60.0, check=wait_for_upload_permission) +        except TimeoutError: +            await bot_reply.edit(content=f"~~{bot_reply.content}~~") +            await bot_reply.clear_reactions() +            return + +        logging.info({f.filename: f.content_type for f in message.attachments}) + +        files = [ +            await self._convert_attachment(f) +            for f in message.attachments +            if f.content_type.startswith("text") +        ] + +        try: +            async with aiohttp.ClientSession() as session: +                paste_response = await paste_service.send_to_paste_service(files=files, http_session=session) +        except (paste_service.PasteTooLongError, ValueError): +            # paste is too long +            await bot_reply.edit(content="Your paste is too long, and couldn't be uploaded.") +            return +        except paste_service.PasteUploadError: +            await bot_reply.edit(content="There was an error uploading your paste.") +            return + +        # The angle brackets around the remove link are required to stop Discord from visiting the URL to produce a +        # preview, thereby deleting the paste +        await message.author.send(content=f"[Click here](<{paste_response.removal}>) to delete your recent paste.") + +        await bot_reply.edit(content=f"[Click here]({paste_response.link}) to see this code in our pastebin.") +        await bot_reply.clear_reactions() +        await bot_reply.add_reaction(DELETE_PASTE_EMOJI) + +        def wait_for_delete_reaction(reaction: discord.Reaction, user: discord.User) -> bool: +            return ( +                reaction.message.id == bot_reply.id +                and str(reaction.emoji) == DELETE_PASTE_EMOJI +                and user == message.author +            ) + +        try: +            await self.bot.wait_for("reaction_add", timeout=60.0 * 10, check=wait_for_delete_reaction) +            await paste_response.delete() +            await bot_reply.delete() +        except TimeoutError: +            pass diff --git a/bot/exts/filtering/filtering.py b/bot/exts/filtering/filtering.py index 844f2942e..929eb064c 100644 --- a/bot/exts/filtering/filtering.py +++ b/bot/exts/filtering/filtering.py @@ -28,6 +28,7 @@ from bot.constants import BaseURLs, Channels, Guild, MODERATION_ROLES, Roles  from bot.exts.backend.branding._repository import HEADERS, PARAMS  from bot.exts.filtering._filter_context import Event, FilterContext  from bot.exts.filtering._filter_lists import FilterList, ListType, ListTypeConverter, filter_list_types +from bot.exts.filtering._filter_lists.extension import EmbedFileHandler  from bot.exts.filtering._filter_lists.filter_list import AtomicList  from bot.exts.filtering._filters.filter import Filter, UniqueFilter  from bot.exts.filtering._settings import ActionSettings @@ -1492,3 +1493,4 @@ class Filtering(Cog):  async def setup(bot: Bot) -> None:      """Load the Filtering cog."""      await bot.add_cog(Filtering(bot)) +    await bot.add_cog(EmbedFileHandler(bot))  |