Просмотр исходного кода

Slash commands registering but not receiving callbacks

pull/13/head
Rocketsoup 2 месяцев назад
Родитель
Сommit
644f31cda0
6 измененных файлов: 123 добавлений и 68 удалений
  1. 18
    6
      rocketbot/bot.py
  2. 5
    4
      rocketbot/cogs/basecog.py
  3. 0
    6
      rocketbot/cogs/generalcog.py
  4. 4
    2
      rocketbot/cogs/urlspamcog.py
  5. 95
    49
      rocketbot/cogsetting.py
  6. 1
    1
      rocketbot/utils.py

+ 18
- 6
rocketbot/bot.py Просмотреть файл

5
 from discord.ext import commands
5
 from discord.ext import commands
6
 
6
 
7
 from config import CONFIG
7
 from config import CONFIG
8
-from rocketbot.utils import bot_log
8
+from rocketbot.cogs.basecog import BaseCog
9
+from rocketbot.cogsetting import CogSetting
10
+from rocketbot.utils import bot_log, dump_stacktrace
11
+
9
 
12
 
10
 class Rocketbot(commands.Bot):
13
 class Rocketbot(commands.Bot):
11
 	"""
14
 	"""
16
 
19
 
17
 	async def on_command_error(self, context: commands.Context, exception: BaseException) -> None:
20
 	async def on_command_error(self, context: commands.Context, exception: BaseException) -> None:
18
 		bot_log(None, None, f'Command error')
21
 		bot_log(None, None, f'Command error')
19
-		ex = exception
20
-		while ex is not None:
21
-			print(f'Caused by {ex}')
22
-			traceback.print_exception(type(ex), ex, ex.__traceback__)
23
-			ex = ex.__cause__ if ex.__cause__ != ex else None
22
+		dump_stacktrace(exception)
24
 		if context.guild is None or \
23
 		if context.guild is None or \
25
 				context.message.channel is None or \
24
 				context.message.channel is None or \
26
 				context.message.author.bot:
25
 				context.message.author.bot:
43
 			f'	event kwargs: {kwargs}' + \
42
 			f'	event kwargs: {kwargs}' + \
44
 			traceback.format_exc())
43
 			traceback.format_exc())
45
 
44
 
45
+	async def on_ready(self):
46
+		for cog in self.cogs.values():
47
+			if isinstance(cog, BaseCog):
48
+				bcog: BaseCog = cog
49
+				if len(bcog.settings) > 0:
50
+					CogSetting.set_up_all(bcog, self, bcog.settings)
51
+		try:
52
+			synced_commands = await self.tree.sync()
53
+			for command in synced_commands:
54
+				bot_log(None, None, f'Synced command: /{command.name}')
55
+		except Exception as e:
56
+			dump_stacktrace(e)
57
+
46
 # Current active bot instance
58
 # Current active bot instance
47
 rocketbot: Optional[Rocketbot] = None
59
 rocketbot: Optional[Rocketbot] = None
48
 
60
 

+ 5
- 4
rocketbot/cogs/basecog.py Просмотреть файл

2
 Base cog class and helper classes.
2
 Base cog class and helper classes.
3
 """
3
 """
4
 from datetime import datetime, timedelta, timezone
4
 from datetime import datetime, timedelta, timezone
5
-from typing import Optional
5
+from typing import Optional, ForwardRef
6
 
6
 
7
 from discord import Guild, Member, Message, RawReactionActionEvent, TextChannel
7
 from discord import Guild, Member, Message, RawReactionActionEvent, TextChannel
8
 from discord.abc import GuildChannel
8
 from discord.abc import GuildChannel
9
 from discord.ext import commands
9
 from discord.ext import commands
10
 
10
 
11
 from config import CONFIG
11
 from config import CONFIG
12
-from rocketbot.bot import Rocketbot
13
 from rocketbot.botmessage import BotMessage, BotMessageReaction
