|
1 | 1 | from __future__ import annotations
|
2 | 2 |
|
3 |
| -from typing import TYPE_CHECKING, Optional |
| 3 | +from typing import TYPE_CHECKING, Annotated, Optional |
4 | 4 |
|
5 | 5 | import asyncpg
|
6 | 6 | import discord
|
7 | 7 | import msgspec
|
8 | 8 | from async_lru import alru_cache
|
| 9 | +from discord import app_commands |
9 | 10 | from discord.ext import commands
|
10 | 11 | from libs.utils import GuildContext
|
11 | 12 | from libs.utils.checks import bot_check_permissions, check_permissions
|
| 13 | +from libs.utils.embeds import Embed |
| 14 | +from libs.utils.prefix import get_prefix |
12 | 15 |
|
13 | 16 | if TYPE_CHECKING:
|
14 | 17 | from rodhaj import Rodhaj
|
@@ -96,6 +99,16 @@ class SetupFlags(commands.FlagConverter):
|
96 | 99 | )
|
97 | 100 |
|
98 | 101 |
|
| 102 | +class PrefixConverter(commands.Converter): |
| 103 | + async def convert(self, ctx: commands.Context, argument: str): |
| 104 | + user_id = ctx.bot.user.id |
| 105 | + if argument.startswith((f"<@{user_id}>", f"<@!{user_id}>")): |
| 106 | + raise commands.BadArgument("That is a reserved prefix already in use.") |
| 107 | + if len(argument) > 100: |
| 108 | + raise commands.BadArgument("That prefix is too long.") |
| 109 | + return argument |
| 110 | + |
| 111 | + |
99 | 112 | class Config(commands.Cog):
|
100 | 113 | """Config and setup commands for Rodhaj"""
|
101 | 114 |
|
@@ -334,6 +347,102 @@ async def delete(self, ctx: GuildContext) -> None:
|
334 | 347 | else:
|
335 | 348 | await ctx.send("Cancelling.")
|
336 | 349 |
|
| 350 | + @check_permissions(manage_guild=True) |
| 351 | + @commands.guild_only() |
| 352 | + @config.group(name="prefix", fallback="info") |
| 353 | + async def prefix(self, ctx: GuildContext) -> None: |
| 354 | + """Manages custom prefixes for the guild. |
| 355 | +
|
| 356 | + Passing in no subcommands will effectively show the currently set prefixes. |
| 357 | + """ |
| 358 | + user_id = self.bot.user.id # type: ignore |
| 359 | + prefixes = await get_prefix(self.bot, ctx.message) |
| 360 | + cleaned = ", ".join( |
| 361 | + f"`{prefix}`" for prefix in prefixes if str(user_id) not in prefix |
| 362 | + ) |
| 363 | + embed = Embed() |
| 364 | + embed.add_field(name="Prefixes", value=cleaned) |
| 365 | + embed.set_author(name=ctx.guild.name, icon_url=ctx.guild.icon.url) # type: ignore |
| 366 | + await ctx.send(embed=embed) |
| 367 | + |
| 368 | + @prefix.command(name="add") |
| 369 | + @app_commands.describe(prefix="The new prefix to add") |
| 370 | + async def prefix_add( |
| 371 | + self, ctx: GuildContext, prefix: Annotated[str, PrefixConverter] |
| 372 | + ) -> None: |
| 373 | + """Adds an custom prefix""" |
| 374 | + prefixes = await get_prefix(self.bot, ctx.message) |
| 375 | + if isinstance(prefixes, list) and len(prefixes) > 12 or prefix in prefixes: |
| 376 | + desc = ( |
| 377 | + "There was a validation issue. " |
| 378 | + "This is caused by these reasons: \n" |
| 379 | + "- You have more than 12 prefixes for your server\n" |
| 380 | + "- Your prefix fails the validation rules\n" |
| 381 | + "- The prefix you want to set already exists" |
| 382 | + ) |
| 383 | + await ctx.send(desc) |
| 384 | + return |
| 385 | + |
| 386 | + query = """ |
| 387 | + UPDATE guild_config |
| 388 | + SET prefix = ARRAY_APPEND(prefix, $1) |
| 389 | + WHERE id = $2; |
| 390 | + """ |
| 391 | + await self.pool.execute(query, prefix, ctx.guild.id) |
| 392 | + get_prefix.cache_invalidate(self.bot, ctx.message) |
| 393 | + await ctx.send(f"Added prefix: `{prefix}`") |
| 394 | + |
| 395 | + @prefix.command(name="edit") |
| 396 | + @app_commands.describe( |
| 397 | + old="The prefix to edit", new="A new prefix to replace the old" |
| 398 | + ) |
| 399 | + @app_commands.rename(old="old_prefix", new="new_prefix") |
| 400 | + async def prefix_edit( |
| 401 | + self, |
| 402 | + ctx: GuildContext, |
| 403 | + old: Annotated[str, PrefixConverter], |
| 404 | + new: Annotated[str, PrefixConverter], |
| 405 | + ) -> None: |
| 406 | + """Edits and replaces a prefix""" |
| 407 | + query = """ |
| 408 | + UPDATE guild_config |
| 409 | + SET prefix = ARRAY_REPLACE(prefix, $1, $2) |
| 410 | + WHERE id = $3; |
| 411 | + """ |
| 412 | + prefixes = await get_prefix(self.bot, ctx.message) |
| 413 | + |
| 414 | + guild_id = ctx.guild.id |
| 415 | + if old in prefixes: |
| 416 | + await self.pool.execute(query, old, new, guild_id) |
| 417 | + get_prefix.cache_invalidate(self.bot, ctx.message) |
| 418 | + await ctx.send(f"Prefix updated to from `{old}` to `{new}`") |
| 419 | + else: |
| 420 | + await ctx.send("The prefix is not in the list of prefixes for your server") |
| 421 | + |
| 422 | + @prefix.command(name="delete") |
| 423 | + @app_commands.describe(prefix="The prefix to delete") |
| 424 | + async def prefix_delete( |
| 425 | + self, ctx: GuildContext, prefix: Annotated[str, PrefixConverter] |
| 426 | + ) -> None: |
| 427 | + """Deletes a set prefix""" |
| 428 | + query = """ |
| 429 | + UPDATE guild_config |
| 430 | + SET prefix = ARRAY_REMOVE(prefix, $1) |
| 431 | + WHERE id=$2; |
| 432 | + """ |
| 433 | + msg = f"Do you want to delete the following prefix: {prefix}" |
| 434 | + confirm = await ctx.prompt(msg, timeout=120.0, delete_after=True) |
| 435 | + if confirm: |
| 436 | + await self.pool.execute(query, prefix, ctx.guild.id) |
| 437 | + get_prefix.cache_invalidate(self.bot, ctx.message) |
| 438 | + await ctx.send(f"The prefix `{prefix}` has been successfully deleted") |
| 439 | + return |
| 440 | + elif confirm is None: |
| 441 | + await ctx.send("Confirmation timed out. Cancelled deletion...") |
| 442 | + return |
| 443 | + else: |
| 444 | + await ctx.send("Confirmation cancelled. Please try again") |
| 445 | + |
337 | 446 |
|
338 | 447 | async def setup(bot: Rodhaj) -> None:
|
339 | 448 | await bot.add_cog(Config(bot))
|
0 commit comments