- classes.FrontendPermissionCatalog: the seeded rows, then codes activated plugins declare through pact.HasFrontendPermissions (seeded row wins); both permission editors offer it - classes.MCPUserGuard (guard "user"): reads user.api_token, user.scope:* and user.permission:*, allows with the route's checks (session scopes, group grants, every code), dispatches with an in-memory token credential, resolves usr_ personal tokens; registered in *pact.MCPGuards and published as pact.MCPPersonalTokenResolver - GET /_user/api/v1/token/me (user.api_token, user.scope:read) and the MCP tool me (user_me) - pact.MCPSubjectChanged on token revoke, Users saves and User Groups saves and deletes
60 lines
1.9 KiB
Go
60 lines
1.9 KiB
Go
package classes
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"git.golem15.com/golem15/summercms/modules/cabana"
|
|
"git.golem15.com/golem15/summercms/modules/pact"
|
|
"git.golem15.com/golem15/summercms/modules/party"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// FrontendPermissionCatalog is what the user and user group permission
|
|
// editors offer (D-09): the rows of golem15_user_frontend_permissions first,
|
|
// in FrontendPermissionOptions order and unchanged, then the codes activated
|
|
// plugins declare through pact.HasFrontendPermissions, in activation order.
|
|
// A declared code that a seeded row already has is skipped (the seeded row
|
|
// wins), and so is a code an earlier plugin declared; an empty code is
|
|
// skipped. The table, its rows and the stored permissions are never
|
|
// written.
|
|
func FrontendPermissionCatalog(ctx context.Context, app *backpack.App, db *gorm.DB) ([]cabana.PermissionOption, error) {
|
|
rows, err := FrontendPermissionOptions(ctx, db)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
options := make([]cabana.PermissionOption, 0, len(rows))
|
|
seen := make(map[string]bool, len(rows))
|
|
for _, row := range rows {
|
|
option := cabana.PermissionOption{Code: row.Code, Label: row.Label, Tab: row.Tab}
|
|
if row.Comment != nil {
|
|
option.Comment = *row.Comment
|
|
}
|
|
options = append(options, option)
|
|
seen[row.Code] = true
|
|
}
|
|
if app == nil {
|
|
return options, nil
|
|
}
|
|
activated, ok := app.Lookup[party.Activated]()
|
|
if !ok {
|
|
return options, nil
|
|
}
|
|
for _, plugin := range activated {
|
|
declares, ok := plugin.(pact.HasFrontendPermissions)
|
|
if !ok || declares == nil {
|
|
continue
|
|
}
|
|
for _, perm := range declares.FrontendPermissions() {
|
|
code := strings.TrimSpace(perm.Code)
|
|
if code == "" || seen[code] {
|
|
continue
|
|
}
|
|
seen[code] = true
|
|
options = append(options, cabana.PermissionOption{Code: code, Label: perm.Label, Tab: perm.Tab, Comment: perm.Comment})
|
|
}
|
|
}
|
|
return options, nil
|
|
}
|