aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Steele Farnsworth <[email protected]>2025-01-12 17:41:47 -0500
committerGravatar Steele Farnsworth <[email protected]>2025-01-12 17:41:47 -0500
commit7f131172eb72677418303c85c5d892fc11cc963e (patch)
tree49548cab7f0d707715d6998b16b87e130eb07a4c
parentFurther 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.
-rw-r--r--bot/exts/filtering/_filter_lists/extension.py92
-rw-r--r--bot/exts/filtering/filtering.py2
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))