feat: sites and authors integration into existing screens (& formated all frontend files kinda accidentally)

This commit is contained in:
Florian Sylvain committed 2026-10-15 05:25:44 +02:00
1 parent 3d81d2c717
commit 6b8990c55e
239 files changed
+9194 -1354

No files matched your search

+122 -9
View File
@@ -119,7 +119,12 @@ const ARTICLE_LIST_QUERY: ApiField[] = [
required: false,
rule: 'Up to 200 characters, matched anywhere in the title, ignoring case and accents.',
},
{ name: 'status', type: 'string', required: false, rule: 'online or draft. Default both.' },
{
name: 'status',
type: 'string',
required: false,
rule: 'online or draft. Default both.',
},
{
name: 'sort',
type: 'string',
@@ -209,6 +214,20 @@ const site = (overrides: Record<string, unknown> = {}) => ({
...overrides,
})
const author = (overrides: Record<string, unknown> = {}) => ({
id: 2,
name: 'Inès Duarte',
slug: 'ines-duarte',
bio: 'Site manager and restoration carpenter.',
avatar_id: null,
website: 'https://ines-duarte.example',
social_links: [],
user_id: 3,
is_linked: true,
article_count: 9,
...overrides,
})
const me = {
id: 1,
username: 'marta',
@@ -318,7 +337,11 @@ const ownerOnly = (
'Owner only',
[...errors, e(403, OWNER_REQUIRED_MESSAGE), e(429, TOO_MANY_REQUESTS)],
response,
{ rateLimited: true, pathId: path.includes('{id}') ? 7 : null, ...extra },
{
rateLimited: true,
pathId: path.includes('{id}') ? 7 : null,
...extra,
},
)
export const API_GROUPS: ApiGroup[] = [
@@ -618,7 +641,10 @@ export const API_GROUPS: ApiGroup[] = [
rule: '1 to 365. Leave out to keep the current value.',
},
],
bodySample: { auto_purge_enabled: true, auto_purge_interval_days: 30 },
bodySample: {
auto_purge_enabled: true,
auto_purge_interval_days: 30,
},
},
),
endpoint(
@@ -847,6 +873,52 @@ export const API_GROUPS: ApiGroup[] = [
),
],
},
{
key: 'authors',
title: 'Authors',
description:
'The people credited on articles. Any verified user can read them; changes are made in the browser by an owner or admin.',
endpoints: [
endpoint(
'author-list',
'GET',
'/v1/author/',
'List the authors by name, each with its article count.',
'Verified user',
verified([e(400, 'The page, size or search is not valid.'), e(401, UNAUTHORIZED)]),
json({
items: [
author(),
author({
id: 7,
name: 'Camille Roche',
slug: 'camille-roche',
bio: 'Freelance writer on lime and stone.',
website: null,
user_id: null,
is_linked: false,
article_count: 3,
}),
],
total: 2,
page: 1,
size: 25,
}),
{
query: [
PAGE_QUERY,
SIZE_QUERY,
{
name: 'q',
type: 'string',
required: false,
rule: 'Up to 200 characters, matched in the name or the slug.',
},
],
},
),
],
},
]
const row = (
@@ -891,6 +963,23 @@ export const SESSION_GROUPS: SessionGroup[] = [
row('DELETE', '/v1/site/{id}', 'Delete a site, moving its articles with reassign_to'),
],
},
{
title: 'Authors · owner and admin',
rows: [
row('POST', '/v1/author/', 'Create an author'),
row(
'PATCH',
'/v1/author/{id}',
'Edit an author, or your own author as a verified user',
),
row(
'DELETE',
'/v1/author/{id}',
'Delete an author, moving its articles with reassign_to',
),
row('POST', '/v1/author/me', 'Create your own author profile, as any verified user'),
],
},
{
title: 'Settings · owner only',
rows: [row('PATCH', '/v1/settings', 'Change the activity log retention')],
@@ -915,15 +1004,31 @@ export const SESSION_GROUPS: SessionGroup[] = [
export const PUBLIC_AUTH_ROWS: PublicRow[] = [
{ method: 'GET', path: '/v1/', description: 'Hello world.' },
{ method: 'GET', path: '/v1/auth/registration', description: 'Whether registration is open.' },
{
method: 'GET',
path: '/v1/auth/registration',
description: 'Whether registration is open.',
},
{
method: 'POST',
path: '/v1/auth/password-reset/confirm',
description: 'Set a new password with the emailed code.',
},
{ method: 'GET', path: '/v1/auth/invite', description: 'Check an invite code.' },
{ method: 'POST', path: '/v1/auth/invite/accept', description: 'Accept an invite.' },
{ method: 'GET', path: '/healthz', description: 'Plain text "ok". Outside /v1.' },
{
method: 'GET',
path: '/v1/auth/invite',
description: 'Check an invite code.',
},
{
method: 'POST',
path: '/v1/auth/invite/accept',
description: 'Accept an invite.',
},
{
method: 'GET',
path: '/healthz',
description: 'Plain text "ok". Outside /v1.',
},
]
export const ERROR_ROWS: ErrorRow[] = [
@@ -951,8 +1056,16 @@ export const ERROR_ROWS: ErrorRow[] = [
'This invite has already been accepted.',
],
},
{ status: 429, meaning: 'Too many requests', messages: [TOO_MANY_REQUESTS] },
{ status: 500, meaning: 'Server error', messages: ['Internal server error'] },
{
status: 429,
meaning: 'Too many requests',
messages: [TOO_MANY_REQUESTS],
},
{
status: 500,
meaning: 'Server error',
messages: ['Internal server error'],
},
]
export const ERROR_SAMPLE = `HTTP/1.1 403 Forbidden\nContent-Type: text/plain\n\n${SESSION_REQUIRED_MESSAGE}`