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 pagination_params() ++ [embed_relationships_param()],
162 200 => Operation.response("Accounts", "application/json", array_of_accounts())
167 def following_operation do
170 summary: "Following",
171 operationId: "AccountController.following",
172 security: [%{"oAuth" => ["read:accounts"]}],
174 "Accounts which the given account is following, if network is not hidden by the account owner.",
176 [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++
177 pagination_params() ++ [embed_relationships_param()],
178 responses: %{200 => Operation.response("Accounts", "application/json", array_of_accounts())}
182 def lists_operation do
185 summary: "Lists containing this account",
186 operationId: "AccountController.lists",
187 security: [%{"oAuth" => ["read:lists"]}],
188 description: "User lists that you have added this account to.",
189 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
190 responses: %{200 => Operation.response("Lists", "application/json", array_of_lists())}
194 def follow_operation do
198 operationId: "AccountController.follow",
199 security: [%{"oAuth" => ["follow", "write:follows"]}],
200 description: "Follow the given account",
202 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
207 "Receive this account's reblogs in home timeline? Defaults to true."
211 200 => Operation.response("Relationship", "application/json", AccountRelationship),
212 400 => Operation.response("Error", "application/json", ApiError),
213 404 => Operation.response("Error", "application/json", ApiError)
218 def unfollow_operation do
222 operationId: "AccountController.unfollow",
223 security: [%{"oAuth" => ["follow", "write:follows"]}],
224 description: "Unfollow the given account",
225 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
227 200 => Operation.response("Relationship", "application/json", AccountRelationship),
228 400 => Operation.response("Error", "application/json", ApiError),
229 404 => Operation.response("Error", "application/json", ApiError)
234 def mute_operation do
238 operationId: "AccountController.mute",
239 security: [%{"oAuth" => ["follow", "write:mutes"]}],
240 requestBody: request_body("Parameters", mute_request()),
242 "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).",
244 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
248 %Schema{allOf: [BooleanLike], default: true},
249 "Mute notifications in addition to statuses? Defaults to `true`."
253 200 => Operation.response("Relationship", "application/json", AccountRelationship)
258 def unmute_operation do
262 operationId: "AccountController.unmute",
263 security: [%{"oAuth" => ["follow", "write:mutes"]}],
264 description: "Unmute the given account.",
265 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
267 200 => Operation.response("Relationship", "application/json", AccountRelationship)
272 def block_operation do
276 operationId: "AccountController.block",
277 security: [%{"oAuth" => ["follow", "write:blocks"]}],
279 "Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
280 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
282 200 => Operation.response("Relationship", "application/json", AccountRelationship)
287 def unblock_operation do
291 operationId: "AccountController.unblock",
292 security: [%{"oAuth" => ["follow", "write:blocks"]}],
293 description: "Unblock the given account.",
294 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
296 200 => Operation.response("Relationship", "application/json", AccountRelationship)
301 def follow_by_uri_operation do
304 summary: "Follow by URI",
305 operationId: "AccountController.follows",
306 security: [%{"oAuth" => ["follow", "write:follows"]}],
307 requestBody: request_body("Parameters", follow_by_uri_request(), required: true),
309 200 => Operation.response("Account", "application/json", AccountRelationship),
310 400 => Operation.response("Error", "application/json", ApiError),
311 404 => Operation.response("Error", "application/json", ApiError)
316 def mutes_operation do
319 summary: "Muted accounts",
320 operationId: "AccountController.mutes",
321 description: "Accounts the user has muted.",
322 security: [%{"oAuth" => ["follow", "read:mutes"]}],
324 200 => Operation.response("Accounts", "application/json", array_of_accounts())
329 def blocks_operation do
332 summary: "Blocked users",
333 operationId: "AccountController.blocks",
334 description: "View your blocks. See also accounts/:id/{block,unblock}",
335 security: [%{"oAuth" => ["read:blocks"]}],
337 200 => Operation.response("Accounts", "application/json", array_of_accounts())
342 def endorsements_operation do
345 summary: "Endorsements",
346 operationId: "AccountController.endorsements",
347 description: "Not implemented",
348 security: [%{"oAuth" => ["read:accounts"]}],
350 200 => empty_array_response()
355 def identity_proofs_operation do
358 summary: "Identity proofs",
359 operationId: "AccountController.identity_proofs",
360 description: "Not implemented",
362 200 => empty_array_response()
367 defp create_request do
369 title: "AccountCreateRequest",
370 description: "POST body for creating an account",
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"},
382 "The email address to be used for login. Required when `account_activation_required` is enabled.",
387 description: "The password to be used for login",
393 "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."
397 description: "The language of the confirmation email that will be sent"
399 # Pleroma-specific properties:
400 fullname: %Schema{type: :string, description: "Full name"},
401 bio: %Schema{type: :string, description: "Bio", default: ""},
402 captcha_solution: %Schema{
404 description: "Provider-specific captcha solution"
406 captcha_token: %Schema{type: :string, description: "Provider-specific captcha token"},
407 captcha_answer_data: %Schema{type: :string, description: "Provider-specific captcha data"},
410 description: "Invite token required when the registrations aren't public"
413 required: [:username, :password, :agreement],
415 "username" => "cofe",
416 "email" => "cofe@example.com",
417 "password" => "secret",
418 "agreement" => "true",
424 defp create_response do
426 title: "AccountCreateResponse",
427 description: "Response schema for an account",
430 token_type: %Schema{type: :string},
431 access_token: %Schema{type: :string},
432 scope: %Schema{type: :array, items: %Schema{type: :string}},
433 created_at: %Schema{type: :integer, format: :"date-time"}
436 "access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
437 "created_at" => 1_585_918_714,
438 "scope" => ["read", "write", "follow", "push"],
439 "token_type" => "Bearer"
444 defp update_creadentials_request do
446 title: "AccountUpdateCredentialsRequest",
447 description: "POST body for creating an account",
452 description: "Whether the account has a bot flag."
454 display_name: %Schema{
456 description: "The display name to use for the profile."
458 note: %Schema{type: :string, description: "The account bio."},
461 description: "Avatar image encoded using multipart/form-data",
466 description: "Header image encoded using multipart/form-data",
471 description: "Whether manual approval of follow requests is required."
473 fields_attributes: %Schema{
475 %Schema{type: :array, items: attribute_field()},
476 %Schema{type: :object, additionalProperties: %Schema{type: attribute_field()}}
479 # NOTE: `source` field is not supported
484 # privacy: %Schema{type: :string},
485 # sensitive: %Schema{type: :boolean},
486 # language: %Schema{type: :string}
490 # Pleroma-specific fields
491 no_rich_text: %Schema{
493 description: "html tags are stripped from all statuses requested from the API"
495 hide_followers: %Schema{type: :boolean, description: "user's followers will be hidden"},
496 hide_follows: %Schema{type: :boolean, description: "user's follows will be hidden"},
497 hide_followers_count: %Schema{
499 description: "user's follower count will be hidden"
501 hide_follows_count: %Schema{
503 description: "user's follow count will be hidden"
505 hide_favorites: %Schema{
507 description: "user's favorites timeline will be hidden"
511 description: "user's role (e.g admin, moderator) will be exposed to anyone in the
514 default_scope: VisibilityScope,
515 pleroma_settings_store: %Schema{
517 description: "Opaque user settings to be saved on the backend."
519 skip_thread_containment: %Schema{
521 description: "Skip filtering out broken threads"
523 allow_following_move: %Schema{
525 description: "Allows automatically follow moved following accounts"
527 pleroma_background_image: %Schema{
529 description: "Sets the background image of the user.",
532 discoverable: %Schema{
535 "Discovery of this account in search results and other services is allowed."
537 actor_type: ActorType
541 display_name: "cofe",
543 fields_attributes: [%{name: "foo", value: "bar"}],
545 hide_followers: true,
547 hide_followers_count: false,
548 hide_follows_count: false,
549 hide_favorites: false,
551 default_scope: "private",
552 pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
553 skip_thread_containment: false,
554 allow_following_move: false,
561 def array_of_accounts do
563 title: "ArrayOfAccounts",
566 example: [Account.schema().example]
570 defp array_of_relationships do
572 title: "ArrayOfRelationships",
573 description: "Response schema for account relationships",
575 items: AccountRelationship,
580 "showing_reblogs" => true,
581 "followed_by" => true,
583 "blocked_by" => true,
585 "muting_notifications" => false,
586 "requested" => false,
587 "domain_blocking" => false,
588 "subscribing" => false,
594 "showing_reblogs" => true,
595 "followed_by" => true,
597 "blocked_by" => true,
599 "muting_notifications" => false,
601 "domain_blocking" => false,
602 "subscribing" => false,
608 "showing_reblogs" => true,
609 "followed_by" => true,
611 "blocked_by" => false,
613 "muting_notifications" => false,
614 "requested" => false,
615 "domain_blocking" => true,
616 "subscribing" => true,
623 defp follow_by_uri_request do
625 title: "AccountFollowsRequest",
626 description: "POST body for muting an account",
629 uri: %Schema{type: :string, format: :uri}
637 title: "AccountMuteRequest",
638 description: "POST body for muting an account",
641 notifications: %Schema{
643 description: "Mute notifications in addition to statuses? Defaults to true.",
648 "notifications" => true
653 defp array_of_lists do
655 title: "ArrayOfLists",
656 description: "Response schema for lists",
660 %{"id" => "123", "title" => "my list"},
661 %{"id" => "1337", "title" => "anotehr list"}
666 defp array_of_statuses do
668 title: "ArrayOfStatuses",
674 defp attribute_field do
676 title: "AccountAttributeField",
677 description: "Request schema for account custom fields",
680 name: %Schema{type: :string},
681 value: %Schema{type: :string}
683 required: [:name, :value],
686 "value" => "https://pleroma.com"