Ver código fonte

Very WIP for converting config settings to slash commands

pull/13/head
Rocketsoup 2 meses atrás
pai
commit
2fc71547d5

+ 1
- 1
rocketbot/cogs/autokickcog.py Ver arquivo

53
 	STATE_KEY_RECENT_KICKS = "AutoKickCog.recent_joins"
53
 	STATE_KEY_RECENT_KICKS = "AutoKickCog.recent_joins"
54
 
54
 
55
 	def __init__(self, bot):
55
 	def __init__(self, bot):
56
-		super().__init__(bot)
56
+		super().__init__(bot, 'autokick')
57
 		self.add_setting(AutoKickCog.SETTING_ENABLED)
57
 		self.add_setting(AutoKickCog.SETTING_ENABLED)
58
 		self.add_setting(AutoKickCog.SETTING_BAN_COUNT)
58
 		self.add_setting(AutoKickCog.SETTING_BAN_COUNT)
59
 		self.add_setting(AutoKickCog.SETTING_OFFLINE_ONLY)
59
 		self.add_setting(AutoKickCog.SETTING_OFFLINE_ONLY)

+ 14
- 3
rocketbot/cogs/basecog.py Ver arquivo

28
 	Superclass for all Rocketbot cogs. Provides lots of conveniences for
28
 	Superclass for all Rocketbot cogs. Provides lots of conveniences for
29
 	common tasks.
29
 	common tasks.
30
 	"""
30
 	"""
31
-	def __init__(self, bot):
31
+	def __init__(self, bot: Rocketbot, config_prefix: Optional[str]):
32
+		"""
33
+		Parameters
34
+		----------
35
+		bot: Rocketbot
36
+		config_prefix: str
37
+		    Prefix to show on variables in /set and /get commands to namespace
38
+		    configuration variables. E.g. if config_prefix is "foo", a config
39
+		    variable named "bar" in that cog will show as "foo.bar". If None,
40
+		    config variable acts as a top-level variable with no prefix.
41
+		"""
32
 		self.bot: Rocketbot = bot
42
 		self.bot: Rocketbot = bot
33
-		self.are_settings_setup = False
34
-		self.settings = []
43
+		self.are_settings_setup: bool = False
44
+		self.settings: list[CogSetting] = []
45
+		self.config_prefix: Optional[str] = config_prefix
35
 
46
 
36
 	# Config
47
 	# Config
37
 
48
 

+ 5
- 0
rocketbot/cogs/configcog.py Ver arquivo

3
 """
3
 """
4
 from discord import Guild, TextChannel
4
 from discord import Guild, TextChannel
5
 from discord.ext import commands
5
 from discord.ext import commands
6
+from discord.ext.commands import Bot
6
 
7
 
7
 from config import CONFIG
8
 from config import CONFIG
8
 from rocketbot.storage import ConfigKey, Storage
9
 from rocketbot.storage import ConfigKey, Storage
12
 	"""
13
 	"""
13
 	Cog for handling general bot configuration.
14
 	Cog for handling general bot configuration.
14
 	"""
15
 	"""
16
+
17
+	def __init__(self, bot: Bot) -> None:
18
+		super().__init__(bot, 'config')
19
+
15
 	@commands.group(
20
 	@commands.group(
16
 		brief='Manages general bot configuration'
21
 		brief='Manages general bot configuration'
17
 	)
22
 	)

+ 1
- 1
rocketbot/cogs/crosspostcog.py Ver arquivo

95
 	STATE_KEY_SPAM_CONTEXT = "CrossPostCog.spam_context"
95
 	STATE_KEY_SPAM_CONTEXT = "CrossPostCog.spam_context"
96
 
96
 
97
 	def __init__(self, bot):
97
 	def __init__(self, bot):
98
-		super().__init__(bot)
98
+		super().__init__(bot, 'crosspost')
99
 		self.add_setting(CrossPostCog.SETTING_ENABLED)
99
 		self.add_setting(CrossPostCog.SETTING_ENABLED)
100
 		self.add_setting(CrossPostCog.SETTING_WARN_COUNT)
