1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.ApiSpec.StatusOperation do
6 alias OpenApiSpex.Operation
7 alias OpenApiSpex.Schema
8 alias Pleroma.Web.ApiSpec.AccountOperation
9 alias Pleroma.Web.ApiSpec.Schemas.ApiError
10 alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
11 alias Pleroma.Web.ApiSpec.Schemas.FlakeID
12 alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus
13 alias Pleroma.Web.ApiSpec.Schemas.Status
14 alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
16 import Pleroma.Web.ApiSpec.Helpers
18 def open_api_operation(action) do
19 operation = String.to_existing_atom("#{action}_operation")
20 apply(__MODULE__, operation, [])
23 def index_operation do
26 summary: "Get multiple statuses by IDs",
27 security: [%{"oAuth" => ["read:statuses"]}],
32 %Schema{type: :array, items: FlakeID},
36 operationId: "StatusController.index",
38 200 => Operation.response("Array of Status", "application/json", array_of_statuses())
43 def create_operation do
46 summary: "Publish new status",
47 security: [%{"oAuth" => ["write:statuses"]}],
48 description: "Post a new status",
49 operationId: "StatusController.create",
50 requestBody: request_body("Parameters", create_request(), required: true),
54 "Status. When `scheduled_at` is present, ScheduledStatus is returned instead",
56 %Schema{oneOf: [Status, ScheduledStatus]}
58 422 => Operation.response("Bad Request / MRF Rejection", "application/json", ApiError)
66 summary: "View specific status",
67 description: "View information about a status",
68 operationId: "StatusController.show",
69 security: [%{"oAuth" => ["read:statuses"]}],
70 parameters: [id_param()],
72 200 => status_response(),
73 404 => Operation.response("Not Found", "application/json", ApiError)
78 def delete_operation do
81 summary: "Delete status",
82 security: [%{"oAuth" => ["write:statuses"]}],
83 description: "Delete one of your own statuses",
84 operationId: "StatusController.delete",
85 parameters: [id_param()],
87 200 => status_response(),
88 403 => Operation.response("Forbidden", "application/json", ApiError),
89 404 => Operation.response("Not Found", "application/json", ApiError)
94 def reblog_operation do
98 security: [%{"oAuth" => ["write:statuses"]}],
99 description: "Share a status",
100 operationId: "StatusController.reblog",
101 parameters: [id_param()],
103 request_body("Parameters", %Schema{
106 visibility: %Schema{allOf: [VisibilityScope], default: "public"}
110 200 => status_response(),
111 404 => Operation.response("Not Found", "application/json", ApiError)
116 def unreblog_operation do
119 summary: "Undo boost",
120 security: [%{"oAuth" => ["write:statuses"]}],
121 description: "Undo a reshare of a status",
122 operationId: "StatusController.unreblog",
123 parameters: [id_param()],
125 200 => status_response(),
126 404 => Operation.response("Not Found", "application/json", ApiError)
131 def favourite_operation do
134 summary: "Favourite",
135 security: [%{"oAuth" => ["write:favourites"]}],
136 description: "Add a status to your favourites list",
137 operationId: "StatusController.favourite",
138 parameters: [id_param()],
140 200 => status_response(),
141 404 => Operation.response("Not Found", "application/json", ApiError)
146 def unfavourite_operation do
149 summary: "Undo favourite",
150 security: [%{"oAuth" => ["write:favourites"]}],
151 description: "Remove a status from your favourites list",
152 operationId: "StatusController.unfavourite",
153 parameters: [id_param()],
155 200 => status_response(),
156 404 => Operation.response("Not Found", "application/json", ApiError)
164 summary: "Pin to profile",
165 security: [%{"oAuth" => ["write:accounts"]}],
166 description: "Feature one of your own public statuses at the top of your profile",
167 operationId: "StatusController.pin",
168 parameters: [id_param()],
170 200 => status_response(),
171 400 => Operation.response("Error", "application/json", ApiError)
176 def unpin_operation do
179 summary: "Unpin to profile",
180 security: [%{"oAuth" => ["write:accounts"]}],
181 description: "Unfeature a status from the top of your profile",
182 operationId: "StatusController.unpin",
183 parameters: [id_param()],
185 200 => status_response(),
186 400 => Operation.response("Error", "application/json", ApiError)
191 def bookmark_operation do
195 security: [%{"oAuth" => ["write:bookmarks"]}],
196 description: "Privately bookmark a status",
197 operationId: "StatusController.bookmark",
198 parameters: [id_param()],
200 200 => status_response()
205 def unbookmark_operation do
208 summary: "Undo bookmark",
209 security: [%{"oAuth" => ["write:bookmarks"]}],
210 description: "Remove a status from your private bookmarks",
211 operationId: "StatusController.unbookmark",
212 parameters: [id_param()],
214 200 => status_response()
219 def mute_conversation_operation do
222 summary: "Mute conversation",
223 security: [%{"oAuth" => ["write:mutes"]}],
224 description: "Do not receive notifications for the thread that this status is part of.",
225 operationId: "StatusController.mute_conversation",
227 request_body("Parameters", %Schema{
233 description: "Expire the mute in `expires_in` seconds. Default 0 for infinity",
243 %Schema{type: :integer, default: 0},
244 "Expire the mute in `expires_in` seconds. Default 0 for infinity"
248 200 => status_response(),
249 400 => Operation.response("Error", "application/json", ApiError)
254 def unmute_conversation_operation do
257 summary: "Unmute conversation",
258 security: [%{"oAuth" => ["write:mutes"]}],
260 "Start receiving notifications again for the thread that this status is part of",
261 operationId: "StatusController.unmute_conversation",
262 parameters: [id_param()],
264 200 => status_response(),
265 400 => Operation.response("Error", "application/json", ApiError)
270 def card_operation do
274 summary: "Preview card",
275 description: "Deprecated in favor of card property inlined on Status entity",
276 operationId: "StatusController.card",
277 parameters: [id_param()],
278 security: [%{"oAuth" => ["read:statuses"]}],
281 Operation.response("Card", "application/json", %Schema{
285 type: %Schema{type: :string, enum: ["link", "photo", "video", "rich"]},
286 provider_name: %Schema{type: :string, nullable: true},
287 provider_url: %Schema{type: :string, format: :uri},
288 url: %Schema{type: :string, format: :uri},
289 image: %Schema{type: :string, nullable: true, format: :uri},
290 title: %Schema{type: :string},
291 description: %Schema{type: :string}
298 def favourited_by_operation do
301 summary: "Favourited by",
302 description: "View who favourited a given status",
303 operationId: "StatusController.favourited_by",
304 security: [%{"oAuth" => ["read:accounts"]}],
305 parameters: [id_param()],
311 AccountOperation.array_of_accounts()
313 404 => Operation.response("Not Found", "application/json", ApiError)
318 def reblogged_by_operation do
321 summary: "Boosted by",
322 description: "View who boosted a given status",
323 operationId: "StatusController.reblogged_by",
324 security: [%{"oAuth" => ["read:accounts"]}],
325 parameters: [id_param()],
331 AccountOperation.array_of_accounts()
333 404 => Operation.response("Not Found", "application/json", ApiError)
338 def context_operation do
341 summary: "Parent and child statuses",
342 description: "View statuses above and below this status in the thread",
343 operationId: "StatusController.context",
344 security: [%{"oAuth" => ["read:statuses"]}],
345 parameters: [id_param()],
347 200 => Operation.response("Context", "application/json", context())
352 def favourites_operation do
355 summary: "Favourited statuses",
357 "Statuses the user has favourited. Please note that you have to use the link headers to paginate this. You can not build the query parameters yourself.",
358 operationId: "StatusController.favourites",
359 parameters: pagination_params(),
360 security: [%{"oAuth" => ["read:favourites"]}],
362 200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
367 def bookmarks_operation do
370 summary: "Bookmarked statuses",
371 description: "Statuses the user has bookmarked",
372 operationId: "StatusController.bookmarks",
373 parameters: pagination_params(),
374 security: [%{"oAuth" => ["read:bookmarks"]}],
376 200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
381 def array_of_statuses do
382 %Schema{type: :array, items: Status, example: [Status.schema().example]}
385 defp create_request do
387 title: "StatusCreateRequest",
394 "Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided."
399 items: %Schema{type: :string},
400 description: "Array of Attachment ids to be attached as media."
405 required: [:options],
409 items: %Schema{type: :string},
410 description: "Array of possible answers. Must be provided with `poll[expires_in]`."
416 "Duration the poll should be open, in seconds. Must be provided with `poll[options]`"
419 allOf: [BooleanLike],
421 description: "Allow multiple choices?"
423 hide_totals: %Schema{
424 allOf: [BooleanLike],
426 description: "Hide vote counts until the poll ends?"
430 in_reply_to_id: %Schema{
433 description: "ID of the status being replied to, if status is a reply"
436 allOf: [BooleanLike],
438 description: "Mark status and attached media as sensitive?"
440 spoiler_text: %Schema{
444 "Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field."
446 scheduled_at: %Schema{
448 format: :"date-time",
451 "ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future."
456 description: "ISO 639 language code for this status."
458 # Pleroma-specific properties:
460 allOf: [BooleanLike],
463 "If set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example"
465 content_type: %Schema{
469 "The MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint."
474 items: %Schema{type: :string},
476 "A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply"
482 %Schema{type: :string, description: "`list:LIST_ID`", example: "LIST:123"}
485 "Visibility of the posted status. Besides standard MastoAPI values (`direct`, `private`, `unlisted` or `public`) it can be used to address a List by setting it to `list:LIST_ID`"
491 "The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour."
493 in_reply_to_conversation_id: %Schema{
497 "Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`."
501 "status" => "What time is it?",
502 "sensitive" => "false",
504 "options" => ["Cofe", "Adventure"],
512 Operation.parameter(:id, :path, FlakeID, "Status ID",
513 example: "9umDrYheeY451cQnEe",
518 defp status_response do
519 Operation.response("Status", "application/json", Status)
524 title: "StatusContext",
526 "Represents the tree around a given status. Used for reconstructing threads of statuses.",
528 required: [:ancestors, :descendants],
530 ancestors: array_of_statuses(),
531 descendants: array_of_statuses()
534 "ancestors" => [Status.schema().example],
535 "descendants" => [Status.schema().example]