Skip to content

Commit a848847

Browse files
committed
merge from master
2 parents b73d3ce + d8af5f4 commit a848847

File tree

7 files changed

+90
-18
lines changed

7 files changed

+90
-18
lines changed

CHANGELOG.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,38 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
# v2.17.1
8+
9+
### What's new?
10+
11+
Stricter fallback genesis embed search.
12+
13+
### What's changed?
14+
How modmail checks if a channel is a thread:
15+
16+
1. First the bot checks if the channel topic is in the format `User ID: xxxx`, this means it is a thread.
17+
2. If a channel topic is not found, the bot searches through message history of a channel to find the thread creation embed. This step should never yield a thread for a normal user, but in the case of a another bot messing up the channel topic (happened to a user before) this extra step was added.
18+
19+
20+
# v2.17.0
21+
22+
### What's new?
23+
24+
Added a config option `reply_without_command` which when present, enables the bot to forward any message sent in a thread channel to the recipient. (Replying without using a command)
25+
26+
To enable this functionality, do `?config set reply_without_command true` and to disable it, use `?config del reply_without_command`.
27+
28+
29+
### Changed
30+
31+
The `move` command now only requires `manage_messages` perms instead of `manage_channels`
32+
33+
# v2.16.1
34+
35+
### Fixed
36+
37+
An issue where a scheduled close would not execute over a long period of time if the recipient no shares any servers with the bot.
38+
739
# v2.16.0
840

941
### What's changed?
@@ -13,6 +45,8 @@ If you're still using api.modmail.tk, you will need to migrate to the self-hoste
1345
option ASAP. Your bot will not work unless you switch to the self-hosted option. Refer to the
1446
installation tutorial for information regarding self-hosted Modmail.
1547

48+
If a member leaves/joins (again) while they are a recipient of a thread, a message will be sent to notify you that this has occured.
49+
1650
# v2.15.1
1751

1852
### Fixed