100
 		self.add_setting(CrossPostCog.SETTING_WARN_COUNT)
101
 		self.add_setting(CrossPostCog.SETTING_DUPE_WARN_COUNT)
101
 		self.add_setting(CrossPostCog.SETTING_DUPE_WARN_COUNT)

+ 3
- 2
rocketbot/cogs/generalcog.py Ver arquivo

10
 from discord.ext import commands
10
 from discord.ext import commands
11
 
11
 
12
 from config import CONFIG
12
 from config import CONFIG
13
+from rocketbot.bot import Rocketbot
13
 from rocketbot.cogs.basecog import BaseCog, BotMessage
14
 from rocketbot.cogs.basecog import BaseCog, BotMessage
14
 from rocketbot.utils import timedelta_from_str, describe_timedelta, dump_stacktrace
15
 from rocketbot.utils import timedelta_from_str, describe_timedelta, dump_stacktrace
15
 from rocketbot.storage import ConfigKey, Storage
16
 from rocketbot.storage import ConfigKey, Storage
19
 	Cog for handling high-level bot functionality and commands. Should be the
20
 	Cog for handling high-level bot functionality and commands. Should be the
20
 	first cog added to the bot.
21
 	first cog added to the bot.
21
 	"""
22
 	"""
22
-	def __init__(self, bot: commands.Bot):
23
-		super().__init__(bot)
23
+	def __init__(self, bot: Rocketbot):
24
+		super().__init__(bot, None)
24
 		self.is_connected = False
25
 		self.is_connected = False
25
 		self.is_ready = False
26
 		self.is_ready = False
26
 		self.is_first_ready = True
27
 		self.is_first_ready = True

+ 3
- 2
rocketbot/cogs/joinagecog.py Ver arquivo

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.bot import Rocketbot
8
 from rocketbot.cogs.basecog import BaseCog, BotMessage, BotMessageReaction, CogSetting
9
 from rocketbot.cogs.basecog import BaseCog, BotMessage, BotMessageReaction, CogSetting
9
 from rocketbot.collections import AgeBoundList
10
 from rocketbot.collections import AgeBoundList
10
 from rocketbot.storage import Storage
11
 from rocketbot.storage import Storage
36
 
37
 
37
 	STATE_KEY_RECENT_JOINS = "JoinAgeCog.recent_joins"
38
 	STATE_KEY_RECENT_JOINS = "JoinAgeCog.recent_joins"
38
 
39
 
39
-	def __init__(self, bot):
40
-		super().__init__(bot)
40
+	def __init__(self, bot: Rocketbot):
41
+		super().__init__(bot, 'joinage')
41
 		self.add_setting(JoinAgeCog.SETTING_ENABLED)
42
 		self.add_setting(JoinAgeCog.SETTING_ENABLED)
42
 		self.add_setting(JoinAgeCog.SETTING_JOIN_TIME)
43
 		self.add_setting(JoinAgeCog.SETTING_JOIN_TIME)
43
 
44
 

+ 1
- 1
rocketbot/cogs/joinraidcog.py Ver arquivo

51
 	STATE_KEY_LAST_RAID = "JoinRaidCog.last_raid"
51
 	STATE_KEY_LAST_RAID = "JoinRaidCog.last_raid"
52
 
52
 
53
 	def __init__(self, bot):
53
 	def __init__(self, bot):
54
-		super().__init__(bot)
54
+		super().__init__(bot, 'joinraid')
55
 		self.add_setting(JoinRaidCog.SETTING_ENABLED)
55
 		self.add_setting(JoinRaidCog.SETTING_ENABLED)
56
 		self.add_setting(JoinRaidCog.SETTING_JOIN_COUNT)
56
 		self.add_setting(JoinRaidCog.SETTING_JOIN_COUNT)
57
 		self.add_setting(JoinRaidCog.SETTING_JOIN_TIME)
57
 		self.add_setting(JoinRaidCog.SETTING_JOIN_TIME)

+ 1
- 1
rocketbot/cogs/logcog.py Ver arquivo

44
 	STATE_EVENT_BUFFER = 'LoggingCog.eventBuffer'
