diff --git a/bot/logic/open.go b/bot/logic/open.go index b2f3da5b..1f87017a 100644 --- a/bot/logic/open.go +++ b/bot/logic/open.go @@ -66,7 +66,7 @@ func OpenTicket(ctx context.Context, cmd registry.InteractionContext, panel *dat // Make sure ticket count is within ticket limit // Check ticket limit before ratelimit token to prevent 1 person from stopping everyone opening tickets - violatesTicketLimit, limit := getTicketLimit(ctx, cmd) + violatesTicketLimit, limit := getTicketLimit(ctx, cmd, panel) if violatesTicketLimit { // Notify the user ticketsPluralised := "ticket" @@ -794,7 +794,7 @@ func refreshCachedChannels(ctx context.Context, worker *worker.Context, guildId } // has hit ticket limit, ticket limit -func getTicketLimit(ctx context.Context, cmd registry.CommandContext) (bool, int) { +func getTicketLimit(ctx context.Context, cmd registry.CommandContext, panel *database.Panel) (bool, int) { isStaff, err := cmd.UserPermissionLevel(ctx) if err != nil { sentry.ErrorWithContext(err, cmd.ToErrorContext()) @@ -805,28 +805,39 @@ func getTicketLimit(ctx context.Context, cmd registry.CommandContext) (bool, int return false, 50 } - var openedTickets []database.Ticket + var openTicketCount int var ticketLimit uint8 group, _ := errgroup.WithContext(ctx) - // get ticket limit - group.Go(func() (err error) { - ticketLimit, err = dbclient.Client.TicketLimit.Get(ctx, cmd.GuildId()) - return - }) + // If panel has a per-panel limit, use it and count only panel tickets + if panel != nil && panel.TicketLimit != nil { + ticketLimit = *panel.TicketLimit - group.Go(func() (err error) { - openedTickets, err = dbclient.Client.Tickets.GetOpenByUser(ctx, cmd.GuildId(), cmd.UserId()) - return - }) + group.Go(func() (err error) { + openTicketCount, err = dbclient.Client.Tickets.GetOpenCountByUserAndPanel( + ctx, cmd.GuildId(), cmd.UserId(), panel.PanelId) + return + }) + } else { + // Use global limit and count all tickets + group.Go(func() (err error) { + ticketLimit, err = dbclient.Client.TicketLimit.Get(ctx, cmd.GuildId()) + return + }) + + group.Go(func() (err error) { + openTicketCount, err = dbclient.Client.Tickets.GetOpenCountByUser(ctx, cmd.GuildId(), cmd.UserId()) + return + }) + } if err := group.Wait(); err != nil { sentry.ErrorWithContext(err, cmd.ToErrorContext()) return true, 1 } - return len(openedTickets) >= int(ticketLimit), int(ticketLimit) + return openTicketCount >= int(ticketLimit), int(ticketLimit) } func createWebhook(ctx context.Context, c registry.CommandContext, ticketId int, guildId, channelId uint64) error { diff --git a/bot/logic/reopen.go b/bot/logic/reopen.go index 44a1e4fd..e9cd7ff8 100644 --- a/bot/logic/reopen.go +++ b/bot/logic/reopen.go @@ -10,10 +10,23 @@ import ( "github.com/TicketsBot-cloud/worker/bot/customisation" "github.com/TicketsBot-cloud/worker/bot/dbclient" "github.com/TicketsBot-cloud/worker/bot/utils" + "github.com/TicketsBot-cloud/database" "github.com/TicketsBot-cloud/worker/i18n" ) func ReopenTicket(ctx context.Context, cmd registry.CommandContext, ticketId int) { + // Get the ticket first so we can check per-panel limits + ticket, err := dbclient.Client.Tickets.Get(ctx, ticketId, cmd.GuildId()) + if err != nil { + cmd.HandleError(err) + return + } + + if ticket.Id == 0 || ticket.GuildId != cmd.GuildId() { + cmd.Reply(customisation.Red, i18n.Error, i18n.MessageReopenTicketNotFound) + return + } + // Check ticket limit permLevel, err := cmd.UserPermissionLevel(ctx) if err != nil { @@ -22,36 +35,51 @@ func ReopenTicket(ctx context.Context, cmd registry.CommandContext, ticketId int } if permLevel == permission.Everyone { - ticketLimit, err := dbclient.Client.TicketLimit.Get(ctx, cmd.GuildId()) - if err != nil { - cmd.HandleError(err) - return + // Fetch panel if ticket has one for per-panel limit check + var panel *database.Panel + if ticket.PanelId != nil { + p, err := dbclient.Client.Panel.GetById(ctx, *ticket.PanelId) + if err != nil { + cmd.HandleError(err) + return + } + if p.PanelId != 0 { + panel = &p + } } - // TODO: count() - openTickets, err := dbclient.Client.Tickets.GetOpenByUser(ctx, cmd.GuildId(), cmd.UserId()) - if err != nil { - cmd.HandleError(err) - return + var ticketLimit uint8 + var openTicketCount int + + if panel != nil && panel.TicketLimit != nil { + // Use per-panel limit and count only panel tickets + ticketLimit = *panel.TicketLimit + openTicketCount, err = dbclient.Client.Tickets.GetOpenCountByUserAndPanel(ctx, cmd.GuildId(), cmd.UserId(), panel.PanelId) + if err != nil { + cmd.HandleError(err) + return + } + } else { + // Use global limit and count all tickets + ticketLimit, err = dbclient.Client.TicketLimit.Get(ctx, cmd.GuildId()) + if err != nil { + cmd.HandleError(err) + return + } + + openTicketCount, err = dbclient.Client.Tickets.GetOpenCountByUser(ctx, cmd.GuildId(), cmd.UserId()) + if err != nil { + cmd.HandleError(err) + return + } } - if len(openTickets) >= int(ticketLimit) { + if openTicketCount >= int(ticketLimit) { cmd.Reply(customisation.Green, i18n.Error, i18n.MessageTicketLimitReached) return } } - ticket, err := dbclient.Client.Tickets.Get(ctx, ticketId, cmd.GuildId()) - if err != nil { - cmd.HandleError(err) - return - } - - if ticket.Id == 0 || ticket.GuildId != cmd.GuildId() { - cmd.Reply(customisation.Red, i18n.Error, i18n.MessageReopenTicketNotFound) - return - } - // Ensure user has permissino to reopen the ticket hasPermission, err := HasPermissionForTicket(ctx, cmd.Worker(), ticket, cmd.UserId()) if err != nil { diff --git a/go.mod b/go.mod index 660035dd..61b3bf86 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/TicketsBot-cloud/analytics-client v0.0.0-20250604180646-6606dfc8fc8c github.com/TicketsBot-cloud/archiverclient v0.0.0-20251015181023-f0b66a074704 github.com/TicketsBot-cloud/common v0.0.0-20260210203202-54154661338e - github.com/TicketsBot-cloud/database v0.0.0-20260215113825-54c67fb267fc + github.com/TicketsBot-cloud/database v0.0.0-20260217113520-9cc86e3b374b github.com/TicketsBot-cloud/gdl v0.0.0-20260213180045-11af01c262ca github.com/caarlos0/env/v10 v10.0.0 github.com/elliotchance/orderedmap v1.8.0 diff --git a/go.sum b/go.sum index a35a124f..1d355629 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ github.com/TicketsBot-cloud/archiverclient v0.0.0-20251015181023-f0b66a074704 h1 github.com/TicketsBot-cloud/archiverclient v0.0.0-20251015181023-f0b66a074704/go.mod h1:Mux1bEPpOHwRw1wo6Fa6qJLJH9Erk9qv1yAIfLi1Wmw= github.com/TicketsBot-cloud/common v0.0.0-20260210203202-54154661338e h1:nFKV7yEm8MWbCP7dtsJ88+agcxDUD0YKIotVHMVvytw= github.com/TicketsBot-cloud/common v0.0.0-20260210203202-54154661338e/go.mod h1:tGrTHFz09OM3eDWF+62hIi9ELpT4igCFi868FKSvKBg= -github.com/TicketsBot-cloud/database v0.0.0-20260215113825-54c67fb267fc h1:9fQmqYQN7Hc85ds+uklaNU1ab199NAhpT5A3fQ3P8g8= -github.com/TicketsBot-cloud/database v0.0.0-20260215113825-54c67fb267fc/go.mod h1:HQXAgmNSm7/FmBYwcsa6qpZqMrDhbLoEl+AyqFQ+RwY= +github.com/TicketsBot-cloud/database v0.0.0-20260217113520-9cc86e3b374b h1:nE8VAv13rUPOSMTnULKsuCDHXlWnbst7DmocviUN6I8= +github.com/TicketsBot-cloud/database v0.0.0-20260217113520-9cc86e3b374b/go.mod h1:HQXAgmNSm7/FmBYwcsa6qpZqMrDhbLoEl+AyqFQ+RwY= github.com/TicketsBot-cloud/gdl v0.0.0-20260213180045-11af01c262ca h1:/HRqcgOPfv6d9NzE6CqHXN4U1QgElyJ9DcxNNT8kV6g= github.com/TicketsBot-cloud/gdl v0.0.0-20260213180045-11af01c262ca/go.mod h1:CdwBR2egPtxUXjD2CgC9ZwfuB8dz9HPePM8nuG6dt7Y= github.com/TicketsBot-cloud/logarchiver v0.0.0-20251018211319-7a7df5cacbdc h1:qTLNpCvIqM7UwZ6MdWQ9EztcDsIJfHh+VJdG+ULLEaA=