First
[anni] / lib / pleroma / web / api_spec / operations / account_operation.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
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
17
18   import Pleroma.Web.ApiSpec.Helpers
19
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, [])
24   end
25
26   @spec create_operation() :: Operation.t()
27   def create_operation do
28     %Operation{
29       tags: ["Account credentials"],
30       summary: "Register an account",
31       description:
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),
35       responses: %{
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)
40       }
41     }
42   end
43
44   def verify_credentials_operation do
45     %Operation{
46       tags: ["Account credentials"],
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"]}],
51       responses: %{
52         200 => Operation.response("Account", "application/json", Account)
53       }
54     }
55   end
56
57   def update_credentials_operation do
58     %Operation{
59       tags: ["Account credentials"],
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),
65       responses: %{
66         200 => Operation.response("Account", "application/json", Account),
67         403 => Operation.response("Error", "application/json", ApiError),
68         413 => Operation.response("Error", "application/json", ApiError)
69       }
70     }
71   end
72
73   def relationships_operation do
74     %Operation{
75       tags: ["Retrieve account information"],
76       summary: "Relationship with current account",
77       operationId: "AccountController.relationships",
78       description: "Find out whether a given account is followed, blocked, muted, etc.",
79       security: [%{"oAuth" => ["read:follows"]}],
80       parameters: [
81         Operation.parameter(
82           :id,
83           :query,
84           %Schema{
85             oneOf: [%Schema{type: :array, items: %Schema{type: :string}}, %Schema{type: :string}]
86           },
87           "Account IDs",
88           example: "123"
89         )
90       ],
91       responses: %{
92         200 => Operation.response("Account", "application/json", array_of_relationships())
93       }
94     }
95   end
96
97   def show_operation do
98     %Operation{
99       tags: ["Retrieve account information"],
100       summary: "Account",
101       operationId: "AccountController.show",
102       description: "View information about a profile.",
103       parameters: [
104         %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
105         with_relationships_param()
106       ],
107       responses: %{
108         200 => Operation.response("Account", "application/json", Account),
109         401 => Operation.response("Error", "application/json", ApiError),
110         404 => Operation.response("Error", "application/json", ApiError)
111       }
112     }
113   end
114
115   def statuses_operation do
116     %Operation{
117       summary: "Statuses",
118       tags: ["Retrieve account information"],
119       operationId: "AccountController.statuses",
120       description:
121         "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)",
122       parameters:
123         [
124           %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
125           Operation.parameter(:pinned, :query, BooleanLike, "Include only pinned statuses"),
126           Operation.parameter(:tagged, :query, :string, "With tag"),
127           Operation.parameter(
128             :only_media,
129             :query,
130             BooleanLike,
131             "Include only statuses with media attached"
132           ),
133           Operation.parameter(
134             :with_muted,
135             :query,
136             BooleanLike,
137             "Include statuses from muted accounts."
138           ),
139           Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
140           Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
141           Operation.parameter(
142             :exclude_visibilities,
143             :query,
144             %Schema{type: :array, items: VisibilityScope},
145             "Exclude visibilities"
146           ),
147           Operation.parameter(
148             :with_muted,
149             :query,
150             BooleanLike,
151             "Include reactions from muted accounts."
152           )
153         ] ++ pagination_params(),
154       responses: %{
155         200 => Operation.response("Statuses", "application/json", array_of_statuses()),
156         401 => Operation.response("Error", "application/json", ApiError),
157         404 => Operation.response("Error", "application/json", ApiError)
158       }
159     }
160   end
161
162   def followers_operation do
163     %Operation{
164       tags: ["Retrieve account information"],
165       summary: "Followers",
166       operationId: "AccountController.followers",
167       security: [%{"oAuth" => ["read:accounts"]}],
168       description:
169         "Accounts which follow the given account, if network is not hidden by the account owner.",
170       parameters: [
171         %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
172         Operation.parameter(:id, :query, :string, "ID of the resource owner"),
173         with_relationships_param() | pagination_params()
174       ],
175       responses: %{
176         200 => Operation.response("Accounts", "application/json", array_of_accounts())
177       }
178     }
179   end
180
181   def following_operation do
182     %Operation{
183       tags: ["Retrieve account information"],
184       summary: "Following",
185       operationId: "AccountController.following",
186       security: [%{"oAuth" => ["read:accounts"]}],
187       description:
188         "Accounts which the given account is following, if network is not hidden by the account owner.",
189       parameters: [
190         %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
191         Operation.parameter(:id, :query, :string, "ID of the resource owner"),
192         with_relationships_param() | pagination_params()
193       ],
194       responses: %{200 => Operation.response("Accounts", "application/json", array_of_accounts())}
195     }
196   end
197
198   def lists_operation do
199     %Operation{
200       tags: ["Retrieve account information"],
201       summary: "Lists containing this account",
202       operationId: "AccountController.lists",
203       security: [%{"oAuth" => ["read:lists"]}],
204       description: "User lists that you have added this account to.",
205       parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
206       responses: %{200 => Operation.response("Lists", "application/json", array_of_lists())}
207     }
208   end
209
210   def follow_operation do
211     %Operation{
212       tags: ["Account actions"],
213       summary: "Follow",
214       operationId: "AccountController.follow",
215       security: [%{"oAuth" => ["follow", "write:follows"]}],
216       description: "Follow the given account",
217       parameters: [
218         %Reference{"$ref": "#/components/parameters/accountIdOrNickname"}
219       ],
220       requestBody:
221         request_body(
222           "Parameters",
223           %Schema{
224             type: :object,
225             properties: %{
226               reblogs: %Schema{
227                 allOf: [BooleanLike],
228                 description: "Receive this account's reblogs in home timeline? Defaults to true.",
229                 default: true
230               },
231               notify: %Schema{
232                 allOf: [BooleanLike],
233                 description:
234                   "Receive notifications for all statuses posted by the account? Defaults to false.",
235                 default: false
236               }
237             }
238           },
239           required: false
240         ),
241       responses: %{
242         200 => Operation.response("Relationship", "application/json", AccountRelationship),
243         400 => Operation.response("Error", "application/json", ApiError),
244         404 => Operation.response("Error", "application/json", ApiError)
245       }
246     }
247   end
248
249   def unfollow_operation do
250     %Operation{
251       tags: ["Account actions"],
252       summary: "Unfollow",
253       operationId: "AccountController.unfollow",
254       security: [%{"oAuth" => ["follow", "write:follows"]}],
255       description: "Unfollow the given account",
256       parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
257       responses: %{
258         200 => Operation.response("Relationship", "application/json", AccountRelationship),
259         400 => Operation.response("Error", "application/json", ApiError),
260         404 => Operation.response("Error", "application/json", ApiError)
261       }
262     }
263   end
264
265   def mute_operation do
266     %Operation{
267       tags: ["Account actions"],
268       summary: "Mute",
269       operationId: "AccountController.mute",
270       security: [%{"oAuth" => ["follow", "write:mutes"]}],
271       requestBody: request_body("Parameters", mute_request()),
272       description:
273         "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).",
274       parameters: [
275         %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
276         Operation.parameter(
277           :notifications,
278           :query,
279           %Schema{allOf: [BooleanLike], default: true},
280           "Mute notifications in addition to statuses? Defaults to `true`."
281         ),
282         Operation.parameter(
283           :duration,
284           :query,
285           %Schema{type: :integer},
286           "Expire the mute in `duration` seconds. Default 0 for infinity"
287         ),
288         Operation.parameter(
289           :expires_in,
290           :query,
291           %Schema{type: :integer, default: 0},
292           "Deprecated, use `duration` instead"
293         )
294       ],
295       responses: %{
296         200 => Operation.response("Relationship", "application/json", AccountRelationship)
297       }
298     }
299   end
300
301   def unmute_operation do
302     %Operation{
303       tags: ["Account actions"],
304       summary: "Unmute",
305       operationId: "AccountController.unmute",
306       security: [%{"oAuth" => ["follow", "write:mutes"]}],
307       description: "Unmute the given account.",
308       parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
309       responses: %{
310         200 => Operation.response("Relationship", "application/json", AccountRelationship)
311       }
312     }
313   end
314
315   def block_operation do
316     %Operation{
317       tags: ["Account actions"],
318       summary: "Block",
319       operationId: "AccountController.block",
320       security: [%{"oAuth" => ["follow", "write:blocks"]}],
321       description:
322         "Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
323       parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
324       responses: %{
325         200 => Operation.response("Relationship", "application/json", AccountRelationship)
326       }
327     }
328   end
329
330   def unblock_operation do
331     %Operation{
332       tags: ["Account actions"],
333       summary: "Unblock",
334       operationId: "AccountController.unblock",
335       security: [%{"oAuth" => ["follow", "write:blocks"]}],
336       description: "Unblock the given account.",
337       parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
338       responses: %{
339         200 => Operation.response("Relationship", "application/json", AccountRelationship)
340       }
341     }
342   end
343
344   def endorse_operation do
345     %Operation{
346       tags: ["Account actions"],
347       summary: "Endorse",
348       operationId: "AccountController.endorse",
349       security: [%{"oAuth" => ["follow", "write:accounts"]}],
350       description: "Addds the given account to endorsed accounts list.",
351       parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
352       responses: %{
353         200 => Operation.response("Relationship", "application/json", AccountRelationship),
354         400 =>
355           Operation.response("Bad Request", "application/json", %Schema{
356             allOf: [ApiError],
357             title: "Unprocessable Entity",
358             example: %{
359               "error" => "You have already pinned the maximum number of users"
360             }
361           })
362       }
363     }
364   end
365
366   def unendorse_operation do
367     %Operation{
368       tags: ["Account actions"],
369       summary: "Unendorse",
370       operationId: "AccountController.unendorse",
371       security: [%{"oAuth" => ["follow", "write:accounts"]}],
372       description: "Removes the given account from endorsed accounts list.",
373       parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
374       responses: %{
375         200 => Operation.response("Relationship", "application/json", AccountRelationship)
376       }
377     }
378   end
379
380   def remove_from_followers_operation do
381     %Operation{
382       tags: ["Account actions"],
383       summary: "Remove from followers",
384       operationId: "AccountController.remove_from_followers",
385       security: [%{"oAuth" => ["follow", "write:follows"]}],
386       description: "Remove the given account from followers",
387       parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
388       responses: %{
389         200 => Operation.response("Relationship", "application/json", AccountRelationship),
390         400 => Operation.response("Error", "application/json", ApiError),
391         404 => Operation.response("Error", "application/json", ApiError)
392       }
393     }
394   end
395
396   def note_operation do
397     %Operation{
398       tags: ["Account actions"],
399       summary: "Set a private note about a user.",
400       operationId: "AccountController.note",
401       security: [%{"oAuth" => ["follow", "write:accounts"]}],
402       requestBody: request_body("Parameters", note_request()),
403       description: "Create a note for the given account.",
404       parameters: [
405         %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
406         Operation.parameter(
407           :comment,
408           :query,
409           %Schema{type: :string},
410           "Account note body"
411         )
412       ],
413       responses: %{
414         200 => Operation.response("Relationship", "application/json", AccountRelationship)
415       }
416     }
417   end
418
419   def follow_by_uri_operation do
420     %Operation{
421       tags: ["Account actions"],
422       summary: "Follow by URI",
423       operationId: "AccountController.follows",
424       security: [%{"oAuth" => ["follow", "write:follows"]}],
425       requestBody: request_body("Parameters", follow_by_uri_request(), required: true),
426       responses: %{
427         200 => Operation.response("Account", "application/json", AccountRelationship),
428         400 => Operation.response("Error", "application/json", ApiError),
429         404 => Operation.response("Error", "application/json", ApiError)
430       }
431     }
432   end
433
434   def mutes_operation do
435     %Operation{
436       tags: ["Blocks and mutes"],
437       summary: "Retrieve list of mutes",
438       operationId: "AccountController.mutes",
439       description: "Accounts the user has muted.",
440       security: [%{"oAuth" => ["follow", "read:mutes"]}],
441       parameters: [with_relationships_param() | pagination_params()],
442       responses: %{
443         200 => Operation.response("Accounts", "application/json", array_of_accounts())
444       }
445     }
446   end
447
448   def blocks_operation do
449     %Operation{
450       tags: ["Blocks and mutes"],
451       summary: "Retrieve list of blocks",
452       operationId: "AccountController.blocks",
453       description: "View your blocks. See also accounts/:id/{block,unblock}",
454       security: [%{"oAuth" => ["read:blocks"]}],
455       parameters: pagination_params(),
456       responses: %{
457         200 => Operation.response("Accounts", "application/json", array_of_accounts())
458       }
459     }
460   end
461
462   def lookup_operation do
463     %Operation{
464       tags: ["Account lookup"],
465       summary: "Find a user by nickname",
466       operationId: "AccountController.lookup",
467       parameters: [
468         Operation.parameter(
469           :acct,
470           :query,
471           :string,
472           "User nickname"
473         )
474       ],
475       responses: %{
476         200 => Operation.response("Account", "application/json", Account),
477         404 => Operation.response("Error", "application/json", ApiError)
478       }
479     }
480   end
481
482   def endorsements_operation do
483     %Operation{
484       tags: ["Retrieve account information"],
485       summary: "Endorsements",
486       operationId: "AccountController.endorsements",
487       description: "Returns endorsed accounts",
488       security: [%{"oAuth" => ["read:accounts"]}],
489       responses: %{
490         200 => Operation.response("Array of Accounts", "application/json", array_of_accounts())
491       }
492     }
493   end
494
495   def identity_proofs_operation do
496     %Operation{
497       tags: ["Retrieve account information"],
498       summary: "Identity proofs",
499       operationId: "AccountController.identity_proofs",
500       # Validators complains about unused path params otherwise
501       parameters: [
502         %Reference{"$ref": "#/components/parameters/accountIdOrNickname"}
503       ],
504       description: "Not implemented",
505       responses: %{
506         200 => empty_array_response()
507       }
508     }
509   end
510
511   defp create_request do
512     %Schema{
513       title: "AccountCreateRequest",
514       description: "POST body for creating an account",
515       type: :object,
516       required: [:username, :password, :agreement],
517       properties: %{
518         reason: %Schema{
519           type: :string,
520           nullable: true,
521           description:
522             "Text that will be reviewed by moderators if registrations require manual approval"
523         },
524         username: %Schema{type: :string, description: "The desired username for the account"},
525         email: %Schema{
526           type: :string,
527           nullable: true,
528           description:
529             "The email address to be used for login. Required when `account_activation_required` is enabled.",
530           format: :email
531         },
532         password: %Schema{
533           type: :string,
534           description: "The password to be used for login",
535           format: :password
536         },
537         agreement: %Schema{
538           allOf: [BooleanLike],
539           description:
540             "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."
541         },
542         locale: %Schema{
543           type: :string,
544           nullable: true,
545           description: "The language of the confirmation email that will be sent"
546         },
547         # Pleroma-specific properties:
548         fullname: %Schema{type: :string, nullable: true, description: "Full name"},
549         bio: %Schema{type: :string, description: "Bio", nullable: true, default: ""},
550         captcha_solution: %Schema{
551           type: :string,
552           nullable: true,
553           description: "Provider-specific captcha solution"
554         },
555         captcha_token: %Schema{
556           type: :string,
557           nullable: true,
558           description: "Provider-specific captcha token"
559         },
560         captcha_answer_data: %Schema{
561           type: :string,
562           nullable: true,
563           description: "Provider-specific captcha data"
564         },
565         token: %Schema{
566           type: :string,
567           nullable: true,
568           description: "Invite token required when the registrations aren't public"
569         },
570         birthday: %Schema{
571           nullable: true,
572           description: "User's birthday",
573           anyOf: [
574             %Schema{
575               type: :string,
576               format: :date
577             },
578             %Schema{
579               type: :string,
580               maxLength: 0
581             }
582           ]
583         },
584         language: %Schema{
585           type: :string,
586           nullable: true,
587           description: "User's preferred language for emails"
588         }
589       },
590       example: %{
591         "username" => "cofe",
592         "email" => "cofe@example.com",
593         "password" => "secret",
594         "agreement" => "true",
595         "bio" => "☕️"
596       }
597     }
598   end
599
600   # Note: this is a token response (if login succeeds!), but there's no oauth operation file yet.
601   defp create_response do
602     %Schema{
603       title: "AccountCreateResponse",
604       description: "Response schema for an account",
605       type: :object,
606       properties: %{
607         # The response when auto-login on create succeeds (token is issued):
608         token_type: %Schema{type: :string},
609         access_token: %Schema{type: :string},
610         refresh_token: %Schema{type: :string},
611         scope: %Schema{type: :string},
612         created_at: %Schema{type: :integer, format: :"date-time"},
613         me: %Schema{type: :string},
614         expires_in: %Schema{type: :integer},
615         #
616         # The response when registration succeeds but auto-login fails (no token):
617         identifier: %Schema{type: :string},
618         message: %Schema{type: :string}
619       },
620       # Note: example of successful registration with failed login response:
621       # example: %{
622       #   "identifier" => "missing_confirmed_email",
623       #   "message" => "You have been registered. Please check your email for further instructions."
624       # },
625       example: %{
626         "token_type" => "Bearer",
627         "access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
628         "refresh_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzz",
629         "created_at" => 1_585_918_714,
630         "expires_in" => 600,
631         "scope" => "read write follow push",
632         "me" => "https://gensokyo.2hu/users/raymoo"
633       }
634     }
635   end
636
637   defp update_credentials_request do
638     %Schema{
639       title: "AccountUpdateCredentialsRequest",
640       description: "POST body for creating an account",
641       type: :object,
642       properties: %{
643         bot: %Schema{
644           allOf: [BooleanLike],
645           nullable: true,
646           description: "Whether the account has a bot flag."
647         },
648         display_name: %Schema{
649           type: :string,
650           nullable: true,
651           description: "The display name to use for the profile."
652         },
653         note: %Schema{type: :string, description: "The account bio."},
654         avatar: %Schema{
655           type: :string,
656           nullable: true,
657           description: "Avatar image encoded using multipart/form-data",
658           format: :binary
659         },
660         header: %Schema{
661           type: :string,
662           nullable: true,
663           description: "Header image encoded using multipart/form-data",
664           format: :binary
665         },
666         locked: %Schema{
667           allOf: [BooleanLike],
668           nullable: true,
669           description: "Whether manual approval of follow requests is required."
670         },
671         accepts_chat_messages: %Schema{
672           allOf: [BooleanLike],
673           nullable: true,
674           description: "Whether the user accepts receiving chat messages."
675         },
676         fields_attributes: %Schema{
677           nullable: true,
678           oneOf: [
679             %Schema{type: :array, items: attribute_field()},
680             %Schema{type: :object, additionalProperties: attribute_field()}
681           ]
682         },
683         # NOTE: `source` field is not supported
684         #
685         # source: %Schema{
686         #   type: :object,
687         #   properties: %{
688         #     privacy: %Schema{type: :string},
689         #     sensitive: %Schema{type: :boolean},
690         #     language: %Schema{type: :string}
691         #   }
692         # },
693
694         # Pleroma-specific fields
695         no_rich_text: %Schema{
696           allOf: [BooleanLike],
697           nullable: true,
698           description: "html tags are stripped from all statuses requested from the API"
699         },
700         hide_followers: %Schema{
701           allOf: [BooleanLike],
702           nullable: true,
703           description: "user's followers will be hidden"
704         },
705         hide_follows: %Schema{
706           allOf: [BooleanLike],
707           nullable: true,
708           description: "user's follows will be hidden"
709         },
710         hide_followers_count: %Schema{
711           allOf: [BooleanLike],
712           nullable: true,
713           description: "user's follower count will be hidden"
714         },
715         hide_follows_count: %Schema{
716           allOf: [BooleanLike],
717           nullable: true,
718           description: "user's follow count will be hidden"
719         },
720         hide_favorites: %Schema{
721           allOf: [BooleanLike],
722           nullable: true,
723           description: "user's favorites timeline will be hidden"
724         },
725         show_role: %Schema{
726           allOf: [BooleanLike],
727           nullable: true,
728           description: "user's role (e.g admin, moderator) will be exposed to anyone in the
729         API"
730         },
731         default_scope: VisibilityScope,
732         pleroma_settings_store: %Schema{
733           type: :object,
734           nullable: true,
735           description: "Opaque user settings to be saved on the backend."
736         },
737         skip_thread_containment: %Schema{
738           allOf: [BooleanLike],
739           nullable: true,
740           description: "Skip filtering out broken threads"
741         },
742         allow_following_move: %Schema{
743           allOf: [BooleanLike],
744           nullable: true,
745           description: "Allows automatically follow moved following accounts"
746         },
747         also_known_as: %Schema{
748           type: :array,
749           items: %Schema{type: :string},
750           nullable: true,
751           description: "List of alternate ActivityPub IDs"
752         },
753         pleroma_background_image: %Schema{
754           type: :string,
755           nullable: true,
756           description: "Sets the background image of the user.",
757           format: :binary
758         },
759         discoverable: %Schema{
760           allOf: [BooleanLike],
761           nullable: true,
762           description:
763             "Discovery (listing, indexing) of this account by external services (search bots etc.) is allowed."
764         },
765         actor_type: ActorType,
766         birthday: %Schema{
767           nullable: true,
768           description: "User's birthday",
769           anyOf: [
770             %Schema{
771               type: :string,
772               format: :date
773             },
774             %Schema{
775               type: :string,
776               maxLength: 0
777             }
778           ]
779         },
780         show_birthday: %Schema{
781           allOf: [BooleanLike],
782           nullable: true,
783           description: "User's birthday will be visible"
784         }
785       },
786       example: %{
787         bot: false,
788         display_name: "cofe",
789         note: "foobar",
790         fields_attributes: [%{name: "foo", value: "bar"}],
791         no_rich_text: false,
792         hide_followers: true,
793         hide_follows: false,
794         hide_followers_count: false,
795         hide_follows_count: false,
796         hide_favorites: false,
797         show_role: false,
798         default_scope: "private",
799         pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
800         skip_thread_containment: false,
801         allow_following_move: false,
802         also_known_as: ["https://foo.bar/users/foo"],
803         discoverable: false,
804         actor_type: "Person",
805         show_birthday: false,
806         birthday: "2001-02-12"
807       }
808     }
809   end
810
811   def array_of_accounts do
812     %Schema{
813       title: "ArrayOfAccounts",
814       type: :array,
815       items: Account,
816       example: [Account.schema().example]
817     }
818   end
819
820   defp array_of_relationships do
821     %Schema{
822       title: "ArrayOfRelationships",
823       description: "Response schema for account relationships",
824       type: :array,
825       items: AccountRelationship,
826       example: [
827         %{
828           "id" => "1",
829           "following" => true,
830           "showing_reblogs" => true,
831           "followed_by" => true,
832           "blocking" => false,
833           "blocked_by" => true,
834           "muting" => false,
835           "muting_notifications" => false,
836           "note" => "",
837           "requested" => false,
838           "domain_blocking" => false,
839           "subscribing" => false,
840           "notifying" => false,
841           "endorsed" => true
842         },
843         %{
844           "id" => "2",
845           "following" => true,
846           "showing_reblogs" => true,
847           "followed_by" => true,
848           "blocking" => false,
849           "blocked_by" => true,
850           "muting" => true,
851           "muting_notifications" => false,
852           "note" => "",
853           "requested" => true,
854           "domain_blocking" => false,
855           "subscribing" => false,
856           "notifying" => false,
857           "endorsed" => false
858         },
859         %{
860           "id" => "3",
861           "following" => true,
862           "showing_reblogs" => true,
863           "followed_by" => true,
864           "blocking" => true,
865           "blocked_by" => false,
866           "muting" => true,
867           "muting_notifications" => false,
868           "note" => "",
869           "requested" => false,
870           "domain_blocking" => true,
871           "subscribing" => true,
872           "notifying" => true,
873           "endorsed" => false
874         }
875       ]
876     }
877   end
878
879   defp follow_by_uri_request do
880     %Schema{
881       title: "AccountFollowsRequest",
882       description: "POST body for muting an account",
883       type: :object,
884       properties: %{
885         uri: %Schema{type: :string, nullable: true, format: :uri}
886       },
887       required: [:uri]
888     }
889   end
890
891   defp mute_request do
892     %Schema{
893       title: "AccountMuteRequest",
894       description: "POST body for muting an account",
895       type: :object,
896       properties: %{
897         notifications: %Schema{
898           allOf: [BooleanLike],
899           nullable: true,
900           description: "Mute notifications in addition to statuses? Defaults to true.",
901           default: true
902         },
903         duration: %Schema{
904           type: :integer,
905           nullable: true,
906           description: "Expire the mute in `expires_in` seconds. Default 0 for infinity"
907         },
908         expires_in: %Schema{
909           type: :integer,
910           nullable: true,
911           description: "Deprecated, use `duration` instead",
912           default: 0
913         }
914       },
915       example: %{
916         "notifications" => true,
917         "expires_in" => 86_400
918       }
919     }
920   end
921
922   defp note_request do
923     %Schema{
924       title: "AccountNoteRequest",
925       description: "POST body for adding a note for an account",
926       type: :object,
927       properties: %{
928         comment: %Schema{
929           type: :string,
930           description: "Account note body"
931         }
932       },
933       example: %{
934         "comment" => "Example note"
935       }
936     }
937   end
938
939   defp array_of_lists do
940     %Schema{
941       title: "ArrayOfLists",
942       description: "Response schema for lists",
943       type: :array,
944       items: List,
945       example: [
946         %{"id" => "123", "title" => "my list"},
947         %{"id" => "1337", "title" => "anotehr list"}
948       ]
949     }
950   end
951
952   defp array_of_statuses do
953     %Schema{
954       title: "ArrayOfStatuses",
955       type: :array,
956       items: Status
957     }
958   end
959
960   defp attribute_field do
961     %Schema{
962       title: "AccountAttributeField",
963       description: "Request schema for account custom fields",
964       type: :object,
965       properties: %{
966         name: %Schema{type: :string},
967         value: %Schema{type: :string}
968       },
969       required: [:name, :value],
970       example: %{
971         "name" => "Website",
972         "value" => "https://pleroma.com"
973       }
974     }
975   end
976 end