Skip to content

Commit 5bf4a98

Browse files
committed
Merge branch 'development'
2 parents 9ec23df + 4acbbe4 commit 5bf4a98

File tree

9 files changed

+103
-42
lines changed

9 files changed

+103
-42
lines changed

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66
This project mostly adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html);
77
however, insignificant breaking changes do not guarantee a major version bump, see the reasoning [here](https://github.com/kyb3r/modmail/issues/319). If you're a plugin developer, note the "BREAKING" section.
88

9+
# v3.7.8-dev1
10+
11+
### Added
12+
13+
- Added `thread_contact_silently` to allow opening threads silently by default
14+
15+
### Fixed
16+
- Permission levels were not respected
17+
- `perms remove` was not working
18+
- `logs` and `block` would not recognise users in a seperate server setup.
19+
- Custom emojis were not working with `confirm_thread_creation`
20+
21+
### Internal
22+
- Optimised `perms get`, bot should respond faster now
23+
924
# v3.7.7
1025

1126
### Added

bot.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "3.7.7"
1+
__version__ = "3.7.8-dev1"
22

33

44
import asyncio
@@ -1002,6 +1002,11 @@ async def update_perms(
10021002
else:
10031003
if value in permissions[name]:
10041004
permissions[name].remove(value)
1005+
1006+
if isinstance(name, PermissionLevel):
1007+
self.config["level_permissions"] = permissions
1008+
else:
1009+
self.config["command_permissions"] = permissions
10051010
logger.info("Updating permissions for %s, %s (add=%s).", name, value, add)
10061011
await self.config.update()
10071012

@@ -1159,7 +1164,7 @@ async def handle_reaction_events(self, payload):
11591164
logger.warning("Failed to find linked message for reactions: %s", e)
11601165
return
11611166

1162-
if self.config["transfer_reactions"]:
1167+
if self.config["transfer_reactions"] and linked_message is not None:
11631168
if payload.event_type == "REACTION_ADD":
11641169
if await self.add_reaction(linked_message, reaction):
11651170
await self.add_reaction(message, reaction)
@@ -1355,6 +1360,7 @@ async def on_error(self, event_method, *args, **kwargs):
13551360

13561361
async def on_command_error(self, context, exception):
13571362
if isinstance(exception, commands.BadUnionArgument):
1363+
logger.error("Expected exception:", exc_info=exception)
13581364
msg = "Could not find the specified " + human_join(
13591365
[c.__name__ for c in exception.converters]
13601366
)

cogs/modmail.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ async def contact(
989989
if self.bot.config["dm_disabled"] in (DMDisabled.NEW_THREADS, DMDisabled.ALL_THREADS):
990990
logger.info("Contacting user %s when Modmail DM is disabled.", user)
991991

992-
if not silent:
992+
if not silent and not self.bot.config.get("thread_contact_silently"):
993993
if ctx.author.id == user.id:
994994
description = "You have opened a Modmail thread."
995995
else:

cogs/utility.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ async def about(self, ctx):
345345
embed.add_field(
346346
name="Want Modmail in Your Server?",
347347
value="Follow the installation guide on [GitHub](https://github.com/kyb3r/modmail/) "
348-
"and join our [Discord server](https://discord.gg/F34cRU8/)!",
348+
"and join our [Discord server](https://discord.gg/F34cRU8)!",
349349
inline=False,
350350
)
351351

@@ -1496,23 +1496,23 @@ async def permissions_get(
14961496
"""
14971497

14981498
if name is None and user_or_role not in {"command", "level", "override"}:
1499-
value = self._verify_user_or_role(user_or_role)
1499+
value = str(self._verify_user_or_role(user_or_role))
15001500

15011501
cmds = []
15021502
levels = []
15031503

15041504
done = set()
1505+
command_permissions = self.bot.config["command_permissions"]
1506+
level_permissions = self.bot.config["level_permissions"]
15051507
for command in self.bot.walk_commands():
15061508
if command not in done:
15071509
done.add(command)
1508-
permissions = self.bot.config["command_permissions"].get(
1509-
command.qualified_name, []
1510-
)
1510+
permissions = command_permissions.get(command.qualified_name, [])
15111511
if value in permissions:
15121512
cmds.append(command.qualified_name)
15131513

15141514
for level in PermissionLevel:
1515-
permissions = self.bot.config["level_permissions"].get(level.name, [])
1515+
permissions = level_permissions.get(level.name, [])
15161516
if value in permissions:
15171517
levels.append(level.name)
15181518

core/checks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ async def check_permissions(ctx, command_name) -> bool:
6262
if command_name in command_permissions:
6363
# -1 is for @everyone
6464
return -1 in command_permissions[command_name] or any(
65-
check.id in command_permissions[command_name] for check in checkables
65+
str(check.id) in command_permissions[command_name] for check in checkables
6666
)
6767

6868
level_permissions = ctx.bot.config["level_permissions"]
@@ -71,7 +71,7 @@ async def check_permissions(ctx, command_name) -> bool:
7171
if level >= permission_level and level.name in level_permissions:
7272
# -1 is for @everyone
7373
if -1 in level_permissions[level.name] or any(
74-
check.id in level_permissions[level.name] for check in checkables
74+
str(check.id) in level_permissions[level.name] for check in checkables
7575
):
7676
return True
7777
return False

core/config.py

+36-8
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from core._color_data import ALL_COLORS
1515
from core.models import DMDisabled, InvalidConfigError, Default, getLogger
1616
from core.time import UserFriendlyTimeSync
17-
from core.utils import strtobool
17+
from core.utils import strtobool, tryint
1818

1919
logger = getLogger(__name__)
2020
load_dotenv()
@@ -53,6 +53,7 @@ class ConfigManager:
5353
"thread_auto_close_response": "This thread has been closed automatically due to inactivity after {timeout}.",
5454
"thread_creation_response": "The staff team will get back to you as soon as possible.",
5555
"thread_creation_footer": "Your message has been sent",
56+
"thread_contact_silently": False,
5657
"thread_self_closable_creation_footer": "Click the lock to close the thread",
5758
"thread_creation_title": "Thread Created",
5859
"thread_close_footer": "Replying will create a new thread",
@@ -167,6 +168,7 @@ class ConfigManager:
167168
"data_collection",
168169
"enable_eval",
169170
"disable_autoupdates",
171+
"thread_contact_silently",
170172
}
171173

172174
enums = {
@@ -175,6 +177,8 @@ class ConfigManager:
175177
"activity_type": discord.ActivityType,
176178
}
177179

180+
force_str = {"command_permissions", "level_permissions"}
181+
178182
defaults = {**public_keys, **private_keys, **protected_keys}
179183
all_keys = set(defaults.keys())
180184

@@ -245,18 +249,19 @@ def __setitem__(self, key: str, item: typing.Any) -> None:
245249
self._cache[key] = item
246250

247251
def __getitem__(self, key: str) -> typing.Any:
248-
key = key.lower()
249-
if key not in self.all_keys:
250-
raise InvalidConfigError(f'Configuration "{key}" is invalid.')
251-
if key not in self._cache:
252-
self._cache[key] = deepcopy(self.defaults[key])
253-
return self._cache[key]
252+
# make use of the custom methods in func:get:
253+
return self.get(key)
254254

255255
def __delitem__(self, key: str) -> None:
256256
return self.remove(key)
257257

258258
def get(self, key: str, convert=True) -> typing.Any:
259-
value = self.__getitem__(key)
259+
key = key.lower()
260+
if key not in self.all_keys:
261+
raise InvalidConfigError(f'Configuration "{key}" is invalid.')
262+
if key not in self._cache:
263+
self._cache[key] = deepcopy(self.defaults[key])
264+
value = self._cache[key]
260265

261266
if not convert:
262267
return value
@@ -295,6 +300,29 @@ def get(self, key: str, convert=True) -> typing.Any:
295300
logger.warning("Invalid %s %s.", key, value)
296301
value = self.remove(key)
297302

303+
elif key in self.force_str:
304+
# Temporary: as we saved in int previously, leading to int32 overflow,
305+
# this is transitioning IDs to strings
306+
new_value = {}
307+
changed = False
308+
for k, v in value.items():
309+
new_v = v
310+
if isinstance(v, list):
311+
new_v = []
312+
for n in v:
313+
print("x", n, v)
314+
if n != -1 and not isinstance(n, str):
315+
changed = True
316+
n = str(n)
317+
new_v.append(n)
318+
new_value[k] = new_v
319+
320+
if changed:
321+
# transition the database as well
322+
self.set(key, new_value)
323+
324+
value = new_value
325+
298326
return value
299327

300328
def set(self, key: str, item: typing.Any, convert=True) -> None:

core/config_help.json

+16-5
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,17 @@
303303
"See also: `thread_creation_title`, `thread_creation_response`, `thread_self_closable_creation_footer`, `thread_close_footer`."
304304
]
305305
},
306+
"thread_contact_silently": {
307+
"default": "No",
308+
"description": "Setting this configuration will always open a new thread silently in contact.",
309+
"examples": [
310+
"`{prefix}config set thread_contact_silently yes`",
311+
"`{prefix}config set thread_contact_silently no`"
312+
],
313+
"notes": [
314+
"Works like `{prefix}contact <user> silent` for every new thread."
315+
]
316+
},
306317
"thread_self_closable_creation_footer": {
307318
"default": "\"Click the lock to close the thread\"",
308319
"description": "This is the message embed footer sent to the recipient upon the creation of a new thread.",
@@ -644,7 +655,7 @@
644655
"`{prefix}config set confirm_thread_creation yes`"
645656
],
646657
"notes": [
647-
"See also: `confirm_thread_creation_title`, `confirm_thread_response`, `confirm_thread_creation_accept`, confirm_thread_creation_deny`"
658+
"See also: `confirm_thread_creation_title`, `confirm_thread_response`, `confirm_thread_creation_accept`, `confirm_thread_creation_deny``"
648659
]
649660
},
650661
"confirm_thread_creation_title": {
@@ -654,7 +665,7 @@
654665
"`{prefix}config set confirm_thread_creation_title Are you sure you want to create a new thread?`"
655666
],
656667
"notes": [
657-
"See also: `confirm_thread_creation`, `confirm_thread_response`, `confirm_thread_creation_accept`, confirm_thread_creation_deny`"
668+
"See also: `confirm_thread_creation`, `confirm_thread_response`, `confirm_thread_creation_accept`, `confirm_thread_creation_deny`"
658669
]
659670
},
660671
"confirm_thread_response": {
@@ -664,7 +675,7 @@
664675
"`{prefix}config set confirm_thread_response React to confirm`"
665676
],
666677
"notes": [
667-
"See also: `confirm_thread_creation`, `confirm_thread_creation_title`, `confirm_thread_creation_accept`, confirm_thread_creation_deny`"
678+
"See also: `confirm_thread_creation`, `confirm_thread_creation_title`, `confirm_thread_creation_accept`, `confirm_thread_creation_deny`"
668679
]
669680
},
670681
"confirm_thread_creation_accept": {
@@ -675,7 +686,7 @@
675686
],
676687
"notes": [
677688
"This has no effect unless `confirm_thread_creation` is set",
678-
"See also: `confirm_thread_creation`, `confirm_thread_creation_title`, `confirm_thread_response`, confirm_thread_creation_deny`"
689+
"See also: `confirm_thread_creation`, `confirm_thread_creation_title`, `confirm_thread_response`, `confirm_thread_creation_deny`"
679690
]
680691
},
681692
"confirm_thread_creation_deny": {
@@ -686,7 +697,7 @@
686697
],
687698
"notes": [
688699
"This has no effect unless `confirm_thread_creation` is set",
689-
"See also: `confirm_thread_creation`, `confirm_thread_creation_title`, `confirm_thread_response`, confirm_thread_creation_accept`"
700+
"See also: `confirm_thread_creation`, `confirm_thread_creation_title`, `confirm_thread_response`, `confirm_thread_creation_accept`"
690701
]
691702
},
692703
"use_regex_autotrigger": {

core/thread.py

+17-16
Original file line numberDiff line numberDiff line change
@@ -663,22 +663,23 @@ async def find_linked_message_from_dm(self, message, either_direction=False):
663663
else:
664664
compare_url = None
665665

666-
async for linked_message in self.channel.history():
667-
if not linked_message.embeds:
668-
continue
669-
url = linked_message.embeds[0].author.url
670-
if not url:
671-
continue
672-
if url == compare_url:
673-
return linked_message
666+
if self.channel is not None:
667+
async for linked_message in self.channel.history():
668+
if not linked_message.embeds:
669+
continue
670+
url = linked_message.embeds[0].author.url
671+
if not url:
672+
continue
673+
if url == compare_url:
674+
return linked_message
674675

675-
msg_id = url.split("#")[-1]
676-
if not msg_id.isdigit():
677-
continue
678-
msg_id = int(msg_id)
679-
if int(msg_id) == message.id:
680-
return linked_message
681-
raise ValueError("Thread channel message not found.")
676+
msg_id = url.split("#")[-1]
677+
if not msg_id.isdigit():
678+
continue
679+
msg_id = int(msg_id)
680+
if int(msg_id) == message.id:
681+
return linked_message
682+
raise ValueError("Thread channel message not found.")
682683

683684
async def edit_dm_message(self, message: discord.Message, content: str) -> None:
684685
try:
@@ -1181,7 +1182,7 @@ async def create(
11811182
check=lambda r, u: u.id == message.author.id
11821183
and r.message.id == confirm.id
11831184
and r.message.channel.id == confirm.channel.id
1184-
and r.emoji in (accept_emoji, deny_emoji),
1185+
and str(r.emoji) in (accept_emoji, deny_emoji),
11851186
timeout=20,
11861187
)
11871188
except asyncio.TimeoutError:

core/utils.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ class User(commands.IDConverter):
5656
# noinspection PyCallByClass,PyTypeChecker
5757
async def convert(self, ctx, argument):
5858
try:
59-
return await commands.MemberConverter.convert(self, ctx, argument)
59+
return await commands.MemberConverter().convert(ctx, argument)
6060
except commands.BadArgument:
6161
pass
6262
try:
63-
return await commands.UserConverter.convert(self, ctx, argument)
63+
return await commands.UserConverter().convert(ctx, argument)
6464
except commands.BadArgument:
6565
pass
6666
match = self._get_id_match(argument)

0 commit comments

Comments
 (0)