44
 	STATE_EVENT_BUFFER = 'LoggingCog.eventBuffer'
45
 
45
 
46
 	def __init__(self, bot):
46
 	def __init__(self, bot):
47
-		super().__init__(bot)
47
+		super().__init__(bot, 'logging')
48
 		self.add_setting(LoggingCog.SETTING_ENABLED)
48
 		self.add_setting(LoggingCog.SETTING_ENABLED)
49
 		self.flush_buffers.start()
49
 		self.flush_buffers.start()
50
 		self.buffered_guilds: set[Guild] = set()
50
 		self.buffered_guilds: set[Guild] = set()

+ 4
- 0
rocketbot/cogs/patterncog.py Ver arquivo

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
12
 from rocketbot.cogs.basecog import BaseCog, BotMessage, BotMessageReaction
13
 from rocketbot.cogs.basecog import BaseCog, BotMessage, BotMessageReaction
13
 from rocketbot.cogsetting import CogSetting
14
 from rocketbot.cogsetting import CogSetting
14
 from rocketbot.pattern import PatternCompiler, PatternDeprecationError, \
15
 from rocketbot.pattern import PatternCompiler, PatternDeprecationError, \
35
 
36
 
36
 	SETTING_PATTERNS = CogSetting('patterns', None)
37
 	SETTING_PATTERNS = CogSetting('patterns', None)
37
 
38
 
39
+	def __init__(self, bot: Rocketbot):
40
+		super().__init__(bot, 'patterns')
41
+
38
 	def __get_patterns(self, guild: Guild) -> dict[str, PatternStatement]:
42
 	def __get_patterns(self, guild: Guild) -> dict[str, PatternStatement]:
39
 		"""
43
 		"""
40
 		Returns a name -> PatternStatement lookup for the guild.
44
 		Returns a name -> PatternStatement lookup for the guild.

+ 1
- 1
rocketbot/cogs/urlspamcog.py Ver arquivo

52
 				'chatwarn', 'chatwarndelete', 'delete', 'kick', 'ban'})
52
 				'chatwarn', 'chatwarndelete', 'delete', 'kick', 'ban'})
53
 
53
 
54
 	def __init__(self, bot):
54
 	def __init__(self, bot):
55
-		super().__init__(bot)
55
+		super().__init__(bot, 'urlspam')
56
 		self.add_setting(URLSpamCog.SETTING_ENABLED)
56
 		self.add_setting(URLSpamCog.SETTING_ENABLED)
57
 		self.add_setting(URLSpamCog.SETTING_ACTION)
57
 		self.add_setting(URLSpamCog.SETTING_ACTION)
58
 		self.add_setting(URLSpamCog.SETTING_JOIN_AGE)
58
 		self.add_setting(URLSpamCog.SETTING_JOIN_AGE)

+ 1
- 1
rocketbot/cogs/usernamecog.py Ver arquivo

51
 	SETTING_PATTERNS = CogSetting('patterns', None)
51
 	SETTING_PATTERNS = CogSetting('patterns', None)
52
 
52
 
53
 	def __init__(self, bot):
53
 	def __init__(self, bot):
54
-		super().__init__(bot)
54
+		super().__init__(bot, 'username')
55
 		self.add_setting(UsernamePatternCog.SETTING_ENABLED)
55
 		self.add_setting(UsernamePatternCog.SETTING_ENABLED)
56
 
56
 
57
 	def __get_patterns(self, guild: Guild) -> list[str]:
57
 	def __get_patterns(self, guild: Guild) -> list[str]:

+ 167
- 129
rocketbot/cogsetting.py Ver arquivo

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 typing import Any, Callable, Coroutine, Optional, Type
4
+from __future__ import annotations
5
+from typing import Any, Optional, Type
5
 
6
 
6
-from discord.ext import commands
7
-from discord.ext.commands import Bot, Command, Context, Group, Cog
7
+from discord import Interaction, Permissions
8
+from discord.app_commands.commands import Command, Group
9
+from discord.ext.commands import Bot
8
 
10
 
9
 from config import CONFIG
