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.FlakeID
11 alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus
12 alias Pleroma.Web.ApiSpec.Schemas.Status
13 alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
15 import Pleroma.Web.ApiSpec.Helpers
17 def open_api_operation(action) do
18 operation = String.to_existing_atom("#{action}_operation")
19 apply(__MODULE__, operation, [])
22 def index_operation do
25 summary: "Get multiple statuses by IDs",
26 security: [%{"oAuth" => ["read:statuses"]}],
31 %Schema{type: :array, items: FlakeID},
35 operationId: "StatusController.index",
37 200 => Operation.response("Array of Status", "application/json", array_of_statuses())
42 def create_operation do
45 summary: "Publish new status",
46 security: [%{"oAuth" => ["write:statuses"]}],
47 description: "Post a new status",
48 operationId: "StatusController.create",
49 requestBody: request_body("Parameters", create_request(), required: true),
53 "Status. When `scheduled_at` is present, ScheduledStatus is returned instead",
55 %Schema{oneOf: [Status, ScheduledStatus]}
57 422 => Operation.response("Bad Request", "application/json", ApiError)
65 summary: "View specific status",
66 description: "View information about a status",
67 operationId: "StatusController.show",
68 security: [%{"oAuth" => ["read:statuses"]}],
69 parameters: [id_param()],
71 200 => status_response(),
72 404 => Operation.response("Not Found", "application/json", ApiError)
77 def delete_operation do
80 summary: "Delete status",
81 security: [%{"oAuth" => ["write:statuses"]}],
82 description: "Delete one of your own statuses",
83 operationId: "StatusController.delete",
84 parameters: [id_param()],
86 200 => empty_object_response(),
87 403 => Operation.response("Forbidden", "application/json", ApiError),
88 404 => Operation.response("Not Found", "application/json", ApiError)
93 def reblog_operation do
97 security: [%{"oAuth" => ["write:statuses"]}],
98 description: "Share a status",
99 operationId: "StatusController.reblog",
100 parameters: [id_param()],
102 request_body("Parameters", %Schema{
105 visibility: %Schema{allOf: [VisibilityScope], default: "public"}
109 200 => status_response(),
110 404 => Operation.response("Not Found", "application/json", ApiError)
115 def unreblog_operation do
118 summary: "Undo boost",
119 security: [%{"oAuth" => ["write:statuses"]}],
120 description: "Undo a reshare of a status",
121 operationId: "StatusController.unreblog",
122 parameters: [id_param()],
124 200 => status_response(),
125 404 => Operation.response("Not Found", "application/json", ApiError)
130 def favourite_operation do
133 summary: "Favourite",
134 security: [%{"oAuth" => ["write:favourites"]}],
135 description: "Add a status to your favourites list",
136 operationId: "StatusController.favourite",
137 parameters: [id_param()],
139 200 => status_response(),
140 404 => Operation.response("Not Found", "application/json", ApiError)
145 def unfavourite_operation do
148 summary: "Undo favourite",
149 security: [%{"oAuth" => ["write:favourites"]}],
150 description: "Remove a status from your favourites list",
151 operationId: "StatusController.unfavourite",
152 parameters: [id_param()],
154 200 => status_response(),
155 404 => Operation.response("Not Found", "application/json", ApiError)
163 summary: "Pin to profile",
164 security: [%{"oAuth" => ["write:accounts"]}],
165 description: "Feature one of your own public statuses at the top of your profile",
166 operationId: "StatusController.pin",
167 parameters: [id_param()],
169 200 => status_response(),
170 400 => Operation.response("Error", "application/json", ApiError)
175 def unpin_operation do
178 summary: "Unpin to profile",
179 security: [%{"oAuth" => ["write:accounts"]}],
180 description: "Unfeature a status from the top of your profile",
181 operationId: "StatusController.unpin",
182 parameters: [id_param()],
184 200 => status_response(),
185 400 => Operation.response("Error", "application/json", ApiError)
190 def bookmark_operation do
194 security: [%{"oAuth" => ["write:bookmarks"]}],
195 description: "Privately bookmark a status",
196 operationId: "StatusController.bookmark",
197 parameters: [id_param()],
199 200 => status_response()
204 def unbookmark_operation do
207 summary: "Undo bookmark",
208 security: [%{"oAuth" => ["write:bookmarks"]}],
209 description: "Remove a status from your private bookmarks",
210 operationId: "StatusController.unbookmark",
211 parameters: [id_param()],
213 200 => status_response()
218 def mute_conversation_operation do
221 summary: "Mute conversation",
222 security: [%{"oAuth" => ["write:mutes"]}],
223 description: "Do not receive notifications for the thread that this status is part of.",
224 operationId: "StatusController.mute_conversation",
225 parameters: [id_param()],
227 200 => status_response(),
228 400 => Operation.response("Error", "application/json", ApiError)
233 def unmute_conversation_operation do
236 summary: "Unmute conversation",
237 security: [%{"oAuth" => ["write:mutes"]}],
239 "Start receiving notifications again for the thread that this status is part of",
240 operationId: "StatusController.unmute_conversation",
241 parameters: [id_param()],
243 200 => status_response(),
244 400 => Operation.response("Error", "application/json", ApiError)
249 def card_operation do
253 summary: "Preview card",
254 description: "Deprecated in favor of card property inlined on Status entity",
255 operationId: "StatusController.card",
256 parameters: [id_param()],
257 security: [%{"oAuth" => ["read:statuses"]}],
260 Operation.response("Card", "application/json", %Schema{
264 type: %Schema{type: :string, enum: ["link", "photo", "video", "rich"]},
265 provider_name: %Schema{type: :string, nullable: true},
266 provider_url: %Schema{type: :string, format: :uri},
267 url: %Schema{type: :string, format: :uri},
268 image: %Schema{type: :string, nullable: true, format: :uri},
269 title: %Schema{type: :string},
270 description: %Schema{type: :string}
277 def favourited_by_operation do
280 summary: "Favourited by",
281 description: "View who favourited a given status",
282 operationId: "StatusController.favourited_by",
283 security: [%{"oAuth" => ["read:accounts"]}],
284 parameters: [id_param()],
290 AccountOperation.array_of_accounts()
292 404 => Operation.response("Not Found", "application/json", ApiError)
297 def reblogged_by_operation do
300 summary: "Boosted by",
301 description: "View who boosted a given status",
302 operationId: "StatusController.reblogged_by",
303 security: [%{"oAuth" => ["read:accounts"]}],
304 parameters: [id_param()],
310 AccountOperation.array_of_accounts()
312 404 => Operation.response("Not Found", "application/json", ApiError)
317 def context_operation do
320 summary: "Parent and child statuses",
321 description: "View statuses above and below this status in the thread",
322 operationId: "StatusController.context",
323 security: [%{"oAuth" => ["read:statuses"]}],
324 parameters: [id_param()],
326 200 => Operation.response("Context", "application/json", context())
331 def favourites_operation do
334 summary: "Favourited statuses",
335 description: "Statuses the user has favourited",
336 operationId: "StatusController.favourites",
337 parameters: pagination_params(),
338 security: [%{"oAuth" => ["read:favourites"]}],
340 200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
345 def bookmarks_operation do
348 summary: "Bookmarked statuses",
349 description: "Statuses the user has bookmarked",
350 operationId: "StatusController.bookmarks",
351 parameters: pagination_params(),
352 security: [%{"oAuth" => ["read:bookmarks"]}],
354 200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
359 def array_of_statuses do
360 %Schema{type: :array, items: Status, example: [Status.schema().example]}
363 defp create_request do
365 title: "StatusCreateRequest",
372 "Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided."
377 items: %Schema{type: :string},
378 description: "Array of Attachment ids to be attached as media."
383 required: [:options],
387 items: %Schema{type: :string},
388 description: "Array of possible answers. Must be provided with `poll[expires_in]`."
394 "Duration the poll should be open, in seconds. Must be provided with `poll[options]`"
399 description: "Allow multiple choices?"
401 hide_totals: %Schema{
404 description: "Hide vote counts until the poll ends?"
408 in_reply_to_id: %Schema{
411 description: "ID of the status being replied to, if status is a reply"
416 description: "Mark status and attached media as sensitive?"
418 spoiler_text: %Schema{
422 "Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field."
424 scheduled_at: %Schema{
426 format: :"date-time",
429 "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."
434 description: "ISO 639 language code for this status."
436 # Pleroma-specific properties:
441 "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"
443 content_type: %Schema{
447 "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."
452 items: %Schema{type: :string},
454 "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"
460 %Schema{type: :string, description: "`list:LIST_ID`", example: "LIST:123"}
463 "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`"
469 "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."
471 in_reply_to_conversation_id: %Schema{
475 "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`."
479 "status" => "What time is it?",
480 "sensitive" => "false",
482 "options" => ["Cofe", "Adventure"],
490 Operation.parameter(:id, :path, FlakeID, "Status ID",
491 example: "9umDrYheeY451cQnEe",
496 defp status_response do
497 Operation.response("Status", "application/json", Status)
502 title: "StatusContext",
504 "Represents the tree around a given status. Used for reconstructing threads of statuses.",
506 required: [:ancestors, :descendants],
508 ancestors: array_of_statuses(),
509 descendants: array_of_statuses()
512 "ancestors" => [Status.schema().example],
513 "descendants" => [Status.schema().example]