From 41686e20b9e9184f8c98f429eef77d7155ef4f09 Mon Sep 17 00:00:00 2001 From: semper-lux Date: Sat, 25 Oct 2025 22:09:20 +0100 Subject: [PATCH] Adds ACL scoping for certain ticket subcommands In particular, adds the `ticket_review` acl action which enables qualifying users to use some ticket subcommands for tickets they do not own. Additionally, made Notes auto-approve. Updated README. --- README.md | 4 ++-- plugins/tickets.py | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c2a503b..c41bb6b 100644 --- a/README.md +++ b/README.md @@ -101,10 +101,10 @@ Manage infractions and administrative actions on a server. Administrative action Upon doing an action, the responsible moderator will DM'ed with a prompt to enter a duration and a comment for their action. The response should be a duration (if omitted -- permanent) followed by a comment. Durations are specified by a numbed followed by: `s`/`sec`/`second`, `m`/`min`,`minute`, `h`/`hr`/`hour`, `d`/`day`, `w`/`wk`/`week`, `M`/`month`, `y`/`yr`/`year`; or `p`/`perm`/`permanent`. If multiple actions are taken, they are put into a queue and prompted one at a time. -If the responsible moderator doesn't match the `auto_approve_tickets` action, the ticket will be marked as "unapproved". +If the responsible moderator doesn't match the `auto_approve_tickets` action, the ticket will be marked as "unapproved". The `ticket_review` action enables qualifying moderators to use with `set`, `append`, and `revert` on tickets they do not own. Commands: -- `note [comment]` -- create a "note" ticket, not associated with any action, merely bearing a comment. If a duration is set, after it expires the ticket is hidden. +- `note [comment]` -- create a "note" ticket, not associated with any action, merely bearing a comment. If a duration is set, after it expires the ticket is hidden. Notes are automatically approved. - `ticket top` -- re-deliver the prompt for comment for the first ticket in your queue. - `ticket queue [mod]` -- display the ticket queue of the specified moderator (or yourself). - `ticket take ` -- assign the specified ticket to yourself. diff --git a/plugins/tickets.py b/plugins/tickets.py index 2e4319c..1e995e1 100644 --- a/plugins/tickets.py +++ b/plugins/tickets.py @@ -67,7 +67,7 @@ from sqlalchemy.schema import DDL, CreateSchema import bot.acl -from bot.acl import EvalResult, privileged +from bot.acl import EvalResult, evaluate_ctx, privileged from bot.client import client from bot.cogs import Cog, cog, command, group import bot.commands @@ -110,6 +110,7 @@ class TicketsConf(Awaitable[None], Protocol): conf: TicketsConf auto_approve_tickets = bot.acl.register_action("auto_approve_tickets") +ticket_review = bot.acl.register_action("ticket_review") cleanup_exempt: Set[int] = set() @@ -1721,7 +1722,7 @@ async def note_command(self, ctx: Context, target: PartialUserConverter, *, note note, modid=ctx.author.id, targetid=target.id, - approved=auto_approve_tickets.evaluate(ctx.author, None) == EvalResult.TRUE, + approved=True, ) if not ticket.approved: update_unapproved_list.run_coalesced(30) @@ -1821,6 +1822,10 @@ async def ticket_set( async with sessionmaker() as session: tkt = await resolve_ticket(ctx.message.reference, ticket, session) + if tkt.modid != ctx.author.id: + if ticket_review.evaluate(*evaluate_ctx(ctx)) == EvalResult.FALSE: + raise UserError("Insufficient permissions to set a ticket you do not own.") + duration, have_duration, comment = TicketMod.parse_duration_comment(duration_comment) duration, have_duration, message = tkt.duration_message(duration, have_duration) if have_duration: @@ -1852,6 +1857,10 @@ async def ticket_append(self, ctx: Context, ticket: Optional[Union[PartialMessag """Append to a ticket's comment.""" async with sessionmaker() as session: tkt = await resolve_ticket(ctx.message.reference, ticket, session) + + if tkt.modid != ctx.author.id: + if ticket_review.evaluate(*evaluate_ctx(ctx)) == EvalResult.FALSE: + raise UserError("Insufficient permissions to append to a ticket you do not own.") if len(tkt.comment or "") + len(comment) > 2000: raise UserError("Cannot append, exceeds maximum comment length!") @@ -1868,6 +1877,10 @@ async def ticket_revert(self, ctx: Context, ticket: Optional[Union[PartialMessag """Manually revert a ticket.""" async with sessionmaker() as session: tkt = await resolve_ticket(ctx.message.reference, ticket, session) + + if tkt.modid != ctx.author.id: + if ticket_review.evaluate(*evaluate_ctx(ctx)) == EvalResult.FALSE: + raise UserError("Insufficient permissions to revert a ticket you do not own.") if not tkt.can_revert: raise UserError("This ticket type ({}) cannot be reverted!".format(tkt.type.value)) if not tkt.status in (TicketStatus.IN_EFFECT, TicketStatus.EXPIRE_FAILED):