11
 from config import CONFIG
12
+from rocketbot.cogs.basecog import BaseCog
10
 from rocketbot.storage import Storage
13
 from rocketbot.storage import Storage
11
-from rocketbot.utils import first_command_group
12
 
14
 
13
-def _fix_command(command: Command) -> None:
14
-	"""
15
-	HACK: Fixes bug in discord.py 2.3.2 where it's requiring the user to
16
-	supply the context argument. This removes that argument from the list.
17
-	"""
18
-	params = command.params
19
-	del params['context']
20
-	command.params = params
15
+# def _fix_command(command: Command) -> None:
16
+# 	"""
17
+# 	HACK: Fixes bug in discord.py 2.3.2 where it's requiring the user to
18
+# 	supply the context argument. This removes that argument from the list.
19
+# 	"""
20
+# 	params = command.params
21
+# 	del params['context']
22
+# 	command.params = params
21
 
23
 
22
 class CogSetting:
24
 class CogSetting:
23
 	"""
25
 	"""
36
 			max_value: Optional[Any] = None,
38
 			max_value: Optional[Any] = None,
37
 			enum_values: Optional[set[Any]] = None):
39
 			enum_values: Optional[set[Any]] = None):
38
 		"""
40
 		"""
39
-		Params:
40
-		- name         Setting identifier. Must follow variable naming
41
-		               conventions.
42
-		- datatype     Datatype of the setting. E.g. int, float, str
43
-		- brief        Description of the setting, starting with lower case.
44
-		               Will be inserted into phrases like "Sets <brief>" and
45
-					   "Gets <brief".
46
-		- description  Long-form description. Min, max, and enum values will be
47
-		               appended to the end, so does not need to include these.
48
-		- usage        Description of the value argument in a set command, e.g.
49
-		               "<maxcount:int>"
50
-		- min_value    Smallest allowable value. Must be of the same datatype as
51
-		               the value. None for no minimum.
52
-		- max_value    Largest allowable value. None for no maximum.
53
-		- enum_values  Set of allowed values. None if unconstrained.
41
+		Parameters
42
+		----------
43
+		name: str
44
+			Setting identifier. Must follow variable naming conventions.
45
+		datatype: Optional[Type]
46
+		    Datatype of the setting. E.g. int, float, str
47
+		brief: Optional[str]
48
+			Description of the setting, starting with lower case.
49
+			Will be inserted into phrases like "Sets <brief>" and
50
+			"Gets <brief".
51
+		description: Optional[str]
52
+		  	Long-form description. Min, max, and enum values will be
53
+		    appended to the end, so does not need to include these.
54
+		usage: Optional[str]
55
+		    Description of the value argument in a set command, e.g. "<maxcount:int>"
56
+		min_value: Optional[Any]
57
+		    Smallest allowable value. Must be of the same datatype as
58
+		    the value. None for no minimum.
59
+		max_value: Optional[Any]
60
+		    Largest allowable value. None for no maximum.
61
+		enum_values: Optional[set[Any]]
62
+		  	Set of allowed values. None if unconstrained.
54
 		"""
63
 		"""
55
 		self.name: str = name
64
 		self.name: str = name
56
 		self.datatype: Type = datatype
65
 		self.datatype: Type = datatype
72
 		if self.usage is None:
81
 		if self.usage is None:
73
 			self.usage = f'<{self.name}>'
82
 			self.usage = f'<{self.name}>'
74
 
83
 
75
-	def validate_value(self, new_value) -> None:
84
+	def validate_value(self, new_value: Any) -> None:
76
 		"""
85
 		"""
77
 		Checks if a value is legal for this setting. Raises a ValueError if not.
86
 		Checks if a value is legal for this setting. Raises a ValueError if not.
78
 		"""
87
 		"""
84
 			allowed_values = '`' + ('`, `'.join(self.enum_values)) + '`'
93
 			allowed_values = '`' + ('`, `'.join(self.enum_values)) + '`'
85
 			raise ValueError(f'`{self.name}` must be one of {allowed_values}')
94
 			raise ValueError(f'`{self.name}` must be one of {allowed_values}')
