Files
bot_ticket_r6_elite/internal/tickets/auth.go
T
2026-05-10 18:07:51 +02:00

110 lines
2.3 KiB
Go

package tickets
import (
"github.com/leolionad58/ticketbot/internal/config"
"github.com/leolionad58/ticketbot/internal/db"
)
type Action int
const (
ActionAdmin Action = iota
ActionClaim
ActionClose
ActionAdd
ActionRemove
ActionRename
ActionTranscript
ActionConvocation
ActionReclaim
)
type AuthService struct {
Config *config.Provider
}
func NewAuthService(cfg *config.Provider) *AuthService {
return &AuthService{Config: cfg}
}
// CanClose returns true if the user can close the given ticket.
// Ticket owner can close if status is 'open' (not yet claimed). Staff/admin can always close.
func (a *AuthService) CanClose(memberRoles []string, userID string, ticket *db.Ticket) bool {
if ticket == nil {
return false
}
// Owner can close their own unclaimed ticket
if userID == ticket.UserID && ticket.Status == "open" {
return true
}
return a.Can(memberRoles, ActionClose, ticket)
}
// Can returns true if the member (by their role IDs) is authorized to perform action on ticket.
// ticket may be nil for actions that don't require a specific ticket context (e.g. ActionAdmin, ActionConvocation).
func (a *AuthService) Can(memberRoles []string, action Action, ticket *db.Ticket) bool {
cfg := a.Config.Get()
hasRole := func(roleID string) bool {
for _, r := range memberRoles {
if r == roleID {
return true
}
}
return false
}
isAdmin := hasRole(cfg.Bot.AdminRole)
staffRoleForTicket := func() string {
if ticket == nil {
return ""
}
// Prefer role stored on the ticket itself (populated at open time for DB panels)
if ticket.StaffRoleID != "" {
return ticket.StaffRoleID
}
if p, ok := cfg.Panels[ticket.Panel]; ok {
if t, ok := p.Types[ticket.Type]; ok {
return t.StaffRole
}
}
return ""
}
switch action {
case ActionAdmin:
return isAdmin
case ActionClaim:
if isAdmin {
return true
}
role := staffRoleForTicket()
return role != "" && hasRole(role)
case ActionClose, ActionAdd, ActionRemove, ActionRename, ActionTranscript, ActionReclaim:
if isAdmin {
return true
}
role := staffRoleForTicket()
return role != "" && hasRole(role)
case ActionConvocation:
if isAdmin {
return true
}
for _, panel := range cfg.Panels {
for _, t := range panel.Types {
if hasRole(t.StaffRole) {
return true
}
}
}
return false
default:
return false
}
}