feat(12.1-01): cabana.ForbiddenError answers a refused write with 403
- hooks and bulk, record, toolbar and widget actions may return it - 403 forbidden with the localized message and field details; the write's transaction is rolled back; other errors stay the opaque 500 - form shows a refused save as a persistent banner and keeps the values; a refused delete is a toast - smoke tests, OpenAPI notes, dist, README, docs
This commit is contained in:
@@ -255,8 +255,8 @@ func (s *service) allowAction(w http.ResponseWriter, r *http.Request, permission
|
||||
}
|
||||
|
||||
// runAction calls the plugin's Run and writes the D-10 envelope. A
|
||||
// *ValidationError is a 422; any other error is logged and answered with the
|
||||
// generic 500 body, never the error text.
|
||||
// *ValidationError is a 422 and a *ForbiddenError a 403; any other error is
|
||||
// logged and answered with the generic 500 body, never the error text.
|
||||
func (s *service) runAction(w http.ResponseWriter, r *http.Request, cc *CompiledController, action pact.AdminAction, input pact.AdminActionInput, fill []string) {
|
||||
tr := s.translator()
|
||||
ctx := towel.WithLocale(r.Context(), schemaLocale(r.Context(), tr))
|
||||
@@ -267,6 +267,12 @@ func (s *service) runAction(w http.ResponseWriter, r *http.Request, cc *Compiled
|
||||
writeCRUDError(w, err)
|
||||
return
|
||||
}
|
||||
// A refusal (D-27) is a 403 with the action's localized message.
|
||||
var refused *ForbiddenError
|
||||
if errors.As(err, &refused) {
|
||||
writeCRUDError(w, localizeForbidden(ctx, tr, err))
|
||||
return
|
||||
}
|
||||
slog.Error("cabana: admin action failed", "controller", controllerID(cc), "action", action.Name, "field", input.Field, "error", err)
|
||||
WriteError(w, http.StatusInternalServerError, "error", msgServerError)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user