86
 
95
 
87
-	def set_up(self, cog: Cog, bot: Bot, group: Group) -> None:
96
+	def set_up(self, cog: BaseCog, bot: Bot) -> None:
88
 		"""
97
 		"""
89
 		Sets up getter and setter commands for this setting. This should
98
 		Sets up getter and setter commands for this setting. This should
90
 		usually only be called by BaseCog.
99
 		usually only be called by BaseCog.
91
 		"""
100
 		"""
92
 		if self.name in ('enabled', 'is_enabled'):
101
 		if self.name in ('enabled', 'is_enabled'):
93
-			(group or bot).add_command(self.__make_enable_command(cog))
94
-			(group or bot).add_command(self.__make_disable_command(cog))
102
+			bot.tree.add_command(self.__make_enable_command(cog))
103
+			bot.tree.add_command(self.__make_disable_command(cog))
95
 		else:
104
 		else:
96
-			(group or bot).add_command(self.__make_getter_command(cog))
97
-			(group or bot).add_command(self.__make_setter_command(cog))
105
+			bot.tree.add_command(self.__make_getter_command(cog))
106
+			bot.tree.add_command(self.__make_setter_command(cog))
98
 
107
 
99
-	def __make_getter_command(self, cog: Cog) -> Command:
108
+	def __make_getter_command(self, cog: BaseCog) -> Command:
100
 		setting: CogSetting = self
109
 		setting: CogSetting = self
101
-		async def getter(cog0: Cog, context: Context) -> None:
102
-			setting_name = setting.name
103
-			if isinstance(context.command.parent, Group):
104
-				setting_name = f'{context.command.parent.name}.{setting_name}'
110
+		setting_name = setting.name
111
+		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:
105
 			key = f'{cog0.__class__.__name__}.{setting.name}'
114
 			key = f'{cog0.__class__.__name__}.{setting.name}'
106
-			value = Storage.get_config_value(context.guild, key)
115
+			value = Storage.get_config_value(interaction.guild, key)
107
 			if value is None:
116
 			if value is None:
108
 				value = cog0.get_cog_default(setting.name)
117
 				value = cog0.get_cog_default(setting.name)
109
-				await context.message.reply(
118
+				await interaction.response.send_message(
110
 					f'{CONFIG["info_emoji"]} `{setting_name}` is using default of `{value}`',
119
 					f'{CONFIG["info_emoji"]} `{setting_name}` is using default of `{value}`',
111
-					mention_author=False)
120
+					ephemeral=True
121
+				)
112
 			else:
122
 			else:
113
-				await context.message.reply(
123
+				await interaction.response.send_message(
114
 					f'{CONFIG["info_emoji"]} `{setting_name}` is set to `{value}`',
124
 					f'{CONFIG["info_emoji"]} `{setting_name}` is set to `{value}`',
115
-					mention_author=False)
125
+					ephemeral=True
126
+				)
116
 		command = Command(
127
 		command = Command(
117
-			getter,
118
-			name=f'get{setting.name}',
119
-			brief=f'Shows {setting.brief}',
128
+			name=setting_name,
120
 			description=setting.description,
129
 			description=setting.description,
121
-			checks=[
122
-				commands.has_permissions(ban_members=True),
123
-				commands.guild_only(),
124
-			])
125
-		command.cog = cog
126
-		_fix_command(command)
130
+			callback=getter,
131
+			parent=CogSetting.__get_group
132
+		)
127
 		return command
133
 		return command
128
 
134
 
129
-	def __make_setter_command(self, cog: Cog) -> Command:
135
+	def __make_setter_command(self, cog: BaseCog) -> Command:
130
 		setting: CogSetting = self
136
 		setting: CogSetting = self
131
-		async def setter_common(cog0: Cog, context: Context, new_value) -> None:
137
+		setting_name = setting.name
138
+		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:
132
 			try:
141
 			try:
133
 				setting.validate_value(new_value)
142
 				setting.validate_value(new_value)
134
 			except ValueError as ve:
143
 			except ValueError as ve:
135
-				await context.message.reply(
144
+				await interaction.response.send_message(
136
 					f'{CONFIG["failure_emoji"]} {ve}',
145
 					f'{CONFIG["failure_emoji"]} {ve}',
137
-					mention_author=False)
146
+					ephemeral=True
147
+				)
138
 				return
148
 				return
139
-			setting_name = setting.name
140
-			if isinstance(context.command.parent, Group):
141
-				setting_name = f'{context.command.parent.name}.{setting_name}'
142
 			key = f'{cog0.__class__.__name__}.{setting.name}'
149
 			key = f'{cog0.__class__.__name__}.{setting.name}'
143
-			Storage.set_config_value(context.guild, key, new_value)
144
-			await context.message.reply(
150
+			Storage.set_config_value(interaction.guild, key, new_value)
151
+			await interaction.response.send_message(
145
 				f'{CONFIG["success_emoji"]} `{setting_name}` is now set to `{new_value}`',
152
 				f'{CONFIG["success_emoji"]} `{setting_name}` is now set to `{new_value}`',
146
-				mention_author=False)
147
-			await cog0.on_setting_updated(context.guild, setting)
148
-			cog0.log(context.guild, f'{context.author.name} set {key} to {new_value}')
149
-
150
-		async def setter_int(cog1, context, new_value: int):
151
-			await setter_common(cog1, context, new_value)
152
-		async def setter_float(cog2, context, new_value: float):
153
-			await setter_common(cog2, context, new_value)
154
-		async def setter_str(cog3, context, new_value: str):
155
-			await setter_common(cog3, context, new_value)
156
-		async def setter_bool(cog4, context, new_value: bool):
157
-			await setter_common(cog4, context, new_value)
158
-
159
-		setter: Callable[[Cog, Context, Any], Coroutine]
160
-		if setting.datatype == int:
161
-			setter = setter_int
162
-		elif setting.datatype == float:
163
-			setter = setter_float
153
+				ephemeral=True
154
+			)
155
+			await cog0.on_setting_updated(interaction.guild, setting)
156
+			cog0.log(interaction.guild, f'{interaction.message.author.name} set {key} to {new_value}')
157
+
158
+		type_str: str = 'any'
159
+		if self.datatype == int:
160
+			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}]'
162
+			else:
163
+				type_str = 'int'
164
 		elif setting.datatype == str:
164
 		elif setting.datatype == str:
165
-			setter = setter_str
165
+			if self.enum_values is not None:
166
+				value_list = '"' + '", "'.join(self.enum_values) + '"'
167
+				type_str = f'typing.Literal[{value_list}]'
168
+			else:
169
+				type_str = 'str'
166
 		elif setting.datatype == bool:
170
 		elif setting.datatype == bool:
