110 lines
3.6 KiB
Go
110 lines
3.6 KiB
Go
// Package rbac is the admin panel's permission catalog.
|
|
//
|
|
// Permissions are "resource:action" strings. The catalog lives in code, not in
|
|
// the database, so a permission can't exist without a route enforcing it, and
|
|
// adding one is a reviewed change. Roles (in admin_roles) are just named sets
|
|
// of these strings.
|
|
package rbac
|
|
|
|
import "slices"
|
|
|
|
// Wildcard grants everything. Only the seeded superadmin role carries it.
|
|
const Wildcard = "*"
|
|
|
|
// ManageStaff is held by superadmins alone: granting, changing, revoking and
|
|
// blocking other staff. It is deliberately absent from Catalog, so no custom
|
|
// role can ever be given it.
|
|
const ManageStaff = "admins:manage"
|
|
|
|
// Permission is one grantable capability.
|
|
type Permission struct {
|
|
Key string `json:"key"`
|
|
Group string `json:"group"`
|
|
Label string `json:"label"`
|
|
}
|
|
|
|
// Catalog is every permission a custom role may hold, grouped for the editor.
|
|
var Catalog = []Permission{
|
|
{"stats:read", "Overview", "View dashboard stats"},
|
|
|
|
{"users:read", "Users", "View users"},
|
|
{"users:notify", "Users", "Send users a message"},
|
|
{"users:ban", "Users", "Ban and unban users"},
|
|
{"users:limits", "Users", "Change bookmark and collection limits"},
|
|
{"disciples:manage", "Users", "Link and unlink direct disciples"},
|
|
|
|
{"posts:moderate", "Moderation", "Hide, delete and restore posts"},
|
|
{"comments:moderate", "Moderation", "Delete and restore comments"},
|
|
{"collections:read", "Moderation", "View collections"},
|
|
{"reports:read", "Moderation", "View reports"},
|
|
{"reports:resolve", "Moderation", "Resolve reports"},
|
|
|
|
{"feedback:read", "Feedback", "View feedback"},
|
|
{"feedback:reply", "Feedback", "Reply to feedback"},
|
|
{"feedback:resolve", "Feedback", "Acknowledge and resolve feedback"},
|
|
|
|
{"vani:read", "Vāṇī of the Day", "View the schedule"},
|
|
{"vani:write", "Vāṇī of the Day", "Pin and clear days"},
|
|
|
|
{"rewards:read", "Rewards", "View the reward catalog"},
|
|
{"rewards:write", "Rewards", "Add custom gifts"},
|
|
{"rewards:send", "Rewards", "Send gifts to everyone"},
|
|
{"rewards:delete", "Rewards", "Delete custom gifts"},
|
|
|
|
{"broadcasts:read", "Announcements", "View announcements"},
|
|
{"broadcasts:write", "Announcements", "Create and delete drafts"},
|
|
{"broadcasts:publish", "Announcements", "Publish to everyone"},
|
|
|
|
{"quizzes:read", "Quizzes", "View quizzes"},
|
|
{"quizzes:write", "Quizzes", "Create, edit and publish quizzes"},
|
|
{"quizzes:delete", "Quizzes", "Delete quizzes"},
|
|
{"quizzes:results", "Quizzes", "View participants and responses"},
|
|
{"quizzes:reset", "Quizzes", "Reset a participant's attempt"},
|
|
|
|
{"short_urls:read", "Short URLs", "View short links and stats"},
|
|
}
|
|
|
|
// Valid reports whether p is a grantable permission.
|
|
func Valid(p string) bool {
|
|
return slices.ContainsFunc(Catalog, func(c Permission) bool { return c.Key == p })
|
|
}
|
|
|
|
// Set is a resolved permission set for one staff member.
|
|
type Set struct {
|
|
all bool
|
|
keys map[string]bool
|
|
}
|
|
|
|
// NewSet resolves a role's stored permissions.
|
|
func NewSet(perms []string) Set {
|
|
s := Set{keys: map[string]bool{}}
|
|
for _, p := range perms {
|
|
if p == Wildcard {
|
|
s.all = true
|
|
}
|
|
s.keys[p] = true
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Has reports whether the set grants p.
|
|
func (s Set) Has(p string) bool { return s.all || s.keys[p] }
|
|
|
|
// List is the effective permissions, for the admin UI to decide what to show.
|
|
// A wildcard expands to the full catalog plus ManageStaff.
|
|
func (s Set) List() []string {
|
|
if s.all {
|
|
out := make([]string, 0, len(Catalog)+1)
|
|
for _, c := range Catalog {
|
|
out = append(out, c.Key)
|
|
}
|
|
return append(out, ManageStaff)
|
|
}
|
|
out := make([]string, 0, len(s.keys))
|
|
for k := range s.keys {
|
|
out = append(out, k)
|
|
}
|
|
slices.Sort(out)
|
|
return out
|
|
}
|