12
 from rocketbot.botmessage import BotMessage, BotMessageReaction
14
 from rocketbot.cogsetting import CogSetting
13
 from rocketbot.cogsetting import CogSetting
15
 from rocketbot.collections import AgeBoundDict
14
 from rocketbot.collections import AgeBoundDict
16
 from rocketbot.storage import Storage
15
 from rocketbot.storage import Storage
17
 from rocketbot.utils import bot_log
16
 from rocketbot.utils import bot_log
18
 
17
 
18
+Rocketbot = ForwardRef('rocketbot.bot.Rocketbot')
19
+
19
 class WarningContext:
20
 class WarningContext:
20
 	def __init__(self, member: Member, warn_time: datetime):
21
 	def __init__(self, member: Member, warn_time: datetime):
21
 		self.member = member
22
 		self.member = member
107
 		key = f'{cls.__name__}.{setting.name}'
108
 		key = f'{cls.__name__}.{setting.name}'
108
 		Storage.set_config_value(guild, key, new_value)
109
 		Storage.set_config_value(guild, key, new_value)
109
 
110
 
110
-	@commands.Cog.listener()
111
-	async def on_ready(self):
111
+	# @commands.Cog.listener()
112
+	async def __on_ready(self):
112
 		"""Event listener"""
113
 		"""Event listener"""
113
 		if not self.are_settings_setup:
114
 		if not self.are_settings_setup:
114
 			self.are_settings_setup = True
115
 			self.are_settings_setup = True

+ 0
- 6
rocketbot/cogs/generalcog.py Просмотреть файл

53
 		"""Event handler"""
53
 		"""Event handler"""
54
 		self.log(None, 'Bot done initializing')
54
 		self.log(None, 'Bot done initializing')
55
 		self.is_ready = True
55
 		self.is_ready = True
56
-		try:
57
-			synced_commands = await self.bot.tree.sync()
58
-			for command in synced_commands:
59
-				self.log(None, f'Synced command: {command.name}')
60
-		except Exception as e:
61
-			dump_stacktrace(e)
62
 		if self.is_first_ready:
56
 		if self.is_first_ready:
63
 			print('----------------------------------------------------------')
57
 			print('----------------------------------------------------------')
64
 			self.is_first_ready = False
58
 			self.is_first_ready = False

+ 4
- 2
rocketbot/cogs/urlspamcog.py Просмотреть файл

3
 """
3
 """
4
 import re
4
 import re
5
 from datetime import timedelta
5
 from datetime import timedelta
6
+from typing import Literal
7
+
6
 from discord import Member, Message, utils as discordutils
8
 from discord import Member, Message, utils as discordutils
7
 from discord.ext import commands
9
 from discord.ext import commands
8
 from discord.utils import escape_markdown
10
 from discord.utils import escape_markdown
30
 	SETTING_ENABLED = CogSetting('enabled', bool,
32
 	SETTING_ENABLED = CogSetting('enabled', bool,
31
 			brief='URL spam detection',
33
 			brief='URL spam detection',
32
 			description='Whether URLs posted soon after joining are flagged.')
34
 			description='Whether URLs posted soon after joining are flagged.')
33
-	SETTING_ACTION = CogSetting('action', str,
35
+	SETTING_ACTION = CogSetting('action', Literal['nothing', 'modwarn', 'delete', 'kick', 'ban'],
34
 			brief='action to take on spam',
36
 			brief='action to take on spam',
35
 			description='The action to take on detected URL spam.',
37
 			description='The action to take on detected URL spam.',
36
 			enum_values={'nothing', 'modwarn', 'delete', 'kick', 'ban'})
38
 			enum_values={'nothing', 'modwarn', 'delete', 'kick', 'ban'})
44
 				'disables URL spam detection.',
46
 				'disables URL spam detection.',
45
 			usage='<seconds:int>',
47
 			usage='<seconds:int>',
46
 			min_value=0)