167
-			setter = setter_bool
168
-		else:
169
-			raise ValueError(f'Datatype {setting.datatype} unsupported')
171
+			type_str = f'typing.Literal["false", "true"]'
170
 
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
+"""
171
 		command = Command(
181
 		command = Command(
172
-			setter,
173
-			name=f'set{setting.name}',
174
-			brief=f'Sets {setting.brief}',
182
+			name=f'{setting.name}',
175
 			description=setting.description,
183
 			description=setting.description,
176
-			usage=setting.usage,
177
-			checks=[
178
-				commands.has_permissions(ban_members=True),
179
-				commands.guild_only(),
180
-			])
184
+			callback=setter,
185
+			parent=CogSetting.__set_group,
186
+		)
181
 		# HACK: Passing `cog` in init gets ignored and set to `None` so set after.
187
 		# HACK: Passing `cog` in init gets ignored and set to `None` so set after.
182
 		# This ensures the callback is passed the cog as `self` argument.
188
 		# This ensures the callback is passed the cog as `self` argument.
183
-		command.cog = cog
184
-		_fix_command(command)
189
+		# command.cog = cog
190
+		# _fix_command(command)
185
 		return command
191
 		return command
186
 
192
 
187
-	def __make_enable_command(self, cog: Cog) -> Command:
193
+	def __make_enable_command(self, cog: BaseCog) -> Command:
188
 		setting: CogSetting = self
194
 		setting: CogSetting = self
189
-		async def enabler(cog0: Cog, context: Context) -> None:
195
+		async def enabler(cog0: BaseCog, interaction: Interaction) -> None:
190
 			key = f'{cog0.__class__.__name__}.{setting.name}'
196
 			key = f'{cog0.__class__.__name__}.{setting.name}'
191
-			Storage.set_config_value(context.guild, key, True)
192
-			await context.message.reply(
197
+			Storage.set_config_value(interaction.guild, key, True)
198
+			await interaction.response.send_message(
193
 				f'{CONFIG["success_emoji"]} {setting.brief.capitalize()} enabled.',
199
 				f'{CONFIG["success_emoji"]} {setting.brief.capitalize()} enabled.',
194
-				mention_author=False)
195
-			await cog0.on_setting_updated(context.guild, setting)
196
-			cog0.log(context.guild, f'{context.author.name} enabled {cog0.__class__.__name__}')
200
+				ephemeral=True
201
+			)
202
+			await cog0.on_setting_updated(interaction.guild, setting)
203
+			cog0.log(interaction.guild, f'{interaction.message.author.name} enabled {cog0.__class__.__name__}')
197
 
204
 
198
 		command = Command(
205
 		command = Command(
199
-			enabler,
200
-			name='enable',
201
-			brief=f'Enables {setting.brief}',
206
+			name=cog.config_prefix,
202
 			description=setting.description,
207
 			description=setting.description,
203
-			checks=[
204
-				commands.has_permissions(ban_members=True),
205
-				commands.guild_only(),
206
-			])
207
-		command.cog = cog
208
-		_fix_command(command)
208
+			callback=enabler,
209
+			parent=CogSetting.__enable_group,
210
+		)
211
+		# command.cog = cog
212
+		# _fix_command(command)
209
 		return command
213
 		return command
210
 
214
 
211
-	def __make_disable_command(self, cog: Cog) -> Command:
215
+	def __make_disable_command(self, cog: BaseCog) -> Command:
212
 		setting: CogSetting = self
216
 		setting: CogSetting = self
213
-		async def disabler(cog0: Cog, context: Context) -> None:
217
+		async def disabler(cog0: BaseCog, interaction: Interaction) -> None:
214
 			key = f'{cog0.__class__.__name__}.{setting.name}'
218
 			key = f'{cog0.__class__.__name__}.{setting.name}'
215
-			Storage.set_config_value(context.guild, key, False)
216
-			await context.message.reply(
219
+			Storage.set_config_value(interaction.guild, key, False)
220
+			await interaction.response.send_message(
217
 				f'{CONFIG["success_emoji"]} {setting.brief.capitalize()} disabled.',
221
 				f'{CONFIG["success_emoji"]} {setting.brief.capitalize()} disabled.',
218
-				mention_author=False)
219
-			await cog0.on_setting_updated(context.guild, setting)
220
-			cog0.log(context.guild, f'{context.author.name} disabled {cog0.__class__.__name__}')
222
+				ephemeral=True
223
+			)
224
+			await cog0.on_setting_updated(interaction.guild, setting)
225
+			cog0.log(interaction.guild, f'{interaction.message.author.name} disabled {cog0.__class__.__name__}')
221
 
226
 
222
 		command = Command(
227
 		command = Command(
223
-			disabler,
224
-			name='disable',
225
-			brief=f'Disables {setting.brief}',
228
+			name=cog.config_prefix,
226
 			description=setting.description,
229
 			description=setting.description,
227
-			checks=[
228
-				commands.has_permissions(ban_members=True),
229
-				commands.guild_only(),
230
-			])
231
-		command.cog = cog
232
-		_fix_command(command)
230
+			callback=disabler,
231
+			parent=CogSetting.__disable_group,
232
+		)
233
+		# command.cog = cog
234
+		# _fix_command(command)
233
 		return command
235
 		return command
234
 
236
 
237
+	__has_set_up_base_commands: bool = False
238
+	__set_group: Group
239
+	__get_group: Group
240
+	__enable_group: Group
241
+	__disable_group: Group
242
+
235
 	@classmethod
243
 	@classmethod
236
-	def set_up_all(cls, cog: Cog, bot: Bot, settings: list) -> None:
244
+	def set_up_all(cls, cog: BaseCog, bot: Bot, settings: list['CogSetting']) -> None:
237
 		"""
