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.Status
15 alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
17 import Pleroma.Web.ApiSpec.Helpers
19 @spec open_api_operation(atom) :: Operation.t()
20 def open_api_operation(action) do
21 operation = String.to_existing_atom("#{action}_operation")
22 apply(__MODULE__, operation, [])
25 @spec create_operation() :: Operation.t()
26 def create_operation do
29 summary: "Register an account",
31 "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.",
32 operationId: "AccountController.create",
33 requestBody: request_body("Parameters", create_request(), required: true),
35 200 => Operation.response("Account", "application/json", create_response()),
36 400 => Operation.response("Error", "application/json", ApiError),
37 403 => Operation.response("Error", "application/json", ApiError),
38 429 => Operation.response("Error", "application/json", ApiError)
43 def verify_credentials_operation do
46 description: "Test to make sure that the user token works.",
47 summary: "Verify account credentials",
48 operationId: "AccountController.verify_credentials",
49 security: [%{"oAuth" => ["read:accounts"]}],
51 200 => Operation.response("Account", "application/json", Account)
56 def update_credentials_operation do
59 summary: "Update account credentials",
60 description: "Update the user's display and preferences.",
61 operationId: "AccountController.update_credentials",
62 security: [%{"oAuth" => ["write:accounts"]}],
63 requestBody: request_body("Parameters", update_creadentials_request(), required: true),
65 200 => Operation.response("Account", "application/json", Account),
66 403 => Operation.response("Error", "application/json", ApiError)
71 def relationships_operation do
74 summary: "Check relationships to other accounts",
75 operationId: "AccountController.relationships",
76 description: "Find out whether a given account is followed, blocked, muted, etc.",
77 security: [%{"oAuth" => ["read:follows"]}],
83 oneOf: [%Schema{type: :array, items: %Schema{type: :string}}, %Schema{type: :string}]
90 200 => Operation.response("Account", "application/json", array_of_relationships())
99 operationId: "AccountController.show",
100 description: "View information about a profile.",
101 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
103 200 => Operation.response("Account", "application/json", Account),
104 404 => Operation.response("Error", "application/json", ApiError)
109 def statuses_operation do
113 operationId: "AccountController.statuses",
115 "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)",
118 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
119 Operation.parameter(:pinned, :query, BooleanLike, "Include only pinned statuses"),
120 Operation.parameter(:tagged, :query, :string, "With tag"),
125 "Include only statuses with media attached"
131 "Include statuses from muted acccounts."
133 Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
134 Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
136 :exclude_visibilities,
138 %Schema{type: :array, items: VisibilityScope},
139 "Exclude visibilities"
141 ] ++ pagination_params(),
143 200 => Operation.response("Statuses", "application/json", array_of_statuses()),
144 404 => Operation.response("Error", "application/json", ApiError)
149 def followers_operation do
152 summary: "Followers",
153 operationId: "AccountController.followers",
154 security: [%{"oAuth" => ["read:accounts"]}],
156 "Accounts which follow the given account, if network is not hidden by the account owner.",
158 [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
160 200 => Operation.response("Accounts", "application/json", array_of_accounts())
165 def following_operation do
168 summary: "Following",
169 operationId: "AccountController.following",
170 security: [%{"oAuth" => ["read:accounts"]}],
172 "Accounts which the given account is following, if network is not hidden by the account owner.",
174 [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
175 responses: %{200 => Operation.response("Accounts", "application/json", array_of_accounts())}
179 def lists_operation do
182 summary: "Lists containing this account",
183 operationId: "AccountController.lists",
184 security: [%{"oAuth" => ["read:lists"]}],
185 description: "User lists that you have added this account to.",
186 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
187 responses: %{200 => Operation.response("Lists", "application/json", array_of_lists())}
191 def follow_operation do
195 operationId: "AccountController.follow",
196 security: [%{"oAuth" => ["follow", "write:follows"]}],
197 description: "Follow the given account",
199 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
204 "Receive this account's reblogs in home timeline? Defaults to true."
208 200 => Operation.response("Relationship", "application/json", AccountRelationship),
209 400 => Operation.response("Error", "application/json", ApiError),
210 404 => Operation.response("Error", "application/json", ApiError)
215 def unfollow_operation do
219 operationId: "AccountController.unfollow",
220 security: [%{"oAuth" => ["follow", "write:follows"]}],
221 description: "Unfollow the given account",
222 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
224 200 => Operation.response("Relationship", "application/json", AccountRelationship),
225 400 => Operation.response("Error", "application/json", ApiError),
226 404 => Operation.response("Error", "application/json", ApiError)
231 def mute_operation do
235 operationId: "AccountController.mute",
236 security: [%{"oAuth" => ["follow", "write:mutes"]}],
237 requestBody: request_body("Parameters", mute_request()),
239 "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).",
241 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
245 %Schema{allOf: [BooleanLike], default: true},
246 "Mute notifications in addition to statuses? Defaults to `true`."
250 200 => Operation.response("Relationship", "application/json", AccountRelationship)
255 def unmute_operation do
259 operationId: "AccountController.unmute",
260 security: [%{"oAuth" => ["follow", "write:mutes"]}],
261 description: "Unmute the given account.",
262 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
264 200 => Operation.response("Relationship", "application/json", AccountRelationship)
269 def block_operation do
273 operationId: "AccountController.block",
274 security: [%{"oAuth" => ["follow", "write:blocks"]}],
276 "Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
277 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
279 200 => Operation.response("Relationship", "application/json", AccountRelationship)
284 def unblock_operation do
288 operationId: "AccountController.unblock",
289 security: [%{"oAuth" => ["follow", "write:blocks"]}],
290 description: "Unblock the given account.",
291 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
293 200 => Operation.response("Relationship", "application/json", AccountRelationship)
298 def follow_by_uri_operation do
301 summary: "Follow by URI",
302 operationId: "AccountController.follows",
303 security: [%{"oAuth" => ["follow", "write:follows"]}],
304 requestBody: request_body("Parameters", follow_by_uri_request(), required: true),
306 200 => Operation.response("Account", "application/json", AccountRelationship),
307 400 => Operation.response("Error", "application/json", ApiError),
308 404 => Operation.response("Error", "application/json", ApiError)
313 def mutes_operation do
316 summary: "Muted accounts",
317 operationId: "AccountController.mutes",
318 description: "Accounts the user has muted.",
319 security: [%{"oAuth" => ["follow", "read:mutes"]}],
321 200 => Operation.response("Accounts", "application/json", array_of_accounts())
326 def blocks_operation do
329 summary: "Blocked users",
330 operationId: "AccountController.blocks",
331 description: "View your blocks. See also accounts/:id/{block,unblock}",
332 security: [%{"oAuth" => ["read:blocks"]}],
334 200 => Operation.response("Accounts", "application/json", array_of_accounts())
339 def endorsements_operation do
342 summary: "Endorsements",
343 operationId: "AccountController.endorsements",
344 description: "Not implemented",
345 security: [%{"oAuth" => ["read:accounts"]}],
347 200 => empty_array_response()
352 def identity_proofs_operation do
355 summary: "Identity proofs",
356 operationId: "AccountController.identity_proofs",
357 description: "Not implemented",
359 200 => empty_array_response()
364 defp create_request do
366 title: "AccountCreateRequest",
367 description: "POST body for creating an account",
373 "Text that will be reviewed by moderators if registrations require manual approval"
375 username: %Schema{type: :string, description: "The desired username for the account"},
379 "The email address to be used for login. Required when `account_activation_required` is enabled.",
384 description: "The password to be used for login",
390 "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."
394 description: "The language of the confirmation email that will be sent"
396 # Pleroma-specific properties:
397 fullname: %Schema{type: :string, description: "Full name"},
398 bio: %Schema{type: :string, description: "Bio", default: ""},
399 captcha_solution: %Schema{
401 description: "Provider-specific captcha solution"
403 captcha_token: %Schema{type: :string, description: "Provider-specific captcha token"},
404 captcha_answer_data: %Schema{type: :string, description: "Provider-specific captcha data"},
407 description: "Invite token required when the registrations aren't public"
410 required: [:username, :password, :agreement],
412 "username" => "cofe",
413 "email" => "cofe@example.com",
414 "password" => "secret",
415 "agreement" => "true",
421 defp create_response do
423 title: "AccountCreateResponse",
424 description: "Response schema for an account",
427 token_type: %Schema{type: :string},
428 access_token: %Schema{type: :string},
429 scope: %Schema{type: :array, items: %Schema{type: :string}},
430 created_at: %Schema{type: :integer, format: :"date-time"}
433 "access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
434 "created_at" => 1_585_918_714,
435 "scope" => ["read", "write", "follow", "push"],
436 "token_type" => "Bearer"
441 defp update_creadentials_request do
443 title: "AccountUpdateCredentialsRequest",
444 description: "POST body for creating an account",
449 description: "Whether the account has a bot flag."
451 display_name: %Schema{
453 description: "The display name to use for the profile."
455 note: %Schema{type: :string, description: "The account bio."},
458 description: "Avatar image encoded using multipart/form-data",
463 description: "Header image encoded using multipart/form-data",
468 description: "Whether manual approval of follow requests is required."
470 fields_attributes: %Schema{
472 %Schema{type: :array, items: attribute_field()},
473 %Schema{type: :object, additionalProperties: %Schema{type: attribute_field()}}
476 # NOTE: `source` field is not supported
481 # privacy: %Schema{type: :string},
482 # sensitive: %Schema{type: :boolean},
483 # language: %Schema{type: :string}
487 # Pleroma-specific fields
488 no_rich_text: %Schema{
490 description: "html tags are stripped from all statuses requested from the API"
492 hide_followers: %Schema{type: :boolean, description: "user's followers will be hidden"},
493 hide_follows: %Schema{type: :boolean, description: "user's follows will be hidden"},
494 hide_followers_count: %Schema{
496 description: "user's follower count will be hidden"
498 hide_follows_count: %Schema{
500 description: "user's follow count will be hidden"
502 hide_favorites: %Schema{
504 description: "user's favorites timeline will be hidden"
508 description: "user's role (e.g admin, moderator) will be exposed to anyone in the
511 default_scope: VisibilityScope,
512 pleroma_settings_store: %Schema{
514 description: "Opaque user settings to be saved on the backend."
516 skip_thread_containment: %Schema{
518 description: "Skip filtering out broken threads"
520 allow_following_move: %Schema{
522 description: "Allows automatically follow moved following accounts"
524 pleroma_background_image: %Schema{
526 description: "Sets the background image of the user.",
529 discoverable: %Schema{
532 "Discovery of this account in search results and other services is allowed."
534 actor_type: ActorType
538 display_name: "cofe",
540 fields_attributes: [%{name: "foo", value: "bar"}],
542 hide_followers: true,
544 hide_followers_count: false,
545 hide_follows_count: false,
546 hide_favorites: false,
548 default_scope: "private",
549 pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
550 skip_thread_containment: false,
551 allow_following_move: false,
558 defp array_of_accounts do
560 title: "ArrayOfAccounts",
566 defp array_of_relationships do
568 title: "ArrayOfRelationships",
569 description: "Response schema for account relationships",
571 items: AccountRelationship,
576 "showing_reblogs" => true,
577 "followed_by" => true,
579 "blocked_by" => true,
581 "muting_notifications" => false,
582 "requested" => false,
583 "domain_blocking" => false,
584 "subscribing" => false,
590 "showing_reblogs" => true,
591 "followed_by" => true,
593 "blocked_by" => true,
595 "muting_notifications" => false,
597 "domain_blocking" => false,
598 "subscribing" => false,
604 "showing_reblogs" => true,
605 "followed_by" => true,
607 "blocked_by" => false,
609 "muting_notifications" => false,
610 "requested" => false,
611 "domain_blocking" => true,
612 "subscribing" => true,
619 defp follow_by_uri_request do
621 title: "AccountFollowsRequest",
622 description: "POST body for muting an account",
625 uri: %Schema{type: :string, format: :uri}
633 title: "AccountMuteRequest",
634 description: "POST body for muting an account",
637 notifications: %Schema{
639 description: "Mute notifications in addition to statuses? Defaults to true.",
644 "notifications" => true
652 description: "Response schema for a list",
655 id: %Schema{type: :string},
656 title: %Schema{type: :string}
665 defp array_of_lists do
667 title: "ArrayOfLists",
668 description: "Response schema for lists",
672 %{"id" => "123", "title" => "my list"},
673 %{"id" => "1337", "title" => "anotehr list"}
678 defp array_of_statuses do
680 title: "ArrayOfStatuses",
686 defp attribute_field do
688 title: "AccountAttributeField",
689 description: "Request schema for account custom fields",
692 name: %Schema{type: :string},
693 value: %Schema{type: :string}
695 required: [:name, :value],
698 "value" => "https://pleroma.com"