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"},
160 with_relationships_param() | pagination_params()
163 200 => Operation.response("Accounts", "application/json", array_of_accounts())
168 def following_operation do
171 summary: "Following",
172 operationId: "AccountController.following",
173 security: [%{"oAuth" => ["read:accounts"]}],
175 "Accounts which the given account is following, if network is not hidden by the account owner.",
177 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
178 with_relationships_param() | pagination_params()
180 responses: %{200 => Operation.response("Accounts", "application/json", array_of_accounts())}
184 def lists_operation do
187 summary: "Lists containing this account",
188 operationId: "AccountController.lists",
189 security: [%{"oAuth" => ["read:lists"]}],
190 description: "User lists that you have added this account to.",
191 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
192 responses: %{200 => Operation.response("Lists", "application/json", array_of_lists())}
196 def follow_operation do
200 operationId: "AccountController.follow",
201 security: [%{"oAuth" => ["follow", "write:follows"]}],
202 description: "Follow the given account",
204 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
209 "Receive this account's reblogs in home timeline? Defaults to true."
213 200 => Operation.response("Relationship", "application/json", AccountRelationship),
214 400 => Operation.response("Error", "application/json", ApiError),
215 404 => Operation.response("Error", "application/json", ApiError)
220 def unfollow_operation do
224 operationId: "AccountController.unfollow",
225 security: [%{"oAuth" => ["follow", "write:follows"]}],
226 description: "Unfollow the given account",
227 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
229 200 => Operation.response("Relationship", "application/json", AccountRelationship),
230 400 => Operation.response("Error", "application/json", ApiError),
231 404 => Operation.response("Error", "application/json", ApiError)
236 def mute_operation do
240 operationId: "AccountController.mute",
241 security: [%{"oAuth" => ["follow", "write:mutes"]}],
242 requestBody: request_body("Parameters", mute_request()),
244 "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).",
246 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
250 %Schema{allOf: [BooleanLike], default: true},
251 "Mute notifications in addition to statuses? Defaults to `true`."
255 200 => Operation.response("Relationship", "application/json", AccountRelationship)
260 def unmute_operation do
264 operationId: "AccountController.unmute",
265 security: [%{"oAuth" => ["follow", "write:mutes"]}],
266 description: "Unmute the given account.",
267 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
269 200 => Operation.response("Relationship", "application/json", AccountRelationship)
274 def block_operation do
278 operationId: "AccountController.block",
279 security: [%{"oAuth" => ["follow", "write:blocks"]}],
281 "Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
282 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
284 200 => Operation.response("Relationship", "application/json", AccountRelationship)
289 def unblock_operation do
293 operationId: "AccountController.unblock",
294 security: [%{"oAuth" => ["follow", "write:blocks"]}],
295 description: "Unblock the given account.",
296 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
298 200 => Operation.response("Relationship", "application/json", AccountRelationship)
303 def follow_by_uri_operation do
306 summary: "Follow by URI",
307 operationId: "AccountController.follows",
308 security: [%{"oAuth" => ["follow", "write:follows"]}],
309 requestBody: request_body("Parameters", follow_by_uri_request(), required: true),
311 200 => Operation.response("Account", "application/json", AccountRelationship),
312 400 => Operation.response("Error", "application/json", ApiError),
313 404 => Operation.response("Error", "application/json", ApiError)
318 def mutes_operation do
321 summary: "Muted accounts",
322 operationId: "AccountController.mutes",
323 description: "Accounts the user has muted.",
324 security: [%{"oAuth" => ["follow", "read:mutes"]}],
326 200 => Operation.response("Accounts", "application/json", array_of_accounts())
331 def blocks_operation do
334 summary: "Blocked users",
335 operationId: "AccountController.blocks",
336 description: "View your blocks. See also accounts/:id/{block,unblock}",
337 security: [%{"oAuth" => ["read:blocks"]}],
339 200 => Operation.response("Accounts", "application/json", array_of_accounts())
344 def endorsements_operation do
347 summary: "Endorsements",
348 operationId: "AccountController.endorsements",
349 description: "Not implemented",
350 security: [%{"oAuth" => ["read:accounts"]}],
352 200 => empty_array_response()
357 def identity_proofs_operation do
360 summary: "Identity proofs",
361 operationId: "AccountController.identity_proofs",
362 description: "Not implemented",
364 200 => empty_array_response()
369 defp create_request do
371 title: "AccountCreateRequest",
372 description: "POST body for creating an account",
374 required: [:username, :password, :agreement],
380 "Text that will be reviewed by moderators if registrations require manual approval"
382 username: %Schema{type: :string, description: "The desired username for the account"},
387 "The email address to be used for login. Required when `account_activation_required` is enabled.",
392 description: "The password to be used for login",
398 "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."
403 description: "The language of the confirmation email that will be sent"
405 # Pleroma-specific properties:
406 fullname: %Schema{type: :string, nullable: true, description: "Full name"},
407 bio: %Schema{type: :string, description: "Bio", nullable: true, default: ""},
408 captcha_solution: %Schema{
411 description: "Provider-specific captcha solution"
413 captcha_token: %Schema{
416 description: "Provider-specific captcha token"
418 captcha_answer_data: %Schema{
421 description: "Provider-specific captcha data"
426 description: "Invite token required when the registrations aren't public"
430 "username" => "cofe",
431 "email" => "cofe@example.com",
432 "password" => "secret",
433 "agreement" => "true",
439 defp create_response do
441 title: "AccountCreateResponse",
442 description: "Response schema for an account",
445 token_type: %Schema{type: :string},
446 access_token: %Schema{type: :string},
447 scope: %Schema{type: :array, items: %Schema{type: :string}},
448 created_at: %Schema{type: :integer, format: :"date-time"}
451 "access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
452 "created_at" => 1_585_918_714,
453 "scope" => ["read", "write", "follow", "push"],
454 "token_type" => "Bearer"
459 defp update_creadentials_request do
461 title: "AccountUpdateCredentialsRequest",
462 description: "POST body for creating an account",
468 description: "Whether the account has a bot flag."
470 display_name: %Schema{
473 description: "The display name to use for the profile."
475 note: %Schema{type: :string, description: "The account bio."},
479 description: "Avatar image encoded using multipart/form-data",
485 description: "Header image encoded using multipart/form-data",
491 description: "Whether manual approval of follow requests is required."
493 fields_attributes: %Schema{
496 %Schema{type: :array, items: attribute_field()},
497 %Schema{type: :object, additionalProperties: %Schema{type: attribute_field()}}
500 # NOTE: `source` field is not supported
505 # privacy: %Schema{type: :string},
506 # sensitive: %Schema{type: :boolean},
507 # language: %Schema{type: :string}
511 # Pleroma-specific fields
512 no_rich_text: %Schema{
515 description: "html tags are stripped from all statuses requested from the API"
517 hide_followers: %Schema{
520 description: "user's followers will be hidden"
522 hide_follows: %Schema{
525 description: "user's follows will be hidden"
527 hide_followers_count: %Schema{
530 description: "user's follower count will be hidden"
532 hide_follows_count: %Schema{
535 description: "user's follow count will be hidden"
537 hide_favorites: %Schema{
540 description: "user's favorites timeline will be hidden"
545 description: "user's role (e.g admin, moderator) will be exposed to anyone in the
548 default_scope: VisibilityScope,
549 pleroma_settings_store: %Schema{
552 description: "Opaque user settings to be saved on the backend."
554 skip_thread_containment: %Schema{
557 description: "Skip filtering out broken threads"
559 allow_following_move: %Schema{
562 description: "Allows automatically follow moved following accounts"
564 pleroma_background_image: %Schema{
567 description: "Sets the background image of the user.",
570 discoverable: %Schema{
574 "Discovery of this account in search results and other services is allowed."
576 actor_type: ActorType
580 display_name: "cofe",
582 fields_attributes: [%{name: "foo", value: "bar"}],
584 hide_followers: true,
586 hide_followers_count: false,
587 hide_follows_count: false,
588 hide_favorites: false,
590 default_scope: "private",
591 pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
592 skip_thread_containment: false,
593 allow_following_move: false,
600 def array_of_accounts do
602 title: "ArrayOfAccounts",
605 example: [Account.schema().example]
609 defp array_of_relationships do
611 title: "ArrayOfRelationships",
612 description: "Response schema for account relationships",
614 items: AccountRelationship,
619 "showing_reblogs" => true,
620 "followed_by" => true,
622 "blocked_by" => true,
624 "muting_notifications" => false,
625 "requested" => false,
626 "domain_blocking" => false,
627 "subscribing" => false,
633 "showing_reblogs" => true,
634 "followed_by" => true,
636 "blocked_by" => true,
638 "muting_notifications" => false,
640 "domain_blocking" => false,
641 "subscribing" => false,
647 "showing_reblogs" => true,
648 "followed_by" => true,
650 "blocked_by" => false,
652 "muting_notifications" => false,
653 "requested" => false,
654 "domain_blocking" => true,
655 "subscribing" => true,
662 defp follow_by_uri_request do
664 title: "AccountFollowsRequest",
665 description: "POST body for muting an account",
668 uri: %Schema{type: :string, nullable: true, format: :uri}
676 title: "AccountMuteRequest",
677 description: "POST body for muting an account",
680 notifications: %Schema{
683 description: "Mute notifications in addition to statuses? Defaults to true.",
688 "notifications" => true
693 defp array_of_lists do
695 title: "ArrayOfLists",
696 description: "Response schema for lists",
700 %{"id" => "123", "title" => "my list"},
701 %{"id" => "1337", "title" => "anotehr list"}
706 defp array_of_statuses do
708 title: "ArrayOfStatuses",
714 defp attribute_field do
716 title: "AccountAttributeField",
717 description: "Request schema for account custom fields",
720 name: %Schema{type: :string},
721 value: %Schema{type: :string}
723 required: [:name, :value],
726 "value" => "https://pleroma.com"