1
- __version__ = "3.2.2 "
1
+ __version__ = "3.3.0-dev1 "
2
2
3
3
import asyncio
4
4
import logging
19
19
from aiohttp import ClientSession
20
20
from emoji import UNICODE_EMOJI
21
21
from motor .motor_asyncio import AsyncIOMotorClient
22
+ from pkg_resources import parse_version
22
23
from pymongo .errors import ConfigurationError
23
24
24
25
try :
32
33
from core import checks
33
34
from core .clients import ApiClient , PluginDatabaseClient
34
35
from core .config import ConfigManager
35
- from core .utils import human_join , strtobool , parse_alias
36
+ from core .utils import human_join , parse_alias
36
37
from core .models import PermissionLevel , ModmailLogger , SafeFormatter
37
38
from core .thread import ThreadManager
38
39
from core .time import human_timedelta
@@ -70,6 +71,7 @@ def __init__(self):
70
71
self ._api = None
71
72
self .metadata_loop = None
72
73
self .formatter = SafeFormatter ()
74
+ self .loaded_cogs = ["cogs.modmail" , "cogs.plugins" , "cogs.utility" ]
73
75
74
76
self ._connected = asyncio .Event ()
75
77
self .start_time = datetime .utcnow ()
@@ -97,17 +99,7 @@ def __init__(self):
97
99
sys .exit (0 )
98
100
99
101
self .plugin_db = PluginDatabaseClient (self )
100
-
101
- logger .line ()
102
- logger .info ("┌┬┐┌─┐┌┬┐┌┬┐┌─┐┬┬" )
103
- logger .info ("││││ │ │││││├─┤││" )
104
- logger .info ("┴ ┴└─┘─┴┘┴ ┴┴ ┴┴┴─┘" )
105
- logger .info ("v%s" , __version__ )
106
- logger .info ("Authors: kyb3r, fourjr, Taaku18" )
107
- logger .line ()
108
-
109
- self ._load_extensions ()
110
- logger .line ()
102
+ self .startup ()
111
103
112
104
@property
113
105
def uptime (self ) -> str :
@@ -123,6 +115,24 @@ def uptime(self) -> str:
123
115
124
116
return self .formatter .format (fmt , d = days , h = hours , m = minutes , s = seconds )
125
117
118
+ def startup (self ):
119
+ logger .line ()
120
+ logger .info ("┌┬┐┌─┐┌┬┐┌┬┐┌─┐┬┬" )
121
+ logger .info ("││││ │ │││││├─┤││" )
122
+ logger .info ("┴ ┴└─┘─┴┘┴ ┴┴ ┴┴┴─┘" )
123
+ logger .info ("v%s" , __version__ )
124
+ logger .info ("Authors: kyb3r, fourjr, Taaku18" )
125
+ logger .line ()
126
+
127
+ for cog in self .loaded_cogs :
128
+ logger .info ("Loading %s." , cog )
129
+ try :
130
+ self .load_extension (cog )
131
+ logger .info ("Successfully loaded %s." , cog )
132
+ except Exception :
133
+ logger .exception ("Failed to load %s." , cog )
134
+ logger .line ()
135
+
126
136
def _configure_logging (self ):
127
137
level_text = self .config ["log_level" ].upper ()
128
138
logging_levels = {
@@ -161,8 +171,8 @@ def _configure_logging(self):
161
171
logger .debug ("Successfully configured logging." )
162
172
163
173
@property
164
- def version (self ) -> str :
165
- return __version__
174
+ def version (self ):
175
+ return parse_version ( __version__ )
166
176
167
177
@property
168
178
def session (self ) -> ClientSession :
@@ -179,18 +189,6 @@ def api(self):
179
189
async def get_prefix (self , message = None ):
180
190
return [self .prefix , f"<@{ self .user .id } > " , f"<@!{ self .user .id } > " ]
181
191
182
- def _load_extensions (self ):
183
- """Adds commands automatically"""
184
- for file in os .listdir ("cogs" ):
185
- if not file .endswith (".py" ):
186
- continue
187
- cog = f"cogs.{ file [:- 3 ]} "
188
- logger .info ("Loading %s." , cog )
189
- try :
190
- self .load_extension (cog )
191
- except Exception :
192
- logger .exception ("Failed to load %s." , cog )
193
-
194
192
def run (self , * args , ** kwargs ):
195
193
try :
196
194
self .loop .run_until_complete (self .start (self .token ))
@@ -366,25 +364,21 @@ def blocked_whitelisted_users(self) -> typing.List[str]:
366
364
def prefix (self ) -> str :
367
365
return str (self .config ["prefix" ])
368
366
369
- def _parse_color (self , conf_name ):
370
- color = self .config [conf_name ]
371
- try :
372
- return int (color .lstrip ("#" ), base = 16 )
373
- except ValueError :
374
- logger .error ("Invalid %s provided." , conf_name )
375
- return int (self .config .remove (conf_name ).lstrip ("#" ), base = 16 )
376
-
377
367
@property
378
368
def mod_color (self ) -> int :
379
- return self ._parse_color ("mod_color" )
369
+ return self .config . get ("mod_color" )
380
370
381
371
@property
382
372
def recipient_color (self ) -> int :
383
- return self ._parse_color ("recipient_color" )
373
+ return self .config . get ("recipient_color" )
384
374
385
375
@property
386
376
def main_color (self ) -> int :
387
- return self ._parse_color ("main_color" )
377
+ return self .config .get ("main_color" )
378
+
379
+ @property
380
+ def error_color (self ) -> int :
381
+ return self .config .get ("error_color" )
388
382
389
383
def command_perm (self , command_name : str ) -> PermissionLevel :
390
384
level = self .config ["override_command_level" ].get (command_name )
@@ -518,7 +512,6 @@ async def on_ready(self):
518
512
loop = None ,
519
513
)
520
514
self .metadata_loop .before_loop (self .before_post_metadata )
521
- self .metadata_loop .after_loop (self .after_post_metadata )
522
515
self .metadata_loop .start ()
523
516
524
517
async def convert_emoji (self , name : str ) -> str :
@@ -574,38 +567,14 @@ async def _process_blocked(self, message: discord.Message) -> bool:
574
567
575
568
now = datetime .utcnow ()
576
569
577
- account_age = self .config [ "account_age" ]
578
- guild_age = self .config [ "guild_age" ]
570
+ account_age = self .config . get ( "account_age" )
571
+ guild_age = self .config . get ( "guild_age" )
579
572
580
573
if account_age is None :
581
574
account_age = isodate .Duration ()
582
575
if guild_age is None :
583
576
guild_age = isodate .Duration ()
584
577
585
- if not isinstance (account_age , isodate .Duration ):
586
- try :
587
- account_age = isodate .parse_duration (account_age )
588
- except isodate .ISO8601Error :
589
- logger .warning (
590
- "The account age limit needs to be a "
591
- "ISO-8601 duration formatted duration string "
592
- 'greater than 0 days, not "%s".' ,
593
- str (account_age ),
594
- )
595
- account_age = self .config .remove ("account_age" )
596
-
597
- if not isinstance (guild_age , isodate .Duration ):
598
- try :
599
- guild_age = isodate .parse_duration (guild_age )
600
- except isodate .ISO8601Error :
601
- logger .warning (
602
- "The guild join age limit needs to be a "
603
- "ISO-8601 duration formatted duration string "
604
- 'greater than 0 days, not "%s".' ,
605
- str (guild_age ),
606
- )
607
- guild_age = self .config .remove ("guild_age" )
608
-
609
578
reason = self .blocked_users .get (str (message .author .id )) or ""
610
579
min_guild_age = min_account_age = now
611
580
@@ -643,7 +612,7 @@ async def _process_blocked(self, message: discord.Message) -> bool:
643
612
title = "Message not sent!" ,
644
613
description = f"Your must wait for { delta } "
645
614
f"before you can contact me." ,
646
- color = discord . Color . red () ,
615
+ color = self . error_color ,
647
616
)
648
617
)
649
618
@@ -667,7 +636,7 @@ async def _process_blocked(self, message: discord.Message) -> bool:
667
636
title = "Message not sent!" ,
668
637
description = f"Your must wait for { delta } "
669
638
f"before you can contact me." ,
670
- color = discord . Color . red () ,
639
+ color = self . error_color ,
671
640
)
672
641
)
673
642
@@ -898,23 +867,15 @@ async def _void(*_args, **_kwargs):
898
867
pass
899
868
900
869
if isinstance (channel , discord .DMChannel ):
901
- try :
902
- user_typing = strtobool (self .config ["user_typing" ])
903
- except ValueError :
904
- user_typing = self .config .remove ("user_typing" )
905
- if not user_typing :
870
+ if not self .config .get ("user_typing" ):
906
871
return
907
872
908
873
thread = await self .threads .find (recipient = user )
909
874
910
875
if thread :
911
876
await thread .channel .trigger_typing ()
912
877
else :
913
- try :
914
- mod_typing = strtobool (self .config ["mod_typing" ])
915
- except ValueError :
916
- mod_typing = self .config .remove ("mod_typing" )
917
- if not mod_typing :
878
+ if not self .config .get ("mod_typing" ):
918
879
return
919
880
920
881
thread = await self .threads .find (channel = channel )
@@ -952,15 +913,7 @@ async def on_raw_reaction_add(self, payload):
952
913
953
914
if isinstance (channel , discord .DMChannel ):
954
915
if str (reaction ) == str (close_emoji ): # closing thread
955
- try :
956
- recipient_thread_close = strtobool (
957
- self .config ["recipient_thread_close" ]
958
- )
959
- except ValueError :
960
- recipient_thread_close = self .config .remove (
961
- "recipient_thread_close"
962
- )
963
- if not recipient_thread_close :
916
+ if not self .config .get ("recipient_thread_close" ):
964
917
return
965
918
thread = await self .threads .find (recipient = user )
966
919
ts = message .embeds [0 ].timestamp if message .embeds else None
@@ -1018,8 +971,7 @@ async def on_member_remove(self, member):
1018
971
thread = await self .threads .find (recipient = member )
1019
972
if thread :
1020
973
embed = discord .Embed (
1021
- description = "The recipient has left the server." ,
1022
- color = discord .Color .red (),
974
+ description = "The recipient has left the server." , color = self .error_color
1023
975
)
1024
976
await thread .channel .send (embed = embed )
1025
977
@@ -1077,15 +1029,13 @@ async def on_command_error(self, context, exception):
1077
1029
)
1078
1030
await context .trigger_typing ()
1079
1031
await context .send (
1080
- embed = discord .Embed (color = discord . Color . red () , description = msg )
1032
+ embed = discord .Embed (color = self . error_color , description = msg )
1081
1033
)
1082
1034
1083
1035
elif isinstance (exception , commands .BadArgument ):
1084
1036
await context .trigger_typing ()
1085
1037
await context .send (
1086
- embed = discord .Embed (
1087
- color = discord .Color .red (), description = str (exception )
1088
- )
1038
+ embed = discord .Embed (color = self .error_color , description = str (exception ))
1089
1039
)
1090
1040
elif isinstance (exception , commands .CommandNotFound ):
1091
1041
logger .warning ("CommandNotFound: %s" , exception )
@@ -1097,7 +1047,7 @@ async def on_command_error(self, context, exception):
1097
1047
if hasattr (check , "fail_msg" ):
1098
1048
await context .send (
1099
1049
embed = discord .Embed (
1100
- color = discord . Color . red () , description = check .fail_msg
1050
+ color = self . error_color , description = check .fail_msg
1101
1051
)
1102
1052
)
1103
1053
if hasattr (check , "permission_level" ):
@@ -1157,7 +1107,7 @@ async def post_metadata(self):
1157
1107
"member_count" : len (self .guild .members ),
1158
1108
"uptime" : (datetime .utcnow () - self .start_time ).total_seconds (),
1159
1109
"latency" : f"{ self .ws .latency * 1000 :.4f} " ,
1160
- "version" : self .version ,
1110
+ "version" : str ( self .version ) ,
1161
1111
"selfhosted" : True ,
1162
1112
"last_updated" : str (datetime .utcnow ()),
1163
1113
}
@@ -1172,10 +1122,6 @@ async def before_post_metadata(self):
1172
1122
if not self .guild :
1173
1123
self .metadata_loop .cancel ()
1174
1124
1175
- @staticmethod
1176
- async def after_post_metadata ():
1177
- logger .info ("Metadata loop has been cancelled." )
1178
-
1179
1125
1180
1126
if __name__ == "__main__" :
1181
1127
try :
0 commit comments