bot.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
SOFTWARE.
2323
"""
2424

25-
__version__ = '2.16.0'
25+
__version__ = '2.17.1'
2626

2727
import asyncio
2828
import logging
@@ -392,25 +392,23 @@ async def on_ready(self):
392392
datetime.utcnow()).total_seconds()
393393
if after < 0:
394394
after = 0
395-
recipient = self.get_user(int(recipient_id))
396395

397-
thread = await self.threads.find(recipient=recipient)
396+
thread = await self.threads.find(recipient_id=int(recipient_id))
398397

399398
if not thread:
400-
# If the recipient is gone or channel is deleted
399+
# If the channel is deleted
401400
self.config.closures.pop(str(recipient_id))
402401
await self.config.update()
403402
continue
404403

405-
# TODO: Low priority,
406-
# Retrieve messages/replies when bot is down, from history?
407404
await thread.close(
408405
closer=self.get_user(items['closer_id']),
409406
after=after,
410407
silent=items['silent'],
411408
delete_channel=items['delete_channel'],
412409
message=items['message']
413410
)
411+
414412
logger.info(LINE)
415413

416414
async def convert_emoji(self, name):
@@ -605,7 +603,10 @@ async def on_message(self, message):
605603

606604
thread = await self.threads.find(channel=ctx.channel)
607605
if thread is not None:
608-
await self.api.append_log(message, type_='internal')
606+
if self.config.get('reply_without_command'):
607+
await thread.reply(message)
608+
else:
609+
await self.api.append_log(message, type_='internal')
609610
elif ctx.invoked_with:
610611
exc = commands.CommandNotFound(
611612
'Command "{}" is not found'.format(ctx.invoked_with)
@@ -698,6 +699,24 @@ async def on_guild_channel_delete(self, channel):
698699
return
699700

700701
await thread.close(closer=mod, silent=True, delete_channel=False)
702+
703+
async def on_member_remove(self, member):
704+
thread = await self.threads.find(recipient=member)
705+
if thread:
706+
em = discord.Embed(
707+
description='The recipient has left the server.',
708+
color=discord.Color.red()
709+
)
710+
await thread.channel.send(embed=em)
711+
712+
async def on_member_join(self, member):
713+
thread = await self.threads.find(recipient=member)
714+
if thread:
715+
em = discord.Embed(
716+
description='The recipient has joined the server.',
717+
color=self.mod_color
718+
)
719+
await thread.channel.send(embed=em)
701720

702721
async def on_message_delete(self, message):
703722
"""Support for deleting linked messages"""
@@ -742,6 +761,8 @@ async def on_command_error(self, context, exception):
742761
command=str(context.command))
743762
elif isinstance(exception, commands.CommandNotFound):
744763
logger.warning(error('CommandNotFound: ' + str(exception)))
764+
elif isinstance(exception, commands.CheckFailure):
765+
logger.warning(error('CheckFailure: ' + str(exception)))
745766
else:
746767
logger.error(error('Unexpected exception:'), exc_info=exception)
747768

@@ -830,5 +851,5 @@ async def autoupdate_loop(self):
830851
if os.name != 'nt':
831852
import uvloop
832853
uvloop.install()
833-
bot = ModmailBot() # pylint: disable=invalid-name
854+
bot = ModmailBot()
834855
bot.run()

cogs/modmail.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ async def del_(self, ctx, *, name: str.lower):
142142
await ctx.send(embed=embed)
143143

144144
@commands.command()
145-
@checks.has_permissions(manage_channels=True)
145+
@checks.has_permissions(manage_messages=True)
146146
async def move(self, ctx, *, category: discord.CategoryChannel):
147147
"""Moves a thread to a specified category."""
148148
thread = ctx.thread

core/checks.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
import logging
12
from discord.ext import commands
3+
from core.utils import error
4+
5+
logger = logging.getLogger('Modmail')
26

37

48
def has_permissions(**perms):
@@ -33,11 +37,17 @@ async def predicate(ctx):
3337

3438
resolved = ctx.channel.permissions_for(ctx.author)
3539

36-
return resolved.administrator or all(
40+
has_perm = resolved.administrator or all(
3741
getattr(resolved, name, None) == value
3842
for name, value in perms.items()
3943
)
4044

45+
if not has_perm:
46+
restrictions = ', '.join(f'{name.replace("_", " ").title()} ({"yes" if value else "no"})'
47+
for name, value in perms.items())
48+
logger.error(error(f'Command `{ctx.command.qualified_name}` processes '
49+
f'the following restrictions(s): {restrictions}.'))
50+
return has_perm
4151
return commands.check(predicate)
4252

4353

core/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class ConfigManager(ConfigManagerABC):
1919

2020
# bot settings
2121
'main_category_id', 'disable_autoupdates', 'prefix', 'mention',
22-
'main_color', 'user_typing', 'mod_typing', 'account_age',
22+
'main_color', 'user_typing', 'mod_typing', 'account_age', 'reply_without_command',
2323

2424
# logging
2525
'log_channel_id',

core/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ def __getitem__(self, item: str) -> 'ThreadABC':
363363
@abc.abstractmethod
364364
async def find(self, *,
365365
recipient: typing.Union[Member, User] = None,
366-
channel: TextChannel = None) -> \
366+
channel: TextChannel = None,
367+
recipient_id: int = None) -> \
367368
typing.Optional['ThreadABC']:
368369
raise NotImplementedError
369370

core/thread.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ async def reply(self, message, anonymous=False):
357357
tasks.append(message.channel.send(
358358
embed=discord.Embed(
359359
color=discord.Color.red(),
360-
description='Your message could not be delivered because '
360+
description='Your message could not be delivered as '
361361
'the recipient is only accepting direct '
362362
'messages from friends, or the bot was '
363363
'blocked by the recipient.'
@@ -478,7 +478,7 @@ async def send(self, message, destination=None,
478478
):
479479
embed.set_image(url=att[0])
480480
if att[1]:
481-
embed.add_field(name='Image', value=f'[**{att[1]}**]({att[0]})')
481+
embed.add_field(name='Image', value=f'[{att[1]}]({att[0]})')
482482
embedded_image = True
483483
elif att[1] is not None:
484484
if note:
@@ -583,22 +583,26 @@ def __iter__(self):
583583
def __getitem__(self, item):
584584
return self.cache[item]
585585

586-
async def find(self, *, recipient=None, channel=None):
586+
async def find(self, *, recipient=None, channel=None, recipient_id=None):
587587
"""Finds a thread from cache or from discord channel topics."""
588588
if recipient is None and channel is not None:
589589
return await self._find_from_channel(channel)
590590

591591
thread = None
592+
593+
if recipient:
594+
recipient_id = recipient.id
595+
592596
try:
593-
thread = self.cache[recipient.id]
597+
thread = self.cache[recipient_id]
594598
except KeyError:
595599
channel = discord.utils.get(
596600
self.bot.modmail_guild.text_channels,
597-
topic=f'User ID: {recipient.id}'
601+
topic=f'User ID: {recipient_id}'
598602
)
599603
if channel:
600604
thread = Thread(self, recipient, channel)
601-
self.cache[recipient.id] = thread
605+
self.cache[recipient_id] = thread
602606
thread.ready = True
603607
return thread
604608

@@ -619,6 +623,8 @@ async def _find_from_channel(self, channel):
619623
elif channel.topic is None:
620624
try:
621625
async for message in channel.history(limit=100):
626+
if message.author != self.bot.user:
627+
continue
622628
if message.embeds:
623629
embed = message.embeds[0]
624630
if embed.footer.text:

0 commit comments

Comments
 (0)