Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bot/button/handlers/addadmin.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"github.com/TicketsBot-cloud/worker/bot/command/context"
"github.com/TicketsBot-cloud/worker/bot/customisation"
"github.com/TicketsBot-cloud/worker/bot/dbclient"
"github.com/TicketsBot-cloud/worker/bot/logic"
"github.com/TicketsBot-cloud/common/botpermissions"
"github.com/TicketsBot-cloud/worker/bot/utils"
"github.com/TicketsBot-cloud/worker/i18n"
)
Expand Down Expand Up @@ -210,7 +210,7 @@ func (h *AddAdminHandler) Execute(ctx *context.ButtonContext) {
overwrites := append(ch.PermissionOverwrites, channel.PermissionOverwrite{
Id: id,
Type: mentionableType.OverwriteType(),
Allow: permission.BuildPermissions(logic.StandardPermissions[:]...),
Allow: permission.BuildPermissions(botpermissions.StandardPermissions...),
Deny: 0,
})

Expand Down
4 changes: 2 additions & 2 deletions bot/button/handlers/addsupport.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
cmdregistry "github.com/TicketsBot-cloud/worker/bot/command/registry"
"github.com/TicketsBot-cloud/worker/bot/customisation"
"github.com/TicketsBot-cloud/worker/bot/dbclient"
"github.com/TicketsBot-cloud/worker/bot/logic"
"github.com/TicketsBot-cloud/common/botpermissions"
"github.com/TicketsBot-cloud/worker/bot/utils"
"github.com/TicketsBot-cloud/worker/i18n"
)
Expand Down Expand Up @@ -235,7 +235,7 @@ func updateChannelPermissions(ctx cmdregistry.CommandContext, id uint64, mention
overwrites := append(ch.PermissionOverwrites, channel.PermissionOverwrite{
Id: id,
Type: mentionableType.OverwriteType(),
Allow: permission.BuildPermissions(logic.StandardPermissions[:]...),
Allow: permission.BuildPermissions(botpermissions.StandardPermissions...),
Deny: 0,
})

Expand Down
55 changes: 26 additions & 29 deletions bot/button/handlers/admindebug/server/modals/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"
"time"

"github.com/TicketsBot-cloud/common/botpermissions"
permcache "github.com/TicketsBot-cloud/common/permission"
"github.com/TicketsBot-cloud/database"
"github.com/TicketsBot-cloud/gdl/objects/interaction"
Expand All @@ -20,7 +21,6 @@ import (
"github.com/TicketsBot-cloud/worker/bot/command/context"
"github.com/TicketsBot-cloud/worker/bot/customisation"
"github.com/TicketsBot-cloud/worker/bot/dbclient"
"github.com/TicketsBot-cloud/worker/bot/logic"
"github.com/TicketsBot-cloud/worker/bot/permissionwrapper"
"github.com/TicketsBot-cloud/worker/bot/utils"
)
Expand Down Expand Up @@ -152,23 +152,25 @@ func (h *AdminDebugServerPermissionsModalSubmitHandler) Execute(ctx *context.Mod
}

func processPermissionChecks(selectedValues []string, worker *w.Context, guildId uint64, botMember member.Member, settings database.Settings, panels []database.Panel) ([]string, bool) {
// Server-wide permissions
serverWidePermissions := append(
[]permission.Permission{
// Thread mode specific
// Server-wide permissions depend on the active mode so we don't report
// false failures for permissions that are irrelevant to the current mode
serverWidePermissions := []permission.Permission{
// Required in both modes
permission.ManageWebhooks,
permission.PinMessages,
// Server-wide only
permission.ManageRoles,
}
if settings.UseThreads {
serverWidePermissions = append(serverWidePermissions,
permission.CreatePrivateThreads,
permission.SendMessagesInThreads,
permission.ManageThreads,
// Channel mode specific
permission.ManageChannels,
// Both modes
permission.ManageWebhooks,
permission.PinMessages,
// Server-wide only
permission.ManageRoles,
},
logic.StandardPermissions[:]...,
)
)
} else {
serverWidePermissions = append(serverWidePermissions, permission.ManageChannels)
}
serverWidePermissions = append(serverWidePermissions, botpermissions.StandardPermissions...)

var results []string
var hasMissingPermissions bool
Expand Down Expand Up @@ -256,26 +258,21 @@ func checkPanelPermissions(worker *w.Context, guildId uint64, botMember member.M
var hasMissingPermissions bool

// Determine if this panel uses threads or channels
usesThreads := panel.UseThreads
usesThreads := settings.UseThreads || panel.UseThreads

// Check panel channel permissions (if panel has a channel)
if panel.ChannelId != 0 {
var panelChannelPerms []permission.Permission
if usesThreads {
// Thread mode: specific thread permissions + standard permissions
// Thread mode: permissions needed in the panel channel where threads are created.
panelChannelPerms = append(
[]permission.Permission{
permission.CreatePrivateThreads,
permission.SendMessagesInThreads,
permission.ManageThreads,
permission.ManageWebhooks,
permission.PinMessages,
},
logic.StandardPermissions[:]...,
botpermissions.ThreadModeRequired,
permission.ManageWebhooks,
permission.PinMessages,
)
} else {
// Channel mode: just standard permissions (no special ones needed for panel channel in channel mode)
panelChannelPerms = append([]permission.Permission{}, logic.StandardPermissions[:]...)
panelChannelPerms = append([]permission.Permission{}, botpermissions.StandardPermissions...)
}
result, hasMissing := checkChannelPermissions(worker, panel.ChannelId, botMember, guildId, panelChannelPerms, "Panel Channel")
results = append(results, result)
Expand All @@ -293,7 +290,7 @@ func checkPanelPermissions(worker *w.Context, guildId uint64, botMember member.M
permission.ManageWebhooks,
permission.PinMessages,
},
logic.StandardPermissions[:]...,
botpermissions.StandardPermissions...,
)
result, hasMissing := checkChannelPermissions(worker, panel.TargetCategory, botMember, guildId, categoryPerms, "Category")
results = append(results, result)
Expand All @@ -305,7 +302,7 @@ func checkPanelPermissions(worker *w.Context, guildId uint64, botMember member.M
// Check transcript channel if enabled for this panel
if panel.TranscriptChannelId != nil {
// Transcript channel needs minimal message permissions
transcriptPerms := append([]permission.Permission{}, logic.MinimalPermissions[:]...)
transcriptPerms := append([]permission.Permission{}, botpermissions.MinimalPermissions...)
result, hasMissing := checkChannelPermissions(worker, *panel.TranscriptChannelId, botMember, guildId, transcriptPerms, "Transcript Channel")
results = append(results, result)
if hasMissing {
Expand All @@ -321,7 +318,7 @@ func checkPanelPermissions(worker *w.Context, guildId uint64, botMember member.M
permission.EmbedLinks,
permission.AttachFiles,
},
logic.MinimalPermissions[:]...,
botpermissions.MinimalPermissions...,
)
result, hasMissing := checkChannelPermissions(worker, *settings.TicketNotificationChannel, botMember, guildId, notificationPerms, "Notification Channel")
results = append(results, result)
Expand Down
3 changes: 2 additions & 1 deletion bot/button/handlers/unclaim.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package handlers
import (
"fmt"

"github.com/TicketsBot-cloud/common/botpermissions"
"github.com/TicketsBot-cloud/common/permission"
"github.com/TicketsBot-cloud/database"
"github.com/TicketsBot-cloud/gdl/objects/channel"
Expand Down Expand Up @@ -148,7 +149,7 @@ func (h *UnclaimHandler) Execute(ctx *context.ButtonContext) {
overwrites = append(overwrites, channel.PermissionOverwrite{
Id: whoClaimed,
Type: channel.PermissionTypeMember,
Allow: discordpermission.BuildPermissions(logic.StandardPermissions[:]...),
Allow: discordpermission.BuildPermissions(botpermissions.StandardPermissions...),
Deny: 0,
})
case database.SwitchPanelRemoveOnUnclaim:
Expand Down
116 changes: 73 additions & 43 deletions bot/command/context/replyable.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"time"

"github.com/TicketsBot-cloud/common/botpermissions"
permcache "github.com/TicketsBot-cloud/common/permission"
"github.com/TicketsBot-cloud/common/premium"
"github.com/TicketsBot-cloud/common/sentry"
Expand All @@ -22,7 +23,6 @@ import (
"github.com/TicketsBot-cloud/worker/bot/command/registry"
"github.com/TicketsBot-cloud/worker/bot/customisation"
"github.com/TicketsBot-cloud/worker/bot/dbclient"
"github.com/TicketsBot-cloud/worker/bot/logic"
"github.com/TicketsBot-cloud/worker/bot/permissionwrapper"
"github.com/TicketsBot-cloud/worker/bot/utils"
"github.com/TicketsBot-cloud/worker/config"
Expand Down Expand Up @@ -212,15 +212,21 @@ func (r *Replyable) buildErrorResponse(err error, eventId string, includeInviteL
interactionCtx, ok := r.ctx.(registry.InteractionContext)
docsUrl := fmt.Sprintf("%s/miscellaneous/permissions-explained", config.Conf.Bot.DocsUrl)
if ok {
missingPermissions, err := findMissingPermissions(interactionCtx)
missingByLocation, err := findMissingPermissions(interactionCtx)
if err == nil {
if len(missingPermissions) > 0 {
message = r.GetMessage(i18n.MessageErrorMissingPermissionsTitle) + ":\n"
for _, perm := range missingPermissions {
message += fmt.Sprintf("* `%s`\n", perm.String())
if len(missingByLocation) > 0 {
title := r.GetMessage(i18n.MessageErrorMissingPermissionsTitle) + ":\n"
footer := "\n" + r.GetMessage(i18n.MessageErrorMissingPermissionsBody, docsUrl)

var locationMsg string
for _, loc := range missingByLocation {
locationMsg += fmt.Sprintf("**%s:**\n", loc.label)
for _, perm := range loc.missing {
locationMsg += fmt.Sprintf("* `%s`\n", perm.String())
}
}

message += "\n" + r.GetMessage(i18n.MessageErrorMissingPermissionsBody, docsUrl)
message = title + locationMsg + footer
} else {
message = r.GetMessage(i18n.MessageErrorMissingAccess, docsUrl)
}
Expand Down Expand Up @@ -308,16 +314,19 @@ func (r *Replyable) formatDiscordError(restError request.RestError, eventId stri
r.GetMessage(i18n.MessageErrorId) + ": `" + eventId + "`"
}

func findMissingPermissions(ctx registry.InteractionContext) ([]permission.Permission, error) {
type missingPermLocation struct {
label string
missing []permission.Permission
}

func findMissingPermissions(ctx registry.InteractionContext) ([]missingPermLocation, error) {
if permission.HasPermissionRaw(ctx.InteractionMetadata().AppPermissions, permission.Administrator) {
return nil, nil
}

var useThreads bool
var targetChannelId uint64

settings, err := ctx.Settings()
if err == nil {
settings, settingsErr := ctx.Settings()
if settingsErr == nil {
useThreads = settings.UseThreads
}

Expand All @@ -326,55 +335,76 @@ func findMissingPermissions(ctx registry.InteractionContext) ([]permission.Permi
p, panelExists, err := dbclient.Client.Panel.GetByCustomId(context.Background(), ctx.GuildId(), btnCtx.InteractionData.CustomId)
if err == nil && panelExists {
panel = &p
// Panel can enable threads if global setting is disabled
if !useThreads {
useThreads = panel.UseThreads
}
}
}

checkChannel := func(channelId uint64, label string, required []permission.Permission) missingPermLocation {
missing := permissionwrapper.GetMissingPermissionsChannel(ctx.Worker(), ctx.GuildId(), ctx.Worker().BotId, channelId, required...)
return missingPermLocation{label: label, missing: missing}
}

var locations []missingPermLocation

// 1. Primary location: panel channel (thread mode) or ticket category (channel mode)
var primaryChannelId uint64
var primaryLabel string
var primaryRequired []permission.Permission

if useThreads {
// Thread mode - check permissions in the current channel
targetChannelId = ctx.ChannelId()
primaryChannelId = ctx.ChannelId()
primaryLabel = "Panel channel"
primaryRequired = botpermissions.ThreadModeRequired
} else {
// Channel mode - check permissions in the ticket category
primaryLabel = "Ticket category"
primaryRequired = botpermissions.ChannelModeRequired
if panel != nil && panel.TargetCategory != 0 {
// Use panel's target category
targetChannelId = panel.TargetCategory
primaryChannelId = panel.TargetCategory
} else {
// Fall back to guild default category
targetChannelId, _ = dbclient.Client.ChannelCategory.Get(context.Background(), ctx.GuildId())
primaryChannelId, _ = dbclient.Client.ChannelCategory.Get(context.Background(), ctx.GuildId())
}
}

// Build required permissions based on mode
var requiredPermissions []permission.Permission
if useThreads {
// Thread mode permissions
requiredPermissions = append(
[]permission.Permission{
permission.CreatePrivateThreads,
permission.SendMessagesInThreads,
permission.ManageThreads,
},
logic.StandardPermissions[:]...,
)
if primaryChannelId != 0 {
loc := checkChannel(primaryChannelId, primaryLabel, primaryRequired)
if len(loc.missing) > 0 {
locations = append(locations, loc)
}
} else {
// Channel mode permissions
requiredPermissions = append(
[]permission.Permission{
permission.ManageChannels,
},
logic.StandardPermissions[:]...,
)
missing := permissionwrapper.GetMissingPermissions(ctx.Worker(), ctx.GuildId(), ctx.Worker().BotId, primaryRequired...)
if len(missing) > 0 {
locations = append(locations, missingPermLocation{label: primaryLabel, missing: missing})
}
}

// 2. Notification channel (thread mode only)
if useThreads {
var notifChannelId *uint64
if panel != nil && panel.TicketNotificationChannel != nil {
notifChannelId = panel.TicketNotificationChannel
} else if settingsErr == nil && settings.TicketNotificationChannel != nil {
notifChannelId = settings.TicketNotificationChannel
}
if notifChannelId != nil {
notifRequired := botpermissions.NotifChannelRequired
loc := checkChannel(*notifChannelId, "Notification channel", notifRequired)
if len(loc.missing) > 0 {
locations = append(locations, loc)
}
}
}

if targetChannelId != 0 {
return permissionwrapper.GetMissingPermissionsChannel(ctx.Worker(), ctx.GuildId(), ctx.Worker().BotId, targetChannelId, requiredPermissions...), nil
// 3. Transcript channel (panel-level, both modes)
if panel != nil && panel.TranscriptChannelId != nil {
loc := checkChannel(*panel.TranscriptChannelId, "Transcript channel", botpermissions.TranscriptChannelRequired)
if len(loc.missing) > 0 {
locations = append(locations, loc)
}
}

// If no target channel, just return guild-level missing permissions
return permissionwrapper.GetMissingPermissions(ctx.Worker(), ctx.GuildId(), ctx.Worker().BotId, requiredPermissions...), nil
return locations, nil
}

func formatTimestamp(seconds float64) string {
Expand Down
6 changes: 3 additions & 3 deletions bot/command/impl/tickets/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/TicketsBot-cloud/worker/bot/command/registry"
"github.com/TicketsBot-cloud/worker/bot/customisation"
"github.com/TicketsBot-cloud/worker/bot/dbclient"
"github.com/TicketsBot-cloud/worker/bot/logic"
"github.com/TicketsBot-cloud/common/botpermissions"
"github.com/TicketsBot-cloud/worker/bot/utils"
"github.com/TicketsBot-cloud/worker/i18n"
)
Expand Down Expand Up @@ -238,7 +238,7 @@ func (RemoveCommand) Execute(ctx registry.CommandContext, id uint64) {
Id: id,
Type: channel.PermissionTypeMember,
Allow: 0,
Deny: permission.BuildPermissions(logic.StandardPermissions[:]...),
Deny: permission.BuildPermissions(botpermissions.StandardPermissions...),
}

if err := ctx.Worker().EditChannelPermissions(reasonCtx, ticketChannelId, data); err != nil {
Expand Down Expand Up @@ -322,7 +322,7 @@ func (RemoveCommand) Execute(ctx registry.CommandContext, id uint64) {
Id: id,
Type: channel.PermissionTypeRole,
Allow: 0,
Deny: permission.BuildPermissions(logic.StandardPermissions[:]...),
Deny: permission.BuildPermissions(botpermissions.StandardPermissions...),
}

executor, err := ctx.Member()
Expand Down
3 changes: 2 additions & 1 deletion bot/command/impl/tickets/unclaim.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tickets
import (
"fmt"

"github.com/TicketsBot-cloud/common/botpermissions"
"github.com/TicketsBot-cloud/common/permission"
"github.com/TicketsBot-cloud/database"
"github.com/TicketsBot-cloud/gdl/objects/channel"
Expand Down Expand Up @@ -144,7 +145,7 @@ func (UnclaimCommand) Execute(ctx *context.SlashCommandContext) {
overwrites = append(overwrites, channel.PermissionOverwrite{
Id: whoClaimed,
Type: channel.PermissionTypeMember,
Allow: discordpermission.BuildPermissions(logic.StandardPermissions[:]...),
Allow: discordpermission.BuildPermissions(botpermissions.StandardPermissions...),
Deny: 0,
})
case database.SwitchPanelRemoveOnUnclaim:
Expand Down
Loading