feat(cabana): add the My account page with subtitle and password change
- lagoon: 202610090001_backend_users_metadata adds WinterCMS's nullable jsonable backend_users.metadata column (TEXT); rollback drops only it - cabana.BackendUser.Metadata and Subtitle read metadata.subtitle leniently (NULL, blank, null, [], invalid JSON and non-strings read as empty) - GET /auth/me returns subtitle; PUT /account edits the signed-in admin's own names, email and subtitle, and the password with current_password; any other key is a 422 and nothing is written - email: required, valid, 6-255 chars, unique against other admins' email and login ignoring case (soft-deleted included); a unique-index race is 422 - a password change sets tokens_valid_after, revokes the presented token and gives a cookie session a fresh cookie - swag annotation, regenerated admin.json and schema.d.ts; route inventories, CSRF walk (27) and OpenAPI conformance learn the route - SPA: My account item in the user menu opens /account (AccountView), which saves through PUT /account and updates the top bar via setCurrentUser - backend::lang.myaccount strings (en, pl), rebuilt boardwalk dist - cabana and lagoon READMEs, users-and-permissions and admin-spa docs
This commit is contained in:
@@ -1,6 +1,35 @@
|
||||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
"cabana.AdminAccountRequest": {
|
||||
"properties": {
|
||||
"current_password": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"first_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"last_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"password_confirmation": {
|
||||
"type": "string"
|
||||
},
|
||||
"subtitle": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"email"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"cabana.AdminActionRequest": {
|
||||
"properties": {
|
||||
"payload": {
|
||||
@@ -149,6 +178,10 @@
|
||||
},
|
||||
"role": {
|
||||
"$ref": "#/components/schemas/cabana.AdminRoleSummary"
|
||||
},
|
||||
"subtitle": {
|
||||
"description": "Subtitle is backend_users.metadata.subtitle; \"\" when not set.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -157,7 +190,8 @@
|
||||
"id",
|
||||
"is_superuser",
|
||||
"last_name",
|
||||
"login"
|
||||
"login",
|
||||
"subtitle"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
@@ -2021,6 +2055,83 @@
|
||||
},
|
||||
"openapi": "3.0.3",
|
||||
"paths": {
|
||||
"/account": {
|
||||
"put": {
|
||||
"description": "Saves the signed-in admin's own first name, last name, email and subtitle; the row is the token subject, never a request value. Only the AdminAccountRequest keys are accepted: any other key (login, role_id, is_superuser, permissions, is_activated, id) is a 422 on that key and nothing is written. The email must be valid, 6 to 255 characters, and not equal (ignoring case) the email or login of another admin. A non-empty password needs current_password, at least 4 characters, at most 72 bytes and an equal password_confirmation; it ends every other session, and a cookie session receives a fresh cookie.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/cabana.AdminAccountRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Profile and optional password change",
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/cabana.Envelope-cabana_AdminProfile"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "OK"
|
||||
},
|
||||
"401": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/cabana.ErrorEnvelope"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Unauthorized"
|
||||
},
|
||||
"403": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/cabana.ErrorEnvelope"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Forbidden"
|
||||
},
|
||||
"413": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/cabana.ErrorEnvelope"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Request Entity Too Large"
|
||||
},
|
||||
"422": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/cabana.ErrorEnvelope"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Unprocessable Entity"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"BackendBearer": []
|
||||
}
|
||||
],
|
||||
"summary": "Update my account",
|
||||
"tags": [
|
||||
"admin"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/auth/login": {
|
||||
"post": {
|
||||
"parameters": [
|
||||
@@ -2129,6 +2240,7 @@
|
||||
},
|
||||
"/auth/me": {
|
||||
"get": {
|
||||
"description": "The signed-in admin's profile: login, email, names, the subtitle (backend_users.metadata.subtitle, \"\" when not set), the superuser flag and the role.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
|
||||
Reference in New Issue
Block a user