1
1
import inspect
2
+ import logging
2
3
import os
3
4
import traceback
4
5
from contextlib import redirect_stdout
10
11
11
12
import discord
12
13
from discord import Embed , Color , Activity
13
- from discord .enums import ActivityType
14
+ from discord .enums import ActivityType , Status
14
15
from discord .ext import commands
15
16
16
17
from aiohttp import ClientResponseError
20
21
from core .decorators import github_access_token_required , trigger_typing
21
22
from core .models import Bot , InvalidConfigError
22
23
from core .paginator import PaginatorSession , MessagePaginatorSession
23
- from core .utils import cleanup_code
24
+ from core .utils import cleanup_code , info , error
25
+
26
+ logger = logging .getLogger ('Modmail' )
24
27
25
28
26
29
class Utility :
@@ -244,7 +247,7 @@ async def debug(self, ctx):
244
247
245
248
with open (os .path .join (os .path .dirname (os .path .abspath (__file__ )),
246
249
'../temp/logs.log' ), 'r+' ) as f :
247
- logs = f .read ().strip (' \n \r ' )
250
+ logs = f .read ().strip ()
248
251
249
252
if not logs :
250
253
embed = Embed (
@@ -299,7 +302,7 @@ async def hastebin(self, ctx):
299
302
"""Upload logs to hastebin."""
300
303
with open (os .path .join (os .path .dirname (os .path .abspath (__file__ )),
301
304
'../temp/logs.log' ), 'r+' ) as f :
302
- logs = f .read ().strip (' \n \r ' )
305
+ logs = f .read ().strip ()
303
306
304
307
try :
305
308
async with self .bot .session .post ('https://hastebin.com/documents' ,
@@ -431,10 +434,10 @@ async def activity(self, ctx, activity_type: str, *, message: str = ''):
431
434
it must be followed by a "to": "listening to..."
432
435
"""
433
436
if activity_type == 'clear' :
434
- await self .bot .change_presence (activity = None )
435
437
self .bot .config ['activity_type' ] = None
436
438
self .bot .config ['activity_message' ] = None
437
439
await self .bot .config .update ()
440
+ await self .set_presence (log = False )
438
441
embed = Embed (
439
442
title = 'Activity Removed' ,
440
443
color = self .bot .main_color
@@ -445,42 +448,167 @@ async def activity(self, ctx, activity_type: str, *, message: str = ''):
445
448
raise commands .UserInputError
446
449
447
450
try :
448
- activity_type = ActivityType [activity_type .lower ()]
449
- except KeyError :
451
+ activity , msg = (await self .set_presence (
452
+ activity_identifier = activity_type ,
453
+ activity_by_key = True ,
454
+ activity_message = message ,
455
+ log = False
456
+ ))['activity' ]
457
+ except ValueError :
450
458
raise commands .UserInputError
451
459
452
- if activity_type == ActivityType .listening :
453
- if not message .lower ().startswith ('to ' ):
454
- # Must be listening to...
455
- raise commands .UserInputError
456
- normalized_message = message [3 :].strip ()
457
- else :
458
- # Discord does not allow leading/trailing spaces anyways
459
- normalized_message = message .strip ()
460
+ self .bot .config ['activity_type' ] = activity .type .value
461
+ self .bot .config ['activity_message' ] = message
462
+ await self .bot .config .update ()
460
463
461
- if activity_type == ActivityType .streaming :
462
- url = self .bot .config .get ('twitch_url' ,
463
- 'https://www.twitch.tv/discord-Modmail/' )
464
- else :
465
- url = None
464
+ embed = Embed (
465
+ title = 'Activity Changed' ,
466
+ description = msg ,
467
+ color = self .bot .main_color
468
+ )
469
+ return await ctx .send (embed = embed )
466
470
467
- activity = Activity (type = activity_type ,
468
- name = normalized_message ,
469
- url = url )
470
- await self .bot .change_presence (activity = activity )
471
+ @commands .command ()
472
+ @checks .has_permissions (administrator = True )
473
+ async def status (self , ctx , * , status_type : str ):
474
+ """
475
+ Set a custom status for the bot.
476
+
477
+ Possible status types:
478
+ - `online`
479
+ - `idle`
480
+ - `dnd`
481
+ - `do_not_disturb` or `do not disturb`
482
+ - `invisible` or `offline`
483
+ - `clear`
471
484
472
- self .bot .config ['activity_type' ] = activity_type
473
- self .bot .config ['activity_message' ] = message
485
+ When status type is set to `clear`, the current status is removed.
486
+ """
487
+ if status_type == 'clear' :
488
+ self .bot .config ['status' ] = None
489
+ await self .bot .config .update ()
490
+ await self .set_presence (log = False )
491
+ embed = Embed (
492
+ title = 'Status Removed' ,
493
+ color = self .bot .main_color
494
+ )
495
+ return await ctx .send (embed = embed )
496
+ status_type = status_type .replace (' ' , '_' )
497
+
498
+ try :
499
+ status , msg = (await self .set_presence (
500
+ status_identifier = status_type ,
501
+ status_by_key = True ,
502
+ log = False
503
+ ))['status' ]
504
+ except ValueError :
505
+ raise commands .UserInputError
506
+
507
+ self .bot .config ['status' ] = status .value
474
508
await self .bot .config .update ()
475
509
476
- desc = f'Current activity is: { activity_type .name } { message } .'
477
510
embed = Embed (
478
- title = 'Activity Changed' ,
479
- description = desc ,
511
+ title = 'Status Changed' ,
512
+ description = msg ,
480
513
color = self .bot .main_color
481
514
)
482
515
return await ctx .send (embed = embed )
483
516
517
+ async def set_presence (self , * ,
518
+ status_identifier = None ,
519
+ status_by_key = True ,
520
+ activity_identifier = None ,
521
+ activity_by_key = True ,
522
+ activity_message = None ,
523
+ log = True ):
524
+
525
+ activity = status = None
526
+ if status_identifier is None :
527
+ status_identifier = self .bot .config .get ('status' , None )
528
+ status_by_key = False
529
+
530
+ try :
531
+ if status_by_key :
532
+ status = Status [status_identifier ]
533
+ else :
534
+ status = Status (status_identifier )
535
+ except (KeyError , ValueError ):
536
+ if status_identifier is not None :
537
+ msg = f'Invalid status type: { status_identifier } '
538
+ if log :
539
+ logger .warning (error (msg ))
540
+ else :
541
+ raise ValueError (msg )
542
+
543
+ if activity_identifier is None :
544
+ if activity_message is not None :
545
+ raise ValueError ('activity_message must be None '
546
+ 'if activity_identifier is None.' )
547
+ activity_identifier = self .bot .config .get ('activity_type' , None )
548
+ activity_by_key = False
549
+
550
+ try :
551
+ if activity_by_key :
552
+ activity_type = ActivityType [activity_identifier ]
553
+ else :
554
+ activity_type = ActivityType (activity_identifier )
555
+ except (KeyError , ValueError ):
556
+ if activity_identifier is not None :
557
+ msg = f'Invalid activity type: { activity_identifier } '
558
+ if log :
559
+ logger .warning (error (msg ))
560
+ else :
561
+ raise ValueError (msg )
562
+ else :
563
+ url = None
564
+ activity_message = (
565
+ activity_message or
566
+ self .bot .config .get ('activity_message' , '' )
567
+ ).strip ()
568
+
569
+ if activity_type == ActivityType .listening :
570
+ if activity_message .lower ().startswith ('to ' ):
571
+ # The actual message is after listening to [...]
572
+ # discord automatically add the "to"
573
+ activity_message = activity_message [3 :].strip ()
574
+ elif activity_type == ActivityType .streaming :
575
+ url = self .bot .config .get (
576
+ 'twitch_url' , 'https://www.twitch.tv/discord-modmail/'
577
+ )
578
+
579
+ if activity_message :
580
+ activity = Activity (type = activity_type ,
581
+ name = activity_message ,
582
+ url = url )
583
+ else :
584
+ msg = 'You must supply an activity message to use custom activity.'
585
+ if log :
586
+ logger .warning (error (msg ))
587
+ else :
588
+ raise ValueError (msg )
589
+
590
+ await self .bot .change_presence (activity = activity , status = status )
591
+
592
+ presence = {'activity' : (None , 'No activity has been set.' ),
593
+ 'status' : (None , 'No status has been set.' )}
594
+ if activity is not None :
595
+ # TODO: Trim message
596
+ to = 'to ' if activity .type == ActivityType .listening else ''
597
+ msg = f'Activity set to: { activity .type .name .capitalize ()} '
598
+ msg += f'{ to } { activity .name } .'
599
+ presence ['activity' ] = (activity , msg )
600
+ if status is not None :
601
+ msg = f'Status set to: { status .value } .'
602
+ presence ['status' ] = (status , msg )
603
+ return presence
604
+
605
+ async def on_ready (self ):
606
+ # Wait until config cache is populated with stuff from db
607
+ await self .bot .config .wait_until_ready ()
608
+ presence = await self .set_presence ()
609
+ logger .info (info (presence ['activity' ][1 ]))
610
+ logger .info (info (presence ['status' ][1 ]))
611
+
484
612
@commands .command ()
485
613
@trigger_typing
486
614
@checks .has_permissions (administrator = True )
0 commit comments