feat(16.3-01): account token API with OpenAPI and phrase keys

- Add list/create/revoke/scopes handlers, validation, and soft revoke
- Regenerate admin OpenAPI and TS types; inventory and conformance cases
- Add server-side api_tokens phrase keys (en/pl)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-11 01:51:11 +02:00
parent 183583e0e9
commit ffdb5d00ca
13 changed files with 1430 additions and 49 deletions

View File

@@ -540,6 +540,27 @@ func conformCases() []conformCase {
}
return rec
}, into[cabana.Envelope[cabana.AdminProfile]](), nil},
{"POST /account/tokens", 201, "cabana.Envelope-cabana_AdminAPITokenCreated", func(t *testing.T, e *conformEnv) *httptest.ResponseRecorder {
rec := e.send(t, http.MethodPost, "/account/tokens", map[string]any{"name": "conform", "expires": "90d", "scopes": []string{"*"}}, true)
var body cabana.Envelope[cabana.AdminAPITokenCreated]
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil || body.Data.Token == "" || body.Data.ID == 0 {
t.Fatalf("token create body = %s (%v)", rec.Body.String(), err)
}
e.tokenID = body.Data.ID
return rec
}, into[cabana.Envelope[cabana.AdminAPITokenCreated]](), nil},
{"GET /account/tokens", 200, "cabana.Envelope-array_cabana_AdminAPIToken", func(t *testing.T, e *conformEnv) *httptest.ResponseRecorder {
return e.send(t, http.MethodGet, "/account/tokens", nil, true)
}, into[cabana.Envelope[[]cabana.AdminAPIToken]](), nil},
{"GET /account/tokens/scopes", 200, "cabana.Envelope-array_cabana_AdminAPITokenScope", func(t *testing.T, e *conformEnv) *httptest.ResponseRecorder {
return e.send(t, http.MethodGet, "/account/tokens/scopes", nil, true)
}, into[cabana.Envelope[[]cabana.AdminAPITokenScope]](), nil},
{"DELETE /account/tokens/{id}", 200, "cabana.Envelope-cabana_AdminAPIToken", func(t *testing.T, e *conformEnv) *httptest.ResponseRecorder {
if e.tokenID == 0 {
t.Fatal("token id missing from create case")
}
return e.send(t, http.MethodDelete, fmt.Sprintf("/account/tokens/%d", e.tokenID), nil, true)
}, into[cabana.Envelope[cabana.AdminAPIToken]](), nil},
{"POST /auth/logout", 200, "cabana.Envelope-cabana_AdminLogoutData", func(t *testing.T, e *conformEnv) *httptest.ResponseRecorder {
return e.send(t, http.MethodPost, "/auth/logout", nil, true)
}, into[cabana.Envelope[cabana.AdminLogoutData]](), nil},
@@ -603,6 +624,7 @@ type conformEnv struct {
partID uint
partFileID uint
childKey string
tokenID uint
}
// sendWith sends a raw body with extra headers through the assembled router.