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.AccountOperation do
6 alias OpenApiSpex.Operation
7 alias OpenApiSpex.Reference
8 alias OpenApiSpex.Schema
9 alias Pleroma.Web.ApiSpec.Schemas.Account
10 alias Pleroma.Web.ApiSpec.Schemas.AccountRelationship
11 alias Pleroma.Web.ApiSpec.Schemas.ActorType
12 alias Pleroma.Web.ApiSpec.Schemas.ApiError
13 alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
14 alias Pleroma.Web.ApiSpec.Schemas.List
15 alias Pleroma.Web.ApiSpec.Schemas.Status
16 alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
18 import Pleroma.Web.ApiSpec.Helpers
20 @spec open_api_operation(atom) :: Operation.t()
21 def open_api_operation(action) do
22 operation = String.to_existing_atom("#{action}_operation")
23 apply(__MODULE__, operation, [])
26 @spec create_operation() :: Operation.t()
27 def create_operation do
30 summary: "Register an account",
32 "Creates a user and account records. Returns an account access token for the app that initiated the request. The app should save this token for later, and should wait for the user to confirm their account by clicking a link in their email inbox.",
33 operationId: "AccountController.create",
34 requestBody: request_body("Parameters", create_request(), required: true),
36 200 => Operation.response("Account", "application/json", create_response()),
37 400 => Operation.response("Error", "application/json", ApiError),
38 403 => Operation.response("Error", "application/json", ApiError),
39 429 => Operation.response("Error", "application/json", ApiError)
44 def verify_credentials_operation do
47 description: "Test to make sure that the user token works.",
48 summary: "Verify account credentials",
49 operationId: "AccountController.verify_credentials",
50 security: [%{"oAuth" => ["read:accounts"]}],
52 200 => Operation.response("Account", "application/json", Account)
57 def update_credentials_operation do
60 summary: "Update account credentials",
61 description: "Update the user's display and preferences.",
62 operationId: "AccountController.update_credentials",
63 security: [%{"oAuth" => ["write:accounts"]}],
64 requestBody: request_body("Parameters", update_creadentials_request(), required: true),
66 200 => Operation.response("Account", "application/json", Account),
67 403 => Operation.response("Error", "application/json", ApiError)
72 def relationships_operation do
75 summary: "Check relationships to other accounts",
76 operationId: "AccountController.relationships",
77 description: "Find out whether a given account is followed, blocked, muted, etc.",
78 security: [%{"oAuth" => ["read:follows"]}],
84 oneOf: [%Schema{type: :array, items: %Schema{type: :string}}, %Schema{type: :string}]
91 200 => Operation.response("Account", "application/json", array_of_relationships())
100 operationId: "AccountController.show",
101 description: "View information about a profile.",
102 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
104 200 => Operation.response("Account", "application/json", Account),
105 404 => Operation.response("Error", "application/json", ApiError)
110 def statuses_operation do
114 operationId: "AccountController.statuses",
116 "Statuses posted to the given account. Public (for public statuses only), or user token + `read:statuses` (for private statuses the user is authorized to see)",
119 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
120 Operation.parameter(:pinned, :query, BooleanLike, "Include only pinned statuses"),
121 Operation.parameter(:tagged, :query, :string, "With tag"),
126 "Include only statuses with media attached"
132 "Include statuses from muted acccounts."
134 Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
135 Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
137 :exclude_visibilities,
139 %Schema{type: :array, items: VisibilityScope},
140 "Exclude visibilities"
142 ] ++ pagination_params(),
144 200 => Operation.response("Statuses", "application/json", array_of_statuses()),
145 404 => Operation.response("Error", "application/json", ApiError)
150 def followers_operation do
153 summary: "Followers",
154 operationId: "AccountController.followers",
155 security: [%{"oAuth" => ["read:accounts"]}],
157 "Accounts which follow the given account, if network is not hidden by the account owner.",
159 [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
161 200 => Operation.response("Accounts", "application/json", array_of_accounts())
166 def following_operation do
169 summary: "Following",
170 operationId: "AccountController.following",
171 security: [%{"oAuth" => ["read:accounts"]}],
173 "Accounts which the given account is following, if network is not hidden by the account owner.",
175 [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
176 responses: %{200 => Operation.response("Accounts", "application/json", array_of_accounts())}
180 def lists_operation do
183 summary: "Lists containing this account",
184 operationId: "AccountController.lists",
185 security: [%{"oAuth" => ["read:lists"]}],
186 description: "User lists that you have added this account to.",
187 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
188 responses: %{200 => Operation.response("Lists", "application/json", array_of_lists())}
192 def follow_operation do
196 operationId: "AccountController.follow",
197 security: [%{"oAuth" => ["follow", "write:follows"]}],
198 description: "Follow the given account",
200 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
205 "Receive this account's reblogs in home timeline? Defaults to true."
209 200 => Operation.response("Relationship", "application/json", AccountRelationship),
210 400 => Operation.response("Error", "application/json", ApiError),
211 404 => Operation.response("Error", "application/json", ApiError)
216 def unfollow_operation do
220 operationId: "AccountController.unfollow",
221 security: [%{"oAuth" => ["follow", "write:follows"]}],
222 description: "Unfollow the given account",
223 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
225 200 => Operation.response("Relationship", "application/json", AccountRelationship),
226 400 => Operation.response("Error", "application/json", ApiError),
227 404 => Operation.response("Error", "application/json", ApiError)
232 def mute_operation do
236 operationId: "AccountController.mute",
237 security: [%{"oAuth" => ["follow", "write:mutes"]}],
238 requestBody: request_body("Parameters", mute_request()),
240 "Mute the given account. Clients should filter statuses and notifications from this account, if received (e.g. due to a boost in the Home timeline).",
242 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
246 %Schema{allOf: [BooleanLike], default: true},
247 "Mute notifications in addition to statuses? Defaults to `true`."
251 200 => Operation.response("Relationship", "application/json", AccountRelationship)
256 def unmute_operation do
260 operationId: "AccountController.unmute",
261 security: [%{"oAuth" => ["follow", "write:mutes"]}],
262 description: "Unmute the given account.",
263 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
265 200 => Operation.response("Relationship", "application/json", AccountRelationship)
270 def block_operation do
274 operationId: "AccountController.block",
275 security: [%{"oAuth" => ["follow", "write:blocks"]}],
277 "Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
278 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
280 200 => Operation.response("Relationship", "application/json", AccountRelationship)
285 def unblock_operation do
289 operationId: "AccountController.unblock",
290 security: [%{"oAuth" => ["follow", "write:blocks"]}],
291 description: "Unblock the given account.",
292 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
294 200 => Operation.response("Relationship", "application/json", AccountRelationship)
299 def follow_by_uri_operation do
302 summary: "Follow by URI",
303 operationId: "AccountController.follows",
304 security: [%{"oAuth" => ["follow", "write:follows"]}],
305 requestBody: request_body("Parameters", follow_by_uri_request(), required: true),
307 200 => Operation.response("Account", "application/json", AccountRelationship),
308 400 => Operation.response("Error", "application/json", ApiError),
309 404 => Operation.response("Error", "application/json", ApiError)
314 def mutes_operation do
317 summary: "Muted accounts",
318 operationId: "AccountController.mutes",
319 description: "Accounts the user has muted.",
320 security: [%{"oAuth" => ["follow", "read:mutes"]}],
322 200 => Operation.response("Accounts", "application/json", array_of_accounts())
327 def blocks_operation do
330 summary: "Blocked users",
331 operationId: "AccountController.blocks",
332 description: "View your blocks. See also accounts/:id/{block,unblock}",
333 security: [%{"oAuth" => ["read:blocks"]}],
335 200 => Operation.response("Accounts", "application/json", array_of_accounts())
340 def endorsements_operation do
343 summary: "Endorsements",
344 operationId: "AccountController.endorsements",
345 description: "Not implemented",
346 security: [%{"oAuth" => ["read:accounts"]}],
348 200 => empty_array_response()
353 def identity_proofs_operation do
356 summary: "Identity proofs",
357 operationId: "AccountController.identity_proofs",
358 description: "Not implemented",
360 200 => empty_array_response()
365 defp create_request do
367 title: "AccountCreateRequest",
368 description: "POST body for creating an account",
370 required: [:username, :password, :agreement],
376 "Text that will be reviewed by moderators if registrations require manual approval"
378 username: %Schema{type: :string, description: "The desired username for the account"},
383 "The email address to be used for login. Required when `account_activation_required` is enabled.",
388 description: "The password to be used for login",
394 "Whether the user agrees to the local rules, terms, and policies. These should be presented to the user in order to allow them to consent before setting this parameter to TRUE."
399 description: "The language of the confirmation email that will be sent"
401 # Pleroma-specific properties:
402 fullname: %Schema{type: :string, nullable: true, description: "Full name"},
403 bio: %Schema{type: :string, description: "Bio", nullable: true, default: ""},
404 captcha_solution: %Schema{
407 description: "Provider-specific captcha solution"
409 captcha_token: %Schema{
412 description: "Provider-specific captcha token"
414 captcha_answer_data: %Schema{
417 description: "Provider-specific captcha data"
422 description: "Invite token required when the registrations aren't public"
426 "username" => "cofe",
427 "email" => "cofe@example.com",
428 "password" => "secret",
429 "agreement" => "true",
435 defp create_response do
437 title: "AccountCreateResponse",
438 description: "Response schema for an account",
441 token_type: %Schema{type: :string},
442 access_token: %Schema{type: :string},
443 scope: %Schema{type: :array, items: %Schema{type: :string}},
444 created_at: %Schema{type: :integer, format: :"date-time"}
447 "access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
448 "created_at" => 1_585_918_714,
449 "scope" => ["read", "write", "follow", "push"],
450 "token_type" => "Bearer"
455 defp update_creadentials_request do
457 title: "AccountUpdateCredentialsRequest",
458 description: "POST body for creating an account",
464 description: "Whether the account has a bot flag."
466 display_name: %Schema{
469 description: "The display name to use for the profile."
471 note: %Schema{type: :string, description: "The account bio."},
475 description: "Avatar image encoded using multipart/form-data",
481 description: "Header image encoded using multipart/form-data",
487 description: "Whether manual approval of follow requests is required."
489 fields_attributes: %Schema{
492 %Schema{type: :array, items: attribute_field()},
493 %Schema{type: :object, additionalProperties: %Schema{type: attribute_field()}}
496 # NOTE: `source` field is not supported
501 # privacy: %Schema{type: :string},
502 # sensitive: %Schema{type: :boolean},
503 # language: %Schema{type: :string}
507 # Pleroma-specific fields
508 no_rich_text: %Schema{
511 description: "html tags are stripped from all statuses requested from the API"
513 hide_followers: %Schema{
516 description: "user's followers will be hidden"
518 hide_follows: %Schema{
521 description: "user's follows will be hidden"
523 hide_followers_count: %Schema{
526 description: "user's follower count will be hidden"
528 hide_follows_count: %Schema{
531 description: "user's follow count will be hidden"
533 hide_favorites: %Schema{
536 description: "user's favorites timeline will be hidden"
541 description: "user's role (e.g admin, moderator) will be exposed to anyone in the
544 default_scope: VisibilityScope,
545 pleroma_settings_store: %Schema{
548 description: "Opaque user settings to be saved on the backend."
550 skip_thread_containment: %Schema{
553 description: "Skip filtering out broken threads"
555 allow_following_move: %Schema{
558 description: "Allows automatically follow moved following accounts"
560 pleroma_background_image: %Schema{
563 description: "Sets the background image of the user.",
566 discoverable: %Schema{
570 "Discovery of this account in search results and other services is allowed."
572 actor_type: ActorType
576 display_name: "cofe",
578 fields_attributes: [%{name: "foo", value: "bar"}],
580 hide_followers: true,
582 hide_followers_count: false,
583 hide_follows_count: false,
584 hide_favorites: false,
586 default_scope: "private",
587 pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
588 skip_thread_containment: false,
589 allow_following_move: false,
596 def array_of_accounts do
598 title: "ArrayOfAccounts",
601 example: [Account.schema().example]
605 defp array_of_relationships do
607 title: "ArrayOfRelationships",
608 description: "Response schema for account relationships",
610 items: AccountRelationship,
615 "showing_reblogs" => true,
616 "followed_by" => true,
618 "blocked_by" => true,
620 "muting_notifications" => false,
621 "requested" => false,
622 "domain_blocking" => false,
623 "subscribing" => false,
629 "showing_reblogs" => true,
630 "followed_by" => true,
632 "blocked_by" => true,
634 "muting_notifications" => false,
636 "domain_blocking" => false,
637 "subscribing" => false,
643 "showing_reblogs" => true,
644 "followed_by" => true,
646 "blocked_by" => false,
648 "muting_notifications" => false,
649 "requested" => false,
650 "domain_blocking" => true,
651 "subscribing" => true,
658 defp follow_by_uri_request do
660 title: "AccountFollowsRequest",
661 description: "POST body for muting an account",
664 uri: %Schema{type: :string, nullable: true, format: :uri}
672 title: "AccountMuteRequest",
673 description: "POST body for muting an account",
676 notifications: %Schema{
679 description: "Mute notifications in addition to statuses? Defaults to true.",
684 "notifications" => true
689 defp array_of_lists do
691 title: "ArrayOfLists",
692 description: "Response schema for lists",
696 %{"id" => "123", "title" => "my list"},
697 %{"id" => "1337", "title" => "anotehr list"}
702 defp array_of_statuses do
704 title: "ArrayOfStatuses",
710 defp attribute_field do
712 title: "AccountAttributeField",
713 description: "Request schema for account custom fields",
716 name: %Schema{type: :string},
717 value: %Schema{type: :string}
719 required: [:name, :value],
722 "value" => "https://pleroma.com"