package cabana import ( "encoding/json" "net/http" "strings" "git.golem15.com/golem15/summercms/bouncer" "git.golem15.com/golem15/summercms/pact" ) // Option is a dropdown choice shared with later schema plans. type Option = pact.Option // ListColumn is one compiled columns.yaml entry, in file order. type ListColumn struct { Key string `json:"key"` Label string `json:"label"` Searchable bool `json:"searchable"` Sortable bool `json:"sortable"` Type string `json:"type,omitempty"` } // ListSchema is the boot-compiled list contract for one controller. type ListSchema struct { Title string `json:"title,omitempty"` RecordsPerPage int `json:"recordsPerPage"` ShowSearch bool `json:"showSearch"` Columns []ListColumn `json:"columns"` } // CompiledController is one admin controller after YAML compilation. type CompiledController struct { PluginID string Controller pact.AdminController List *ListSchema } // Registry is the immutable controller map keyed by controller ID. type Registry struct { byID map[string]*CompiledController } // Get returns the compiled controller for a D-09 id (vendor.plugin.controller). func (r *Registry) Get(id string) (*CompiledController, bool) { if r == nil { return nil, false } cc, ok := r.byID[id] return cc, ok && cc != nil } // Allows reports whether principal satisfies every required permission code. // A nil principal fails. Superusers pass. An empty requirement list allows // any authenticated principal. Grants ending in ".*" match by prefix. func Allows(principal *bouncer.Principal, required []string) bool { if principal == nil { return false } if principal.IsSuperuser || len(required) == 0 { return true } for _, code := range required { if !granted(principal.PermissionGrants, code) { return false } } return true } func granted(grants map[string]bool, code string) bool { if grants[code] { return true } for key, on := range grants { if !on || !strings.HasSuffix(key, ".*") { continue } prefix := strings.TrimSuffix(key, "*") if strings.HasPrefix(code, prefix) { return true } } return false } func requiredOf(ctl pact.AdminController) []string { if p, ok := ctl.(pact.AdminPermissioned); ok && p != nil { return p.RequiredPermissions() } return nil } // WriteData writes a D-10 success envelope. func WriteData(w http.ResponseWriter, status int, data, meta any) { if meta == nil { meta = map[string]any{} } writeJSON(w, status, map[string]any{"data": data, "meta": meta}) } // WriteError writes a D-10 error envelope. details is always an object. func WriteError(w http.ResponseWriter, status int, code, message string) { writeJSON(w, status, map[string]any{ "error": map[string]any{ "code": code, "message": message, "details": map[string]any{}, }, }) } func writeJSON(w http.ResponseWriter, status int, body any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(body) }