- Audience-aware mint, verify, refresh, and backend guard keep frontend tokens compatible - Cabana mounts raw admin login, list schema, and record list behind admin.jwt.secret - Framework migration seeds Winter backend users and developer/publisher roles
60 lines
1.5 KiB
Go
60 lines
1.5 KiB
Go
package cabana
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.golem15.com/golem15/summercms/pact"
|
|
"git.golem15.com/golem15/summercms/party"
|
|
)
|
|
|
|
type controllerRef struct {
|
|
plugin party.Plugin
|
|
ctl pact.AdminController
|
|
}
|
|
|
|
func collectControllers(plugins []party.Plugin) ([]controllerRef, error) {
|
|
var out []controllerRef
|
|
for _, p := range plugins {
|
|
src, ok := p.(pact.HasAdminControllers)
|
|
if !ok || p == nil {
|
|
continue
|
|
}
|
|
for _, ctl := range src.AdminControllers() {
|
|
if ctl == nil {
|
|
continue
|
|
}
|
|
id := ctl.ID()
|
|
if id != p.ID() && !strings.HasPrefix(id, p.ID()+".") {
|
|
return nil, fmt.Errorf("cabana: controller %s is not owned by plugin %s", id, p.ID())
|
|
}
|
|
out = append(out, controllerRef{plugin: p, ctl: ctl})
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func compileRegistry(items []controllerRef) (*Registry, error) {
|
|
byID := make(map[string]*CompiledController, len(items))
|
|
for _, item := range items {
|
|
id := item.ctl.ID()
|
|
if _, exists := byID[id]; exists {
|
|
return nil, fmt.Errorf("cabana: duplicate admin controller %s", id)
|
|
}
|
|
assets, ok := item.plugin.(pact.AdminAssets)
|
|
if !ok || assets == nil || assets.AdminFS() == nil {
|
|
return nil, fmt.Errorf("cabana: plugin %s has admin controllers but no AdminFS", item.plugin.ID())
|
|
}
|
|
list, err := compileList(item.plugin.ID(), item.ctl, assets.AdminFS())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
byID[id] = &CompiledController{
|
|
PluginID: item.plugin.ID(),
|
|
Controller: item.ctl,
|
|
List: list,
|
|
}
|
|
}
|
|
return &Registry{byID: byID}, nil
|
|
}
|