Skip to content

Commit 79a577f

Browse files
committed
feat: bulk override perms for commands
1 parent 6e094af commit 79a577f

File tree

1 file changed

+129
-1
lines changed

1 file changed

+129
-1
lines changed

cogs/utility.py

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1382,7 +1382,7 @@ def _parse_level(name):
13821382

13831383
@permissions.command(name="override")
13841384
@checks.has_permissions(PermissionLevel.OWNER)
1385-
async def permissions_override(self, ctx, command_name: str.lower, *, level_name: str):
1385+
async def permissions_override(self, ctx, command_name: str.lower, *, level_name: str = None):
13861386
"""
13871387
Change a permission level for a specific command.
13881388
@@ -1396,8 +1396,16 @@ async def permissions_override(self, ctx, command_name: str.lower, *, level_name
13961396
- `{prefix}perms remove override reply`
13971397
- `{prefix}perms remove override plugin enabled`
13981398
1399+
You can also override multiple commands at once using:
1400+
- `{prefix}perms override bulk`
1401+
13991402
You can retrieve a single or all command level override(s), see`{prefix}help permissions get`.
14001403
"""
1404+
if command_name == "bulk":
1405+
return await self._bulk_override_flow(ctx)
1406+
1407+
if level_name is None:
1408+
raise commands.MissingRequiredArgument(DummyParam("level_name"))
14011409

14021410
command = self.bot.get_command(command_name)
14031411
if command is None:
@@ -1432,6 +1440,126 @@ async def permissions_override(self, ctx, command_name: str.lower, *, level_name
14321440
)
14331441
return await ctx.send(embed=embed)
14341442

1443+
async def _bulk_override_flow(self, ctx):
1444+
await ctx.send(
1445+
"Please list the commands you want to override. "
1446+
"You can list multiple commands separated by spaces or newlines.\n"
1447+
"Example: `ban, kick, mod`."
1448+
)
1449+
1450+
try:
1451+
msg = await self.bot.wait_for(
1452+
"message",
1453+
check=lambda m: m.author == ctx.author and m.channel == ctx.channel,
1454+
timeout=120.0,
1455+
)
1456+
except asyncio.TimeoutError:
1457+
return await ctx.send("Timed out.")
1458+
1459+
raw_commands = msg.content.replace(",", " ").replace("\n", " ").split(" ")
1460+
# Filter empty strings from split
1461+
raw_commands = [c for c in raw_commands if c.strip()]
1462+
1463+
found_commands = []
1464+
invalid_commands = []
1465+
1466+
for cmd_name in raw_commands:
1467+
cmd = self.bot.get_command(cmd_name)
1468+
if cmd:
1469+
found_commands.append(cmd)
1470+
else:
1471+
invalid_commands.append(cmd_name)
1472+
1473+
if invalid_commands:
1474+
embed = discord.Embed(
1475+
title="Invalid Commands Found",
1476+
description=f"The following commands were not found:\n`{', '.join(invalid_commands)}`\n\n"
1477+
"Do you want to continue with the valid commands? (y/n)",
1478+
color=self.bot.error_color,
1479+
)
1480+
await ctx.send(embed=embed)
1481+
try:
1482+
msg = await self.bot.wait_for(
1483+
"message",
1484+
check=lambda m: m.author == ctx.author and m.channel == ctx.channel,
1485+
timeout=60.0,
1486+
)
1487+
if msg.content.lower() not in ("y", "yes"):
1488+
return await ctx.send("Aborted.")
1489+
except asyncio.TimeoutError:
1490+
return await ctx.send("Timed out.")
1491+
1492+
if not found_commands:
1493+
return await ctx.send("No valid commands provided. Aborting.")
1494+
1495+
# Expand subcommands
1496+
final_commands = set()
1497+
1498+
def add_command_recursive(cmd):
1499+
final_commands.add(cmd)
1500+
if hasattr(cmd, "commands"):
1501+
for sub in cmd.commands:
1502+
add_command_recursive(sub)
1503+
1504+
for cmd in found_commands:
1505+
add_command_recursive(cmd)
1506+
1507+
await ctx.send(
1508+
f"Found {len(final_commands)} commands (including subcommands).\n"
1509+
"What permission level should these commands be set to? (e.g. `Owner`, `Admin`, `Moderator`, `Supporter`, `User`)"
1510+
)
1511+
1512+
try:
1513+
msg = await self.bot.wait_for(
1514+
"message",
1515+
check=lambda m: m.author == ctx.author and m.channel == ctx.channel,
1516+
timeout=60.0,
1517+
)
1518+
except asyncio.TimeoutError:
1519+
return await ctx.send("Timed out.")
1520+
1521+
level_name = msg.content
1522+
level = self._parse_level(level_name)
1523+
if level == PermissionLevel.INVALID:
1524+
return await ctx.send(f"Invalid permission level: `{level_name}`. Aborting.")
1525+
1526+
# Confirmation
1527+
command_list_str = ", ".join(f"`{c.qualified_name}`" for c in sorted(final_commands, key=lambda x: x.qualified_name))
1528+
1529+
# Truncate if too long for embed description
1530+
if len(command_list_str) > 2000:
1531+
command_list_str = command_list_str[:1997] + "..."
1532+
1533+
embed = discord.Embed(
1534+
title="Confirm Bulk Override",
1535+
description=f"**Level:** {level.name}\n\n**Commands:**\n{command_list_str}\n\n"
1536+
"Type `confirm` to apply these changes or `cancel` to abort.",
1537+
color=self.bot.main_color,
1538+
)
1539+
await ctx.send(embed=embed)
1540+
1541+
try:
1542+
msg = await self.bot.wait_for(
1543+
"message",
1544+
check=lambda m: m.author == ctx.author and m.channel == ctx.channel and m.content.lower() in ("confirm", "cancel"),
1545+
timeout=30.0,
1546+
)
1547+
except asyncio.TimeoutError:
1548+
return await ctx.send("Timed out. No changes applied.")
1549+
1550+
if msg.content.lower() == "cancel":
1551+
return await ctx.send("Aborted.")
1552+
1553+
# Apply changes
1554+
count = 0
1555+
for cmd in final_commands:
1556+
self.bot.config["override_command_level"][cmd.qualified_name] = level.name
1557+
count += 1
1558+
1559+
await self.bot.config.update()
1560+
1561+
await ctx.send(f"Successfully updated permissions for {count} commands.")
1562+
14351563
@permissions.command(name="add", usage="[command/level] [name] [user/role]")
14361564
@checks.has_permissions(PermissionLevel.OWNER)
14371565
async def permissions_add(

0 commit comments

Comments
 (0)