Skip to content

Commit 9b05a4a

Browse files
committed
Resolve feedback.
1 parent d013fa7 commit 9b05a4a

7 files changed

Lines changed: 429 additions & 189 deletions

File tree

bot.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ async def wait_for_connected(self) -> None:
393393
await self.config.wait_until_ready()
394394

395395
@property
396-
def snippets(self) -> typing.Dict[str, str]:
396+
def snippets(self) -> typing.Dict[str, typing.Union[str, typing.Dict[str, str]]]:
397397
return self.config["snippets"]
398398

399399
@property
@@ -1382,7 +1382,7 @@ async def get_contexts(self, message, *, cls=commands.Context):
13821382
snippet_text = snippet_data.get("text", "")
13831383
attachment = await self._download_snippet_attachment(snippet_data)
13841384
if attachment is not None:
1385-
context_message.attachments = [attachment]
1385+
context_message.attachments = [*message.attachments, attachment]
13861386
else:
13871387
snippet_text = None
13881388
except KeyError:
@@ -1409,7 +1409,7 @@ async def get_contexts(self, message, *, cls=commands.Context):
14091409
attachment = await self._download_snippet_attachment(snippet_data)
14101410
if attachment is not None:
14111411
snippet_message = copy.copy(message)
1412-
snippet_message.attachments = [attachment]
1412+
snippet_message.attachments = [*message.attachments, attachment]
14131413
ctx.message = snippet_message
14141414
ctx.command = self._get_snippet_command()
14151415
reply_view = StringView(f"{invoked_prefix}{ctx.command} {snippet_text}")

cogs/modmail.py

Lines changed: 377 additions & 169 deletions
Large diffs are not rendered by default.

cogs/utility.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ async def format_cog_help(self, cog, *, no_cog=False):
109109
return embeds
110110

111111
def process_help_msg(self, help_: str):
112-
return help_.replace("{prefix}", self.context.clean_prefix) if help_ else "No help message."
112+
return help_.format(prefix=self.context.clean_prefix) if help_ else "No help message."
113113

114114
async def send_bot_help(self, mapping):
115115
embeds = []
@@ -195,6 +195,8 @@ async def send_error_message(self, error):
195195
command = self.context.kwargs.get("command")
196196
val = self.context.bot.snippets.get(command)
197197
if val is not None:
198+
if isinstance(val, dict):
199+
val = val.get("text") or "This is an attachment-only snippet."
198200
embed = discord.Embed(title=f"{command} is a snippet.", color=self.context.bot.main_color)
199201
embed.add_field(name=f"`{command}` will send:", value=val, inline=False)
200202

core/clients.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
from aiohttp import ClientResponseError, ClientResponse
1111
from bson import ObjectId
12+
from bson.errors import InvalidId
13+
from gridfs.errors import NoFile
1214
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorGridFSBucket
1315
from pymongo.errors import ConfigurationError
1416

@@ -887,6 +889,9 @@ async def delete_snippet_attachment(self, file_id: str) -> bool:
887889
await self.fs.delete(ObjectId(file_id))
888890
logger.debug("Deleted snippet attachment with file_id %s.", file_id)
889891
return True
892+
except (InvalidId, NoFile):
893+
logger.info("Snippet attachment %s was already absent.", file_id)
894+
return True
890895
except Exception as e:
891896
logger.warning("Failed to delete snippet attachment %s: %s", file_id, e)
892897
return False

core/config.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class ConfigManager:
165165
"thread_creation_menu_embed_footer_icon_url": None,
166166
"thread_creation_menu_embed_color": str(discord.Color.green()),
167167
# snippet attachments
168-
"snippet_attachment_max_size": 10, # in MB
168+
"snippet_attachment_max_size": 10, # in MiB
169169
}
170170

