Skip to content

Commit da6dff2

Browse files
lorenzo132sebkuip
authored andcommitted
feat: bulk override perms for commands
1 parent 0df325d commit da6dff2

1 file changed

Lines changed: 129 additions & 1 deletion

File tree

cogs/utility.py

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

14091409
@permissions.command(name="override")
14101410
@checks.has_permissions(PermissionLevel.OWNER)
1411-
async def permissions_override(self, ctx, command_name: str.lower, *, level_name: str):
1411+
async def permissions_override(self, ctx, command_name: str.lower, *, level_name: str = None):
14121412
"""
14131413
Change a permission level for a specific command.
14141414
@@ -1422,8 +1422,16 @@ async def permissions_override(self, ctx, command_name: str.lower, *, level_name
14221422
- `{prefix}perms remove override reply`
14231423
- `{prefix}perms remove override plugin enabled`
14241424
1425+
You can also override multiple commands at once using:
1426+
- `{prefix}perms override bulk`
1427+
14251428
You can retrieve a single or all command level override(s), see`{prefix}help permissions get`.
14261429
"""
1430+
if command_name == "bulk":
1431+
return await self._bulk_override_flow(ctx)
1432+
1433+
if level_name is None:
1434+
raise commands.MissingRequiredArgument(DummyParam("level_name"))
14271435

14281436
command = self.bot.get_command(command_name)
14291437
if command is None:
@@ -1458,6 +1466,126 @@ async def permissions_override(self, ctx, command_name: str.lower, *, level_name
14581466
)
14591467
return await ctx.send(embed=embed)
14601468

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

0 commit comments

Comments
 (0)