feat(10.1-01): serve controller JS/CSS and run registered toolbar actions
- boardwalk exports ContentType and SetSecurityHeaders
- pact.AdminClientAssets files are read and hashed at boot and served by exact
key under {prefix}/assets/{vendor}/{plugin}/ with nosniff, CSP, CORP,
no-cache and an ETag; a miss falls through to the SPA
- list and form schemas carry assets URLs with a ?v= hash
- toolbar.buttons resolves create, delete and registered actions after decode;
toolbarActions is permission-filtered per admin
- POST .../toolbar/{action} behind requireAjax and action permissions
This commit is contained in:
@@ -223,6 +223,9 @@ func (s *service) mount(r pact.Router) {
|
||||
g.Post("/{vendor}/{plugin}/{controller}/widgets/{field}", requireAjax(s.widgetAction))
|
||||
constrainController(g)
|
||||
g.Where("field", "[A-Za-z_][A-Za-z0-9_]*")
|
||||
g.Post("/{vendor}/{plugin}/{controller}/toolbar/{action}", requireAjax(s.toolbarAction))
|
||||
constrainController(g)
|
||||
g.Where("action", "[A-Za-z_][A-Za-z0-9_]*")
|
||||
g.Get("/{vendor}/{plugin}/{controller}/{id}", s.show)
|
||||
constrainController(g)
|
||||
g.Put("/{vendor}/{plugin}/{controller}/{id}", requireAjax(s.update))
|
||||
@@ -244,6 +247,11 @@ func (s *service) mount(r pact.Router) {
|
||||
// The SPA shell: public, no guard. ServeMux prefers every API pattern
|
||||
// above over the {path...} wildcard.
|
||||
r.GroupRaw(s.adminPrefix(), nil, func(g pact.Router) {
|
||||
// Declared plugin JS and CSS (D-16); a miss falls through to the SPA,
|
||||
// which serves its own dist assets under the same /assets/ path.
|
||||
g.Get("/assets/{vendor}/{plugin}/{file...}", s.pluginAsset)
|
||||
g.Where("vendor", "[A-Za-z0-9_-]+")
|
||||
g.Where("plugin", "[A-Za-z0-9_-]+")
|
||||
g.Get("", s.serveSPA)
|
||||
g.Get("/{path...}", s.serveSPA)
|
||||
})
|
||||
@@ -509,6 +517,7 @@ func (s *service) formSchema(w http.ResponseWriter, r *http.Request) {
|
||||
WriteError(w, http.StatusInternalServerError, "error", msgServerError)
|
||||
return
|
||||
}
|
||||
view.Assets = s.controllerAssets(cc)
|
||||
meta := map[string]any{}
|
||||
if view.Meta.Locale != "" {
|
||||
meta["locale"] = view.Meta.Locale
|
||||
@@ -528,6 +537,16 @@ func (s *service) listSchema(w http.ResponseWriter, r *http.Request) {
|
||||
WriteError(w, http.StatusInternalServerError, "error", msgServerError)
|
||||
return
|
||||
}
|
||||
// Only the registered toolbar actions this admin may run are offered.
|
||||
principal, _ := bouncer.User(r.Context())
|
||||
allowed := make([]ToolbarAction, 0, len(view.ToolbarActions))
|
||||
for _, action := range view.ToolbarActions {
|
||||
if registered, ok := cc.Actions[action.Name]; ok && Allows(principal, registered.Permissions) {
|
||||
allowed = append(allowed, action)
|
||||
}
|
||||
}
|
||||
view.ToolbarActions = allowed
|
||||
view.Assets = s.controllerAssets(cc)
|
||||
meta := map[string]any{}
|
||||
if view.Meta != nil {
|
||||
meta["locale"] = view.Meta.Locale
|
||||
|
||||
Reference in New Issue
Block a user