Manage clients, testimonials and talks through the API
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -112,6 +112,12 @@ tags:
|
||||
description: The people in the collective
|
||||
- name: Services
|
||||
description: What the collective offers
|
||||
- name: Clients
|
||||
description: The organisations the work was for
|
||||
- name: Testimonials
|
||||
description: What the people the collective worked with said
|
||||
- name: Talks
|
||||
description: Talks given elsewhere, by members of the collective
|
||||
- name: Technologies
|
||||
description: What the collective uses, and its place on the tech radar
|
||||
- name: Users
|
||||
@@ -1645,6 +1651,352 @@ paths:
|
||||
data: { $ref: "#/components/schemas/Service" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/clients:
|
||||
get:
|
||||
tags: [Clients]
|
||||
summary: List clients
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Lang"
|
||||
- $ref: "#/components/parameters/With"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
- name: is_public
|
||||
in: query
|
||||
schema: { type: boolean }
|
||||
- name: search
|
||||
in: query
|
||||
description: Matches the name.
|
||||
schema: { type: string }
|
||||
- name: trashed
|
||||
in: query
|
||||
schema: { type: boolean }
|
||||
responses:
|
||||
"200":
|
||||
description: Paginated clients
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/ClientCollection" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
post:
|
||||
tags: [Clients]
|
||||
summary: Create a client
|
||||
description: |
|
||||
Send the `path` from `POST /v1/media` with `for=clients` as `logo`.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/ClientWrite" }
|
||||
responses:
|
||||
"201":
|
||||
description: Client created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Client" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"422": { $ref: "#/components/responses/ValidationError" }
|
||||
|
||||
/v1/clients/{client}:
|
||||
parameters:
|
||||
- name: client
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer }
|
||||
get:
|
||||
tags: [Clients]
|
||||
summary: Show a client
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Lang"
|
||||
- $ref: "#/components/parameters/With"
|
||||
responses:
|
||||
"200":
|
||||
description: The client
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Client" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"404": { description: Not found }
|
||||
patch:
|
||||
tags: [Clients]
|
||||
summary: Update a client
|
||||
description: Partial update. Translatable fields merge into the existing map.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/ClientWrite" }
|
||||
responses:
|
||||
"200":
|
||||
description: Client updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Client" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"422": { $ref: "#/components/responses/ValidationError" }
|
||||
delete:
|
||||
tags: [Clients]
|
||||
summary: Soft-delete a client
|
||||
responses:
|
||||
"204": { description: Deleted }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/clients/{client}/restore:
|
||||
post:
|
||||
tags: [Clients]
|
||||
summary: Restore a soft-deleted client
|
||||
parameters:
|
||||
- name: client
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer }
|
||||
responses:
|
||||
"200":
|
||||
description: Client restored
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Client" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/testimonials:
|
||||
get:
|
||||
tags: [Testimonials]
|
||||
summary: List testimonials
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Lang"
|
||||
- $ref: "#/components/parameters/With"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
- name: is_public
|
||||
in: query
|
||||
schema: { type: boolean }
|
||||
- name: client_id
|
||||
in: query
|
||||
schema: { type: integer }
|
||||
- name: project_id
|
||||
in: query
|
||||
schema: { type: integer }
|
||||
- name: service_id
|
||||
in: query
|
||||
schema: { type: integer }
|
||||
- name: search
|
||||
in: query
|
||||
description: Matches the author's name.
|
||||
schema: { type: string }
|
||||
- name: trashed
|
||||
in: query
|
||||
schema: { type: boolean }
|
||||
responses:
|
||||
"200":
|
||||
description: Paginated testimonials
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/TestimonialCollection" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
post:
|
||||
tags: [Testimonials]
|
||||
summary: Create a testimonial
|
||||
description: |
|
||||
`quote` holds what the person said in `original_locale`, and any
|
||||
translations of it. Send the `path` from `POST /v1/media` with
|
||||
`for=testimonials` as `avatar`.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/TestimonialWrite" }
|
||||
responses:
|
||||
"201":
|
||||
description: Testimonial created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Testimonial" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"422": { $ref: "#/components/responses/ValidationError" }
|
||||
|
||||
/v1/testimonials/{testimonial}:
|
||||
parameters:
|
||||
- name: testimonial
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer }
|
||||
get:
|
||||
tags: [Testimonials]
|
||||
summary: Show a testimonial
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Lang"
|
||||
- $ref: "#/components/parameters/With"
|
||||
responses:
|
||||
"200":
|
||||
description: The testimonial
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Testimonial" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"404": { description: Not found }
|
||||
patch:
|
||||
tags: [Testimonials]
|
||||
summary: Update a testimonial
|
||||
description: Partial update. Translatable fields merge into the existing map.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/TestimonialWrite" }
|
||||
responses:
|
||||
"200":
|
||||
description: Testimonial updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Testimonial" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"422": { $ref: "#/components/responses/ValidationError" }
|
||||
delete:
|
||||
tags: [Testimonials]
|
||||
summary: Soft-delete a testimonial
|
||||
responses:
|
||||
"204": { description: Deleted }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/testimonials/{testimonial}/restore:
|
||||
post:
|
||||
tags: [Testimonials]
|
||||
summary: Restore a soft-deleted testimonial
|
||||
parameters:
|
||||
- name: testimonial
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer }
|
||||
responses:
|
||||
"200":
|
||||
description: Testimonial restored
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Testimonial" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/talks:
|
||||
get:
|
||||
tags: [Talks]
|
||||
summary: List talks
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Lang"
|
||||
- $ref: "#/components/parameters/With"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
- name: is_public
|
||||
in: query
|
||||
schema: { type: boolean }
|
||||
- name: member_id
|
||||
in: query
|
||||
schema: { type: integer }
|
||||
- name: project_id
|
||||
in: query
|
||||
schema: { type: integer }
|
||||
- name: search
|
||||
in: query
|
||||
description: Matches the title or the event.
|
||||
schema: { type: string }
|
||||
responses:
|
||||
"200":
|
||||
description: Paginated talks
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/TalkCollection" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
post:
|
||||
tags: [Talks]
|
||||
summary: Create a talk
|
||||
description: |
|
||||
`title` is the one the talk was given under, in `language`. Only
|
||||
`summary` is translated.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/TalkWrite" }
|
||||
responses:
|
||||
"201":
|
||||
description: Talk created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Talk" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"422": { $ref: "#/components/responses/ValidationError" }
|
||||
|
||||
/v1/talks/{talk}:
|
||||
parameters:
|
||||
- name: talk
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer }
|
||||
get:
|
||||
tags: [Talks]
|
||||
summary: Show a talk
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Lang"
|
||||
- $ref: "#/components/parameters/With"
|
||||
responses:
|
||||
"200":
|
||||
description: The talk
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Talk" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"404": { description: Not found }
|
||||
patch:
|
||||
tags: [Talks]
|
||||
summary: Update a talk
|
||||
description: Partial update. Translatable fields merge into the existing map.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/TalkWrite" }
|
||||
responses:
|
||||
"200":
|
||||
description: Talk updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: "#/components/schemas/Talk" }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
"422": { $ref: "#/components/responses/ValidationError" }
|
||||
delete:
|
||||
tags: [Talks]
|
||||
summary: Delete a talk
|
||||
responses:
|
||||
"204": { description: Deleted }
|
||||
"403": { $ref: "#/components/responses/Forbidden" }
|
||||
|
||||
/v1/media:
|
||||
post:
|
||||
tags: [Media]
|
||||
@@ -1665,8 +2017,9 @@ paths:
|
||||
removed. 20 MB at most.
|
||||
|
||||
`for` says which kind of record the image is for — `pages` (the
|
||||
default) or `technologies` — which decides where it is stored and whose
|
||||
permission it takes.
|
||||
default), `technologies`, `projects`, `members`, `clients` or
|
||||
`testimonials` — which decides where it is stored and whose permission
|
||||
it takes.
|
||||
|
||||
The smaller versions and the placeholder are derived afterwards, on the
|
||||
queue: `processed` says whether that has happened, and the image serves
|
||||
@@ -2872,9 +3225,147 @@ components:
|
||||
links: { $ref: "#/components/schemas/PaginationLinks" }
|
||||
meta: { $ref: "#/components/schemas/PaginationMeta" }
|
||||
|
||||
Client:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
locale: { type: string }
|
||||
name: { type: string }
|
||||
slug: { type: string }
|
||||
sector: { type: string, nullable: true }
|
||||
logo: { type: string, nullable: true, description: The stored path. }
|
||||
logo_media:
|
||||
allOf: [{ $ref: "#/components/schemas/Image" }]
|
||||
nullable: true
|
||||
readOnly: true
|
||||
url: { type: string, format: uri, nullable: true }
|
||||
is_public: { type: boolean }
|
||||
position: { type: integer }
|
||||
projects_count: { type: integer }
|
||||
created_at: { type: string, format: date-time }
|
||||
updated_at: { type: string, format: date-time }
|
||||
deleted_at: { type: string, format: date-time, nullable: true }
|
||||
translations: { type: object, nullable: true, description: "Every language, with `?with=translations`." }
|
||||
|
||||
ClientWrite:
|
||||
type: object
|
||||
required: [name, slug]
|
||||
properties:
|
||||
name: { type: string, maxLength: 255, description: A proper noun; not translated. }
|
||||
slug: { type: string, maxLength: 255, pattern: "^[A-Za-z0-9_-]+$" }
|
||||
sector: { $ref: "#/components/schemas/TranslatedField" }
|
||||
logo: { type: string, nullable: true, description: A path from `POST /v1/media` with `for=clients`. }
|
||||
url: { type: string, format: uri, nullable: true }
|
||||
is_public: { type: boolean }
|
||||
position: { type: integer, minimum: 0 }
|
||||
|
||||
ClientCollection:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/Client" }
|
||||
links: { $ref: "#/components/schemas/PaginationLinks" }
|
||||
meta: { $ref: "#/components/schemas/PaginationMeta" }
|
||||
|
||||
Testimonial:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
locale: { type: string }
|
||||
quote: { type: string, nullable: true }
|
||||
author_role: { type: string, nullable: true }
|
||||
original_locale: { type: string, description: The language the person spoke in. }
|
||||
author_name: { type: string }
|
||||
avatar: { type: string, nullable: true, description: The stored path. }
|
||||
avatar_media:
|
||||
allOf: [{ $ref: "#/components/schemas/Image" }]
|
||||
nullable: true
|
||||
readOnly: true
|
||||
client_id: { type: integer, nullable: true }
|
||||
project_id: { type: integer, nullable: true }
|
||||
service_id: { type: integer, nullable: true }
|
||||
is_public: { type: boolean }
|
||||
position: { type: integer }
|
||||
given_at: { type: string, format: date, nullable: true }
|
||||
created_at: { type: string, format: date-time }
|
||||
updated_at: { type: string, format: date-time }
|
||||
deleted_at: { type: string, format: date-time, nullable: true }
|
||||
translations: { type: object, nullable: true, description: "Every language, with `?with=translations`." }
|
||||
|
||||
TestimonialWrite:
|
||||
type: object
|
||||
required: [quote, original_locale, author_name]
|
||||
properties:
|
||||
quote: { $ref: "#/components/schemas/TranslatedField" }
|
||||
original_locale: { type: string, description: A supported language code. }
|
||||
author_name: { type: string, maxLength: 255 }
|
||||
author_role: { $ref: "#/components/schemas/TranslatedField" }
|
||||
avatar: { type: string, nullable: true, description: A path from `POST /v1/media` with `for=testimonials`. }
|
||||
client_id: { type: integer, nullable: true }
|
||||
project_id: { type: integer, nullable: true }
|
||||
service_id: { type: integer, nullable: true }
|
||||
is_public: { type: boolean }
|
||||
position: { type: integer, minimum: 0 }
|
||||
given_at: { type: string, format: date, nullable: true }
|
||||
|
||||
TestimonialCollection:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/Testimonial" }
|
||||
links: { $ref: "#/components/schemas/PaginationLinks" }
|
||||
meta: { $ref: "#/components/schemas/PaginationMeta" }
|
||||
|
||||
Talk:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer }
|
||||
locale: { type: string }
|
||||
title: { type: string }
|
||||
language: { type: string }
|
||||
summary: { type: string, nullable: true }
|
||||
event: { type: string }
|
||||
city: { type: string, nullable: true }
|
||||
held_at: { type: string, format: date, nullable: true }
|
||||
video_url: { type: string, format: uri, nullable: true }
|
||||
slides_url: { type: string, format: uri, nullable: true }
|
||||
member_id: { type: integer, nullable: true }
|
||||
project_id: { type: integer, nullable: true }
|
||||
is_public: { type: boolean }
|
||||
created_at: { type: string, format: date-time }
|
||||
updated_at: { type: string, format: date-time }
|
||||
translations: { type: object, nullable: true, description: "Every language, with `?with=translations`." }
|
||||
|
||||
TalkWrite:
|
||||
type: object
|
||||
required: [title, language, event]
|
||||
properties:
|
||||
title: { type: string, maxLength: 255, description: Not translated. }
|
||||
language: { type: string, description: A supported language code. }
|
||||
summary: { $ref: "#/components/schemas/TranslatedField" }
|
||||
event: { type: string, maxLength: 255 }
|
||||
city: { type: string, nullable: true, maxLength: 120 }
|
||||
held_at: { type: string, format: date, nullable: true }
|
||||
video_url: { type: string, format: uri, nullable: true }
|
||||
slides_url: { type: string, format: uri, nullable: true }
|
||||
member_id: { type: integer, nullable: true }
|
||||
project_id: { type: integer, nullable: true }
|
||||
is_public: { type: boolean }
|
||||
|
||||
TalkCollection:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/Talk" }
|
||||
links: { $ref: "#/components/schemas/PaginationLinks" }
|
||||
meta: { $ref: "#/components/schemas/PaginationMeta" }
|
||||
|
||||
MediaFor:
|
||||
type: string
|
||||
enum: [pages, technologies, projects, members]
|
||||
enum: [pages, technologies, projects, members, clients, testimonials]
|
||||
default: pages
|
||||
description: The kind of record the image is for.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user