22
22
SOFTWARE.
23
23
'''
24
24
25
- __version__ = '1.5.1 '
25
+ __version__ = '1.5.2 '
26
26
27
27
from contextlib import redirect_stdout
28
28
from urllib .parse import urlparse
@@ -58,16 +58,24 @@ def __init__(self):
58
58
def _add_commands (self ):
59
59
'''Adds commands automatically'''
60
60
self .remove_command ('help' )
61
+ print ('-------------------------' )
62
+ print ('┌┬┐┌─┐┌┬┐┌┬┐┌─┐┬┬' ,
63
+ '││││ │ │││││├─┤││' ,
64
+ '┴ ┴└─┘─┴┘┴ ┴┴ ┴┴┴─┘' , sep = '\n ' )
65
+ print (f'v{ __version__ } ' )
66
+ print ('Author: kyb3r' )
61
67
for attr in dir (self ):
62
68
cmd = getattr (self , attr )
63
69
if isinstance (cmd , commands .Command ):
64
70
self .add_command (cmd )
71
+
65
72
@property
66
73
def config (self ):
67
74
try :
68
75
with open ('config.json' ) as f :
69
76
config = json .load (f )
70
77
except FileNotFoundError :
78
+ print ('config.json not found, falling back to env vars.' )
71
79
config = {}
72
80
config .update (os .environ )
73
81
return config
@@ -105,12 +113,13 @@ async def wrapper(self, ctx, *args, **kwargs):
105
113
return wrapper
106
114
107
115
async def on_connect (self ):
108
- print ('---------------' )
109
- print ('Modmail connected!' )
116
+ print ('-------------------------' )
117
+ print ('Connected to gateway.' )
118
+
110
119
self .session = aiohttp .ClientSession ()
111
120
status = os .getenv ('STATUS' ) or self .config .get ('STATUS' )
112
121
if status :
113
- print (f'Setting Status to { status } ' )
122
+ print (f'Changing presence. ' )
114
123
await self .change_presence (activity = discord .Game (status ))
115
124
else :
116
125
print ('No status set.' )
@@ -127,15 +136,14 @@ def guild(self):
127
136
async def on_ready (self ):
128
137
'''Bot startup, sets uptime.'''
129
138
print (textwrap .dedent (f'''
130
- ---------------
131
- Client is ready!
132
- ---------------
133
- Author: kyb3r
134
- ---------------
139
+ -------------------------
140
+ Client ready.
141
+ -------------------------
135
142
Logged in as: { self .user }
136
143
User ID: { self .user .id }
137
- ---------------
138
- ''' ))
144
+ Guild ID: { self .guild .id if self .guild else 0 }
145
+ -------------------------
146
+ ''' ).strip ())
139
147
140
148
async def on_message (self , message ):
141
149
if message .author .bot :
@@ -185,6 +193,14 @@ async def on_message_edit(self, before, after):
185
193
embed .description = after .content
186
194
await msg .edit (embed = embed )
187
195
break
196
+
197
+ async def on_command_error (self , ctx , error ):
198
+ if isinstance (error , (commands .MissingRequiredArgument , commands .UserInputError )):
199
+ prefix = self .config .get ('PREFIX' , 'm.' )
200
+ em = discord .Embed (color = discord .Color .green ())
201
+ em .title = f'`{ prefix } { ctx .command .signature } `'
202
+ em .description = ctx .command .help
203
+ await ctx .send (embed = em )
188
204
189
205
def overwrites (self , ctx , modrole = None ):
190
206
'''Permision overwrites for the guild.'''
@@ -209,6 +225,7 @@ def help_embed(self, prefix):
209
225
f'`{ prefix } about` - Shows general information about the bot.\n ' \
210
226
f'`{ prefix } contact` - Allows a moderator to initiate a thread with a given recipient.\n ' \
211
227
f'`{ prefix } reply` - Sends a message to the current thread\' s recipient.\n ' \
228
+ f'`{ prefix } edit` - Edit a message sent by the reply command.\n ' \
212
229
f'`{ prefix } close` - Closes the current thread and deletes the channel.\n ' \
213
230
f'`{ prefix } archive` - Closes the thread and moves the channel to archive category.\n ' \
214
231
f'`{ prefix } block` - Blocks a user from using modmail.\n ' \
@@ -269,7 +286,7 @@ async def get_latest_updates(self, limit=3):
269
286
270
287
short_sha = commit ['sha' ][:6 ]
271
288
html_url = commit ['html_url' ]
272
- message = commit ['commit' ]['message' ]
289
+ message = commit ['commit' ]['message' ]. splitlines ()[ 0 ]
273
290
author_name = commit ['author' ]['login' ]
274
291
275
292
latest_commits += f'[`{ short_sha } `]({ html_url } ) { message } - { author_name } \n '
@@ -293,6 +310,7 @@ def uptime(self):
293
310
@commands .command ()
294
311
@trigger_typing
295
312
async def help (self , ctx ):
313
+ '''Shows the help message'''
296
314
prefix = self .config .get ('PREFIX' , 'm.' )
297
315
298
316
em1 = self .help_embed (prefix )
@@ -308,6 +326,7 @@ async def help(self, ctx):
308
326
@commands .command ()
309
327
@trigger_typing
310
328
async def about (self , ctx ):
329
+ '''Shows information about the bot.'''
311
330
em = discord .Embed (color = discord .Color .green (), timestamp = datetime .datetime .utcnow ())
312
331
em .set_author (name = 'Mod Mail - Information' , icon_url = self .user .avatar_url )
313
332
em .set_thumbnail (url = self .user .avatar_url )
@@ -722,6 +741,8 @@ async def send_mail(self, message, channel, from_mod, delete_message=True):
722
741
async def process_reply (self , message , user_id = None ):
723
742
user_id = user_id or int (re .findall (r'\d+' , message .channel .topic )[0 ])
724
743
user = self .get_user (user_id )
744
+ if not message .content and not message .attachments :
745
+ raise commands .UserInputError ('msg is required argument.' )
725
746
if not user :
726
747
return await message .channel .send ('This user does not share any servers with the bot and is thus unreachable.' )
727
748
await asyncio .gather (
@@ -836,6 +857,41 @@ async def reply(self, ctx, *, msg=''):
836
857
user_id = await self .find_user_id_from_channel (ctx .channel )
837
858
if user_id :
838
859
await self .process_reply (ctx .message , user_id = user_id )
860
+
861
+ async def _edit_thread_message (self , channel , message_id , message ):
862
+ async for msg in channel .history ():
863
+ if msg .embeds :
864
+ embed = msg .embeds [0 ]
865
+ if f'Moderator - { message_id } ' in embed .footer .text :
866
+ if ' - (Edited)' not in embed .footer .text :
867
+ embed .set_footer (text = embed .footer .text + ' - (Edited)' )
868
+ embed .description = message
869
+ await msg .edit (embed = embed )
870
+ break
871
+
872
+ def edit_thread_message (self , user , channel , message_id , message ):
873
+ return asyncio .gather (
874
+ self ._edit_thread_message (user , message_id , message ),
875
+ self ._edit_thread_message (channel , message_id , message )
876
+ )
877
+
878
+ @commands .command ()
879
+ async def edit (self , ctx , message_id : int , * , new_message ):
880
+ '''Edit a message that was sent using the reply command.
881
+
882
+ `<message_id>` is the id shown in the footer of thread messages.
883
+ `<new_message>` is the new message that will be edited in.
884
+ '''
885
+ categ = ctx .channel .category
886
+ if categ and categ .name in 'Mod Mail Archives' :
887
+ if ctx .channel .topic and 'User ID:' in ctx .channel .topic :
888
+ user = self .get_user (int (re .findall (r'\d+' , ctx .channel .topic )[0 ]))
889
+ await self .edit_thread_message (user , ctx .channel , message_id , new_message )
890
+ if not ctx .channel .topic :
891
+ user_id = await self .find_user_id_from_channel (ctx .channel )
892
+ if user_id :
893
+ user = self .get_user (user_id )
894
+ await self .edit_thread_message (user , ctx .channel , message_id , new_message )
839
895
840
896
@commands .command ()
841
897
@trigger_typing
@@ -875,7 +931,7 @@ async def _status(self, ctx, *, message):
875
931
em .color = discord .Color .green ()
876
932
em .set_footer (text = 'Note: this change is temporary.' )
877
933
await ctx .send (embed = em )
878
-
934
+
879
935
@commands .command ()
880
936
@trigger_typing
881
937
@commands .has_permissions (manage_channels = True )
0 commit comments