48
 			min_value=0)
47
-	SETTING_DECEPTIVE_ACTION = CogSetting('deceptiveaction', str,
49
+	SETTING_DECEPTIVE_ACTION = CogSetting('deceptiveaction', Literal['nothing', 'modwarn', 'modwarndelete', 'chatwarn', 'chatwarndelete', 'delete', 'kick', 'ban'],
48
 			brief='action to take on deceptive link markdown',
50
 			brief='action to take on deceptive link markdown',
49
 			description='The action to take on chat messages with links ' + \
51
 			description='The action to take on chat messages with links ' + \
50
 				'where the text looks like a different URL than the actual link.',
52
 				'where the text looks like a different URL than the actual link.',

+ 95
- 49
rocketbot/cogsetting.py Просмотреть файл

1
 """
1
 """
2
 A guild configuration setting available for editing via bot commands.
2
 A guild configuration setting available for editing via bot commands.
3
 """
3
 """
4
-from __future__ import annotations
5
-from typing import Any, Optional, Type
4
+import inspect
5
+from typing import Any, Optional, Type, TypeVar, Coroutine, Literal
6
 
6
 
7
-from discord import Interaction, Permissions
8
-from discord.app_commands.commands import Command, Group
7
+from discord import Interaction, Permissions, permissions
8
+from discord.app_commands import Range, guild_only, default_permissions
9
+from discord.app_commands.commands import Command, Group, CommandCallback
9
 from discord.ext.commands import Bot
10
 from discord.ext.commands import Bot
10
 
11
 
11
 from config import CONFIG
12
 from config import CONFIG
12
-from rocketbot.cogs.basecog import BaseCog
13
 from rocketbot.storage import Storage
13
 from rocketbot.storage import Storage
14
+from rocketbot.utils import bot_log
14
 
15
 
15
 # def _fix_command(command: Command) -> None:
16
 # def _fix_command(command: Command) -> None:
16
 # 	"""
17
 # 	"""
21
 # 	del params['context']
22
 # 	del params['context']
22
 # 	command.params = params
23
 # 	command.params = params
23
 
24
 
25
+BaseCog = TypeVar('BaseCog', bound='rocketbot.cogs.BaseCog')
26
+
24
 class CogSetting:
27
 class CogSetting:
28
+	permissions: Permissions = Permissions(Permissions.manage_messages.flag)
29
+
25
 	"""
30
 	"""
26
 	Describes a configuration setting for a guild that can be edited by the
31
 	Describes a configuration setting for a guild that can be edited by the
27
 	mods of those guilds. BaseCog can generate "get" and "set" commands (or
32
 	mods of those guilds. BaseCog can generate "get" and "set" commands (or
99
 		usually only be called by BaseCog.
104
 		usually only be called by BaseCog.
100
 		"""
105
 		"""
101
 		if self.name in ('enabled', 'is_enabled'):
106
 		if self.name in ('enabled', 'is_enabled'):
102
-			bot.tree.add_command(self.__make_enable_command(cog))
103
-			bot.tree.add_command(self.__make_disable_command(cog))
107
+			self.__enable_group.add_command(self.__make_enable_command(cog))
108
+			self.__disable_group.add_command(self.__make_disable_command(cog))
104
 		else:
109
 		else:
105
-			bot.tree.add_command(self.__make_getter_command(cog))
106
-			bot.tree.add_command(self.__make_setter_command(cog))
110
+			self.__get_group.add_command(self.__make_getter_command(cog))
111
+			self.__set_group.add_command(self.__make_setter_command(cog))
107
 
112
 
108
 	def __make_getter_command(self, cog: BaseCog) -> Command:
113
 	def __make_getter_command(self, cog: BaseCog) -> Command:
109
 		setting: CogSetting = self
114
 		setting: CogSetting = self
110
 		setting_name = setting.name
115
 		setting_name = setting.name
111
 		if cog.config_prefix is not None:
116
 		if cog.config_prefix is not None:
112
-			setting_name = f'{cog.config_prefix}.{setting_name}'
113
-		async def getter(cog0: BaseCog, interaction: Interaction) -> None:
114
-			key = f'{cog0.__class__.__name__}.{setting.name}'
117
+			setting_name = f'{cog.config_prefix}_{setting_name}'
118
+		async def getter(self, interaction: Interaction) -> None:
119
+			print(f"invoking getter for {setting_name}")
120
+			key = f'{self.__class__.__name__}.{setting.name}'
115
 			value = Storage.get_config_value(interaction.guild, key)
121
 			value = Storage.get_config_value(interaction.guild, key)
116
 			if value is None:
122
 			if value is None:
117
-				value = cog0.get_cog_default(setting.name)
123
+				value = self.get_cog_default(setting.name)
118
 				await interaction.response.send_message(
124
 				await interaction.response.send_message(
119
 					f'{CONFIG["info_emoji"]} `{setting_name}` is using default of `{value}`',
125
 					f'{CONFIG["info_emoji"]} `{setting_name}` is using default of `{value}`',
120
 					ephemeral=True
126
 					ephemeral=True
124
 					f'{CONFIG["info_emoji"]} `{setting_name}` is set to `{value}`',
130
 					f'{CONFIG["info_emoji"]} `{setting_name}` is set to `{value}`',
125
 					ephemeral=True
131
 					ephemeral=True
126
 				)
132
 				)
133
+		setattr(cog.__class__, f'_cmd_get_{setting.name}', getter)
134
+		getter.__qualname__ = f'{self.__class__.__name__}._cmd_get_{setting.name}'
135
+		bot_log(None, cog.__class__, f"Creating /get {setting_name}")
127
 		command = Command(
136
 		command = Command(
128
 			name=setting_name,
137
 			name=setting_name,
129
-			description=setting.description,
138
+			description=f'Shows value of {setting_name}',
130
 			callback=getter,
139
 			callback=getter,
131
-			parent=CogSetting.__get_group
140
+			parent=CogSetting.__get_group,
132
 		)
141
 		)
133
 		return command
142
 		return command
134
 
143
 
136
 		setting: CogSetting = self
145
 		setting: CogSetting = self
137
 		setting_name = setting.name
146
 		setting_name = setting.name
138
 		if cog.config_prefix is not None:
147
 		if cog.config_prefix is not None:
139
-			setting_name = f'{cog.config_prefix}.{setting_name}'
140
-		async def setter(cog0: BaseCog, interaction: Interaction, new_value) -> None:
148
+			setting_name = f'{cog.config_prefix}_{setting_name}'
149
+		async def setter_general(self, interaction: Interaction, new_value) -> None:
150
+			print(f"invoking setter for {setting_name} with value {new_value}")
141
 			try:
151
 			try:
142
 				setting.validate_value(new_value)
152
 				setting.validate_value(new_value)
143
 			except ValueError as ve:
153
 			except ValueError as ve:
146
 					ephemeral=True
156
 					ephemeral=True
147
 				)
157
 				)
148
 				return
158
 				return
149
-			key = f'{cog0.__class__.__name__}.{setting.name}'
159
+			key = f'{self.__class__.__name__}.{setting.name}'
150
 			Storage.set_config_value(interaction.guild, key, new_value)
160
 			Storage.set_config_value(interaction.guild, key, new_value)
151
 			await interaction.response.send_message(
161
 			await interaction.response.send_message(
152
 				f'{CONFIG["success_emoji"]} `{setting_name}` is now set to `{new_value}`',
162
 				f'{CONFIG["success_emoji"]} `{setting_name}` is now set to `{new_value}`',
153
 				ephemeral=True
163
 				ephemeral=True
154
 			)
164
 			)
155
-			await cog0.on_setting_updated(interaction.guild, setting)
156
-			cog0.log(interaction.guild, f'{interaction.message.author.name} set {key} to {new_value}')
165
+			await self.on_setting_updated(interaction.guild, setting)
166
+			self.log(interaction.guild, f'{interaction.message.author.name} set {key} to {new_value}')
157
 
167
 
158
 		type_str: str = 'any'
168
 		type_str: str = 'any'
169
+		setter: CommandCallback = setter_general
159
 		if self.datatype == int:
170
 		if self.datatype == int:
160
 			if self.min_value is not None or self.max_value is not None:
171
 			if self.min_value is not None or self.max_value is not None:
161
 				type_str = f'discord.app_commands.Range[int, {self.min_value}, {self.max_value}]'
172
 				type_str = f'discord.app_commands.Range[int, {self.min_value}, {self.max_value}]'
173
+				r_min = self.min_value
174
+				r_max = self.max_value
175
+				async def setter_range(self, interaction: Interaction, new_value: Range[int, r_min, r_max]) -> None:
176
+					await self.setter_general(interaction, new_value)
177
+				setter = setter_range
162
 			else:
178
 			else:
163
 				type_str = 'int'
179
 				type_str = 'int'
164
-		elif setting.datatype == str:
180
+				async def setter_int(self, interaction: Interaction, new_value: int) -> None:
181
+					await self.setter_general(interaction, new_value)
182
+				setter = setter_int
183
+		elif self.datatype == float:
184
+			type_str = 'float'
185
+			async def setter_float(self, interaction: Interaction, new_value: float) -> None:
186
+				await self.setter_general(interaction, new_value)
187
+			setter = setter_float
188
+		elif getattr(self.datatype, '__origin__', None) == Literal:
189
+			value_list = '"' + '", "'.join(self.enum_values) + '"'
190
+			type_str = f'typing.Literal[{value_list}]'
191
+			values = self.enum_values
192
+			dt = self.datatype
193
+			async def setter_enum(self, interaction: Interaction, new_value: dt) -> None:
194
+				await self.setter_general(interaction, new_value)
195
+
196
+			setter = setter_enum
197
+		elif self.datatype == str:
165
 			if self.enum_values is not None:
198
 			if self.enum_values is not None:
166
-				value_list = '"' + '", "'.join(self.enum_values) + '"'
167
-				type_str = f'typing.Literal[{value_list}]'
199
+				raise ValueError('Type for a setting with enum values should be typing.Literal')
168
 			else:
200
 			else:
169
 				type_str = 'str'
201
 				type_str = 'str'
202
+				async def setter_str(self, interaction: Interaction, new_value: str) -> None:
203
+					await self.setter_general(interaction, new_value)
204
+				setter = setter_str
170
 		elif setting.datatype == bool:
205
 		elif setting.datatype == bool:
171
-			type_str = f'typing.Literal["false", "true"]'
172
-
173
-		setter.__doc__ = f"""Sets {self.description}.
174
-
175
-Parameters
176
-----------
177
-cog: discord.ext.commands.Cog
178
-interaction: discord.Interaction
179
-new_value: {type_str}
180
-"""
206
+			type_str = f'bool'
207
+			async def setter_bool(self, interaction: Interaction, new_value: bool) -> None:
208
+				await self.setter_general(interaction, new_value)
209
+			setter = setter_bool
210
+		elif setting.datatype is not None:
211
+			raise ValueError(f'Invalid type {self.datatype}')
212
+		setattr(cog.__class__, f'_cmd_set_{setting.name}', setter)
213
+		setter.__qualname__ = f'{cog.__class__.__name__}._cmd_set_{setting.name}'
214
+		bot_log(None, cog.__class__, f"Creating /set {setting_name} {type_str}")
181
 		command = Command(
215
 		command = Command(
182
-			name=f'{setting.name}',
183
-			description=setting.description,
216
+			name=setting_name,
217
+			description=f'Sets value of {setting_name}',
184
 			callback=setter,
218
 			callback=setter,
185
 			parent=CogSetting.__set_group,
219
 			parent=CogSetting.__set_group,
186
 		)
220
 		)
192
 
226
 
193
 	def __make_enable_command(self, cog: BaseCog) -> Command:
227
 	def __make_enable_command(self, cog: BaseCog) -> Command:
194
 		setting: CogSetting = self
228
 		setting: CogSetting = self
195
-		async def enabler(cog0: BaseCog, interaction: Interaction) -> None:
196
-			key = f'{cog0.__class__.__name__}.{setting.name}'
229
+		async def enabler(self, interaction: Interaction) -> None:
230
+			print(f"invoking enable for {self.config_prefix}")
231
+			key = f'{self.__class__.__name__}.{setting.name}'
197
 			Storage.set_config_value(interaction.guild, key, True)
232
 			Storage.set_config_value(interaction.guild, key, True)
198
 			await interaction.response.send_message(
233
 			await interaction.response.send_message(
199
 				f'{CONFIG["success_emoji"]} {setting.brief.capitalize()} enabled.',
234
 				f'{CONFIG["success_emoji"]} {setting.brief.capitalize()} enabled.',
200
 				ephemeral=True
235
 				ephemeral=True
201
 			)
236
 			)
202
-			await cog0.on_setting_updated(interaction.guild, setting)
203
-			cog0.log(interaction.guild, f'{interaction.message.author.name} enabled {cog0.__class__.__name__}')
237
+			await self.on_setting_updated(interaction.guild, setting)
238
+			self.log(interaction.guild, f'{interaction.message.author.name} enabled {self.__class__.__name__}')
239
+		setattr(cog.__class__, f'_cmd_enable', enabler)
240
+		enabler.__qualname__ = f'{cog.__class__.__name__}._cmd_enable'
241
+		bot_log(None, cog.__class__, f"Creating /enable {cog.config_prefix}")
204
 
242
 
205
 		command = Command(
243
 		command = Command(
206
 			name=cog.config_prefix,
244
 			name=cog.config_prefix,
207
-			description=setting.description,
245
+			description=f'Enables {cog.config_prefix} functionality',
208
 			callback=enabler,
246
 			callback=enabler,
209
 			parent=CogSetting.__enable_group,
247
 			parent=CogSetting.__enable_group,
210
 		)
248
 		)
214
 
252
 
215
 	def __make_disable_command(self, cog: BaseCog) -> Command:
253
 	def __make_disable_command(self, cog: BaseCog) -> Command:
216
 		setting: CogSetting = self
254
 		setting: CogSetting = self
217
-		async def disabler(cog0: BaseCog, interaction: Interaction) -> None:
218
-			key = f'{cog0.__class__.__name__}.{setting.name}'
255
+		async def disabler(self, interaction: Interaction) -> None:
256
+			print(f"invoking disable for {self.config_prefix}")
257
+			key = f'{self.__class__.__name__}.{setting.name}'
219
 			Storage.set_config_value(interaction.guild, key, False)
258
 			Storage.set_config_value(interaction.guild, key, False)
220
 			await interaction.response.send_message(
259
 			await interaction.response.send_message(
221
 				f'{CONFIG["success_emoji"]} {setting.brief.capitalize()} disabled.',
260
 				f'{CONFIG["success_emoji"]} {setting.brief.capitalize()} disabled.',
222
 				ephemeral=True
261
 				ephemeral=True
223
 			)
262
 			)
224
-			await cog0.on_setting_updated(interaction.guild, setting)
225
-			cog0.log(interaction.guild, f'{interaction.message.author.name} disabled {cog0.__class__.__name__}')
263
+			await self.on_setting_updated(interaction.guild, setting)
264
+			self.log(interaction.guild, f'{interaction.message.author.name} disabled {self.__class__.__name__}')
265
+		setattr(cog.__class__, f'_cmd_disable', disabler)
266
+		disabler.__qualname__ = f'{cog.__class__.__name__}._cmd_disable'
267
+		bot_log(None, cog.__class__, f"Creating /disable {cog.config_prefix}")
226
 
268
 
227
 		command = Command(
269
 		command = Command(
228
 			name=cog.config_prefix,
270
 			name=cog.config_prefix,
229
-			description=setting.description,
271
+			description=f'Disables {cog.config_prefix} functionality',
230
 			callback=disabler,
272
 			callback=disabler,
231
 			parent=CogSetting.__disable_group,
273
 			parent=CogSetting.__disable_group,
232
 		)
274
 		)
248
 		Otherwise, they will be added at the top level.
290
 		Otherwise, they will be added at the top level.
249
 		"""
291
 		"""
250
 		cls.__set_up_base_commands(bot)
292
 		cls.__set_up_base_commands(bot)
293
+		if len(settings) == 0:
294
+			return
295
+		bot_log(None, cog.__class__, f"Setting up slash commands for {cog.__class__.__name__}")
251
 		for setting in settings:
296
 		for setting in settings:
252
 			setting.set_up(cog, bot)
297
 			setting.set_up(cog, bot)
298
+		bot_log(None, cog.__class__, f"Done setting up slash commands for {cog.__class__.__name__}")
253
 
299
 
254
 	@classmethod
300
 	@classmethod
255
 	def __set_up_base_commands(cls, bot: Bot) -> None:
301
 	def __set_up_base_commands(cls, bot: Bot) -> None:
259
 		cls.__set_group = Group(
305
 		cls.__set_group = Group(
260
 			name='set',
306
 			name='set',
261
 			description='Sets a bot configuration value for this guild',
307
 			description='Sets a bot configuration value for this guild',
262
-			default_permissions=Permissions.manage_messages
308
+			default_permissions=cls.permissions
263
 		)
309
 		)
264
 		cls.__get_group = Group(
310
 		cls.__get_group = Group(
265
 			name='get',
311
 			name='get',
266
 			description='Shows a configured bot value for this guild',
312
 			description='Shows a configured bot value for this guild',
267
-			default_permissions=Permissions.manage_messages
313
+			default_permissions=cls.permissions
268
 		)
314
 		)
269
 		cls.__enable_group = Group(
315
 		cls.__enable_group = Group(
270
 			name='enable',
316
 			name='enable',
271
 			description='Enables a set of bot functionality for this guild',
317
 			description='Enables a set of bot functionality for this guild',
272
-			default_permissions=Permissions.manage_messages
318
+			default_permissions=cls.permissions
273
 		)
319
 		)
274
 		cls.__disable_group = Group(
320
 		cls.__disable_group = Group(
275
 			name='disable',
321
 			name='disable',
276
 			description='Disables a set of bot functionality for this guild',
322
 			description='Disables a set of bot functionality for this guild',
277
-			default_permissions=Permissions.manage_messages
323
+			default_permissions=cls.permissions
278
 		)
324
 		)
279
 		bot.tree.add_command(cls.__set_group)
325
 		bot.tree.add_command(cls.__set_group)
280
 		bot.tree.add_command(cls.__get_group)
326
 		bot.tree.add_command(cls.__get_group)

+ 1
- 1
rocketbot/utils.py Просмотреть файл

11
 from discord import Guild
11
 from discord import Guild
12
 from discord.ext.commands import Cog
12
 from discord.ext.commands import Cog
13
 
13
 
14
-def dump_stacktrace(e: Exception) -> None:
14
+def dump_stacktrace(e: BaseException) -> None:
15
 	print(e, file=sys.stderr)
15
 	print(e, file=sys.stderr)
16
 	traceback.print_exception(type(e), e, e.__traceback__)
16
 	traceback.print_exception(type(e), e, e.__traceback__)
17
 
17
 

Загрузка…
Отмена
Сохранить