171171
private_keys = {
@@ -245,7 +245,7 @@ class ConfigManager:
245245

246246
duration_seconds = {"snooze_default_duration", "thread_creation_menu_timeout"}
247247

248-
megabytes = {"snippet_attachment_max_size"}
248+
mebibytes = {"snippet_attachment_max_size"}
249249

250250
booleans = {
251251
"use_user_id_channel_name",
@@ -318,6 +318,23 @@ def __init__(self, bot):
318318
def __repr__(self):
319319
return repr(self._cache)
320320

321+
@staticmethod
322+
def _convert_mebibytes(value: typing.Any) -> int:
323+
"""Convert a positive whole-number MiB value without rounding it."""
324+
if isinstance(value, bool):
325+
raise InvalidConfigError("Must be a positive whole number of MiB.")
326+
327+
if isinstance(value, int):
328+
converted = value
329+
elif isinstance(value, str) and re.fullmatch(r"[1-9]\d*", value.strip()):
330+
converted = int(value)
331+
else:
332+
raise InvalidConfigError("Must be a positive whole number of MiB.")
333+
334+
if converted <= 0:
335+
raise InvalidConfigError("Must be a positive whole number of MiB.")
336+
return converted
337+
321338
def populate_cache(self) -> dict:
322339
data = deepcopy(self.defaults)
323340

@@ -426,13 +443,12 @@ def get(self, key: str, *, convert: bool = True) -> typing.Any:
426443
logger.warning("Invalid %s %s.", key, value)
427444
value = self.remove(key)
428445

429-
elif key in self.megabytes:
430-
if not isinstance(value, int):
431-
try:
432-
value = int(value)
433-
except (ValueError, TypeError):
434-
logger.warning("Invalid %s %s.", key, value)
435-
value = self.remove(key)
446+
elif key in self.mebibytes:
447+
try:
448+
value = self._convert_mebibytes(value)
449+
except InvalidConfigError:
450+
logger.warning("Invalid %s %s.", key, value)
451+
value = self.remove(key)
436452

437453
elif key in self.force_str:
438454
# Temporary: as we saved in int previously, leading to int32 overflow,
@@ -537,6 +553,9 @@ async def set(self, key: str, item: typing.Any, convert=True) -> None:
537553
duration_seconds = int((time.dt - now).total_seconds())
538554
return self.__setitem__(key, duration_seconds)
539555

556+
elif key in self.mebibytes:
557+
return self.__setitem__(key, self._convert_mebibytes(item))
558+
540559
elif key in self.enums:
541560
if isinstance(item, self.enums[key]):
542561
# value is an enum type

core/config_help.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -857,15 +857,16 @@
857857
]
858858
},
859859
"snippet_attachment_max_size": {
860-
"default": "10 (MB)",
861-
"description": "Maximum file size in megabytes (MB) for attachments when creating or editing snippets.",
860+
"default": "10 MiB",
861+
"description": "Maximum file size in mebibytes (MiB) for attachments when creating or editing snippets.",
862862
"examples": [
863-
"`{prefix}config set snippet_attachment_max_size 5` (5 MB)",
864-
"`{prefix}config set snippet_attachment_max_size 20` (20 MB)"
863+
"`{prefix}config set snippet_attachment_max_size 5` (5 MiB)",
864+
"`{prefix}config set snippet_attachment_max_size 20` (20 MiB)"
865865
],
866866
"notes": [
867867
"Attachments larger than this size will be rejected when adding or editing snippets.",
868-
"Value is specified in megabytes (MB)."
868+
"The value must be a positive whole number of MiB; fractional and negative values are rejected.",
869+
"Increasing this limit can substantially increase long-term database storage usage, especially when attachments are used frequently."
869870
]
870871
},
871872
"require_close_reason": {
@@ -1606,4 +1607,4 @@
16061607
"Color names map to the built-in palette (e.g., 'red', 'green', 'blurple')."
16071608
]
16081609
}
1609-
}
1610+
}

core/thread.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1754,7 +1754,12 @@ async def reply(
17541754
if any(
17551755
getattr(attachment, "is_snippet_attachment", False) for attachment in message.attachments
17561756
):
1757-
log_attachments = msg.attachments
1757+
original_attachments = [
1758+
attachment
1759+
for attachment in message.attachments
1760+
if not getattr(attachment, "is_snippet_attachment", False)
1761+
]
1762+
log_attachments = [*original_attachments, *msg.attachments]
17581763
tasks.append(
17591764
self.bot.api.append_log(
17601765
message,

0 commit comments

Comments
 (0)