feat(cabana): add markdown preview admin route

- POST {prefix}/api/v1/markdown/preview renders {markdown} through
  cabana.RenderMarkdown in the backend-guarded group behind requireAjax
- refused output is a 422 validation_failed on markdown with a fixed message
- swag annotation, regenerated admin.json and schema.d.ts
- route inventories, CSRF walk (26) and OpenAPI conformance learn the route
- README and docs/backend/forms.md document the route
This commit is contained in:
Jakub Zych
2026-10-06 20:53:07 +02:00
parent 0ff928d6cf
commit b492e79f2b
13 changed files with 517 additions and 6 deletions

View File

@@ -0,0 +1,33 @@
package cabana_test
import (
"net/http"
"strings"
"testing"
)
// TestMarkdownPreviewRoute drives POST /markdown/preview through the
// assembled router: without credentials the backend guard answers 401, and a
// signed-in administrator gets the sanitized rendering with raw script tags
// stripped by the renderer.
func TestMarkdownPreviewRoute(t *testing.T) {
env := newConformEnv(t)
anon := env.send(t, http.MethodPost, "/markdown/preview", map[string]string{"markdown": "# Hello"}, false)
if anon.Code != http.StatusUnauthorized {
t.Fatalf("anonymous status=%d body=%s", anon.Code, anon.Body.String())
}
env.loginAs(t, env.login)
rec := env.send(t, http.MethodPost, "/markdown/preview", map[string]string{"markdown": "# Hello\n\n<script>alert(1)</script>"}, true)
if rec.Code != http.StatusOK {
t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String())
}
body := strings.ToLower(rec.Body.String())
if strings.Contains(body, "<script") || strings.Contains(body, `<script`) {
t.Fatalf("script survived: %s", rec.Body.String())
}
if !strings.Contains(body, "hello") || !strings.Contains(body, "h1") {
t.Fatalf("heading missing: %s", rec.Body.String())
}
}