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_credentials_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 401 => Operation.response("Error", "application/json", ApiError),
106 404 => Operation.response("Error", "application/json", ApiError)
111 def statuses_operation do
115 operationId: "AccountController.statuses",
117 "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)",
120 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
121 Operation.parameter(:pinned, :query, BooleanLike, "Include only pinned statuses"),
122 Operation.parameter(:tagged, :query, :string, "With tag"),
127 "Include only statuses with media attached"
133 "Include statuses from muted acccounts."
135 Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
136 Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
138 :exclude_visibilities,
140 %Schema{type: :array, items: VisibilityScope},
141 "Exclude visibilities"
143 ] ++ pagination_params(),
145 200 => Operation.response("Statuses", "application/json", array_of_statuses()),
146 401 => Operation.response("Error", "application/json", ApiError),
147 404 => Operation.response("Error", "application/json", ApiError)
152 def followers_operation do
155 summary: "Followers",
156 operationId: "AccountController.followers",
157 security: [%{"oAuth" => ["read:accounts"]}],
159 "Accounts which follow the given account, if network is not hidden by the account owner.",
161 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
162 with_relationships_param() | pagination_params()
165 200 => Operation.response("Accounts", "application/json", array_of_accounts())
170 def following_operation do
173 summary: "Following",
174 operationId: "AccountController.following",
175 security: [%{"oAuth" => ["read:accounts"]}],
177 "Accounts which the given account is following, if network is not hidden by the account owner.",
179 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
180 with_relationships_param() | pagination_params()
182 responses: %{200 => Operation.response("Accounts", "application/json", array_of_accounts())}
186 def lists_operation do
189 summary: "Lists containing this account",
190 operationId: "AccountController.lists",
191 security: [%{"oAuth" => ["read:lists"]}],
192 description: "User lists that you have added this account to.",
193 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
194 responses: %{200 => Operation.response("Lists", "application/json", array_of_lists())}
198 def follow_operation do
202 operationId: "AccountController.follow",
203 security: [%{"oAuth" => ["follow", "write:follows"]}],
204 description: "Follow the given account",
206 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
211 "Receive this account's reblogs in home timeline? Defaults to true."
215 200 => Operation.response("Relationship", "application/json", AccountRelationship),
216 400 => Operation.response("Error", "application/json", ApiError),
217 404 => Operation.response("Error", "application/json", ApiError)
222 def unfollow_operation do
226 operationId: "AccountController.unfollow",
227 security: [%{"oAuth" => ["follow", "write:follows"]}],
228 description: "Unfollow the given account",
229 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
231 200 => Operation.response("Relationship", "application/json", AccountRelationship),
232 400 => Operation.response("Error", "application/json", ApiError),
233 404 => Operation.response("Error", "application/json", ApiError)
238 def mute_operation do
242 operationId: "AccountController.mute",
243 security: [%{"oAuth" => ["follow", "write:mutes"]}],
244 requestBody: request_body("Parameters", mute_request()),
246 "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).",
248 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
252 %Schema{allOf: [BooleanLike], default: true},
253 "Mute notifications in addition to statuses? Defaults to `true`."
257 200 => Operation.response("Relationship", "application/json", AccountRelationship)
262 def unmute_operation do
266 operationId: "AccountController.unmute",
267 security: [%{"oAuth" => ["follow", "write:mutes"]}],
268 description: "Unmute the given account.",
269 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
271 200 => Operation.response("Relationship", "application/json", AccountRelationship)
276 def block_operation do
280 operationId: "AccountController.block",
281 security: [%{"oAuth" => ["follow", "write:blocks"]}],
283 "Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
284 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
286 200 => Operation.response("Relationship", "application/json", AccountRelationship)
291 def unblock_operation do
295 operationId: "AccountController.unblock",
296 security: [%{"oAuth" => ["follow", "write:blocks"]}],
297 description: "Unblock the given account.",
298 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
300 200 => Operation.response("Relationship", "application/json", AccountRelationship)
305 def follow_by_uri_operation do
308 summary: "Follow by URI",
309 operationId: "AccountController.follows",
310 security: [%{"oAuth" => ["follow", "write:follows"]}],
311 requestBody: request_body("Parameters", follow_by_uri_request(), required: true),
313 200 => Operation.response("Account", "application/json", AccountRelationship),
314 400 => Operation.response("Error", "application/json", ApiError),
315 404 => Operation.response("Error", "application/json", ApiError)
320 def mutes_operation do
323 summary: "Muted accounts",
324 operationId: "AccountController.mutes",
325 description: "Accounts the user has muted.",
326 security: [%{"oAuth" => ["follow", "read:mutes"]}],
328 200 => Operation.response("Accounts", "application/json", array_of_accounts())
333 def blocks_operation do
336 summary: "Blocked users",
337 operationId: "AccountController.blocks",
338 description: "View your blocks. See also accounts/:id/{block,unblock}",
339 security: [%{"oAuth" => ["read:blocks"]}],
341 200 => Operation.response("Accounts", "application/json", array_of_accounts())
346 def endorsements_operation do
349 summary: "Endorsements",
350 operationId: "AccountController.endorsements",
351 description: "Not implemented",
352 security: [%{"oAuth" => ["read:accounts"]}],
354 200 => empty_array_response()
359 def identity_proofs_operation do
362 summary: "Identity proofs",
363 operationId: "AccountController.identity_proofs",
364 description: "Not implemented",
366 200 => empty_array_response()
371 defp create_request do
373 title: "AccountCreateRequest",
374 description: "POST body for creating an account",
376 required: [:username, :password, :agreement],
382 "Text that will be reviewed by moderators if registrations require manual approval"
384 username: %Schema{type: :string, description: "The desired username for the account"},
389 "The email address to be used for login. Required when `account_activation_required` is enabled.",
394 description: "The password to be used for login",
398 allOf: [BooleanLike],
400 "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."
405 description: "The language of the confirmation email that will be sent"
407 # Pleroma-specific properties:
408 fullname: %Schema{type: :string, nullable: true, description: "Full name"},
409 bio: %Schema{type: :string, description: "Bio", nullable: true, default: ""},
410 captcha_solution: %Schema{
413 description: "Provider-specific captcha solution"
415 captcha_token: %Schema{
418 description: "Provider-specific captcha token"
420 captcha_answer_data: %Schema{
423 description: "Provider-specific captcha data"
428 description: "Invite token required when the registrations aren't public"
432 "username" => "cofe",
433 "email" => "cofe@example.com",
434 "password" => "secret",
435 "agreement" => "true",
441 defp create_response do
443 title: "AccountCreateResponse",
444 description: "Response schema for an account",
447 token_type: %Schema{type: :string},
448 access_token: %Schema{type: :string},
449 scope: %Schema{type: :array, items: %Schema{type: :string}},
450 created_at: %Schema{type: :integer, format: :"date-time"}
453 "access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
454 "created_at" => 1_585_918_714,
455 "scope" => ["read", "write", "follow", "push"],
456 "token_type" => "Bearer"
461 defp update_credentials_request do
463 title: "AccountUpdateCredentialsRequest",
464 description: "POST body for creating an account",
468 allOf: [BooleanLike],
470 description: "Whether the account has a bot flag."
472 display_name: %Schema{
475 description: "The display name to use for the profile."
477 note: %Schema{type: :string, description: "The account bio."},
481 description: "Avatar image encoded using multipart/form-data",
487 description: "Header image encoded using multipart/form-data",
491 allOf: [BooleanLike],
493 description: "Whether manual approval of follow requests is required."
495 accepts_chat_messages: %Schema{
496 allOf: [BooleanLike],
498 description: "Whether the user accepts receiving chat messages."
500 fields_attributes: %Schema{
503 %Schema{type: :array, items: attribute_field()},
504 %Schema{type: :object, additionalProperties: %Schema{type: attribute_field()}}
507 # NOTE: `source` field is not supported
512 # privacy: %Schema{type: :string},
513 # sensitive: %Schema{type: :boolean},
514 # language: %Schema{type: :string}
518 # Pleroma-specific fields
519 no_rich_text: %Schema{
520 allOf: [BooleanLike],
522 description: "html tags are stripped from all statuses requested from the API"
524 hide_followers: %Schema{
525 allOf: [BooleanLike],
527 description: "user's followers will be hidden"
529 hide_follows: %Schema{
530 allOf: [BooleanLike],
532 description: "user's follows will be hidden"
534 hide_followers_count: %Schema{
535 allOf: [BooleanLike],
537 description: "user's follower count will be hidden"
539 hide_follows_count: %Schema{
540 allOf: [BooleanLike],
542 description: "user's follow count will be hidden"
544 hide_favorites: %Schema{
545 allOf: [BooleanLike],
547 description: "user's favorites timeline will be hidden"
550 allOf: [BooleanLike],
552 description: "user's role (e.g admin, moderator) will be exposed to anyone in the
555 default_scope: VisibilityScope,
556 pleroma_settings_store: %Schema{
559 description: "Opaque user settings to be saved on the backend."
561 skip_thread_containment: %Schema{
562 allOf: [BooleanLike],
564 description: "Skip filtering out broken threads"
566 allow_following_move: %Schema{
567 allOf: [BooleanLike],
569 description: "Allows automatically follow moved following accounts"
571 pleroma_background_image: %Schema{
574 description: "Sets the background image of the user.",
577 discoverable: %Schema{
578 allOf: [BooleanLike],
581 "Discovery of this account in search results and other services is allowed."
583 actor_type: ActorType
587 display_name: "cofe",
589 fields_attributes: [%{name: "foo", value: "bar"}],
591 hide_followers: true,
593 hide_followers_count: false,
594 hide_follows_count: false,
595 hide_favorites: false,
597 default_scope: "private",
598 pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
599 skip_thread_containment: false,
600 allow_following_move: false,
607 def array_of_accounts do
609 title: "ArrayOfAccounts",
612 example: [Account.schema().example]
616 defp array_of_relationships do
618 title: "ArrayOfRelationships",
619 description: "Response schema for account relationships",
621 items: AccountRelationship,
626 "showing_reblogs" => true,
627 "followed_by" => true,
629 "blocked_by" => true,
631 "muting_notifications" => false,
632 "requested" => false,
633 "domain_blocking" => false,
634 "subscribing" => false,
640 "showing_reblogs" => true,
641 "followed_by" => true,
643 "blocked_by" => true,
645 "muting_notifications" => false,
647 "domain_blocking" => false,
648 "subscribing" => false,
654 "showing_reblogs" => true,
655 "followed_by" => true,
657 "blocked_by" => false,
659 "muting_notifications" => false,
660 "requested" => false,
661 "domain_blocking" => true,
662 "subscribing" => true,
669 defp follow_by_uri_request do
671 title: "AccountFollowsRequest",
672 description: "POST body for muting an account",
675 uri: %Schema{type: :string, nullable: true, format: :uri}
683 title: "AccountMuteRequest",
684 description: "POST body for muting an account",
687 notifications: %Schema{
688 allOf: [BooleanLike],
690 description: "Mute notifications in addition to statuses? Defaults to true.",
695 "notifications" => true
700 defp array_of_lists do
702 title: "ArrayOfLists",
703 description: "Response schema for lists",
707 %{"id" => "123", "title" => "my list"},
708 %{"id" => "1337", "title" => "anotehr list"}
713 defp array_of_statuses do
715 title: "ArrayOfStatuses",
721 defp attribute_field do
723 title: "AccountAttributeField",
724 description: "Request schema for account custom fields",
727 name: %Schema{type: :string},
728 value: %Schema{type: :string}
730 required: [:name, :value],
733 "value" => "https://pleroma.com"