245
 		"""
238
 		Sets up editing commands for a list of CogSettings and adds them to a
246
 		Sets up editing commands for a list of CogSettings and adds them to a
239
 		cog. If the cog has a command Group, commands will be added to it.
247
 		cog. If the cog has a command Group, commands will be added to it.
240
-		Otherwise they will be added at the top level.
248
+		Otherwise, they will be added at the top level.
241
 		"""
249
 		"""
242
-		group: Group = first_command_group(cog)
250
+		cls.__set_up_base_commands(bot)
243
 		for setting in settings:
251
 		for setting in settings:
244
-			setting.set_up(cog, bot, group)
252
+			setting.set_up(cog, bot)
253
+
254
+	@classmethod
255
+	def __set_up_base_commands(cls, bot: Bot) -> None:
256
+		if cls.__has_set_up_base_commands:
257
+			return
258
+		cls.__has_set_up_base_commands = True
259
+		cls.__set_group = Group(
260
+			name='set',
261
+			description='Sets a bot configuration value for this guild',
262
+			default_permissions=Permissions.manage_messages
263
+		)
264
+		cls.__get_group = Group(
265
+			name='get',
266
+			description='Shows a configured bot value for this guild',
267
+			default_permissions=Permissions.manage_messages
268
+		)
269
+		cls.__enable_group = Group(
270
+			name='enable',
271
+			description='Enables a set of bot functionality for this guild',
272
+			default_permissions=Permissions.manage_messages
273
+		)
274
+		cls.__disable_group = Group(
275
+			name='disable',
276
+			description='Disables a set of bot functionality for this guild',
277
+			default_permissions=Permissions.manage_messages
278
+		)
279
+		bot.tree.add_command(cls.__set_group)
280
+		bot.tree.add_command(cls.__get_group)
281
+		bot.tree.add_command(cls.__enable_group)
282
+		bot.tree.add_command(cls.__disable_group)

+ 12
- 3
rocketbot/utils.py Ver arquivo

7
 from datetime import datetime, timedelta
7
 from datetime import datetime, timedelta
8
 from typing import Any, Optional, Type, Union
8
 from typing import Any, Optional, Type, Union
9
 
9
 
10
+import discord
10
 from discord import Guild
11
 from discord import Guild
11
-from discord.ext.commands import Cog, Group
12
+from discord.ext.commands import Cog
12
 
13
 
13
 def dump_stacktrace(e: Exception) -> None:
14
 def dump_stacktrace(e: Exception) -> None:
14
 	print(e, file=sys.stderr)
15
 	print(e, file=sys.stderr)
84
 		components = components[0:max_components]
85
 		components = components[0:max_components]
85
 	return ' '.join(components)
86
 	return ' '.join(components)
86
 
87
 
87
-def first_command_group(cog: Cog) -> Optional[Group]:
88
+def _old_first_command_group(cog: Cog) -> Optional[discord.ext.commands.Group]:
88
 	"""Returns the first command Group found in a cog."""
89
 	"""Returns the first command Group found in a cog."""
89
 	for member_name in dir(cog):
90
 	for member_name in dir(cog):
90
 		member = getattr(cog, member_name)
91
 		member = getattr(cog, member_name)
91
-		if isinstance(member, Group):
92
+		if isinstance(member, discord.ext.commands.Group):
93
+			return member
94
+	return None
95
+
96
+def first_command_group(cog: Cog) -> Optional[discord.app_commands.Group]:
97
+	"""Returns the first slash command Group found in a cog."""
98
+	for member_name in dir(cog):
99
+		member = getattr(cog, member_name)
100
+		if isinstance(member, discord.app_commands.Group):
92
 			return member
101
 			return member
93
 	return None
102
 	return None
94
 
103
 

Carregando…
Cancelar
Salvar