44from time import perf_counter
55
66import discord
7+ from discord .ext .commands import cooldowns
78from redbot .core import commands
89from redbot .core .i18n import Translator , cog_i18n
9- from redbot .core .utils .chat_formatting import (
10- box ,
11- humanize_number ,
12- humanize_timedelta ,
13- pagify ,
14- )
10+ from redbot .core .utils .chat_formatting import box , humanize_number , humanize_timedelta , pagify , error , warning , info
1511
1612from ..abc import MixinMeta
1713from ..common import const , utils
@@ -29,6 +25,200 @@ async def levelset(self, ctx: commands.Context):
2925 """Configure LevelUp Settings"""
3026 pass
3127
28+ @levelset .group (name = "bypass" )
29+ async def levelset_bypass (self , ctx : commands .Context ):
30+ """Set roles/members that bypass level requirement and cooldowns set"""
31+ pass
32+
33+ @levelset_bypass .command (name = "member" )
34+ async def levelset_bypass_member (self , ctx : commands .Context , member : t .Optional [discord .Member ] = None ):
35+ """
36+ Add a member to the bypass list.
37+
38+ Run with no arguments to see all the bypass members
39+ Run with a member already in the list to remove them from the list
40+ """
41+ conf = self .db .get_conf (ctx .guild )
42+ if member is None :
43+ if not conf .cmd_bypass_member :
44+ await ctx .reply (
45+ info ("No members configured for bypassing command restrictions." ),
46+ delete_after = 30 ,
47+ mention_author = False ,
48+ )
49+ return
50+ text = "# Bypass Members:\n "
51+ for member_id in conf .cmd_bypass_member .copy ():
52+ member = ctx .guild .get_member (member_id )
53+ if member is None : # member left, remove from conf
54+ conf .cmd_bypass_member .remove (member_id )
55+ continue
56+ text += f"- { member .mention } \n "
57+ pages = list (pagify (text ))
58+ await ctx .send_interactive (pages )
59+ return
60+ if member .id not in conf .cmd_bypass_member :
61+ conf .cmd_bypass_member .append (member .id )
62+ else :
63+ conf .cmd_bypass_member .remove (member .id )
64+ await ctx .reply (
65+ info (f"Member { member .mention } removed from command bypasses." ), delete_after = 30 , mention_author = False
66+ )
67+ await ctx .tick ()
68+
69+ @levelset_bypass .command (name = "role" )
70+ async def levelset_bypass_role (self , ctx : commands .Context , role : t .Optional [discord .Role ] = None ):
71+ """
72+ Add a role to the bypass list.
73+
74+ Run with no arguments to see all the bypass roles
75+ Run with a role already in the list to remove it from the list
76+ """
77+ conf = self .db .get_conf (ctx .guild )
78+ if role is None :
79+ if not conf .cmd_bypass_roles :
80+ await ctx .reply (
81+ info ("No roles configured for bypassing command restrictions." ),
82+ delete_after = 30 ,
83+ mention_author = False ,
84+ )
85+ return
86+ text = "# Bypass Roles:\n "
87+ for role_id in conf .cmd_bypass_roles .copy ():
88+ role = ctx .guild .get_role (role_id )
89+ if role is None : # role gone, remove from conf
90+ conf .cmd_bypass_roles .remove (role_id )
91+ continue
92+ text += f"- { role .mention } \n "
93+ pages = list (pagify (text ))
94+ await ctx .send_interactive (pages )
95+ return
96+ if role .id not in conf .cmd_bypass_roles :
97+ conf .cmd_bypass_roles .append (role .id )
98+ else :
99+ conf .cmd_bypass_roles .remove (role .id )
100+ await ctx .reply (
101+ info (f"Role { role .mention } removed from command bypasses." ),
102+ delete_after = 30 ,
103+ mention_author = False ,
104+ )
105+ await ctx .tick ()
106+
107+ @levelset .group (name = "cooldowns" )
108+ async def levelset_cooldowns (self , ctx : commands .Context ):
109+ """Manage per level command cooldowns"""
110+ pass
111+
112+ @levelset_cooldowns .command (name = "add" )
113+ async def levelset_cooldowns_add (self , ctx : commands .Context , level : int , cooldown : int , * , command : str ):
114+ """
115+ Add a cooldown for a command based on level
116+ Multiple cooldown levels can be set, the cooldown will be applied to members at the specified level and under
117+
118+ **Warning:** This will override any default cooldowns for the command
119+
120+ Example:
121+ [p]lset cooldowns add 5 15 mycommand
122+ [p]lset cooldowns add 10 5 mycommand
123+ Members who are level [0, 5] will have a cooldown of 15 seconds for mycommand (including members at level 5)
124+ Members who are level (5, 10] will have a cooldown of 5 seconds
125+ Members above level 10 will have no cooldown
126+ """
127+ if self .bot .get_command (command ) is None :
128+ return await ctx .reply (error (f"Invalid command: `{ command } `" ), delete_after = 30 , mention_author = False )
129+ conf = self .db .get_conf (ctx .guild )
130+ command_cooldowns = conf .cmd_cooldowns .get (command , {})
131+ command_cooldowns [level ] = cooldown
132+ conf .cmd_cooldowns [command ] = command_cooldowns
133+ self .save ()
134+ await ctx .tick ()
135+
136+ @levelset_cooldowns .command (name = "del" )
137+ async def levelset_cooldowns_del (self , ctx : commands .Context , level : int , * , command : str ):
138+ """Delete a cooldown for a specific command and level"""
139+ if self .bot .get_command (command ) is None :
140+ return await ctx .reply (error (f"Invalid command: `{ command } `" ), delete_after = 30 , mention_author = False )
141+ conf = self .db .get_conf (ctx .guild )
142+ command_cooldowns = conf .cmd_cooldowns .get (command , {})
143+ if not command_cooldowns :
144+ return await ctx .reply (
145+ warning (f"No cooldowns are set for `{ command } `" ), delete_after = 30 , mention_author = False
146+ )
147+ if level not in command_cooldowns :
148+ return await ctx .reply (
149+ warning (f"There is no cooldown for level { level } " ), delete_after = 30 , mention_author = False
150+ )
151+ del command_cooldowns [level ]
152+ conf .cmd_cooldowns [command ] = command_cooldowns
153+ if command_cooldowns == {}:
154+ del conf .cmd_cooldowns [command ]
155+
156+ self .save ()
157+ await ctx .tick ()
158+
159+ @levelset_cooldowns .command (name = "list" )
160+ async def levelset_cooldowns_list (self , ctx : commands .Context ):
161+ """List cooldowns for all commands"""
162+ conf = self .db .get_conf (ctx .guild )
163+ cmds = conf .cmd_cooldowns
164+ if not cmds :
165+ await ctx .send (info ("No commands configured." ))
166+ return
167+
168+ msg = f"# Cooldowns for { ctx .guild .name } \n "
169+ for cmd , cooldowns in cmds .items ():
170+ msg += f"- `{ cmd } `:\n "
171+ for level , cooldown in cooldowns .items ():
172+ msg += f" - Level `{ level } `: `{ humanize_timedelta (seconds = cooldown )} `\n "
173+
174+ for page in pagify (msg ):
175+ await ctx .send (page )
176+
177+ @levelset .group (name = "lvlreq" )
178+ async def levelset_lvlreq (self , ctx : commands .Context ):
179+ """Manage level requirement for commands"""
180+ pass
181+
182+ @levelset_lvlreq .command (name = "add" )
183+ async def levelset_lvlreq_add (self , ctx : commands .Context , level : int , * , command : str ):
184+ """Add a level requirement to a command."""
185+ if self .bot .get_command (command ) is None :
186+ return await ctx .reply (error (f"Invalid command: `{ command } `" ), delete_after = 30 , mention_author = False )
187+ conf = self .db .get_conf (ctx .guild )
188+ conf .cmd_requirements [command ] = level
189+ self .save ()
190+ await ctx .tick ()
191+
192+ @levelset_lvlreq .command (name = "del" )
193+ async def levelset_lvlreq_del (self , ctx : commands .Context , * , command : str ):
194+ """Delete a level requirement for a command."""
195+ conf = self .db .get_conf (ctx .guild )
196+ if command not in conf .cmd_requirements :
197+ return await ctx .reply (
198+ warning (f"No level requirement was set for `{ command } `" ),
199+ delete_after = 30 ,
200+ mention_author = False ,
201+ )
202+ del conf .cmd_requirements [command ]
203+ self .save ()
204+ await ctx .tick ()
205+
206+ @levelset_lvlreq .command (name = "list" )
207+ async def levelset_lvlreq_list (self , ctx : commands .Context ):
208+ """List all command level requirements"""
209+ conf = self .db .get_conf (ctx .guild )
210+ cmds = conf .cmd_requirements
211+ if not cmds :
212+ await ctx .send (info ("No commands configured." ))
213+ return
214+
215+ msg = f"# Command Level Requirements for { ctx .guild .name } \n "
216+ for cmd , level in cmds .items ():
217+ msg += f"- `{ cmd } `: `{ level } `\n "
218+
219+ for page in pagify (msg ):
220+ await ctx .send (page )
221+
32222 @levelset .command (name = "view" )
33223 @commands .bot_has_permissions (embed_links = True )
34224 async def view_settings (self , ctx : commands .Context ):
0 commit comments