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