Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
42070be
fix: ignore typing failures
lorenzo132 Oct 4, 2025
6683311
fix: only surpress failures
lorenzo132 Oct 4, 2025
71fd480
chore: sync local edits before push
lorenzo132 Oct 4, 2025
e764121
Fix: closing with timed words/ command in reply.
lorenzo132 Oct 5, 2025
7e3ce81
Fix: typing in changelog command.
lorenzo132 Oct 5, 2025
7dae055
Merge branch 'development' into development
lorenzo132 Oct 5, 2025
48c4d5a
Fix: closing with timed words (additional))
lorenzo132 Oct 5, 2025
43658e0
Merge branch 'development' of https://github.com/lorenzo132/Modmail-D…
lorenzo132 Oct 5, 2025
7e958fc
Fix changelog entry for command reply issue
lorenzo132 Oct 5, 2025
e853585
Update CHANGELOG for v4.2.0 enhancements
lorenzo132 Oct 5, 2025
d89f405
fix; raceconditions, thread duplication on unsnooze, message queue fo…
lorenzo132 Oct 8, 2025
aa28107
Update package versions in requirements.txt
lorenzo132 Oct 8, 2025
0990639
Merge branch 'development' into development
lorenzo132 Oct 8, 2025
6181467
snooze(move): auto-unsnooze on reply/any mod message; enforce hidden …
lorenzo132 Oct 8, 2025
19c0668
unsnooze: suppress mentions during restore (AllowedMentions.none on r…
lorenzo132 Oct 9, 2025
0cb5150
Remove base64 snooze/unsnooze logic, fix notification crash, clean up…
lorenzo132 Oct 9, 2025
f46a668
fix: escape mentions on unsnooze
lorenzo132 Oct 9, 2025
7fc1359
Fix: Only create log URL button if valid, and robust channel restore …
lorenzo132 Oct 9, 2025
542d9f6
black formatting
lorenzo132 Oct 9, 2025
3ffea2c
Unsnooze: prefix username (user_id) for plain-text replay messages
lorenzo132 Oct 10, 2025
5e7802e
feat: command queue during unsnooze process.
lorenzo132 Oct 15, 2025
b0776da
fix: contact while snooze returned as invalid channel
lorenzo132 Oct 16, 2025
2b3a32c
Update thread.py
lorenzo132 Oct 17, 2025
76f12f7
fix: snooze timing
lorenzo132 Oct 17, 2025
b6d7431
change: rename default snooze time config
lorenzo132 Oct 17, 2025
b60ddbe
fix: parsing
lorenzo132 Oct 17, 2025
15e6391
fix: cache for snooze timer
lorenzo132 Oct 17, 2025
07a0a77
fix: Properly accessing nested data
lorenzo132 Oct 17, 2025
1654c26
rename: default_snooze_time -> snooze_default_duration
lorenzo132 Oct 20, 2025
e3f9f73
improve unsnooze notify
lorenzo132 Oct 20, 2025
c680f67
fix: id extraction for clean database.
lorenzo132 Oct 20, 2025
eaf7cfd
improve: support for user-friendly time input for snooze_default_dura…
lorenzo132 Oct 20, 2025
18947c8
reflect config help snooze_default_duration for userfriendly time
lorenzo132 Oct 20, 2025
71bf970
fix: anonreply showing None
lorenzo132 Oct 23, 2025
a6bef2e
black formatting
lorenzo132 Nov 7, 2025
e54c593
feat: thread creation menu
lorenzo132 Nov 7, 2025
700e4cf
Update requirements.txt
lorenzo132 Nov 7, 2025
ed59cf1
fixes
lorenzo132 Nov 8, 2025
04a33b7
feat: thread_creation_menu_precreate_channel
lorenzo132 Nov 8, 2025
3795ec0
core
lorenzo132 Nov 8, 2025
1a12b70
Change thread_creation_menu config
martinbndr Nov 8, 2025
4710ad7
Change Option Description/Emoji
martinbndr Nov 8, 2025
040df23
fix: disable menu after closure
lorenzo132 Nov 9, 2025
b7c80b2
feats/fixes
lorenzo132 Nov 9, 2025
c8135da
forgot to add help
lorenzo132 Nov 9, 2025
067150f
Merge pull request #5 from LorenzoModmailDev/development
lorenzo132 Nov 9, 2025
4e02991
rely on config for precreating. fix error with unknown channels
lorenzo132 Nov 9, 2025
c59e192
feat: large images in threadmenu embed
lorenzo132 Nov 9, 2025
3a946c0
feat: threadmenu reset
lorenzo132 Nov 9, 2025
b086396
cleanup
lorenzo132 Nov 9, 2025
0427d50
codereviews response. Formatting (ruff)
lorenzo132 Nov 9, 2025
f6413c4
log instead of pass on exception
lorenzo132 Nov 9, 2025
475fd77
format
lorenzo132 Nov 9, 2025
8c341fb
higher delays
lorenzo132 Nov 9, 2025
f2e8766
black formatting, smoothen menu closure
lorenzo132 Nov 10, 2025
6b727b4
smoothen which selecetion was made
lorenzo132 Nov 10, 2025
58da525
solves the command from showing in the replies in rare cases
lorenzo132 Nov 10, 2025
2364890
Update CHANGELOG.md
lorenzo132 Nov 10, 2025
2a91242
Merge pull request #6 from modmail-dev/development
lorenzo132 Nov 11, 2025
b757dea
fix: typeerror
lorenzo132 Nov 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Forwarded messages now properly show in threads, rather than showing as an empty
- Eliminated duplicate logs and notes.
- Addressed inconsistent use of `logkey` after ticket restoration.
- Fixed issues with identifying the user who sent internal messages.
- Solved an ancient bug where closing with words like `evening` wouldn't work.
- Solved an ancient bug where closing with words like `evening` wouldnt work.
- Fixed the command from being included in the reply in rare conditions.

### Added
Expand All @@ -29,16 +29,39 @@ Commands:
* `clearsnoozed`: Clears all snoozed items.

Configuration Options:
* `max_snooze_time`: Sets the maximum duration for snooze.
* `snooze_default_duration`: Sets the maximum duration for snooze.
* `snooze_title`: Customizes the title for snooze notifications.
* `snooze_text`: Customizes the text for snooze notifications.
* `unsnooze_text`: Customizes the text for unsnooze notifications.
* `unsnooze_notify_channel`: Specifies the channel for unsnooze notifications.
* `unsnooze_history_limit`: Limits the number of messages replayed when unsnoozing (genesis message and notes are always shown).
* `snooze_behavior`: Choose between `delete` (legacy) or `move` behavior for snoozing.
* `snoozed_category_id`: Target category for `move` snoozing; required when `snooze_behavior` is `move`.
* `thread_min_characters`: Minimum number of characters required.
* `thread_min_characters_title`: Title shown when the message is too short.
* `thread_min_characters_response`: Response shown to the user if their message is too short.
* `thread_min_characters_footer`: Footer displaying the minimum required characters.

Features:
* Thread-creation menu: Adds an interactive select step before a thread channel is created.
* Commands:
* `threadmenu toggle`: Enable/disable the menu.
* `threadmenu show`: List current top-level options.
* `threadmenu option add`: Interactive wizard to create an option.
* `threadmenu option edit/remove/show`: Manage or inspect an existing option.
* `threadmenu submenu create/delete/list/show`: Manage submenus.
* `threadmenu submenu option add/edit/remove`: Manage options inside a submenu.
* Configuration / Behavior:
* Per-option `category` targeting when creating a thread; falls back to `main_category_id` if invalid/missing.
* Optional selection logging (`thread_creation_menu_selection_log`) posts the chosen option in the new thread.
* Anonymous prompt support (`thread_creation_menu_anonymous_menu`).


Behavioral changes:
- When `snooze_behavior` is set to `move`, the snoozed category now has a hard limit of 49 channels. New snoozes are blocked once it’s full until space is freed.
- When switching `snooze_behavior` to `move` via `?config set`, the bot reminds admins to set `snoozed_category_id` if it’s missing.
- Thread-creation menu options & submenu options now support an optional per-option `category` target. The interactive wizards (`threadmenu option add` / `threadmenu submenu option add`) and edit commands allow specifying or updating a category. If the stored category is missing or invalid at selection time, channel creation automatically falls back to `main_category_id`.

# v4.1.2

### Fixed
Expand Down
299 changes: 261 additions & 38 deletions bot.py

Large diffs are not rendered by default.

433 changes: 346 additions & 87 deletions cogs/modmail.py

Large diffs are not rendered by default.

28 changes: 21 additions & 7 deletions cogs/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ async def load_plugin(self, plugin):

if stderr:
logger.debug("[stderr]\n%s.", stderr.decode())
logger.error("Failed to download requirements for %s.", plugin.ext_string, exc_info=True)
logger.error(
"Failed to download requirements for %s.",
plugin.ext_string,
exc_info=True,
)
raise InvalidPluginError(f"Unable to download requirements: ```\n{stderr.decode()}\n```")

if os.path.exists(USER_SITE):
Expand Down Expand Up @@ -361,7 +365,10 @@ async def plugins_add(self, ctx, *, plugin_name: str):
return

if str(plugin) in self.bot.config["plugins"]:
embed = discord.Embed(description="This plugin is already installed.", color=self.bot.error_color)
embed = discord.Embed(
description="This plugin is already installed.",
color=self.bot.error_color,
)
return await ctx.send(embed=embed)

if plugin.name in self.bot.cogs:
Expand Down Expand Up @@ -470,7 +477,8 @@ async def plugins_remove(self, ctx, *, plugin_name: str):
pass # dir not empty

embed = discord.Embed(
description="The plugin is successfully uninstalled.", color=self.bot.main_color
description="The plugin is successfully uninstalled.",
color=self.bot.main_color,
)
await ctx.send(embed=embed)

Expand All @@ -486,7 +494,8 @@ async def update_plugin(self, ctx, plugin_name):

async with safe_typing(ctx):
embed = discord.Embed(
description=f"Successfully updated {plugin.name}.", color=self.bot.main_color
description=f"Successfully updated {plugin.name}.",
color=self.bot.main_color,
)
await self.download_plugin(plugin, force=True)
if self.bot.config.get("enable_plugins"):
Expand Down Expand Up @@ -570,7 +579,8 @@ async def plugins_reset(self, ctx):
logger.warning("Removing %s.", entry.name)

embed = discord.Embed(
description="Successfully purged all plugins from the bot.", color=self.bot.main_color
description="Successfully purged all plugins from the bot.",
color=self.bot.main_color,
)
return await ctx.send(embed=embed)

Expand Down Expand Up @@ -598,7 +608,8 @@ async def plugins_loaded(self, ctx):

if not self.loaded_plugins:
embed = discord.Embed(
description="There are no plugins currently loaded.", color=self.bot.error_color
description="There are no plugins currently loaded.",
color=self.bot.error_color,
)
return await ctx.send(embed=embed)

Expand Down Expand Up @@ -666,7 +677,10 @@ async def plugins_registry(self, ctx, *, plugin_name: typing.Union[int, str] = N
matches = get_close_matches(plugin_name, self.registry.keys())

if matches:
embed.add_field(name="Perhaps you meant:", value="\n".join(f"`{m}`" for m in matches))
embed.add_field(
name="Perhaps you meant:",
value="\n".join(f"`{m}`" for m in matches),
)

return await ctx.send(embed=embed)

Expand Down
Loading
Loading