refac: DELETE /v1/user/{id}?expected_role_id=N, user.remove audit event, 409 target_role_not_found, GetAll returns its error, Own-scope visibility filter moved into repos, JSON tags removed from use-case types
This commit is contained in:
1 parent
5d6f378fce
commit
b39a41be88
124 files changed
+8816
-523
No files matched your search
@@ -1,5 +1,5 @@
|
||||
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
||||
export type AccessLevel = 'Public' | 'Verified user' | 'Owner or admin' | 'Owner only'
|
||||
export type AccessLevel = 'Public' | 'Verified user' | 'Needs permission' | 'Owner only'
|
||||
|
||||
export interface ApiField {
|
||||
name: string
|
||||
@@ -94,7 +94,7 @@ export const API_KEY_PLACEHOLDER = 'rcms_Kf3x9QwL0aBc…'
|
||||
export const NO_CONTENT_RESPONSE = '204 No Content'
|
||||
export const SESSION_REQUIRED_MESSAGE = 'This action needs a real session.'
|
||||
export const OWNER_REQUIRED_MESSAGE = 'missing_permission'
|
||||
export const OWNER_OR_ADMIN_MESSAGE = 'missing_permission'
|
||||
export const MISSING_PERMISSION_BODY = 'missing_permission'
|
||||
export const IMAGES_AFTER_GROUP = 'sites'
|
||||
export const FIELD_TYPES_ANCHOR = 'ct-fields'
|
||||
export const LOGIN_FAMILY_CAPTION = 'Made for the browser. A key is ignored here, with no 403.'
|
||||
@@ -649,7 +649,7 @@ const literal = (status: number, caption: string, tail?: string): ApiError => ({
|
||||
})
|
||||
|
||||
const e401 = e(401, UNAUTHORIZED)
|
||||
const eOwnerOrAdmin = e(403, OWNER_OR_ADMIN_MESSAGE)
|
||||
const eMissingPermission = literal(403, MISSING_PERMISSION_BODY)
|
||||
const contentTypeNotFound = literal(404, 'content_type_not_found')
|
||||
const entryNotFound = literal(404, 'entry_not_found')
|
||||
const invalidEntryUnique = literal(409, 'invalid_entry: title must be unique')
|
||||
@@ -662,11 +662,7 @@ const verified = (errors: ApiError[]) => [...errors, e(403, VERIFY_REQUIRED)]
|
||||
const verifiedAfterLogin = (errors: ApiError[]) =>
|
||||
errors.flatMap((error) => (error.status === 401 ? [error, e(403, VERIFY_REQUIRED)] : [error]))
|
||||
|
||||
const ownerOrAdminErrors = (...own: ApiError[]) => [
|
||||
...own,
|
||||
e(401, UNAUTHORIZED),
|
||||
e(403, OWNER_OR_ADMIN_MESSAGE),
|
||||
]
|
||||
const permissionErrors = (...own: ApiError[]) => [...own, e(401, UNAUTHORIZED), eMissingPermission]
|
||||
|
||||
const articlePage = () => ({
|
||||
items: [
|
||||
@@ -1032,7 +1028,7 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
key: 'ctypes',
|
||||
title: 'Content types',
|
||||
description:
|
||||
'Define your own kind of content, like events or recipes. An owner or admin creates a type made of 1 to 50 ordered fields; the type then has its own entry routes.',
|
||||
'Define your own kind of content, like events or recipes. A user whose role can create and edit content types defines a type made of 1 to 50 ordered fields; the type then has its own entry routes.',
|
||||
note: 'A content type has a `key` (2 to 40 lowercase letters, digits or hyphens, chosen at creation and never changed) and fields. Each field has a `key` (letters, digits and underscores, starting with a letter), a `label`, a `type` and rules.',
|
||||
fieldTypes: FIELD_TYPE_ROWS,
|
||||
snippet: { key: 'field', label: 'Field object', code: json(eventFields[2]) },
|
||||
@@ -1059,12 +1055,12 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
'ct-create',
|
||||
'POST',
|
||||
'/v1/content-type/',
|
||||
'Create a content type.',
|
||||
'Owner or admin',
|
||||
'Create a content type. Needs the permission "Create and edit content types".',
|
||||
'Needs permission',
|
||||
[
|
||||
e(400, BODY_MISMATCH),
|
||||
e401,
|
||||
eOwnerOrAdmin,
|
||||
eMissingPermission,
|
||||
literal(409, 'content_type_key_taken'),
|
||||
],
|
||||
json(eventType),
|
||||
@@ -1095,12 +1091,12 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
'ct-update',
|
||||
'PUT',
|
||||
'/v1/content-type/{key}',
|
||||
"Replace the name, icon and fields of a type. The key never changes. Saved field keys and types can't change.",
|
||||
'Owner or admin',
|
||||
'Replace the name, icon and fields of a type. The key never changes. Saved field keys and types can\'t change. Needs the permission "Create and edit content types".',
|
||||
'Needs permission',
|
||||
[
|
||||
e(400, BODY_MISMATCH),
|
||||
e401,
|
||||
eOwnerOrAdmin,
|
||||
eMissingPermission,
|
||||
contentTypeNotFound,
|
||||
literal(
|
||||
409,
|
||||
@@ -1128,11 +1124,11 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
'ct-delete',
|
||||
'DELETE',
|
||||
'/v1/content-type/{key}',
|
||||
'Delete a content type. Only possible when it has no entries and no relation field points at it.',
|
||||
'Owner or admin',
|
||||
'Delete a content type. Only possible when it has no entries and no relation field points at it. Needs the permission "Delete content types".',
|
||||
'Needs permission',
|
||||
[
|
||||
e401,
|
||||
eOwnerOrAdmin,
|
||||
eMissingPermission,
|
||||
contentTypeNotFound,
|
||||
literal(409, 'content_type_has_entries'),
|
||||
literal(409, 'content_type_referenced'),
|
||||
@@ -1145,7 +1141,7 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
key: 'entries',
|
||||
title: 'Entries',
|
||||
description:
|
||||
'Read and write the content of a custom type. Any verified user can write entries.',
|
||||
"Read and write the content of a custom type. Each route needs the matching content permission of the key creator's role.",
|
||||
note: "An entry's `data` is an object keyed by field key, validated against the type. Responses add `media` (the resolved images for media fields, keyed by field key: id, filename, width, height, size and thumbnail_url, or { id, missing: true } if the image was deleted) and `relations` (the resolved first field of related entries).",
|
||||
snippet: { key: 'entry', label: 'Entry', code: json(eventEntry()) },
|
||||
endpoints: [
|
||||
@@ -1258,9 +1254,9 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
'bt-list',
|
||||
'GET',
|
||||
'/v1/builtin-type/',
|
||||
'List the built-in types (Articles, Authors, Sites, Media, Users) and their fields. Keys are article, author, site, media and user.',
|
||||
'Owner or admin',
|
||||
[e401, eOwnerOrAdmin],
|
||||
'List the built-in types (Articles, Authors, Sites, Media, Users) and their fields. Keys are article, author, site, media and user. Needs the permission "View content types".',
|
||||
'Needs permission',
|
||||
[e401, eMissingPermission],
|
||||
json([
|
||||
{ key: 'article', name: 'Articles', fields: articleBuiltinFields },
|
||||
{ key: 'author', name: 'Authors', fields: authorBuiltinFields },
|
||||
@@ -1270,9 +1266,9 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
'bt-get',
|
||||
'GET',
|
||||
'/v1/builtin-type/{key}',
|
||||
'Get one built-in type. Keys are article, author, site, media and user.',
|
||||
'Owner or admin',
|
||||
[e401, eOwnerOrAdmin, literal(404, 'builtin_type_not_found')],
|
||||
'Get one built-in type. Keys are article, author, site, media and user. Needs the permission "View content types".',
|
||||
'Needs permission',
|
||||
[e401, eMissingPermission, literal(404, 'builtin_type_not_found')],
|
||||
json({ key: 'author', name: 'Authors', fields: authorBuiltinFields }),
|
||||
),
|
||||
],
|
||||
@@ -1431,18 +1427,18 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
'med-purge-get',
|
||||
'GET',
|
||||
'/v1/media/purge-settings',
|
||||
'Get the automatic duplicate purge settings.',
|
||||
'Owner or admin',
|
||||
ownerOrAdminErrors(),
|
||||
'Get the automatic duplicate purge settings. Needs the permission "View settings".',
|
||||
'Needs permission',
|
||||
permissionErrors(),
|
||||
json(PURGE_SETTINGS),
|
||||
),
|
||||
endpoint(
|
||||
'med-purge-set',
|
||||
'PATCH',
|
||||
'/v1/media/purge-settings',
|
||||
'Turn the automatic purge on or off, or change its interval.',
|
||||
'Owner or admin',
|
||||
ownerOrAdminErrors(e(400, BODY_MISMATCH), e(400, PURGE_INTERVAL)),
|
||||
'Turn the automatic purge on or off, or change its interval. Needs the permission "Edit general settings".',
|
||||
'Needs permission',
|
||||
permissionErrors(e(400, BODY_MISMATCH), e(400, PURGE_INTERVAL)),
|
||||
json(PURGE_SETTINGS),
|
||||
{
|
||||
bodyKind: 'json',
|
||||
@@ -1470,9 +1466,9 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
'med-purge-prev',
|
||||
'GET',
|
||||
'/v1/media/purge-preview',
|
||||
'Preview what a purge would merge. Nothing changes.',
|
||||
'Owner or admin',
|
||||
ownerOrAdminErrors(),
|
||||
'Preview what a purge would merge. Nothing changes. Needs the permission "Delete files".',
|
||||
'Needs permission',
|
||||
permissionErrors(),
|
||||
json({
|
||||
groups: 1,
|
||||
copies: 2,
|
||||
@@ -1494,13 +1490,9 @@ export const API_GROUPS: ApiGroup[] = [
|
||||
'med-purge-run',
|
||||
'POST',
|
||||
'/v1/media/purge',
|
||||
'Merge every group of identical copies. Send the preview fingerprint to refuse a changed library. failed_groups counts groups that could not be purged; the others were still purged.',
|
||||
'Owner or admin',
|
||||
ownerOrAdminErrors(
|
||||
e(400, BODY_MISMATCH),
|
||||
e(409, PURGE_CONFLICT),
|
||||
e(409, PURGE_BUSY),
|
||||
),
|
||||
'Merge every group of identical copies. Send the preview fingerprint to refuse a changed library. failed_groups counts groups that could not be purged; the others were still purged. Needs the permission "Delete files".',
|
||||
'Needs permission',
|
||||
permissionErrors(e(400, BODY_MISMATCH), e(409, PURGE_CONFLICT), e(409, PURGE_BUSY)),
|
||||
json({
|
||||
groups_total: 1,
|
||||
groups_purged: 1,
|
||||
@@ -1885,8 +1877,9 @@ export const ERROR_ROWS: ErrorRow[] = [
|
||||
{
|
||||
status: 403,
|
||||
meaning: 'Forbidden',
|
||||
messages: [SESSION_REQUIRED_MESSAGE, OWNER_OR_ADMIN_MESSAGE, VERIFY_REQUIRED],
|
||||
note: 'Site SEO defaults are owner only. Article SEO fields need only the right to edit the article.',
|
||||
messages: [SESSION_REQUIRED_MESSAGE, VERIFY_REQUIRED],
|
||||
codes: [MISSING_PERMISSION_BODY],
|
||||
note: '`missing_permission` is the literal body, not a sentence. Site SEO defaults need the permission to manage sites. Article SEO fields need only the right to edit the article.',
|
||||
},
|
||||
{
|
||||
status: 404,
|
||||
|
||||
Reference in new issue
Block a user