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"),
135 :exclude_visibilities,
137 %Schema{type: :array, items: VisibilityScope},
138 "Exclude visibilities"
140 ] ++ pagination_params(),
142 200 => Operation.response("Statuses", "application/json", array_of_statuses()),
143 404 => Operation.response("Error", "application/json", ApiError)
148 def followers_operation do
151 summary: "Followers",
152 operationId: "AccountController.followers",
153 security: [%{"oAuth" => ["read:accounts"]}],
155 "Accounts which follow the given account, if network is not hidden by the account owner.",
157 [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
159 200 => Operation.response("Accounts", "application/json", array_of_accounts())
164 def following_operation do
167 summary: "Following",
168 operationId: "AccountController.following",
169 security: [%{"oAuth" => ["read:accounts"]}],
171 "Accounts which the given account is following, if network is not hidden by the account owner.",
173 [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
174 responses: %{200 => Operation.response("Accounts", "application/json", array_of_accounts())}
178 def lists_operation do
181 summary: "Lists containing this account",
182 operationId: "AccountController.lists",
183 security: [%{"oAuth" => ["read:lists"]}],
184 description: "User lists that you have added this account to.",
185 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
186 responses: %{200 => Operation.response("Lists", "application/json", array_of_lists())}
190 def follow_operation do
194 operationId: "AccountController.follow",
195 security: [%{"oAuth" => ["follow", "write:follows"]}],
196 description: "Follow the given account",
198 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
203 "Receive this account's reblogs in home timeline? Defaults to true."
207 200 => Operation.response("Relationship", "application/json", AccountRelationship),
208 400 => Operation.response("Error", "application/json", ApiError),
209 404 => Operation.response("Error", "application/json", ApiError)
214 def unfollow_operation do
218 operationId: "AccountController.unfollow",
219 security: [%{"oAuth" => ["follow", "write:follows"]}],
220 description: "Unfollow the given account",
221 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
223 200 => Operation.response("Relationship", "application/json", AccountRelationship),
224 400 => Operation.response("Error", "application/json", ApiError),
225 404 => Operation.response("Error", "application/json", ApiError)
230 def mute_operation do
234 operationId: "AccountController.mute",
235 security: [%{"oAuth" => ["follow", "write:mutes"]}],
236 requestBody: request_body("Parameters", mute_request()),
238 "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).",
240 %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
244 %Schema{allOf: [BooleanLike], default: true},
245 "Mute notifications in addition to statuses? Defaults to `true`."
249 200 => Operation.response("Relationship", "application/json", AccountRelationship)
254 def unmute_operation do
258 operationId: "AccountController.unmute",
259 security: [%{"oAuth" => ["follow", "write:mutes"]}],
260 description: "Unmute the given account.",
261 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
263 200 => Operation.response("Relationship", "application/json", AccountRelationship)
268 def block_operation do
272 operationId: "AccountController.block",
273 security: [%{"oAuth" => ["follow", "write:blocks"]}],
275 "Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
276 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
278 200 => Operation.response("Relationship", "application/json", AccountRelationship)
283 def unblock_operation do
287 operationId: "AccountController.unblock",
288 security: [%{"oAuth" => ["follow", "write:blocks"]}],
289 description: "Unblock the given account.",
290 parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
292 200 => Operation.response("Relationship", "application/json", AccountRelationship)
297 def follows_operation do
301 operationId: "AccountController.follows",
302 security: [%{"oAuth" => ["follow", "write:follows"]}],
303 requestBody: request_body("Parameters", follows_request(), required: true),
305 200 => Operation.response("Account", "application/json", AccountRelationship),
306 400 => Operation.response("Error", "application/json", ApiError),
307 404 => Operation.response("Error", "application/json", ApiError)
312 def mutes_operation do
315 summary: "Muted accounts",
316 operationId: "AccountController.mutes",
317 description: "Accounts the user has muted.",
318 security: [%{"oAuth" => ["follow", "read:mutes"]}],
320 200 => Operation.response("Accounts", "application/json", array_of_accounts())
325 def blocks_operation do
328 summary: "Blocked users",
329 operationId: "AccountController.blocks",
330 description: "View your blocks. See also accounts/:id/{block,unblock}",
331 security: [%{"oAuth" => ["read:blocks"]}],
333 200 => Operation.response("Accounts", "application/json", array_of_accounts())
338 def endorsements_operation do
341 summary: "Endorsements",
342 operationId: "AccountController.endorsements",
343 description: "Not implemented",
344 security: [%{"oAuth" => ["read:accounts"]}],
346 200 => Operation.response("Empry array", "application/json", %Schema{type: :array})
351 def identity_proofs_operation do
354 summary: "Identity proofs",
355 operationId: "AccountController.identity_proofs",
356 description: "Not implemented",
358 200 => Operation.response("Empry array", "application/json", %Schema{type: :array})
363 defp create_request do
365 title: "AccountCreateRequest",
366 description: "POST body for creating an account",
372 "Text that will be reviewed by moderators if registrations require manual approval"
374 username: %Schema{type: :string, description: "The desired username for the account"},
378 "The email address to be used for login. Required when `account_activation_required` is enabled.",
383 description: "The password to be used for login",
389 "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."
393 description: "The language of the confirmation email that will be sent"
395 # Pleroma-specific properties:
396 fullname: %Schema{type: :string, description: "Full name"},
397 bio: %Schema{type: :string, description: "Bio", default: ""},
398 captcha_solution: %Schema{
400 description: "Provider-specific captcha solution"
402 captcha_token: %Schema{type: :string, description: "Provider-specific captcha token"},
403 captcha_answer_data: %Schema{type: :string, description: "Provider-specific captcha data"},
406 description: "Invite token required when the registrations aren't public"
409 required: [:username, :password, :agreement],
411 "username" => "cofe",
412 "email" => "cofe@example.com",
413 "password" => "secret",
414 "agreement" => "true",
420 defp create_response do
422 title: "AccountCreateResponse",
423 description: "Response schema for an account",
426 token_type: %Schema{type: :string},
427 access_token: %Schema{type: :string},
428 scope: %Schema{type: :array, items: %Schema{type: :string}},
429 created_at: %Schema{type: :integer, format: :"date-time"}
432 "access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
433 "created_at" => 1_585_918_714,
434 "scope" => ["read", "write", "follow", "push"],
435 "token_type" => "Bearer"
440 defp update_creadentials_request do
442 title: "AccountUpdateCredentialsRequest",
443 description: "POST body for creating an account",
448 description: "Whether the account has a bot flag."
450 display_name: %Schema{
452 description: "The display name to use for the profile."
454 note: %Schema{type: :string, description: "The account bio."},
457 description: "Avatar image encoded using multipart/form-data",
462 description: "Header image encoded using multipart/form-data",
467 description: "Whether manual approval of follow requests is required."
469 fields_attributes: %Schema{
471 %Schema{type: :array, items: attribute_field()},
472 %Schema{type: :object, additionalProperties: %Schema{type: attribute_field()}}
475 # NOTE: `source` field is not supported
480 # privacy: %Schema{type: :string},
481 # sensitive: %Schema{type: :boolean},
482 # language: %Schema{type: :string}
486 # Pleroma-specific fields
487 no_rich_text: %Schema{
489 description: "html tags are stripped from all statuses requested from the API"
491 hide_followers: %Schema{type: :boolean, description: "user's followers will be hidden"},
492 hide_follows: %Schema{type: :boolean, description: "user's follows will be hidden"},
493 hide_followers_count: %Schema{
495 description: "user's follower count will be hidden"
497 hide_follows_count: %Schema{
499 description: "user's follow count will be hidden"
501 hide_favorites: %Schema{
503 description: "user's favorites timeline will be hidden"
507 description: "user's role (e.g admin, moderator) will be exposed to anyone in the
510 default_scope: VisibilityScope,
511 pleroma_settings_store: %Schema{
513 description: "Opaque user settings to be saved on the backend."
515 skip_thread_containment: %Schema{
517 description: "Skip filtering out broken threads"
519 allow_following_move: %Schema{
521 description: "Allows automatically follow moved following accounts"
523 pleroma_background_image: %Schema{
525 description: "Sets the background image of the user.",
528 discoverable: %Schema{
531 "Discovery of this account in search results and other services is allowed."
533 actor_type: ActorType
537 display_name: "cofe",
539 fields_attributes: [%{name: "foo", value: "bar"}],
541 hide_followers: true,
543 hide_followers_count: false,
544 hide_follows_count: false,
545 hide_favorites: false,
547 default_scope: "private",
548 pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
549 skip_thread_containment: false,
550 allow_following_move: false,
557 defp array_of_accounts do
559 title: "ArrayOfAccounts",
565 defp array_of_relationships do
567 title: "ArrayOfRelationships",
568 description: "Response schema for account relationships",
570 items: AccountRelationship,
575 "showing_reblogs" => true,
576 "followed_by" => true,
578 "blocked_by" => true,
580 "muting_notifications" => false,
581 "requested" => false,
582 "domain_blocking" => false,
583 "subscribing" => false,
589 "showing_reblogs" => true,
590 "followed_by" => true,
592 "blocked_by" => true,
594 "muting_notifications" => false,
596 "domain_blocking" => false,
597 "subscribing" => false,
603 "showing_reblogs" => true,
604 "followed_by" => true,
606 "blocked_by" => false,
608 "muting_notifications" => false,
609 "requested" => false,
610 "domain_blocking" => true,
611 "subscribing" => true,
618 defp follows_request do
620 title: "AccountFollowsRequest",
621 description: "POST body for muting an account",
624 uri: %Schema{type: :string, format: :uri}
632 title: "AccountMuteRequest",
633 description: "POST body for muting an account",
636 notifications: %Schema{
638 description: "Mute notifications in addition to statuses? Defaults to true.",
643 "notifications" => true
651 description: "Response schema for a list",
654 id: %Schema{type: :string},
655 title: %Schema{type: :string}
664 defp array_of_lists do
666 title: "ArrayOfLists",
667 description: "Response schema for lists",
671 %{"id" => "123", "title" => "my list"},
672 %{"id" => "1337", "title" => "anotehr list"}
677 defp array_of_statuses do
679 title: "ArrayOfStatuses",
685 defp attribute_field do
687 title: "AccountAttributeField",
688 description: "Request schema for account custom fields",
691 name: %Schema{type: :string},
692 value: %Schema{type: :string}
694 required: [:name, :value],
697 "value" => "https://pleroma.com"