GoldyBot.objects.command
1from __future__ import annotations 2import asyncio 3import importlib 4from typing import Dict, List 5import nextcord 6from nextcord.ext import commands 7 8import GoldyBot 9 10MODULE_NAME = "COMMAND" 11 12MISSING = nextcord.utils.MISSING 13 14# Embeds 15#--------- 16class Embeds(): 17 def __init__(self): 18 self.command_usage_embed = GoldyBot.utility.goldy.embed.Embed(title=GoldyBot.utility.msgs.bot.CommandUsage.Embed.title) 19 self.command_usage_embed.set_thumbnail(url=GoldyBot.utility.msgs.bot.CommandUsage.Embed.thumbnail) 20 21 self.no_perms_embed = GoldyBot.utility.goldy.embed.Embed(title=GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.title) 22 self.no_perms_embed.color = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.colour 23 self.no_perms_embed.set_thumbnail(url=GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.thumbnail) 24 25 self.guild_not_registered_embed = GoldyBot.utility.goldy.embed.Embed(title=GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.title) 26 self.guild_not_registered_embed.color = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.colour 27 self.guild_not_registered_embed.set_thumbnail(url=GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.thumbnail) 28 29class Command(Embeds): 30 def __init__(self, func, command_object:nextcord.BaseApplicationCommand | commands.Command=None, command_name=None, 31 required_roles:list=[], slash_options:dict={}, help_des:str=None, hidden:bool=False, 32 parent_cmd:Command=None 33 ): 34 """Generates goldy bot command object with command function object.""" 35 self.func:function = func 36 self.command = command_object 37 """Nextcord command object.""" 38 39 if command_name == None: 40 self.command_name = self.func.__name__ 41 else: 42 self.command_name = command_name 43 self.required_roles_ = required_roles 44 self.slash_options_ = slash_options 45 self.params_ = list(self.func.__code__.co_varnames) 46 self.params_amount_ = self.func.__code__.co_argcount 47 self.help_des_ = help_des 48 self.is_hidden_ = hidden 49 50 self.parent_cmd_ = parent_cmd 51 52 self.in_extension_ = False 53 54 if self.params[0] == "self": 55 self.in_extension_ = True 56 self.params_.pop(0) 57 58 # Add command to extension in cache. 59 if self.in_extension: 60 if self.module.is_internal_module: 61 GoldyBot.cache.main_cache_dict["internal_modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].append(self) 62 else: 63 GoldyBot.cache.main_cache_dict["modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].append(self) 64 else: 65 GoldyBot.cache.main_cache_dict["internal_modules"]["goldy"]["extensions"]["core"]["commands"].append(self) 66 67 super().__init__() 68 69 @property 70 def code_name(self) -> str: 71 """Returns code name of command.""" 72 return self.command_name 73 74 @property 75 def params(self) -> list: 76 """Returns list of function parameters.""" 77 if self.in_extension: 78 return self.params_[0:self.params_amount_ - 1] 79 else: 80 return self.params_[0:self.params_amount_] 81 82 @property 83 def extension_name(self) -> str | None: 84 """Returns extension's code name.""" 85 if self.in_extension: 86 # Command is in extension. 87 return str(self.func).split(" ")[1].split(".")[0] 88 else: 89 # Command is not in any extension. 90 return None 91 92 @property 93 def extension(self) -> GoldyBot.ext.extensions.Extension | None: 94 """Finds and returns the object of the command's extension.""" 95 if self.in_extension: 96 return GoldyBot.cache.FindExtensions().find_object_by_extension_name(extension_name=self.extension_name) 97 else: 98 None 99 100 @property 101 def in_extension(self) -> bool: 102 """Returns true/false if the command is in a extension.""" 103 if self.in_extension_: 104 return True 105 else: 106 return False 107 108 @property 109 def module_name(self) -> str: 110 """Returns name of module the command is located in.""" 111 return self.extension.module_name 112 113 @property 114 def module(self) -> GoldyBot.modules.Module: 115 return GoldyBot.cache.FindModules().find_object_by_module_name(module_name=self.module_name) 116 117 @property 118 def is_hidden(self): 119 """Is the command hidden.""" 120 return self.is_hidden_ 121 122 @property 123 def parent_cmd(self) -> Command|None: 124 """Returns the command object of the parent command if command has parent.""" 125 return self.parent_cmd_ 126 127 @property 128 def is_child(self): 129 """Returns if command is child or not.""" 130 if self.parent_cmd == None: 131 return False 132 else: 133 return True 134 135 def mention(self) -> str: 136 """Returns mention of slash command, if registered as a slash command.""" 137 #TODO: Perhaps have this return codeblock if this command is not a slash command. 138 try: 139 if self.is_child == False: 140 return f"</{self.code_name}:{self.command.command_ids[0]}>" 141 else: 142 return f"</{self.parent_cmd.code_name} {self.code_name}:{self.command.command_ids[0]}>" 143 except (TypeError, AttributeError): 144 GoldyBot.log("warn", f"[{MODULE_NAME}] Tried to mention slash command '{self.code_name}' but could not find it's command id so I'm returning the mention without it.") 145 146 if self.is_child == False: return f"</{self.code_name}:0>" 147 else: return f"</{self.parent_cmd.code_name} {self.code_name}:0>" 148 149 def create_slash(self) -> nextcord.BaseApplicationCommand: 150 """Creates slash command.""" 151 152 GoldyBot.logging.log(f"[{MODULE_NAME}] [{self.command_name.upper()}] Creating slash command...") 153 slash_command_params = self.slash_commands_params_generator() 154 155 return_data = {} 156 157 # Make slash command only visible to admins if it is hidden. 158 default_member_permissions = None 159 if self.is_hidden: default_member_permissions = nextcord.Permissions(permissions=8) 160 161 162 if self.in_extension == True: # Run in EXTENSION! 163 exec(f""" 164@client.slash_command(name=command_name, description=help_des, guild_ids=guilds_allowed_in, default_member_permissions=default_member_permissions) 165async def slash_command_(interaction: Interaction{slash_command_params[0]}): 166 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 167 try: 168 if self.allowed_to_run(ctx): 169 await func(class_, ctx{slash_command_params[1]}) 170 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash command '{self.code_name}' was executed.") 171 172 except GoldyBot.errors.MemberHasNoPermsForCommand: 173 if hidden == False: 174 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 175 message = await ctx.send(embed=no_perms_embed) 176 await asyncio.sleep(6) 177 await message.delete() 178 179 except GoldyBot.errors.GuildNotRegistered: 180 if hidden == False: 181 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 182 message = await ctx.send(embed=guild_not_registered_embed) 183 await asyncio.sleep(15) 184 message.delete() 185 186 except Exception as e: 187 GoldyBot.logging.log("error", e) 188 """, 189 190 {"func":self.func, "client":GoldyBot.cache.main_cache_dict["client"], "command_name":self.command_name, "help_des":self.get_help_des(), "self":self, 191 "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, "class_":self.extension, "no_perms_embed":self.no_perms_embed, 192 "guild_not_registered_embed":self.guild_not_registered_embed, "hidden":self.is_hidden, "guilds_allowed_in":self.guilds_allowed_in, 193 "default_member_permissions":default_member_permissions}, return_data) 194 195 else: # Run as NORMAL command! 196 exec(f""" 197@client.slash_command(name=command_name, description=help_des, guild_ids=guilds_allowed_in, default_member_permissions=default_member_permissions) 198async def slash_command_(interaction: Interaction{slash_command_params[0]}): 199 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 200 try: 201 if self.allowed_to_run(ctx): 202 await func(ctx{slash_command_params[1]}) 203 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash command '{self.code_name}' was executed.") 204 205 except GoldyBot.errors.MemberHasNoPermsForCommand: 206 if hidden == False: 207 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 208 message = await ctx.send(embed=no_perms_embed) 209 await asyncio.sleep(15) 210 await message.delete() 211 212 except GoldyBot.errors.GuildNotRegistered: 213 if hidden == False: 214 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 215 message = await ctx.send(embed=guild_not_registered_embed) 216 await asyncio.sleep(15) 217 await message.delete() 218 219 except Exception as e: 220 GoldyBot.logging.log("error", e) 221 """, 222 223 {"func":self.func, "client":GoldyBot.cache.main_cache_dict["client"], "command_name":self.command_name, "help_des":self.get_help_des(), "self":self, 224 "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, "no_perms_embed":self.no_perms_embed, 225 "guild_not_registered_embed":self.guild_not_registered_embed, "hidden":self.is_hidden, "guilds_allowed_in":self.guilds_allowed_in, 226 "default_member_permissions":default_member_permissions}, return_data) 227 228 GoldyBot.logging.log(f"[{MODULE_NAME}] [{self.command_name.upper()}] Slash command created!") 229 230 self.command = return_data["slash_command_"] 231 return return_data["slash_command_"] 232 233 def remove(self): 234 """Removes command from nextcord.""" 235 command_application_object = self.command 236 237 # Remove command from extension in cache. 238 if self.in_extension: 239 if self.module.is_internal_module: 240 GoldyBot.cache.main_cache_dict["internal_modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].remove(self) 241 else: 242 GoldyBot.cache.main_cache_dict["modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].remove(self) 243 else: 244 GoldyBot.cache.main_cache_dict["internal_modules"]["goldy"]["extensions"]["core"]["commands"].remove(self) 245 246 # Remove from nextcord. 247 client = GoldyBot.cache.client() 248 client.remove_command(name=self.code_name) 249 250 for guild_id in self.guilds_allowed_in: 251 print(command_application_object.command_ids) #TODO: Problem here! 252 GoldyBot.async_loop.run_until_complete(client.delete_application_commands(command_application_object, guild_id=guild_id)) 253 254 GoldyBot.cache.main_cache_dict["client"] = client 255 256 GoldyBot.logging.log("info_5", f"[{MODULE_NAME}] Removed the command '{self.code_name}'!") 257 return True 258 259 def any_args_missing(self, command_executers_args:tuple) -> bool: 260 """Checks if the args given by the command executer matches what parameters the command needs.""" 261 if len(command_executers_args) == len(self.params[1:]): 262 return True 263 else: 264 return False 265 266 def slash_commands_params_generator(self): 267 """Generates a string of params for slash commands. This is more of an in-house thing.""" 268 params_amount = len(self.params[1:]) 269 slash_command_params = "" 270 slash_command_args = "" 271 272 if params_amount >= 1: 273 slash_command_params = ", " 274 slash_command_args = ", " 275 count = 0 276 for param in self.params[1:]: 277 count += 1 278 279 try: 280 # String 281 if isinstance(self.slash_options_[param.lower()], str): 282 default_value = f"='{self.slash_options_[param.lower()]}'" 283 284 # Slash Option 285 if isinstance(self.slash_options_[param.lower()], nextcord.SlashOption): 286 slash_option:nextcord.SlashOption = self.slash_options_[param.lower()] 287 288 if isinstance(slash_option.name, str): 289 name = f"'{slash_option.name}'" 290 else: 291 name = None 292 293 if isinstance(slash_option.description, str): 294 description = f"'{slash_option.description}'" 295 else: 296 description = None 297 298 if isinstance(slash_option.required, nextcord.utils._MissingSentinel): 299 required = None 300 else: 301 required = slash_option.required 302 303 if isinstance(slash_option.choices, nextcord.utils._MissingSentinel): 304 choices = None 305 else: 306 choices = slash_option.choices 307 308 """ 309 if isinstance(slash_option.min_value, nextcord.utils._MissingSentinel): 310 min_value = None 311 else: 312 min_value = slash_option.min_value 313 314 if isinstance(slash_option.max_value, nextcord.utils._MissingSentinel): 315 max_value = None 316 else: 317 max_value = slash_option.max_value 318 """ 319 320 if isinstance(slash_option.autocomplete, nextcord.utils._MissingSentinel): 321 autocomplete = None 322 else: 323 autocomplete = slash_option.autocomplete 324 325 if isinstance(slash_option.default, str): 326 default = f"'{slash_option.default}'" 327 else: 328 default = None 329 330 default_value = f"""=nextcord.SlashOption(name={name}, description={description}, required={required}, 331 choices={choices}, autocomplete={autocomplete}, default={default}, verify={slash_option._verify})""" 332 333 else: 334 default_value = f"={self.slash_options_[param.lower()]}" 335 336 except KeyError: 337 default_value = "" 338 339 if count >= params_amount: 340 slash_command_params += f"{param}{default_value}" 341 slash_command_args += f"{param}" 342 else: 343 slash_command_params += f"{param}{default_value}, " 344 slash_command_args += f"{param}, " 345 346 return (slash_command_params, slash_command_args) 347 348 def update_command_object(self, command_object:commands.Command): 349 """Adds/updates this command object to the class.""" 350 self.command = command_object 351 352 def sub_command(self, command_name:str=None, required_roles:list=[], help_des:str=None, slash_options:Dict[str, nextcord.SlashOption]={}, also_run_parent_CMD:bool=True): 353 """Create a lovely sub command from this slash command. 😀 (Only works with slash commands.)""" 354 355 def decorate(func): 356 def inner(func, command_name, required_roles, help_des, slash_options): 357 parent_command = self.command 358 359 return_data = {} 360 361 goldy_sub_command = Command(func, command_name=command_name, required_roles=required_roles, slash_options=slash_options, help_des=help_des, parent_cmd=self) 362 slash_command_params = goldy_sub_command.slash_commands_params_generator() 363 parent_slash_command_params = self.slash_commands_params_generator() 364 365 if self.in_extension == True: # Run in EXTENSION! 366 exec(f""" 367@parent_command.subcommand(name=command_name, description=help_des) 368async def slash_command_(interaction: Interaction{slash_command_params[0]}): 369 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 370 try: 371 if self.allowed_to_run(ctx): 372 continue_onto_subcommand = None 373 if also_run_parent_CMD == True: continue_onto_subcommand = await goldy_parent_command.func(class_, ctx{parent_slash_command_params[1]}) 374 if not continue_onto_subcommand == False: 375 await func(class_, ctx{slash_command_params[1]}) 376 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash subcommand '{goldy_sub_command.code_name}' was executed.") 377 else: 378 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash subcommand '{goldy_sub_command.code_name}' never executed because parent command returned 'False'.") 379 380 except GoldyBot.errors.MemberHasNoPermsForCommand: 381 if hidden == False: 382 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 383 message = await ctx.send(embed=no_perms_embed) 384 await asyncio.sleep(6) 385 await message.delete() 386 387 except GoldyBot.errors.GuildNotRegistered: 388 if hidden == False: 389 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 390 message = await ctx.send(embed=guild_not_registered_embed) 391 await asyncio.sleep(15) 392 message.delete() 393 394 except Exception as e: 395 GoldyBot.logging.log("error", e) 396 """, 397 # Lambda expression: Returns nc_co 398 {"func":goldy_sub_command.func, "parent_command": parent_command, "command_name":goldy_sub_command.command_name, "help_des":goldy_sub_command.get_help_des(), 399 "self":goldy_sub_command, "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, 400 "class_":goldy_sub_command.extension, "no_perms_embed":self.no_perms_embed, "guild_not_registered_embed":self.guild_not_registered_embed, 401 "hidden":goldy_sub_command.is_hidden, "also_run_parent_CMD":also_run_parent_CMD, "goldy_parent_command": self}, return_data) 402 403 else: # Run as NORMAL command! 404 exec(f""" 405@parent_command.subcommand(name=command_name, description=help_des) 406async def slash_command_(interaction: Interaction{slash_command_params[0]}): 407 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 408 try: 409 if self.allowed_to_run(ctx): 410 if also_run_parent_CMD == True: await goldy_parent_command.func(ctx{parent_slash_command_params[1]}) 411 await func(ctx{slash_command_params[1]}) 412 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash command '{goldy_sub_command.code_name}' was executed.") 413 414 except GoldyBot.errors.MemberHasNoPermsForCommand: 415 if hidden == False: 416 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 417 message = await ctx.send(embed=no_perms_embed) 418 await asyncio.sleep(15) 419 await message.delete() 420 421 except GoldyBot.errors.GuildNotRegistered: 422 if hidden == False: 423 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 424 message = await ctx.send(embed=guild_not_registered_embed) 425 await asyncio.sleep(15) 426 await message.delete() 427 428 except Exception as e: 429 GoldyBot.logging.log("error", e) 430 """, 431 432 {"func":goldy_sub_command.func, "parent_command": parent_command, "command_name":goldy_sub_command.command_name, "help_des":goldy_sub_command.get_help_des(), 433 "self":goldy_sub_command, "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, 434 "no_perms_embed":self.no_perms_embed, "guild_not_registered_embed":self.guild_not_registered_embed, "hidden":goldy_sub_command.is_hidden, 435 "also_run_parent_CMD":also_run_parent_CMD, "goldy_parent_command": self}, return_data) 436 437 goldy_sub_command.update_command_object(return_data["slash_command_"]) 438 439 GoldyBot.logging.log("info_5", f"[{MODULE_NAME}] Sub Command '{goldy_sub_command.command_name}' of '{parent_command.name}' has been loaded.") 440 return goldy_sub_command 441 442 return inner(func, command_name, required_roles, help_des, slash_options) 443 444 return decorate 445 446 def allowed_to_run(self, ctx): 447 """Checks if the command is allowed to run with current circumstances.""" 448 goldy_config = GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.GOLDY_CONFIG_JSON)) 449 450 # Check if guild is registered. 451 #-------------------------------- 452 if str(ctx.guild.id) in goldy_config.read("allowed_guilds"): 453 guild_code_name = GoldyBot.cache.FindGuilds(goldy_config).find_object_by_id(ctx.guild.id).code_name 454 guild_config = GoldyBot.utility.guilds.config.GuildConfig(GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.CONFIG + f"/{guild_code_name}/config.json"))) 455 456 if guild_config.is_extension_allowed(self.extension_name): 457 458 if not self.required_roles_ == []: 459 # If the required roles contain 'bot_dev' and the bot dev is running the command allow the command to execute. 460 #---------------------------------------------------------------------------------------------------------------- 461 if "bot_dev" in self.required_roles_: 462 if str(ctx.author.id) in GoldyBot.settings.BOT_DEVS: 463 return True 464 465 # If the required roles contain 'bot_admin' and a bot admin is running the command allow the command to execute. (NEW) 466 #---------------------------------------------------------------------------------------------------------------- 467 if "bot_admin" in self.required_roles_: 468 if str(ctx.author.id) in goldy_config.read("admin_users"): 469 return True 470 471 # Check if member has any of the required roles. 472 #---------------------------------------------------- 473 for role_code_name in self.required_roles_: 474 if not role_code_name in ["bot_dev", "bot_admin"]: 475 role = guild_config.get_role(ctx, role_code_name) 476 if GoldyBot.objects.member.Member(ctx).has_role(role): 477 return True 478 479 raise GoldyBot.errors.MemberHasNoPermsForCommand(f"The member '{ctx.author.name}' does not have the right permissions to use this command.") 480 481 else: 482 return True 483 484 else: 485 raise GoldyBot.errors.GuildNotRegistered(f"The guild '{ctx.guild.name}' has not been registered.") 486 487 @property 488 def guilds_allowed_in(self) -> List[int]: 489 """Returns the ids of the guilds this command is allowed to function in.""" 490 goldy_config = GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.GOLDY_CONFIG_JSON)) 491 allowed_guilds = goldy_config.read("allowed_guilds") 492 493 guilds_command_is_allowed_in:List[int] = [] 494 495 for guild_id in allowed_guilds: 496 try: 497 guild_config = GoldyBot.utility.guilds.config.GuildConfig(GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.CONFIG + f"/{allowed_guilds[guild_id]}/config.json"))) 498 499 if guild_config.is_extension_allowed(self.extension_name): 500 guilds_command_is_allowed_in.append(int(guild_id)) 501 except FileNotFoundError: 502 pass 503 504 if guilds_command_is_allowed_in == []: guilds_command_is_allowed_in = [123] 505 506 print(guilds_command_is_allowed_in) 507 508 return guilds_command_is_allowed_in 509 510 def get_help_des(self) -> str: 511 """Returns the command's help description.""" 512 if self.help_des_ == None: 513 try: 514 return (importlib.import_module(f'.{self.command_name}', package="GoldyBot.utility.msgs")).help_des 515 516 except ImportError: 517 GoldyBot.logging.log("info", f"[{MODULE_NAME}] The command '{self.command_name}' does not have a 'msg' module, so the help command will not display a help description for it.") 518 return "None" 519 520 except AttributeError: 521 GoldyBot.logging.log("info", f"[{MODULE_NAME}] The command '{self.command_name}' does not contain 'help_des' variable in it's 'msg' module, so the help command will not display a help description.") 522 return "None" 523 else: 524 return self.help_des_
class
Embeds:
17class Embeds(): 18 def __init__(self): 19 self.command_usage_embed = GoldyBot.utility.goldy.embed.Embed(title=GoldyBot.utility.msgs.bot.CommandUsage.Embed.title) 20 self.command_usage_embed.set_thumbnail(url=GoldyBot.utility.msgs.bot.CommandUsage.Embed.thumbnail) 21 22 self.no_perms_embed = GoldyBot.utility.goldy.embed.Embed(title=GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.title) 23 self.no_perms_embed.color = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.colour 24 self.no_perms_embed.set_thumbnail(url=GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.thumbnail) 25 26 self.guild_not_registered_embed = GoldyBot.utility.goldy.embed.Embed(title=GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.title) 27 self.guild_not_registered_embed.color = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.colour 28 self.guild_not_registered_embed.set_thumbnail(url=GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.thumbnail)
Embeds()
18 def __init__(self): 19 self.command_usage_embed = GoldyBot.utility.goldy.embed.Embed(title=GoldyBot.utility.msgs.bot.CommandUsage.Embed.title) 20 self.command_usage_embed.set_thumbnail(url=GoldyBot.utility.msgs.bot.CommandUsage.Embed.thumbnail) 21 22 self.no_perms_embed = GoldyBot.utility.goldy.embed.Embed(title=GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.title) 23 self.no_perms_embed.color = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.colour 24 self.no_perms_embed.set_thumbnail(url=GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.thumbnail) 25 26 self.guild_not_registered_embed = GoldyBot.utility.goldy.embed.Embed(title=GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.title) 27 self.guild_not_registered_embed.color = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.colour 28 self.guild_not_registered_embed.set_thumbnail(url=GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.thumbnail)
30class Command(Embeds): 31 def __init__(self, func, command_object:nextcord.BaseApplicationCommand | commands.Command=None, command_name=None, 32 required_roles:list=[], slash_options:dict={}, help_des:str=None, hidden:bool=False, 33 parent_cmd:Command=None 34 ): 35 """Generates goldy bot command object with command function object.""" 36 self.func:function = func 37 self.command = command_object 38 """Nextcord command object.""" 39 40 if command_name == None: 41 self.command_name = self.func.__name__ 42 else: 43 self.command_name = command_name 44 self.required_roles_ = required_roles 45 self.slash_options_ = slash_options 46 self.params_ = list(self.func.__code__.co_varnames) 47 self.params_amount_ = self.func.__code__.co_argcount 48 self.help_des_ = help_des 49 self.is_hidden_ = hidden 50 51 self.parent_cmd_ = parent_cmd 52 53 self.in_extension_ = False 54 55 if self.params[0] == "self": 56 self.in_extension_ = True 57 self.params_.pop(0) 58 59 # Add command to extension in cache. 60 if self.in_extension: 61 if self.module.is_internal_module: 62 GoldyBot.cache.main_cache_dict["internal_modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].append(self) 63 else: 64 GoldyBot.cache.main_cache_dict["modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].append(self) 65 else: 66 GoldyBot.cache.main_cache_dict["internal_modules"]["goldy"]["extensions"]["core"]["commands"].append(self) 67 68 super().__init__() 69 70 @property 71 def code_name(self) -> str: 72 """Returns code name of command.""" 73 return self.command_name 74 75 @property 76 def params(self) -> list: 77 """Returns list of function parameters.""" 78 if self.in_extension: 79 return self.params_[0:self.params_amount_ - 1] 80 else: 81 return self.params_[0:self.params_amount_] 82 83 @property 84 def extension_name(self) -> str | None: 85 """Returns extension's code name.""" 86 if self.in_extension: 87 # Command is in extension. 88 return str(self.func).split(" ")[1].split(".")[0] 89 else: 90 # Command is not in any extension. 91 return None 92 93 @property 94 def extension(self) -> GoldyBot.ext.extensions.Extension | None: 95 """Finds and returns the object of the command's extension.""" 96 if self.in_extension: 97 return GoldyBot.cache.FindExtensions().find_object_by_extension_name(extension_name=self.extension_name) 98 else: 99 None 100 101 @property 102 def in_extension(self) -> bool: 103 """Returns true/false if the command is in a extension.""" 104 if self.in_extension_: 105 return True 106 else: 107 return False 108 109 @property 110 def module_name(self) -> str: 111 """Returns name of module the command is located in.""" 112 return self.extension.module_name 113 114 @property 115 def module(self) -> GoldyBot.modules.Module: 116 return GoldyBot.cache.FindModules().find_object_by_module_name(module_name=self.module_name) 117 118 @property 119 def is_hidden(self): 120 """Is the command hidden.""" 121 return self.is_hidden_ 122 123 @property 124 def parent_cmd(self) -> Command|None: 125 """Returns the command object of the parent command if command has parent.""" 126 return self.parent_cmd_ 127 128 @property 129 def is_child(self): 130 """Returns if command is child or not.""" 131 if self.parent_cmd == None: 132 return False 133 else: 134 return True 135 136 def mention(self) -> str: 137 """Returns mention of slash command, if registered as a slash command.""" 138 #TODO: Perhaps have this return codeblock if this command is not a slash command. 139 try: 140 if self.is_child == False: 141 return f"</{self.code_name}:{self.command.command_ids[0]}>" 142 else: 143 return f"</{self.parent_cmd.code_name} {self.code_name}:{self.command.command_ids[0]}>" 144 except (TypeError, AttributeError): 145 GoldyBot.log("warn", f"[{MODULE_NAME}] Tried to mention slash command '{self.code_name}' but could not find it's command id so I'm returning the mention without it.") 146 147 if self.is_child == False: return f"</{self.code_name}:0>" 148 else: return f"</{self.parent_cmd.code_name} {self.code_name}:0>" 149 150 def create_slash(self) -> nextcord.BaseApplicationCommand: 151 """Creates slash command.""" 152 153 GoldyBot.logging.log(f"[{MODULE_NAME}] [{self.command_name.upper()}] Creating slash command...") 154 slash_command_params = self.slash_commands_params_generator() 155 156 return_data = {} 157 158 # Make slash command only visible to admins if it is hidden. 159 default_member_permissions = None 160 if self.is_hidden: default_member_permissions = nextcord.Permissions(permissions=8) 161 162 163 if self.in_extension == True: # Run in EXTENSION! 164 exec(f""" 165@client.slash_command(name=command_name, description=help_des, guild_ids=guilds_allowed_in, default_member_permissions=default_member_permissions) 166async def slash_command_(interaction: Interaction{slash_command_params[0]}): 167 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 168 try: 169 if self.allowed_to_run(ctx): 170 await func(class_, ctx{slash_command_params[1]}) 171 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash command '{self.code_name}' was executed.") 172 173 except GoldyBot.errors.MemberHasNoPermsForCommand: 174 if hidden == False: 175 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 176 message = await ctx.send(embed=no_perms_embed) 177 await asyncio.sleep(6) 178 await message.delete() 179 180 except GoldyBot.errors.GuildNotRegistered: 181 if hidden == False: 182 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 183 message = await ctx.send(embed=guild_not_registered_embed) 184 await asyncio.sleep(15) 185 message.delete() 186 187 except Exception as e: 188 GoldyBot.logging.log("error", e) 189 """, 190 191 {"func":self.func, "client":GoldyBot.cache.main_cache_dict["client"], "command_name":self.command_name, "help_des":self.get_help_des(), "self":self, 192 "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, "class_":self.extension, "no_perms_embed":self.no_perms_embed, 193 "guild_not_registered_embed":self.guild_not_registered_embed, "hidden":self.is_hidden, "guilds_allowed_in":self.guilds_allowed_in, 194 "default_member_permissions":default_member_permissions}, return_data) 195 196 else: # Run as NORMAL command! 197 exec(f""" 198@client.slash_command(name=command_name, description=help_des, guild_ids=guilds_allowed_in, default_member_permissions=default_member_permissions) 199async def slash_command_(interaction: Interaction{slash_command_params[0]}): 200 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 201 try: 202 if self.allowed_to_run(ctx): 203 await func(ctx{slash_command_params[1]}) 204 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash command '{self.code_name}' was executed.") 205 206 except GoldyBot.errors.MemberHasNoPermsForCommand: 207 if hidden == False: 208 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 209 message = await ctx.send(embed=no_perms_embed) 210 await asyncio.sleep(15) 211 await message.delete() 212 213 except GoldyBot.errors.GuildNotRegistered: 214 if hidden == False: 215 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 216 message = await ctx.send(embed=guild_not_registered_embed) 217 await asyncio.sleep(15) 218 await message.delete() 219 220 except Exception as e: 221 GoldyBot.logging.log("error", e) 222 """, 223 224 {"func":self.func, "client":GoldyBot.cache.main_cache_dict["client"], "command_name":self.command_name, "help_des":self.get_help_des(), "self":self, 225 "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, "no_perms_embed":self.no_perms_embed, 226 "guild_not_registered_embed":self.guild_not_registered_embed, "hidden":self.is_hidden, "guilds_allowed_in":self.guilds_allowed_in, 227 "default_member_permissions":default_member_permissions}, return_data) 228 229 GoldyBot.logging.log(f"[{MODULE_NAME}] [{self.command_name.upper()}] Slash command created!") 230 231 self.command = return_data["slash_command_"] 232 return return_data["slash_command_"] 233 234 def remove(self): 235 """Removes command from nextcord.""" 236 command_application_object = self.command 237 238 # Remove command from extension in cache. 239 if self.in_extension: 240 if self.module.is_internal_module: 241 GoldyBot.cache.main_cache_dict["internal_modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].remove(self) 242 else: 243 GoldyBot.cache.main_cache_dict["modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].remove(self) 244 else: 245 GoldyBot.cache.main_cache_dict["internal_modules"]["goldy"]["extensions"]["core"]["commands"].remove(self) 246 247 # Remove from nextcord. 248 client = GoldyBot.cache.client() 249 client.remove_command(name=self.code_name) 250 251 for guild_id in self.guilds_allowed_in: 252 print(command_application_object.command_ids) #TODO: Problem here! 253 GoldyBot.async_loop.run_until_complete(client.delete_application_commands(command_application_object, guild_id=guild_id)) 254 255 GoldyBot.cache.main_cache_dict["client"] = client 256 257 GoldyBot.logging.log("info_5", f"[{MODULE_NAME}] Removed the command '{self.code_name}'!") 258 return True 259 260 def any_args_missing(self, command_executers_args:tuple) -> bool: 261 """Checks if the args given by the command executer matches what parameters the command needs.""" 262 if len(command_executers_args) == len(self.params[1:]): 263 return True 264 else: 265 return False 266 267 def slash_commands_params_generator(self): 268 """Generates a string of params for slash commands. This is more of an in-house thing.""" 269 params_amount = len(self.params[1:]) 270 slash_command_params = "" 271 slash_command_args = "" 272 273 if params_amount >= 1: 274 slash_command_params = ", " 275 slash_command_args = ", " 276 count = 0 277 for param in self.params[1:]: 278 count += 1 279 280 try: 281 # String 282 if isinstance(self.slash_options_[param.lower()], str): 283 default_value = f"='{self.slash_options_[param.lower()]}'" 284 285 # Slash Option 286 if isinstance(self.slash_options_[param.lower()], nextcord.SlashOption): 287 slash_option:nextcord.SlashOption = self.slash_options_[param.lower()] 288 289 if isinstance(slash_option.name, str): 290 name = f"'{slash_option.name}'" 291 else: 292 name = None 293 294 if isinstance(slash_option.description, str): 295 description = f"'{slash_option.description}'" 296 else: 297 description = None 298 299 if isinstance(slash_option.required, nextcord.utils._MissingSentinel): 300 required = None 301 else: 302 required = slash_option.required 303 304 if isinstance(slash_option.choices, nextcord.utils._MissingSentinel): 305 choices = None 306 else: 307 choices = slash_option.choices 308 309 """ 310 if isinstance(slash_option.min_value, nextcord.utils._MissingSentinel): 311 min_value = None 312 else: 313 min_value = slash_option.min_value 314 315 if isinstance(slash_option.max_value, nextcord.utils._MissingSentinel): 316 max_value = None 317 else: 318 max_value = slash_option.max_value 319 """ 320 321 if isinstance(slash_option.autocomplete, nextcord.utils._MissingSentinel): 322 autocomplete = None 323 else: 324 autocomplete = slash_option.autocomplete 325 326 if isinstance(slash_option.default, str): 327 default = f"'{slash_option.default}'" 328 else: 329 default = None 330 331 default_value = f"""=nextcord.SlashOption(name={name}, description={description}, required={required}, 332 choices={choices}, autocomplete={autocomplete}, default={default}, verify={slash_option._verify})""" 333 334 else: 335 default_value = f"={self.slash_options_[param.lower()]}" 336 337 except KeyError: 338 default_value = "" 339 340 if count >= params_amount: 341 slash_command_params += f"{param}{default_value}" 342 slash_command_args += f"{param}" 343 else: 344 slash_command_params += f"{param}{default_value}, " 345 slash_command_args += f"{param}, " 346 347 return (slash_command_params, slash_command_args) 348 349 def update_command_object(self, command_object:commands.Command): 350 """Adds/updates this command object to the class.""" 351 self.command = command_object 352 353 def sub_command(self, command_name:str=None, required_roles:list=[], help_des:str=None, slash_options:Dict[str, nextcord.SlashOption]={}, also_run_parent_CMD:bool=True): 354 """Create a lovely sub command from this slash command. 😀 (Only works with slash commands.)""" 355 356 def decorate(func): 357 def inner(func, command_name, required_roles, help_des, slash_options): 358 parent_command = self.command 359 360 return_data = {} 361 362 goldy_sub_command = Command(func, command_name=command_name, required_roles=required_roles, slash_options=slash_options, help_des=help_des, parent_cmd=self) 363 slash_command_params = goldy_sub_command.slash_commands_params_generator() 364 parent_slash_command_params = self.slash_commands_params_generator() 365 366 if self.in_extension == True: # Run in EXTENSION! 367 exec(f""" 368@parent_command.subcommand(name=command_name, description=help_des) 369async def slash_command_(interaction: Interaction{slash_command_params[0]}): 370 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 371 try: 372 if self.allowed_to_run(ctx): 373 continue_onto_subcommand = None 374 if also_run_parent_CMD == True: continue_onto_subcommand = await goldy_parent_command.func(class_, ctx{parent_slash_command_params[1]}) 375 if not continue_onto_subcommand == False: 376 await func(class_, ctx{slash_command_params[1]}) 377 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash subcommand '{goldy_sub_command.code_name}' was executed.") 378 else: 379 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash subcommand '{goldy_sub_command.code_name}' never executed because parent command returned 'False'.") 380 381 except GoldyBot.errors.MemberHasNoPermsForCommand: 382 if hidden == False: 383 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 384 message = await ctx.send(embed=no_perms_embed) 385 await asyncio.sleep(6) 386 await message.delete() 387 388 except GoldyBot.errors.GuildNotRegistered: 389 if hidden == False: 390 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 391 message = await ctx.send(embed=guild_not_registered_embed) 392 await asyncio.sleep(15) 393 message.delete() 394 395 except Exception as e: 396 GoldyBot.logging.log("error", e) 397 """, 398 # Lambda expression: Returns nc_co 399 {"func":goldy_sub_command.func, "parent_command": parent_command, "command_name":goldy_sub_command.command_name, "help_des":goldy_sub_command.get_help_des(), 400 "self":goldy_sub_command, "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, 401 "class_":goldy_sub_command.extension, "no_perms_embed":self.no_perms_embed, "guild_not_registered_embed":self.guild_not_registered_embed, 402 "hidden":goldy_sub_command.is_hidden, "also_run_parent_CMD":also_run_parent_CMD, "goldy_parent_command": self}, return_data) 403 404 else: # Run as NORMAL command! 405 exec(f""" 406@parent_command.subcommand(name=command_name, description=help_des) 407async def slash_command_(interaction: Interaction{slash_command_params[0]}): 408 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 409 try: 410 if self.allowed_to_run(ctx): 411 if also_run_parent_CMD == True: await goldy_parent_command.func(ctx{parent_slash_command_params[1]}) 412 await func(ctx{slash_command_params[1]}) 413 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash command '{goldy_sub_command.code_name}' was executed.") 414 415 except GoldyBot.errors.MemberHasNoPermsForCommand: 416 if hidden == False: 417 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 418 message = await ctx.send(embed=no_perms_embed) 419 await asyncio.sleep(15) 420 await message.delete() 421 422 except GoldyBot.errors.GuildNotRegistered: 423 if hidden == False: 424 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 425 message = await ctx.send(embed=guild_not_registered_embed) 426 await asyncio.sleep(15) 427 await message.delete() 428 429 except Exception as e: 430 GoldyBot.logging.log("error", e) 431 """, 432 433 {"func":goldy_sub_command.func, "parent_command": parent_command, "command_name":goldy_sub_command.command_name, "help_des":goldy_sub_command.get_help_des(), 434 "self":goldy_sub_command, "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, 435 "no_perms_embed":self.no_perms_embed, "guild_not_registered_embed":self.guild_not_registered_embed, "hidden":goldy_sub_command.is_hidden, 436 "also_run_parent_CMD":also_run_parent_CMD, "goldy_parent_command": self}, return_data) 437 438 goldy_sub_command.update_command_object(return_data["slash_command_"]) 439 440 GoldyBot.logging.log("info_5", f"[{MODULE_NAME}] Sub Command '{goldy_sub_command.command_name}' of '{parent_command.name}' has been loaded.") 441 return goldy_sub_command 442 443 return inner(func, command_name, required_roles, help_des, slash_options) 444 445 return decorate 446 447 def allowed_to_run(self, ctx): 448 """Checks if the command is allowed to run with current circumstances.""" 449 goldy_config = GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.GOLDY_CONFIG_JSON)) 450 451 # Check if guild is registered. 452 #-------------------------------- 453 if str(ctx.guild.id) in goldy_config.read("allowed_guilds"): 454 guild_code_name = GoldyBot.cache.FindGuilds(goldy_config).find_object_by_id(ctx.guild.id).code_name 455 guild_config = GoldyBot.utility.guilds.config.GuildConfig(GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.CONFIG + f"/{guild_code_name}/config.json"))) 456 457 if guild_config.is_extension_allowed(self.extension_name): 458 459 if not self.required_roles_ == []: 460 # If the required roles contain 'bot_dev' and the bot dev is running the command allow the command to execute. 461 #---------------------------------------------------------------------------------------------------------------- 462 if "bot_dev" in self.required_roles_: 463 if str(ctx.author.id) in GoldyBot.settings.BOT_DEVS: 464 return True 465 466 # If the required roles contain 'bot_admin' and a bot admin is running the command allow the command to execute. (NEW) 467 #---------------------------------------------------------------------------------------------------------------- 468 if "bot_admin" in self.required_roles_: 469 if str(ctx.author.id) in goldy_config.read("admin_users"): 470 return True 471 472 # Check if member has any of the required roles. 473 #---------------------------------------------------- 474 for role_code_name in self.required_roles_: 475 if not role_code_name in ["bot_dev", "bot_admin"]: 476 role = guild_config.get_role(ctx, role_code_name) 477 if GoldyBot.objects.member.Member(ctx).has_role(role): 478 return True 479 480 raise GoldyBot.errors.MemberHasNoPermsForCommand(f"The member '{ctx.author.name}' does not have the right permissions to use this command.") 481 482 else: 483 return True 484 485 else: 486 raise GoldyBot.errors.GuildNotRegistered(f"The guild '{ctx.guild.name}' has not been registered.") 487 488 @property 489 def guilds_allowed_in(self) -> List[int]: 490 """Returns the ids of the guilds this command is allowed to function in.""" 491 goldy_config = GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.GOLDY_CONFIG_JSON)) 492 allowed_guilds = goldy_config.read("allowed_guilds") 493 494 guilds_command_is_allowed_in:List[int] = [] 495 496 for guild_id in allowed_guilds: 497 try: 498 guild_config = GoldyBot.utility.guilds.config.GuildConfig(GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.CONFIG + f"/{allowed_guilds[guild_id]}/config.json"))) 499 500 if guild_config.is_extension_allowed(self.extension_name): 501 guilds_command_is_allowed_in.append(int(guild_id)) 502 except FileNotFoundError: 503 pass 504 505 if guilds_command_is_allowed_in == []: guilds_command_is_allowed_in = [123] 506 507 print(guilds_command_is_allowed_in) 508 509 return guilds_command_is_allowed_in 510 511 def get_help_des(self) -> str: 512 """Returns the command's help description.""" 513 if self.help_des_ == None: 514 try: 515 return (importlib.import_module(f'.{self.command_name}', package="GoldyBot.utility.msgs")).help_des 516 517 except ImportError: 518 GoldyBot.logging.log("info", f"[{MODULE_NAME}] The command '{self.command_name}' does not have a 'msg' module, so the help command will not display a help description for it.") 519 return "None" 520 521 except AttributeError: 522 GoldyBot.logging.log("info", f"[{MODULE_NAME}] The command '{self.command_name}' does not contain 'help_des' variable in it's 'msg' module, so the help command will not display a help description.") 523 return "None" 524 else: 525 return self.help_des_
Command( func, command_object: nextcord.application_command.BaseApplicationCommand | nextcord.ext.commands.core.Command = None, command_name=None, required_roles: list = [], slash_options: dict = {}, help_des: str = None, hidden: bool = False, parent_cmd: GoldyBot.objects.command.Command = None)
31 def __init__(self, func, command_object:nextcord.BaseApplicationCommand | commands.Command=None, command_name=None, 32 required_roles:list=[], slash_options:dict={}, help_des:str=None, hidden:bool=False, 33 parent_cmd:Command=None 34 ): 35 """Generates goldy bot command object with command function object.""" 36 self.func:function = func 37 self.command = command_object 38 """Nextcord command object.""" 39 40 if command_name == None: 41 self.command_name = self.func.__name__ 42 else: 43 self.command_name = command_name 44 self.required_roles_ = required_roles 45 self.slash_options_ = slash_options 46 self.params_ = list(self.func.__code__.co_varnames) 47 self.params_amount_ = self.func.__code__.co_argcount 48 self.help_des_ = help_des 49 self.is_hidden_ = hidden 50 51 self.parent_cmd_ = parent_cmd 52 53 self.in_extension_ = False 54 55 if self.params[0] == "self": 56 self.in_extension_ = True 57 self.params_.pop(0) 58 59 # Add command to extension in cache. 60 if self.in_extension: 61 if self.module.is_internal_module: 62 GoldyBot.cache.main_cache_dict["internal_modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].append(self) 63 else: 64 GoldyBot.cache.main_cache_dict["modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].append(self) 65 else: 66 GoldyBot.cache.main_cache_dict["internal_modules"]["goldy"]["extensions"]["core"]["commands"].append(self) 67 68 super().__init__()
Generates goldy bot command object with command function object.
extension: GoldyBot.ext.extensions.Extension | None
Finds and returns the object of the command's extension.
module: GoldyBot.modules.Module
parent_cmd: GoldyBot.objects.command.Command | None
Returns the command object of the parent command if command has parent.
def
mention(self) -> str:
136 def mention(self) -> str: 137 """Returns mention of slash command, if registered as a slash command.""" 138 #TODO: Perhaps have this return codeblock if this command is not a slash command. 139 try: 140 if self.is_child == False: 141 return f"</{self.code_name}:{self.command.command_ids[0]}>" 142 else: 143 return f"</{self.parent_cmd.code_name} {self.code_name}:{self.command.command_ids[0]}>" 144 except (TypeError, AttributeError): 145 GoldyBot.log("warn", f"[{MODULE_NAME}] Tried to mention slash command '{self.code_name}' but could not find it's command id so I'm returning the mention without it.") 146 147 if self.is_child == False: return f"</{self.code_name}:0>" 148 else: return f"</{self.parent_cmd.code_name} {self.code_name}:0>"
Returns mention of slash command, if registered as a slash command.
def
create_slash(self) -> nextcord.application_command.BaseApplicationCommand:
150 def create_slash(self) -> nextcord.BaseApplicationCommand: 151 """Creates slash command.""" 152 153 GoldyBot.logging.log(f"[{MODULE_NAME}] [{self.command_name.upper()}] Creating slash command...") 154 slash_command_params = self.slash_commands_params_generator() 155 156 return_data = {} 157 158 # Make slash command only visible to admins if it is hidden. 159 default_member_permissions = None 160 if self.is_hidden: default_member_permissions = nextcord.Permissions(permissions=8) 161 162 163 if self.in_extension == True: # Run in EXTENSION! 164 exec(f""" 165@client.slash_command(name=command_name, description=help_des, guild_ids=guilds_allowed_in, default_member_permissions=default_member_permissions) 166async def slash_command_(interaction: Interaction{slash_command_params[0]}): 167 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 168 try: 169 if self.allowed_to_run(ctx): 170 await func(class_, ctx{slash_command_params[1]}) 171 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash command '{self.code_name}' was executed.") 172 173 except GoldyBot.errors.MemberHasNoPermsForCommand: 174 if hidden == False: 175 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 176 message = await ctx.send(embed=no_perms_embed) 177 await asyncio.sleep(6) 178 await message.delete() 179 180 except GoldyBot.errors.GuildNotRegistered: 181 if hidden == False: 182 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 183 message = await ctx.send(embed=guild_not_registered_embed) 184 await asyncio.sleep(15) 185 message.delete() 186 187 except Exception as e: 188 GoldyBot.logging.log("error", e) 189 """, 190 191 {"func":self.func, "client":GoldyBot.cache.main_cache_dict["client"], "command_name":self.command_name, "help_des":self.get_help_des(), "self":self, 192 "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, "class_":self.extension, "no_perms_embed":self.no_perms_embed, 193 "guild_not_registered_embed":self.guild_not_registered_embed, "hidden":self.is_hidden, "guilds_allowed_in":self.guilds_allowed_in, 194 "default_member_permissions":default_member_permissions}, return_data) 195 196 else: # Run as NORMAL command! 197 exec(f""" 198@client.slash_command(name=command_name, description=help_des, guild_ids=guilds_allowed_in, default_member_permissions=default_member_permissions) 199async def slash_command_(interaction: Interaction{slash_command_params[0]}): 200 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 201 try: 202 if self.allowed_to_run(ctx): 203 await func(ctx{slash_command_params[1]}) 204 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash command '{self.code_name}' was executed.") 205 206 except GoldyBot.errors.MemberHasNoPermsForCommand: 207 if hidden == False: 208 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 209 message = await ctx.send(embed=no_perms_embed) 210 await asyncio.sleep(15) 211 await message.delete() 212 213 except GoldyBot.errors.GuildNotRegistered: 214 if hidden == False: 215 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 216 message = await ctx.send(embed=guild_not_registered_embed) 217 await asyncio.sleep(15) 218 await message.delete() 219 220 except Exception as e: 221 GoldyBot.logging.log("error", e) 222 """, 223 224 {"func":self.func, "client":GoldyBot.cache.main_cache_dict["client"], "command_name":self.command_name, "help_des":self.get_help_des(), "self":self, 225 "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, "no_perms_embed":self.no_perms_embed, 226 "guild_not_registered_embed":self.guild_not_registered_embed, "hidden":self.is_hidden, "guilds_allowed_in":self.guilds_allowed_in, 227 "default_member_permissions":default_member_permissions}, return_data) 228 229 GoldyBot.logging.log(f"[{MODULE_NAME}] [{self.command_name.upper()}] Slash command created!") 230 231 self.command = return_data["slash_command_"] 232 return return_data["slash_command_"]
Creates slash command.
def
remove(self):
234 def remove(self): 235 """Removes command from nextcord.""" 236 command_application_object = self.command 237 238 # Remove command from extension in cache. 239 if self.in_extension: 240 if self.module.is_internal_module: 241 GoldyBot.cache.main_cache_dict["internal_modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].remove(self) 242 else: 243 GoldyBot.cache.main_cache_dict["modules"][f"{self.module_name}"]["extensions"][f"{self.extension_name}"]["commands"].remove(self) 244 else: 245 GoldyBot.cache.main_cache_dict["internal_modules"]["goldy"]["extensions"]["core"]["commands"].remove(self) 246 247 # Remove from nextcord. 248 client = GoldyBot.cache.client() 249 client.remove_command(name=self.code_name) 250 251 for guild_id in self.guilds_allowed_in: 252 print(command_application_object.command_ids) #TODO: Problem here! 253 GoldyBot.async_loop.run_until_complete(client.delete_application_commands(command_application_object, guild_id=guild_id)) 254 255 GoldyBot.cache.main_cache_dict["client"] = client 256 257 GoldyBot.logging.log("info_5", f"[{MODULE_NAME}] Removed the command '{self.code_name}'!") 258 return True
Removes command from nextcord.
def
any_args_missing(self, command_executers_args: tuple) -> bool:
260 def any_args_missing(self, command_executers_args:tuple) -> bool: 261 """Checks if the args given by the command executer matches what parameters the command needs.""" 262 if len(command_executers_args) == len(self.params[1:]): 263 return True 264 else: 265 return False
Checks if the args given by the command executer matches what parameters the command needs.
def
slash_commands_params_generator(self):
267 def slash_commands_params_generator(self): 268 """Generates a string of params for slash commands. This is more of an in-house thing.""" 269 params_amount = len(self.params[1:]) 270 slash_command_params = "" 271 slash_command_args = "" 272 273 if params_amount >= 1: 274 slash_command_params = ", " 275 slash_command_args = ", " 276 count = 0 277 for param in self.params[1:]: 278 count += 1 279 280 try: 281 # String 282 if isinstance(self.slash_options_[param.lower()], str): 283 default_value = f"='{self.slash_options_[param.lower()]}'" 284 285 # Slash Option 286 if isinstance(self.slash_options_[param.lower()], nextcord.SlashOption): 287 slash_option:nextcord.SlashOption = self.slash_options_[param.lower()] 288 289 if isinstance(slash_option.name, str): 290 name = f"'{slash_option.name}'" 291 else: 292 name = None 293 294 if isinstance(slash_option.description, str): 295 description = f"'{slash_option.description}'" 296 else: 297 description = None 298 299 if isinstance(slash_option.required, nextcord.utils._MissingSentinel): 300 required = None 301 else: 302 required = slash_option.required 303 304 if isinstance(slash_option.choices, nextcord.utils._MissingSentinel): 305 choices = None 306 else: 307 choices = slash_option.choices 308 309 """ 310 if isinstance(slash_option.min_value, nextcord.utils._MissingSentinel): 311 min_value = None 312 else: 313 min_value = slash_option.min_value 314 315 if isinstance(slash_option.max_value, nextcord.utils._MissingSentinel): 316 max_value = None 317 else: 318 max_value = slash_option.max_value 319 """ 320 321 if isinstance(slash_option.autocomplete, nextcord.utils._MissingSentinel): 322 autocomplete = None 323 else: 324 autocomplete = slash_option.autocomplete 325 326 if isinstance(slash_option.default, str): 327 default = f"'{slash_option.default}'" 328 else: 329 default = None 330 331 default_value = f"""=nextcord.SlashOption(name={name}, description={description}, required={required}, 332 choices={choices}, autocomplete={autocomplete}, default={default}, verify={slash_option._verify})""" 333 334 else: 335 default_value = f"={self.slash_options_[param.lower()]}" 336 337 except KeyError: 338 default_value = "" 339 340 if count >= params_amount: 341 slash_command_params += f"{param}{default_value}" 342 slash_command_args += f"{param}" 343 else: 344 slash_command_params += f"{param}{default_value}, " 345 slash_command_args += f"{param}, " 346 347 return (slash_command_params, slash_command_args)
Generates a string of params for slash commands. This is more of an in-house thing.
def
update_command_object(self, command_object: nextcord.ext.commands.core.Command):
349 def update_command_object(self, command_object:commands.Command): 350 """Adds/updates this command object to the class.""" 351 self.command = command_object
Adds/updates this command object to the class.
def
sub_command( self, command_name: str = None, required_roles: list = [], help_des: str = None, slash_options: Dict[str, nextcord.application_command.SlashOption] = {}, also_run_parent_CMD: bool = True):
353 def sub_command(self, command_name:str=None, required_roles:list=[], help_des:str=None, slash_options:Dict[str, nextcord.SlashOption]={}, also_run_parent_CMD:bool=True): 354 """Create a lovely sub command from this slash command. 😀 (Only works with slash commands.)""" 355 356 def decorate(func): 357 def inner(func, command_name, required_roles, help_des, slash_options): 358 parent_command = self.command 359 360 return_data = {} 361 362 goldy_sub_command = Command(func, command_name=command_name, required_roles=required_roles, slash_options=slash_options, help_des=help_des, parent_cmd=self) 363 slash_command_params = goldy_sub_command.slash_commands_params_generator() 364 parent_slash_command_params = self.slash_commands_params_generator() 365 366 if self.in_extension == True: # Run in EXTENSION! 367 exec(f""" 368@parent_command.subcommand(name=command_name, description=help_des) 369async def slash_command_(interaction: Interaction{slash_command_params[0]}): 370 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 371 try: 372 if self.allowed_to_run(ctx): 373 continue_onto_subcommand = None 374 if also_run_parent_CMD == True: continue_onto_subcommand = await goldy_parent_command.func(class_, ctx{parent_slash_command_params[1]}) 375 if not continue_onto_subcommand == False: 376 await func(class_, ctx{slash_command_params[1]}) 377 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash subcommand '{goldy_sub_command.code_name}' was executed.") 378 else: 379 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash subcommand '{goldy_sub_command.code_name}' never executed because parent command returned 'False'.") 380 381 except GoldyBot.errors.MemberHasNoPermsForCommand: 382 if hidden == False: 383 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 384 message = await ctx.send(embed=no_perms_embed) 385 await asyncio.sleep(6) 386 await message.delete() 387 388 except GoldyBot.errors.GuildNotRegistered: 389 if hidden == False: 390 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 391 message = await ctx.send(embed=guild_not_registered_embed) 392 await asyncio.sleep(15) 393 message.delete() 394 395 except Exception as e: 396 GoldyBot.logging.log("error", e) 397 """, 398 # Lambda expression: Returns nc_co 399 {"func":goldy_sub_command.func, "parent_command": parent_command, "command_name":goldy_sub_command.command_name, "help_des":goldy_sub_command.get_help_des(), 400 "self":goldy_sub_command, "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, 401 "class_":goldy_sub_command.extension, "no_perms_embed":self.no_perms_embed, "guild_not_registered_embed":self.guild_not_registered_embed, 402 "hidden":goldy_sub_command.is_hidden, "also_run_parent_CMD":also_run_parent_CMD, "goldy_parent_command": self}, return_data) 403 404 else: # Run as NORMAL command! 405 exec(f""" 406@parent_command.subcommand(name=command_name, description=help_des) 407async def slash_command_(interaction: Interaction{slash_command_params[0]}): 408 ctx = GoldyBot.objects.slash.InteractionToCtx(interaction) 409 try: 410 if self.allowed_to_run(ctx): 411 if also_run_parent_CMD == True: await goldy_parent_command.func(ctx{parent_slash_command_params[1]}) 412 await func(ctx{slash_command_params[1]}) 413 GoldyBot.logging.log(f"[{MODULE_NAME}] The slash command '{goldy_sub_command.code_name}' was executed.") 414 415 except GoldyBot.errors.MemberHasNoPermsForCommand: 416 if hidden == False: 417 no_perms_embed.description = GoldyBot.utility.msgs.bot.CommandNoPerms.Embed.des.format(ctx.author.mention) 418 message = await ctx.send(embed=no_perms_embed) 419 await asyncio.sleep(15) 420 await message.delete() 421 422 except GoldyBot.errors.GuildNotRegistered: 423 if hidden == False: 424 guild_not_registered_embed.description = GoldyBot.utility.msgs.bot.CommandGuildNotRegistered.Embed.des.format(ctx.author.mention) 425 message = await ctx.send(embed=guild_not_registered_embed) 426 await asyncio.sleep(15) 427 await message.delete() 428 429 except Exception as e: 430 GoldyBot.logging.log("error", e) 431 """, 432 433 {"func":goldy_sub_command.func, "parent_command": parent_command, "command_name":goldy_sub_command.command_name, "help_des":goldy_sub_command.get_help_des(), 434 "self":goldy_sub_command, "Interaction": GoldyBot.nextcord.Interaction, "GoldyBot": GoldyBot, "asyncio":asyncio, "nextcord":nextcord, 435 "no_perms_embed":self.no_perms_embed, "guild_not_registered_embed":self.guild_not_registered_embed, "hidden":goldy_sub_command.is_hidden, 436 "also_run_parent_CMD":also_run_parent_CMD, "goldy_parent_command": self}, return_data) 437 438 goldy_sub_command.update_command_object(return_data["slash_command_"]) 439 440 GoldyBot.logging.log("info_5", f"[{MODULE_NAME}] Sub Command '{goldy_sub_command.command_name}' of '{parent_command.name}' has been loaded.") 441 return goldy_sub_command 442 443 return inner(func, command_name, required_roles, help_des, slash_options) 444 445 return decorate
Create a lovely sub command from this slash command. 😀 (Only works with slash commands.)
def
allowed_to_run(self, ctx):
447 def allowed_to_run(self, ctx): 448 """Checks if the command is allowed to run with current circumstances.""" 449 goldy_config = GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.GOLDY_CONFIG_JSON)) 450 451 # Check if guild is registered. 452 #-------------------------------- 453 if str(ctx.guild.id) in goldy_config.read("allowed_guilds"): 454 guild_code_name = GoldyBot.cache.FindGuilds(goldy_config).find_object_by_id(ctx.guild.id).code_name 455 guild_config = GoldyBot.utility.guilds.config.GuildConfig(GoldyBot.config.Config(GoldyBot.files.File(GoldyBot.paths.CONFIG + f"/{guild_code_name}/config.json"))) 456 457 if guild_config.is_extension_allowed(self.extension_name): 458 459 if not self.required_roles_ == []: 460 # If the required roles contain 'bot_dev' and the bot dev is running the command allow the command to execute. 461 #---------------------------------------------------------------------------------------------------------------- 462 if "bot_dev" in self.required_roles_: 463 if str(ctx.author.id) in GoldyBot.settings.BOT_DEVS: 464 return True 465 466 # If the required roles contain 'bot_admin' and a bot admin is running the command allow the command to execute. (NEW) 467 #---------------------------------------------------------------------------------------------------------------- 468 if "bot_admin" in self.required_roles_: 469 if str(ctx.author.id) in goldy_config.read("admin_users"): 470 return True 471 472 # Check if member has any of the required roles. 473 #---------------------------------------------------- 474 for role_code_name in self.required_roles_: 475 if not role_code_name in ["bot_dev", "bot_admin"]: 476 role = guild_config.get_role(ctx, role_code_name) 477 if GoldyBot.objects.member.Member(ctx).has_role(role): 478 return True 479 480 raise GoldyBot.errors.MemberHasNoPermsForCommand(f"The member '{ctx.author.name}' does not have the right permissions to use this command.") 481 482 else: 483 return True 484 485 else: 486 raise GoldyBot.errors.GuildNotRegistered(f"The guild '{ctx.guild.name}' has not been registered.")
Checks if the command is allowed to run with current circumstances.
def
get_help_des(self) -> str:
511 def get_help_des(self) -> str: 512 """Returns the command's help description.""" 513 if self.help_des_ == None: 514 try: 515 return (importlib.import_module(f'.{self.command_name}', package="GoldyBot.utility.msgs")).help_des 516 517 except ImportError: 518 GoldyBot.logging.log("info", f"[{MODULE_NAME}] The command '{self.command_name}' does not have a 'msg' module, so the help command will not display a help description for it.") 519 return "None" 520 521 except AttributeError: 522 GoldyBot.logging.log("info", f"[{MODULE_NAME}] The command '{self.command_name}' does not contain 'help_des' variable in it's 'msg' module, so the help command will not display a help description.") 523 return "None" 524 else: 525 return self.help_des_
Returns the command's help description.