Merge remote-tracking branch 'origin/develop' into pr-7444-finish

This commit is contained in:
Lain Soykaf 2026-07-26 13:20:50 +04:00
commit 7a741736ea
No known key found for this signature in database
1544 changed files with 43219 additions and 9351 deletions

View file

@ -18,6 +18,8 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
alias OpenApiSpex.Plug.PutApiSpec
alias Plug.Conn
require Logger
@impl Plug
def init(opts) do
opts
@ -51,6 +53,10 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
conn
{:error, reason} ->
Logger.error(
"Strict ApiSpec: request denied to #{conn.request_path} with params #{inspect(conn.params)}"
)
opts = render_error.init(reason)
conn
@ -100,7 +106,14 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
OpenApiSpex.cast_and_validate(spec, operation, conn, content_type, cast_opts)
end
defp cast_and_validate(spec, operation, conn, content_type, false = _strict, cast_opts) do
defp cast_and_validate(
spec,
operation,
%Conn{} = conn,
content_type,
false = _strict,
cast_opts
) do
case OpenApiSpex.cast_and_validate(spec, operation, conn, content_type) do
{:ok, conn} ->
{:ok, conn}

View file

@ -143,6 +143,12 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
"Include statuses from muted accounts."
),
Operation.parameter(:exclude_reblogs, :query, BooleanLike.schema(), "Exclude reblogs"),
Operation.parameter(
:only_reblogs,
:query,
BooleanLike.schema(),
"Include only reblogs"
),
Operation.parameter(:exclude_replies, :query, BooleanLike.schema(), "Exclude replies"),
Operation.parameter(
:exclude_visibilities,
@ -284,18 +290,6 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
:query,
%Schema{allOf: [BooleanLike], default: true},
"Mute notifications in addition to statuses? Defaults to `true`."
),
Operation.parameter(
:duration,
:query,
%Schema{type: :integer},
"Expire the mute in `duration` seconds. Default 0 for infinity"
),
Operation.parameter(
:expires_in,
:query,
%Schema{type: :integer, default: 0},
"Deprecated, use `duration` instead"
)
],
responses: %{
@ -323,16 +317,37 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
tags: ["Account actions"],
summary: "Block",
operationId: "AccountController.block",
requestBody: request_body("Parameters", block_request()),
security: [%{"oAuth" => ["follow", "write:blocks"]}],
description:
"Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline)",
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
parameters: [
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}
],
responses: %{
200 => Operation.response("Relationship", "application/json", AccountRelationship)
}
}
end
defp block_request do
%Schema{
title: "AccountBlockRequest",
description: "POST body for blocking an account",
type: :object,
properties: %{
duration: %Schema{
type: :integer,
nullable: true,
description: "Expire the mute in `duration` seconds. Default 0 for infinity"
}
},
example: %{
"duration" => 86_400
}
}
end
def unblock_operation do
%Operation{
tags: ["Account actions"],
@ -383,6 +398,28 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
}
end
def endorsements_operation do
%Operation{
tags: ["Retrieve account information"],
summary: "Endorsements",
description: "Returns endorsed accounts",
operationId: "AccountController.endorsements",
parameters: [
with_relationships_param(),
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}
],
responses: %{
200 =>
Operation.response(
"Array of Accounts",
"application/json",
array_of_accounts()
),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def remove_from_followers_operation do
%Operation{
tags: ["Account actions"],
@ -446,7 +483,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
security: [%{"oAuth" => ["follow", "read:mutes"]}],
parameters: [with_relationships_param() | pagination_params()],
responses: %{
200 => Operation.response("Accounts", "application/json", array_of_accounts())
200 => Operation.response("Accounts", "application/json", array_of_muted_accounts())
}
}
end
@ -460,7 +497,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
security: [%{"oAuth" => ["read:blocks"]}],
parameters: [with_relationships_param() | pagination_params()],
responses: %{
200 => Operation.response("Accounts", "application/json", array_of_accounts())
200 => Operation.response("Accounts", "application/json", array_of_blocked_accounts())
}
}
end
@ -480,16 +517,17 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
],
responses: %{
200 => Operation.response("Account", "application/json", Account),
401 => Operation.response("Error", "application/json", ApiError),
404 => Operation.response("Error", "application/json", ApiError)
}
}
end
def endorsements_operation do
def own_endorsements_operation do
%Operation{
tags: ["Retrieve account information"],
summary: "Endorsements",
operationId: "AccountController.endorsements",
operationId: "AccountController.own_endorsements",
description: "Returns endorsed accounts",
security: [%{"oAuth" => ["read:accounts"]}],
responses: %{
@ -498,22 +536,6 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
}
end
def identity_proofs_operation do
%Operation{
tags: ["Retrieve account information"],
summary: "Identity proofs",
operationId: "AccountController.identity_proofs",
# Validators complains about unused path params otherwise
parameters: [
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}
],
description: "Not implemented",
responses: %{
200 => empty_array_response()
}
}
end
def familiar_followers_operation do
%Operation{
tags: ["Retrieve account information"],
@ -829,6 +851,16 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
allOf: [BooleanLike],
nullable: true,
description: "User's birthday will be visible"
},
avatar_description: %Schema{
type: :string,
nullable: true,
description: "Avatar image description."
},
header_description: %Schema{
type: :string,
nullable: true,
description: "Header image description."
}
},
example: %{
@ -865,6 +897,54 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
}
end
def array_of_muted_accounts do
%Schema{
title: "ArrayOfMutedAccounts",
type: :array,
items: %Schema{
title: "MutedAccount",
description: "Response schema for a muted account",
allOf: [
Account,
%Schema{
type: :object,
properties: %{
mute_expires_at: %Schema{type: :string, format: "date-time", nullable: true}
}
}
]
},
example: [
Account.schema().example
|> Map.put("mute_expires_at", "2025-11-29T16:23:13Z")
]
}
end
def array_of_blocked_accounts do
%Schema{
title: "ArrayOfBlockedAccounts",
type: :array,
items: %Schema{
title: "BlockedAccount",
description: "Response schema for a blocked account",
allOf: [
Account,
%Schema{
type: :object,
properties: %{
block_expires_at: %Schema{type: :string, format: "date-time", nullable: true}
}
}
]
},
example: [
Account.schema().example
|> Map.put("block_expires_at", "2025-11-29T16:23:13Z")
]
}
end
defp array_of_relationships do
%Schema{
title: "ArrayOfRelationships",

View file

@ -123,7 +123,10 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
name: %Schema{type: :string, description: "Application Name"},
scopes: %Schema{type: :array, items: %Schema{type: :string}, description: "oAuth scopes"},
redirect_uris: %Schema{
type: :string,
oneOf: [
%Schema{type: :string},
%Schema{type: :array, items: %Schema{type: :string}}
],
description:
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
},
@ -141,7 +144,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
},
example: %{
"name" => "My App",
"redirect_uris" => "https://myapp.com/auth/callback",
"redirect_uris" => ["https://myapp.com/auth/callback"],
"website" => "https://myapp.com/",
"scopes" => ["read", "write"],
"trusted" => true
@ -157,7 +160,10 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
name: %Schema{type: :string, description: "Application Name"},
scopes: %Schema{type: :array, items: %Schema{type: :string}, description: "oAuth scopes"},
redirect_uris: %Schema{
type: :string,
oneOf: [
%Schema{type: :string},
%Schema{type: :array, items: %Schema{type: :string}}
],
description:
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
},
@ -175,7 +181,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
},
example: %{
"name" => "My App",
"redirect_uris" => "https://myapp.com/auth/callback",
"redirect_uris" => ["https://myapp.com/auth/callback"],
"website" => "https://myapp.com/",
"scopes" => ["read", "write"],
"trusted" => true

View file

@ -53,6 +53,12 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
:query,
%Schema{type: :integer, default: 50},
"Number number of log entries per page"
),
Operation.parameter(
:assigned_account,
:query,
%Schema{type: :string},
"Filter by assigned account ID"
)
| admin_api_params()
],
@ -103,6 +109,22 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
}
end
def assign_account_operation do
%Operation{
tags: ["Report management"],
summary: "Assign account to specified reports",
operationId: "AdminAPI.ReportController.assign_account",
security: [%{"oAuth" => ["admin:write:reports"]}],
parameters: admin_api_params(),
requestBody: request_body("Parameters", assign_account_request(), required: true),
responses: %{
204 => no_content_response(),
400 => Operation.response("Bad Request", "application/json", update_400_response()),
403 => Operation.response("Forbidden", "application/json", ApiError)
}
}
end
def notes_create_operation do
%Operation{
tags: ["Report management"],
@ -186,7 +208,10 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
hint: %Schema{type: :string, nullable: true}
}
}
}
},
assigned_account:
account_admin()
|> Map.put(:nullable, true)
}
}
end
@ -242,6 +267,34 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
}
end
defp assign_account_request do
%Schema{
type: :object,
required: [:reports],
properties: %{
reports: %Schema{
type: :array,
items: %Schema{
type: :object,
properties: %{
id: %Schema{allOf: [FlakeID], description: "Required, report ID"},
assigned_account: %Schema{
type: :string,
description: "User nickname",
nullable: true
}
}
},
example: %{
"reports" => [
%{"id" => "123", "assigned_account" => "pleroma"}
]
}
}
}
}
end
defp update_400_response do
%Schema{
type: :array,

View file

@ -16,7 +16,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.RuleOperation do
def index_operation do
%Operation{
tags: ["Instance rule managment"],
tags: ["Instance rule management"],
summary: "Retrieve list of instance rules",
operationId: "AdminAPI.RuleController.index",
security: [%{"oAuth" => ["admin:read"]}],
@ -33,7 +33,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.RuleOperation do
def create_operation do
%Operation{
tags: ["Instance rule managment"],
tags: ["Instance rule management"],
summary: "Create new rule",
operationId: "AdminAPI.RuleController.create",
security: [%{"oAuth" => ["admin:write"]}],
@ -49,7 +49,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.RuleOperation do
def update_operation do
%Operation{
tags: ["Instance rule managment"],
tags: ["Instance rule management"],
summary: "Modify existing rule",
operationId: "AdminAPI.RuleController.update",
security: [%{"oAuth" => ["admin:write"]}],
@ -65,7 +65,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.RuleOperation do
def delete_operation do
%Operation{
tags: ["Instance rule managment"],
tags: ["Instance rule management"],
summary: "Delete rule",
operationId: "AdminAPI.RuleController.delete",
parameters: [Operation.parameter(:id, :path, :string, "Rule ID")],

View file

@ -97,7 +97,10 @@ defmodule Pleroma.Web.ApiSpec.AppOperation do
properties: %{
client_name: %Schema{type: :string, description: "A name for your application."},
redirect_uris: %Schema{
type: :string,
oneOf: [
%Schema{type: :string},
%Schema{type: :array, items: %Schema{type: :string}}
],
description:
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
},

View file

@ -31,7 +31,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The updated chat",
"application/json",
Chat
)
),
404 => Operation.response("Not Found", "application/json", ApiError)
},
security: [
%{
@ -56,7 +57,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The read ChatMessage",
"application/json",
ChatMessage
)
),
404 => Operation.response("Not Found", "application/json", ApiError)
},
security: [
%{
@ -87,7 +89,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The existing chat",
"application/json",
Chat
)
),
404 => Operation.response("Not Found", "application/json", ApiError)
},
security: [
%{
@ -118,7 +121,8 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The created or existing chat",
"application/json",
Chat
)
),
404 => Operation.response("Not Found", "application/json", ApiError)
},
security: [
%{
@ -142,10 +146,12 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
:query,
BooleanLike.schema(),
"Include chats from muted users"
)
),
Operation.parameter(:pinned, :query, BooleanLike.schema(), "Include only pinned chats")
],
responses: %{
200 => Operation.response("The chats of the user", "application/json", chats_response())
200 => Operation.response("The chats of the user", "application/json", chats_response()),
404 => Operation.response("Not Found", "application/json", ApiError)
},
security: [
%{
@ -166,11 +172,13 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
:query,
BooleanLike.schema(),
"Include chats from muted users"
)
),
Operation.parameter(:pinned, :query, BooleanLike.schema(), "Include only pinned chats")
| pagination_params()
],
responses: %{
200 => Operation.response("The chats of the user", "application/json", chats_response())
200 => Operation.response("The chats of the user", "application/json", chats_response()),
404 => Operation.response("Not Found", "application/json", ApiError)
},
security: [
%{
@ -222,6 +230,7 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
ChatMessage
),
400 => Operation.response("Bad Request", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError),
422 => Operation.response("MRF Rejection", "application/json", ApiError)
},
security: [
@ -247,7 +256,48 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"The deleted ChatMessage",
"application/json",
ChatMessage
)
),
404 => Operation.response("Not Found", "application/json", ApiError)
},
security: [
%{
"oAuth" => ["write:chats"]
}
]
}
end
def pin_operation do
%Operation{
tags: ["Chats"],
summary: "Pin a chat",
operationId: "ChatController.pin",
parameters: [
Operation.parameter(:id, :path, :string, "The id of the chat", required: true)
],
responses: %{
200 => Operation.response("The existing chat", "application/json", Chat),
404 => Operation.response("Not Found", "application/json", ApiError)
},
security: [
%{
"oAuth" => ["write:chats"]
}
]
}
end
def unpin_operation do
%Operation{
tags: ["Chats"],
summary: "Unpin a chat",
operationId: "ChatController.unpin",
parameters: [
Operation.parameter(:id, :path, :string, "The id of the chat", required: true)
],
responses: %{
200 => Operation.response("The existing chat", "application/json", Chat),
404 => Operation.response("Not Found", "application/json", ApiError)
},
security: [
%{

View file

@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.ApiNotFoundError
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.Status
@ -35,7 +36,8 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
security: [%{"oAuth" => ["read:statuses"]}],
operationId: "EmojiReactionController.index",
responses: %{
200 => array_of_reactions_response()
200 => array_of_reactions_response(),
404 => Operation.response("Access denied", "application/json", ApiNotFoundError)
}
}
end
@ -54,7 +56,8 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
operationId: "EmojiReactionController.create",
responses: %{
200 => Operation.response("Status", "application/json", Status),
400 => Operation.response("Bad Request", "application/json", ApiError)
400 => Operation.response("Bad Request", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiNotFoundError)
}
}
end

View file

@ -19,6 +19,7 @@ defmodule Pleroma.Web.ApiSpec.FollowRequestOperation do
summary: "Retrieve follow requests",
security: [%{"oAuth" => ["read:follows", "follow"]}],
operationId: "FollowRequestController.index",
parameters: pagination_params(),
responses: %{
200 =>
Operation.response("Array of Account", "application/json", %Schema{
@ -62,4 +63,22 @@ defmodule Pleroma.Web.ApiSpec.FollowRequestOperation do
required: true
)
end
defp pagination_params do
[
Operation.parameter(:max_id, :query, :string, "Return items older than this ID"),
Operation.parameter(
:since_id,
:query,
:string,
"Return the oldest items newer than this ID"
),
Operation.parameter(
:limit,
:query,
%Schema{type: :integer, default: 20},
"Maximum number of items to return. Will be ignored if it's more than 40"
)
]
end
end

View file

@ -52,7 +52,46 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
summary: "Retrieve list of instance rules",
operationId: "InstanceController.rules",
responses: %{
200 => Operation.response("Array of domains", "application/json", array_of_rules())
200 => Operation.response("Array of rules", "application/json", array_of_rules())
}
}
end
def domain_blocks_operation do
%Operation{
tags: ["Instance misc"],
summary: "Retrieve instance domain blocks",
operationId: "InstanceController.domain_blocks",
responses: %{
200 =>
Operation.response(
"Array of domain blocks",
"application/json",
array_of_domain_blocks()
)
}
}
end
def translation_languages_operation do
%Operation{
tags: ["Instance misc"],
summary: "Retrieve supported languages matrix",
operationId: "InstanceController.translation_languages",
responses: %{
200 =>
Operation.response(
"Translation languages matrix",
"application/json",
%Schema{
type: :object,
additionalProperties: %Schema{
type: :array,
items: %Schema{type: :string},
description: "Supported target languages for a source language"
}
}
)
}
}
end
@ -303,6 +342,18 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
max_pinned_statuses: %Schema{
type: :integer,
description: "The maximum number of pinned statuses for each account."
},
max_profile_fields: %Schema{
type: :integer,
description: "The maximum number of custom profile fields allowed to be set."
},
profile_field_name_limit: %Schema{
type: :integer,
description: "The maximum size of a profile field name, in characters."
},
profile_field_value_limit: %Schema{
type: :integer,
description: "The maximum size of a profile field value, in characters."
}
}
},
@ -397,4 +448,19 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
}
}
end
defp array_of_domain_blocks do
%Schema{
type: :array,
items: %Schema{
type: :object,
properties: %{
domain: %Schema{type: :string},
digest: %Schema{type: :string},
severity: %Schema{type: :string},
comment: %Schema{type: :string}
}
}
}
end
end

View file

@ -36,12 +36,13 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do
summary: "Create a list",
description: "Fetch the list with the given ID. Used for verifying the title of a list.",
operationId: "ListController.create",
requestBody: create_update_request(),
requestBody: create_request(),
security: [%{"oAuth" => ["write:lists"]}],
responses: %{
200 => Operation.response("List", "application/json", List),
400 => Operation.response("Error", "application/json", ApiError),
404 => Operation.response("Error", "application/json", ApiError)
404 => Operation.response("Error", "application/json", ApiError),
422 => Operation.response("Error", "application/json", ApiError)
}
}
end
@ -68,7 +69,7 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do
description: "Change the title of a list",
operationId: "ListController.update",
parameters: [id_param()],
requestBody: create_update_request(),
requestBody: update_request(),
security: [%{"oAuth" => ["write:lists"]}],
responses: %{
200 => Operation.response("List", "application/json", List),
@ -164,14 +165,19 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do
)
end
defp create_update_request do
defp create_request do
request_body(
"Parameters",
%Schema{
description: "POST body for creating or updating a List",
description: "POST body for creating a List",
type: :object,
properties: %{
title: %Schema{type: :string, description: "List title"}
title: %Schema{type: :string, description: "List title"},
exclusive: %Schema{
type: :boolean,
description: "Whether members of the list should be removed from the “Home” feed"
},
emoji: %Schema{type: :string, description: "List emoji", nullable: true}
},
required: [:title]
},
@ -179,6 +185,25 @@ defmodule Pleroma.Web.ApiSpec.ListOperation do
)
end
defp update_request do
request_body(
"Parameters",
%Schema{
description: "PUT body for updating a List",
type: :object,
properties: %{
title: %Schema{type: :string, description: "List title"},
exclusive: %Schema{
type: :boolean,
description: "Whether members of the list should be removed from the “Home” feed"
},
emoji: %Schema{type: :string, description: "List emoji", nullable: true}
}
},
required: true
)
end
defp add_remove_accounts_request(required) when is_boolean(required) do
request_body(
"Parameters",

View file

@ -121,7 +121,7 @@ defmodule Pleroma.Web.ApiSpec.MediaOperation do
security: [%{"oAuth" => ["write:media"]}],
requestBody: Helpers.request_body("Parameters", create_request()),
responses: %{
202 => Operation.response("Media", "application/json", Attachment),
200 => Operation.response("Media", "application/json", Attachment),
400 => Operation.response("Media", "application/json", ApiError),
422 => Operation.response("Media", "application/json", ApiError),
500 => Operation.response("Media", "application/json", ApiError)

View file

@ -3,7 +3,6 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.NotificationOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.Account
@ -91,6 +90,79 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
}
end
def grouped_index_operation do
%Operation{
tags: ["Notifications"],
summary: "Retrieve grouped notifications",
description: "Notifications concerning the user, grouped by supported notification types.",
operationId: "NotificationController.grouped_index",
security: [%{"oAuth" => ["read:notifications"]}],
parameters: grouped_notification_params() ++ pagination_params(),
responses: %{
200 => Operation.response("Grouped notifications", "application/json", grouped_result()),
404 => Operation.response("Error", "application/json", ApiError)
}
}
end
def show_group_operation do
%Operation{
tags: ["Notifications"],
summary: "Retrieve a notification group",
operationId: "NotificationController.show_group",
security: [%{"oAuth" => ["read:notifications"]}],
parameters: [group_key_param()],
responses: %{
200 => Operation.response("Grouped notifications", "application/json", grouped_result()),
404 => Operation.response("Error", "application/json", ApiError)
}
}
end
def group_accounts_operation do
%Operation{
tags: ["Notifications"],
summary: "Retrieve notification group accounts",
operationId: "NotificationController.group_accounts",
security: [%{"oAuth" => ["read:notifications"]}],
parameters: [group_key_param()],
responses: %{
200 =>
Operation.response("Accounts", "application/json", %Schema{
type: :array,
items: Account
})
}
}
end
def unread_count_operation do
%Operation{
tags: ["Notifications"],
summary: "Retrieve unread grouped notification count",
operationId: "NotificationController.unread_count",
security: [%{"oAuth" => ["read:notifications"]}],
parameters:
grouped_notification_params() ++
[
Operation.parameter(
:limit,
:query,
%Schema{type: :integer},
"Maximum number of notifications to count"
)
],
responses: %{
200 =>
Operation.response("Unread notification group count", "application/json", %Schema{
type: :object,
properties: %{count: %Schema{type: :integer}}
}),
404 => Operation.response("Error", "application/json", ApiError)
}
}
end
def clear_operation do
%Operation{
tags: ["Notifications"],
@ -114,6 +186,18 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
}
end
def dismiss_group_operation do
%Operation{
tags: ["Notifications"],
summary: "Dismiss a notification group",
description: "Clear all notifications in a notification group from the server.",
operationId: "NotificationController.dismiss_group",
parameters: [group_key_param()],
security: [%{"oAuth" => ["write:notifications"]}],
responses: %{200 => empty_object_response()}
}
end
def dismiss_via_body_operation do
%Operation{
tags: ["Notifications"],
@ -158,6 +242,10 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
type: :object,
properties: %{
id: %Schema{type: :string},
group_key: %Schema{
type: :string,
description: "Group key shared by similar notifications"
},
type: notification_type(),
created_at: %Schema{type: :string, format: :"date-time"},
account: %Schema{
@ -180,6 +268,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
},
example: %{
"id" => "34975861",
"group_key" => "ungrouped-34975861",
"type" => "mention",
"created_at" => "2019-11-23T07:49:02.064Z",
"account" => Account.schema().example,
@ -189,6 +278,73 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
}
end
defp grouped_result do
%Schema{
title: "GroupedNotificationsResults",
type: :object,
properties: %{
accounts: %Schema{type: :array, items: Account},
statuses: %Schema{type: :array, items: Status},
notification_groups: %Schema{type: :array, items: notification_group()}
},
required: [:accounts, :statuses, :notification_groups]
}
end
defp notification_group do
%Schema{
title: "NotificationGroup",
type: :object,
properties: %{
group_key: %Schema{type: :string},
notifications_count: %Schema{type: :integer},
type: notification_type(),
most_recent_notification_id: %Schema{type: :string},
page_min_id: %Schema{type: :string, nullable: true},
page_max_id: %Schema{type: :string, nullable: true},
latest_page_notification_at: %Schema{type: :string, format: :"date-time", nullable: true},
sample_account_ids: %Schema{type: :array, items: %Schema{type: :string}},
status_id: %Schema{type: :string, nullable: true}
},
required: [
:group_key,
:notifications_count,
:type,
:most_recent_notification_id,
:sample_account_ids
]
}
end
defp grouped_notification_params do
[
Operation.parameter(
:exclude_types,
:query,
%Schema{type: :array, items: notification_type()},
"Array of types to exclude"
),
Operation.parameter(
:account_id,
:query,
%Schema{type: :string},
"Return only notifications received from this account"
),
Operation.parameter(
:types,
:query,
%Schema{type: :array, items: notification_type()},
"Include the notifications for activities with the given types"
),
Operation.parameter(
:grouped_types,
:query,
%Schema{type: :array, items: notification_type()},
"Notification types that may be grouped"
)
]
end
defp notification_type do
%Schema{
type: :string,
@ -203,7 +359,10 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
"move",
"follow_request",
"poll",
"status"
"status",
"update",
"admin.sign_up",
"admin.report"
],
description: """
The type of event that resulted in the notification.
@ -218,6 +377,9 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
- `pleroma:chat_mention` - Someone mentioned you in a chat message
- `pleroma:report` - Someone was reported
- `status` - Someone you are subscribed to created a status
- `update` - A status you boosted has been edited
- `admin.sign_up` - Someone signed up (optionally sent to admins)
- `admin.report` - A new report has been filed
"""
}
end
@ -228,4 +390,11 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
required: true
)
end
defp group_key_param do
Operation.parameter(:group_key, :path, :string, "Notification group key",
example: "favourite-123",
required: true
)
end
end

View file

@ -64,30 +64,13 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
}
end
def endorsements_operation do
%Operation{
tags: ["Retrieve account information"],
summary: "Endorsements",
description: "Returns endorsed accounts",
operationId: "PleromaAPI.AccountController.endorsements",
parameters: [with_relationships_param(), id_param()],
responses: %{
200 =>
Operation.response(
"Array of Accounts",
"application/json",
AccountOperation.array_of_accounts()
),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def subscribe_operation do
%Operation{
deprecated: true,
tags: ["Account actions"],
summary: "Subscribe",
description: "Receive notifications for all statuses posted by the account.",
description:
"Receive notifications for all statuses posted by the account. Deprecated, use `notify: true` in follow operation instead.",
operationId: "PleromaAPI.AccountController.subscribe",
parameters: [id_param()],
security: [%{"oAuth" => ["follow", "write:follows"]}],
@ -100,9 +83,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
def unsubscribe_operation do
%Operation{
deprecated: true,
tags: ["Account actions"],
summary: "Unsubscribe",
description: "Stop receiving notifications for all statuses posted by the account.",
description:
"Stop receiving notifications for all statuses posted by the account. Deprecated, use `notify: false` in follow operation instead.",
operationId: "PleromaAPI.AccountController.unsubscribe",
parameters: [id_param()],
security: [%{"oAuth" => ["follow", "write:follows"]}],

View file

@ -65,12 +65,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaBackupOperation do
file_name: %Schema{type: :string},
file_size: %Schema{type: :integer},
processed: %Schema{type: :boolean, description: "whether this backup has succeeded"},
state: %Schema{
type: :string,
description: "the state of the backup",
enum: ["pending", "running", "complete", "failed"]
},
processed_number: %Schema{type: :integer, description: "the number of records processed"}
tempdir: %Schema{type: :string}
},
example: %{
"content_type" => "application/zip",
@ -79,8 +74,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaBackupOperation do
"file_size" => 4105,
"inserted_at" => "2020-09-08T16:42:07.000Z",
"processed" => true,
"state" => "complete",
"processed_number" => 20
"tempdir" => "/tmp/PZIMw40vmpM"
}
}
end

View file

@ -127,6 +127,20 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
}
end
def download_zip_operation do
%Operation{
tags: ["Emoji pack administration"],
summary: "Download a pack from a URL or an uploaded file",
operationId: "PleromaAPI.EmojiPackController.download_zip",
security: [%{"oAuth" => ["admin:write"]}],
requestBody: request_body("Parameters", download_zip_request(), required: true),
responses: %{
200 => ok_response(),
400 => Operation.response("Bad Request", "application/json", ApiError)
}
}
end
defp download_request do
%Schema{
type: :object,
@ -143,6 +157,25 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
}
end
defp download_zip_request do
%Schema{
type: :object,
required: [:name],
properties: %{
url: %Schema{
type: :string,
format: :uri,
description: "URL of the file"
},
file: %Schema{
description: "The uploaded ZIP file",
type: :object
},
name: %Schema{type: :string, format: :uri, description: "Pack Name"}
}
}
end
def create_operation do
%Operation{
tags: ["Emoji pack administration"],

View file

@ -0,0 +1,50 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.PleromaFollowRequestOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.Account
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end
def outgoing_operation do
%Operation{
tags: ["Follow requests"],
summary: "Retrieve outgoing follow requests",
security: [%{"oAuth" => ["read:follows", "follow"]}],
operationId: "PleromaFollowRequestController.outgoing",
parameters: pagination_params(),
responses: %{
200 =>
Operation.response("Array of Account", "application/json", %Schema{
type: :array,
items: Account,
example: [Account.schema().example]
})
}
}
end
defp pagination_params do
[
Operation.parameter(:max_id, :query, :string, "Return items older than this ID"),
Operation.parameter(
:since_id,
:query,
:string,
"Return the oldest items newer than this ID"
),
Operation.parameter(
:limit,
:query,
%Schema{type: :integer, default: 20},
"Maximum number of items to return. Will be ignored if it's more than 40"
)
]
end
end

View file

@ -0,0 +1,65 @@
defmodule Pleroma.Web.ApiSpec.PleromaFrontendSettingsOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
import Pleroma.Web.ApiSpec.Helpers
@spec open_api_operation(atom) :: Operation.t()
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end
def available_frontends_operation do
%Operation{
tags: ["Preferred frontends"],
summary: "Frontend settings profiles",
description: "List frontend setting profiles",
operationId: "PleromaAPI.FrontendSettingsController.available_frontends",
responses: %{
200 =>
Operation.response("Frontends", "application/json", %Schema{
type: :array,
items: %Schema{
type: :string
}
})
}
}
end
def update_preferred_frontend_operation do
%Operation{
tags: ["Preferred frontends"],
summary: "Update preferred frontend setting",
description: "Store preferred frontend in cookies",
operationId: "PleromaAPI.FrontendSettingsController.update_preferred_frontend",
requestBody:
request_body(
"Frontend",
%Schema{
type: :object,
required: [:frontend_name],
properties: %{
frontend_name: %Schema{
type: :string,
description: "Frontend name"
}
}
},
required: true
),
responses: %{
200 =>
Operation.response("Preferred frontend", "application/json", %Schema{
type: :object,
properties: %{
frontend_name: %Schema{
type: :string,
description: "Frontend name"
}
}
})
}
}
end
end

View file

@ -20,7 +20,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
%Operation{
tags: ["Scrobbles"],
summary: "Creates a new Listen activity for an account",
security: [%{"oAuth" => ["write"]}],
security: [%{"oAuth" => ["write:scrobbles"]}],
operationId: "PleromaAPI.ScrobbleController.create",
deprecated: true,
requestBody: request_body("Parameters", create_request(), required: true),
@ -39,7 +39,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
parameters: [
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"} | pagination_params()
],
security: [%{"oAuth" => ["read"]}],
security: [%{"oAuth" => ["read:scrobbles"]}],
responses: %{
200 =>
Operation.response("Array of Scrobble", "application/json", %Schema{
@ -59,11 +59,15 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
album: %Schema{type: :string, description: "The album of the media playing"},
artist: %Schema{type: :string, description: "The artist of the media playing"},
length: %Schema{type: :integer, description: "The length of the media playing"},
externalLink: %Schema{type: :string, description: "A URL referencing the media playing"},
external_link: %Schema{type: :string, description: "A URL referencing the media playing"},
visibility: %Schema{
allOf: [VisibilityScope],
default: "public",
description: "Scrobble visibility"
},
externalLink: %Schema{
type: :string,
description: "Deprecated, use `external_link` instead"
}
},
example: %{
@ -71,7 +75,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
"artist" => "Some Artist",
"album" => "Some Album",
"length" => 180_000,
"externalLink" => "https://www.last.fm/music/Some+Artist/_/Some+Title"
"external_link" => "https://www.last.fm/music/Some+Artist/_/Some+Title"
}
}
end
@ -85,7 +89,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
title: %Schema{type: :string, description: "The title of the media playing"},
album: %Schema{type: :string, description: "The album of the media playing"},
artist: %Schema{type: :string, description: "The artist of the media playing"},
externalLink: %Schema{type: :string, description: "A URL referencing the media playing"},
external_link: %Schema{type: :string, description: "A URL referencing the media playing"},
length: %Schema{
type: :integer,
description: "The length of the media playing",
@ -100,7 +104,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
"artist" => "Some Artist",
"album" => "Some Album",
"length" => 180_000,
"externalLink" => "https://www.last.fm/music/Some+Artist/_/Some+Title",
"external_link" => "https://www.last.fm/music/Some+Artist/_/Some+Title",
"created_at" => "2019-09-28T12:40:45.000Z"
}
}

View file

@ -19,7 +19,8 @@ defmodule Pleroma.Web.ApiSpec.PleromaStatusOperation do
%Operation{
tags: ["Retrieve status information"],
summary: "Quoted by",
description: "View quotes for a given status",
deprecated: true,
description: "View quotes for a given status. Use /api/v1/statuses/:id/quotes instead.",
operationId: "PleromaAPI.StatusController.quotes",
parameters: [id_param() | pagination_params()],
security: [%{"oAuth" => ["read:statuses"]}],

View file

@ -2,7 +2,7 @@
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
defmodule Pleroma.Web.ApiSpec.PleromaUtilOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.ApiError
@ -19,7 +19,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
%Operation{
tags: ["Custom emojis"],
summary: "List all custom emojis",
operationId: "UtilController.emoji",
operationId: "PleromaAPI.UtilController.emoji",
parameters: [],
responses: %{
200 =>
@ -48,7 +48,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
%Operation{
tags: ["Others"],
summary: "Dump frontend configurations",
operationId: "UtilController.frontend_configurations",
operationId: "PleromaAPI.UtilController.frontend_configurations",
parameters: [],
responses: %{
200 =>
@ -70,7 +70,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Account credentials"],
summary: "Change account password",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.change_password",
operationId: "PleromaAPI.UtilController.change_password",
requestBody: request_body("Parameters", change_password_request(), required: true),
responses: %{
200 =>
@ -106,7 +106,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Account credentials"],
summary: "Change account email",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.change_email",
operationId: "PleromaAPI.UtilController.change_email",
requestBody: request_body("Parameters", change_email_request(), required: true),
responses: %{
200 =>
@ -141,7 +141,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Settings"],
summary: "Update Notification Settings",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.update_notification_settings",
operationId: "PleromaAPI.UtilController.update_notification_settings",
parameters: [
Operation.parameter(
:block_from_strangers,
@ -173,7 +173,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Account credentials"],
summary: "Disable Account",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.disable_account",
operationId: "PleromaAPI.UtilController.disable_account",
parameters: [
Operation.parameter(:password, :query, :string, "Password")
],
@ -193,7 +193,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Account credentials"],
summary: "Delete Account",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.delete_account",
operationId: "PleromaAPI.UtilController.delete_account",
parameters: [
Operation.parameter(:password, :query, :string, "Password")
],
@ -212,7 +212,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def captcha_operation do
%Operation{
summary: "Get a captcha",
operationId: "UtilController.captcha",
operationId: "PleromaAPI.UtilController.captcha",
tags: ["Others"],
parameters: [],
responses: %{
@ -226,7 +226,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Account credentials"],
summary: "Move account",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.move_account",
operationId: "PleromaAPI.UtilController.move_account",
requestBody: request_body("Parameters", move_account_request(), required: true),
responses: %{
200 =>
@ -262,7 +262,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Account credentials"],
summary: "List account aliases",
security: [%{"oAuth" => ["read:accounts"]}],
operationId: "UtilController.list_aliases",
operationId: "PleromaAPI.UtilController.list_aliases",
responses: %{
200 =>
Operation.response("Success", "application/json", %Schema{
@ -286,7 +286,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Account credentials"],
summary: "Add an alias to this account",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.add_alias",
operationId: "PleromaAPI.UtilController.add_alias",
requestBody: request_body("Parameters", add_alias_request(), required: true),
responses: %{
200 =>
@ -326,7 +326,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Account credentials"],
summary: "Delete an alias from this account",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.delete_alias",
operationId: "PleromaAPI.UtilController.delete_alias",
requestBody: request_body("Parameters", delete_alias_request(), required: true),
responses: %{
200 =>
@ -366,7 +366,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
tags: ["Others"],
summary: "Quick status check on the instance",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.healthcheck",
operationId: "PleromaAPI.UtilController.healthcheck",
parameters: [],
responses: %{
200 => Operation.response("Healthy", "application/json", %Schema{type: :object}),
@ -376,52 +376,6 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
}
end
def remote_subscribe_operation do
%Operation{
tags: ["Remote interaction"],
summary: "Remote Subscribe",
operationId: "UtilController.remote_subscribe",
parameters: [],
responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})}
}
end
def remote_interaction_operation do
%Operation{
tags: ["Remote interaction"],
summary: "Remote interaction",
operationId: "UtilController.remote_interaction",
requestBody: request_body("Parameters", remote_interaction_request(), required: true),
responses: %{
200 =>
Operation.response("Remote interaction URL", "application/json", %Schema{type: :object})
}
}
end
defp remote_interaction_request do
%Schema{
title: "RemoteInteractionRequest",
description: "POST body for remote interaction",
type: :object,
required: [:ap_id, :profile],
properties: %{
ap_id: %Schema{type: :string, description: "Profile or status ActivityPub ID"},
profile: %Schema{type: :string, description: "Remote profile webfinger"}
}
}
end
def show_subscribe_form_operation do
%Operation{
tags: ["Remote interaction"],
summary: "Show remote subscribe form",
operationId: "UtilController.show_subscribe_form",
parameters: [],
responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})}
}
end
defp delete_account_request do
%Schema{
title: "AccountDeleteRequest",

View file

@ -0,0 +1,99 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.RemoteInteractionOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
import Pleroma.Web.ApiSpec.Helpers
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end
def remote_interaction_operation do
%Operation{
tags: ["Remote interaction"],
summary: "Remote interaction",
operationId: "RemoteInteractionController.remote_interaction",
requestBody: request_body("Parameters", remote_interaction_request(), required: true),
responses: %{
200 =>
Operation.response("Remote interaction URL", "application/json", %Schema{type: :object})
}
}
end
defp remote_interaction_request do
%Schema{
title: "RemoteInteractionRequest",
description: "POST body for remote interaction",
type: :object,
required: [:ap_id, :profile],
properties: %{
ap_id: %Schema{type: :string, description: "Profile or status ActivityPub ID"},
profile: %Schema{type: :string, description: "Remote profile webfinger"}
}
}
end
def follow_operation do
%Operation{
tags: ["Remote interaction"],
summary: "Display follow form",
operationId: "RemoteInteractionController.follow",
parameters: [],
responses: %{
200 => Operation.response("Web Page", "text/html", %Schema{type: :string}),
302 => Operation.response("Redirect to the status page", nil, nil)
}
}
end
def do_follow_operation do
%Operation{
tags: ["Remote interaction"],
summary: "Perform follow activity",
operationId: "RemoteInteractionController.do_follow",
parameters: [],
responses: %{
200 => Operation.response("Web page", "text/html", %Schema{type: :string}),
302 => Operation.response("Redirect to the account page", nil, nil)
}
}
end
def authorize_interaction_operation do
%Operation{
tags: ["Remote interaction"],
summary: "Authorize remote interaction",
operationId: "RemoteInteractionController.authorize_interaction",
parameters: [],
responses: %{
302 => Operation.response("Redirect to remote_interaction path", nil, nil)
}
}
end
def show_subscribe_form_operation do
%Operation{
tags: ["Remote interaction"],
summary: "Show remote subscribe form",
operationId: "RemoteInteractionController.show_subscribe_form",
parameters: [],
responses: %{200 => Operation.response("Web Page", "text/html", %Schema{type: :string})}
}
end
def remote_subscribe_operation do
%Operation{
tags: ["Remote interaction"],
summary: "Remote Subscribe",
operationId: "RemoteInteractionController.remote_subscribe",
parameters: [],
responses: %{200 => Operation.response("Web Page", "text/html", %Schema{type: :string})}
}
end
end

View file

@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.ReportOperation do
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.ApiNotFoundError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
def open_api_operation(action) do
@ -24,7 +25,8 @@ defmodule Pleroma.Web.ApiSpec.ReportOperation do
requestBody: Helpers.request_body("Parameters", create_request(), required: true),
responses: %{
200 => Operation.response("Report", "application/json", create_response()),
400 => Operation.response("Report", "application/json", ApiError)
400 => Operation.response("Report", "application/json", ApiError),
404 => Operation.response("Report", "application/json", ApiNotFoundError)
}
}
end

View file

@ -46,6 +46,12 @@ defmodule Pleroma.Web.ApiSpec.SearchOperation do
:query,
%Schema{allOf: [BooleanLike], default: false},
"Only include accounts that the user is following"
),
Operation.parameter(
:capabilities,
:query,
%Schema{type: :array, items: %Schema{type: :string, enum: ["accepts_chat_messages"]}},
"Only include accounts with given capabilities"
)
],
responses: %{
@ -79,7 +85,9 @@ defmodule Pleroma.Web.ApiSpec.SearchOperation do
%Schema{type: :string, enum: ["accounts", "hashtags", "statuses"]},
"Search type"
),
Operation.parameter(:q, :query, %Schema{type: :string}, "The search query", required: true),
Operation.parameter(:q, :query, %Schema{type: :string}, "The search query",
required: true
),
Operation.parameter(
:resolve,
:query,

View file

@ -8,6 +8,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
alias Pleroma.Web.ApiSpec.AccountOperation
alias Pleroma.Web.ApiSpec.Schemas.Account
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.ApiNotFoundError
alias Pleroma.Web.ApiSpec.Schemas.Attachment
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
alias Pleroma.Web.ApiSpec.Schemas.Emoji
@ -31,11 +32,17 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
security: [%{"oAuth" => ["read:statuses"]}],
parameters: [
Operation.parameter(
:ids,
:id,
:query,
%Schema{type: :array, items: FlakeID},
"Array of status IDs"
),
Operation.parameter(
:ids,
:query,
%Schema{type: :array, items: FlakeID},
"Deprecated, use `id` instead"
),
Operation.parameter(
:with_muted,
:query,
@ -171,6 +178,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
parameters: [id_param()],
responses: %{
200 => status_response(),
400 => Operation.response("Error", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
@ -236,14 +244,19 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
"error" => "You have already pinned the maximum number of statuses"
}
}),
404 =>
Operation.response("Not found", "application/json", %Schema{
allOf: [ApiError],
title: "Unprocessable Entity",
example: %{
"error" => "Record not found"
404 => Operation.response("Not found", "application/json", ApiNotFoundError),
422 =>
Operation.response(
"Unprocessable Entity",
"application/json",
%Schema{
allOf: [ApiError],
title: "Unprocessable Entity",
example: %{
"error" => "Someone else's status cannot be unpinned"
}
}
})
)
}
}
end
@ -269,7 +282,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
}
}),
responses: %{
200 => status_response()
200 => status_response(),
404 => Operation.response("Not found", "application/json", ApiNotFoundError)
}
}
end
@ -283,7 +297,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
operationId: "StatusController.unbookmark",
parameters: [id_param()],
responses: %{
200 => status_response()
200 => status_response(),
404 => Operation.response("Not found", "application/json", ApiNotFoundError)
}
}
end
@ -318,7 +333,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
],
responses: %{
200 => status_response(),
400 => Operation.response("Error", "application/json", ApiError)
400 => Operation.response("Error", "application/json", ApiError),
404 => Operation.response("Not found", "application/json", ApiNotFoundError)
}
}
end
@ -334,7 +350,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
parameters: [id_param()],
responses: %{
200 => status_response(),
400 => Operation.response("Error", "application/json", ApiError)
400 => Operation.response("Error", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiNotFoundError)
}
}
end
@ -393,6 +410,38 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
}
end
def translate_operation do
%Operation{
tags: ["Retrieve status information"],
summary: "Translate status",
description: "Translate status with an external API",
operationId: "StatusController.translate",
security: [%{"oAuth" => ["read:statuses"]}],
parameters: [id_param()],
requestBody:
request_body(
"Parameters",
%Schema{
type: :object,
properties: %{
lang: %Schema{
type: :string,
nullable: true,
description: "Translation target language."
}
}
},
required: false
),
responses: %{
200 => Operation.response("Translation", "application/json", translation()),
400 => Operation.response("Error", "application/json", ApiError),
404 => Operation.response("Error", "application/json", ApiError),
503 => Operation.response("Error", "application/json", ApiError)
}
}
end
def favourites_operation do
%Operation{
tags: ["Timelines"],
@ -483,6 +532,27 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
}
end
def quotes_operation do
%Operation{
tags: ["Retrieve status information"],
summary: "Quoted by",
description: "View quotes for a given status",
operationId: "StatusController.quotes",
parameters: [id_param() | pagination_params()],
security: [%{"oAuth" => ["read:statuses"]}],
responses: %{
200 =>
Operation.response(
"Array of Status",
"application/json",
array_of_statuses()
),
403 => Operation.response("Forbidden", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def array_of_statuses do
%Schema{type: :array, items: Status, example: [Status.schema().example]}
end
@ -533,6 +603,20 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
nullable: true,
description: "ISO 639 language code for this status."
},
visibility: %Schema{
nullable: true,
anyOf: [
VisibilityScope,
%Schema{type: :string, description: "`list:LIST_ID`", example: "LIST:123"}
],
description:
"Visibility of the posted status. Besides standard MastoAPI values (`direct`, `private`, `unlisted` or `public`) it can be used to address a List by setting it to `list:LIST_ID`"
},
quoted_status_id: %Schema{
nullable: true,
allOf: [FlakeID],
description: "ID of the status being quoted, if any"
},
# Pleroma-specific properties:
preview: %Schema{
allOf: [BooleanLike],
@ -553,15 +637,6 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
description:
"A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply"
},
visibility: %Schema{
nullable: true,
anyOf: [
VisibilityScope,
%Schema{type: :string, description: "`list:LIST_ID`", example: "LIST:123"}
],
description:
"Visibility of the posted status. Besides standard MastoAPI values (`direct`, `private`, `unlisted` or `public`) it can be used to address a List by setting it to `list:LIST_ID`"
},
expires_in: %Schema{
nullable: true,
type: :integer,
@ -577,7 +652,8 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
quote_id: %Schema{
nullable: true,
allOf: [FlakeID],
description: "ID of the status being quoted, if any"
description: "Deprecated in favor of `quoted_status_id`",
deprecated: true
}
},
example: %{
@ -785,4 +861,32 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
}
}
end
defp translation do
%Schema{
title: "StatusTranslation",
description: "Represents status translation with related information.",
type: :object,
required: [:content, :detected_source_language, :provider],
properties: %{
content: %Schema{
type: :string,
description: "Translated status content"
},
detected_source_language: %Schema{
type: :string,
description: "Detected source language"
},
provider: %Schema{
type: :string,
description: "Translation provider service name"
}
},
example: %{
"content" => "Software für die nächste Generation der sozialen Medien.",
"detected_source_language" => "en",
"provider" => "Deepl"
}
}
end
end

View file

@ -139,7 +139,7 @@ defmodule Pleroma.Web.ApiSpec.StreamingOperation do
end
defp get_schema(%Schema{} = schema), do: schema
defp get_schema(schema), do: schema.schema
defp get_schema(schema), do: schema.schema()
defp server_sent_event_helper(name, description, type, payload, opts \\ []) do
payload_type = Keyword.get(opts, :payload_type, :json)

View file

@ -0,0 +1,103 @@
defmodule Pleroma.Web.ApiSpec.TagOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.Tag
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end
def show_operation do
%Operation{
tags: ["Tags"],
summary: "Hashtag",
description: "View a hashtag",
security: [%{"oAuth" => ["read"]}],
parameters: [id_param()],
operationId: "TagController.show",
responses: %{
200 => Operation.response("Hashtag", "application/json", Tag),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def follow_operation do
%Operation{
tags: ["Tags"],
summary: "Follow a hashtag",
description: "Follow a hashtag",
security: [%{"oAuth" => ["write:follows"]}],
parameters: [id_param()],
operationId: "TagController.follow",
responses: %{
200 => Operation.response("Hashtag", "application/json", Tag),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def unfollow_operation do
%Operation{
tags: ["Tags"],
summary: "Unfollow a hashtag",
description: "Unfollow a hashtag",
security: [%{"oAuth" => ["write:follows"]}],
parameters: [id_param()],
operationId: "TagController.unfollow",
responses: %{
200 => Operation.response("Hashtag", "application/json", Tag),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def show_followed_operation do
%Operation{
tags: ["Tags"],
summary: "Followed hashtags",
description: "View a list of hashtags the currently authenticated user is following",
parameters: pagination_params(),
security: [%{"oAuth" => ["read:follows"]}],
operationId: "TagController.show_followed",
responses: %{
200 =>
Operation.response("Hashtags", "application/json", %Schema{
type: :array,
items: Tag
}),
403 => Operation.response("Forbidden", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
defp id_param do
Operation.parameter(
:id,
:path,
%Schema{type: :string},
"Name of the hashtag"
)
end
def pagination_params do
[
Operation.parameter(:max_id, :query, :integer, "Return items older than this ID"),
Operation.parameter(
:min_id,
:query,
:integer,
"Return the oldest items newer than this ID"
),
Operation.parameter(
:limit,
:query,
%Schema{type: :integer, default: 20},
"Maximum number of items to return. Will be ignored if it's more than 40"
)
]
end
end

View file

@ -17,11 +17,11 @@ defmodule Pleroma.Web.ApiSpec.RenderError do
def call(conn, errors) do
errors =
Enum.map(errors, fn
%{name: nil, reason: :invalid_enum} = err ->
%OpenApiSpex.Cast.Error{err | name: err.value}
%OpenApiSpex.Cast.Error{name: nil, reason: :invalid_enum} = err ->
%{err | name: err.value}
%{name: nil} = err ->
%OpenApiSpex.Cast.Error{err | name: List.last(err.path)}
%OpenApiSpex.Cast.Error{name: nil} = err ->
%{err | name: List.last(err.path)}
err ->
err

View file

@ -21,6 +21,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
acct: %Schema{type: :string},
avatar_static: %Schema{type: :string, format: :uri},
avatar: %Schema{type: :string, format: :uri},
avatar_description: %Schema{type: :string},
bot: %Schema{type: :boolean},
created_at: %Schema{type: :string, format: "date-time"},
display_name: %Schema{type: :string},
@ -31,9 +32,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
following_count: %Schema{type: :integer},
header_static: %Schema{type: :string, format: :uri},
header: %Schema{type: :string, format: :uri},
header_description: %Schema{type: :string},
id: FlakeID,
locked: %Schema{type: :boolean},
mute_expires_at: %Schema{type: :string, format: "date-time", nullable: true},
note: %Schema{type: :string, format: :html},
statuses_count: %Schema{type: :integer},
url: %Schema{type: :string, format: :uri},
@ -111,7 +112,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
format: :uri,
nullable: true,
description: "Favicon image of the user's instance"
}
},
avatar_description: %Schema{type: :string, deprecated: true},
header_description: %Schema{type: :string, deprecated: true}
}
},
source: %Schema{
@ -152,6 +155,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
example: %{
"acct" => "foobar",
"avatar" => "https://mypleroma.com/images/avi.png",
"avatar_description" => "",
"avatar_static" => "https://mypleroma.com/images/avi.png",
"bot" => false,
"created_at" => "2020-03-24T13:05:58.000Z",
@ -162,6 +166,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
"followers_count" => 0,
"following_count" => 1,
"header" => "https://mypleroma.com/images/banner.png",
"header_description" => "",
"header_static" => "https://mypleroma.com/images/banner.png",
"id" => "9tKi3esbG7OQgZ2920",
"locked" => false,

View file

@ -26,7 +26,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.AccountRelationship do
requested: %Schema{type: :boolean},
showing_reblogs: %Schema{type: :boolean},
subscribing: %Schema{type: :boolean},
notifying: %Schema{type: :boolean}
notifying: %Schema{type: :boolean},
mute_expires_at: %Schema{type: :string, format: "date-time", nullable: true},
block_expires_at: %Schema{type: :string, format: "date-time", nullable: true}
},
example: %{
"blocked_by" => false,

View file

@ -0,0 +1,19 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.Schemas.ApiNotFoundError do
alias OpenApiSpex.Schema
require OpenApiSpex
OpenApiSpex.schema(%{
title: "Not Found",
description: "Response schema for 404 API errors",
type: :object,
properties: %{error: %Schema{type: :string}},
example: %{
"error" => "Record not found"
}
})
end

View file

@ -15,12 +15,18 @@ defmodule Pleroma.Web.ApiSpec.Schemas.BookmarkFolder do
properties: %{
id: FlakeID,
name: %Schema{type: :string, description: "Folder name"},
emoji: %Schema{type: :string, description: "Folder emoji", nullable: true}
emoji: %Schema{type: :string, description: "Folder emoji", nullable: true},
emoji_url: %Schema{
type: :string,
description: "URL of the folder emoji if it's a custom emoji, null otherwise",
nullable: true
}
},
example: %{
"id" => "9toJCu5YZW7O7gfvH6",
"name" => "Read later",
"emoji" => nil
"emoji" => nil,
"emoji_url" => nil
}
})
end

View file

@ -17,7 +17,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Chat do
account: %Schema{type: :object},
unread: %Schema{type: :integer},
last_message: ChatMessage,
updated_at: %Schema{type: :string, format: :"date-time"}
updated_at: %Schema{type: :string, format: :"date-time"},
pinned: %Schema{type: :boolean}
},
example: %{
"account" => %{
@ -68,8 +69,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Chat do
},
"id" => "1",
"unread" => 2,
"last_message" => ChatMessage.schema().example(),
"updated_at" => "2020-04-21T15:06:45.000Z"
"last_message" => ChatMessage.schema().example,
"updated_at" => "2020-04-21T15:06:45.000Z",
"pinned" => false
}
})
end

View file

@ -13,11 +13,30 @@ defmodule Pleroma.Web.ApiSpec.Schemas.List do
type: :object,
properties: %{
id: %Schema{type: :string, description: "The internal database ID of the list"},
title: %Schema{type: :string, description: "The user-defined title of the list"}
title: %Schema{type: :string, description: "The user-defined title of the list"},
exclusive: %Schema{
type: :boolean,
description: "Whether members of the list should be removed from the “Home” feed"
},
pleroma: %Schema{
type: :object,
properties: %{
emoji: %Schema{type: :string, description: "List emoji", nullable: true},
emoji_url: %Schema{
type: :string,
description: "URL of the list emoji if it's a custom emoji, null otherwise",
nullable: true
}
}
}
},
example: %{
"id" => "12249",
"title" => "Friends"
"title" => "Friends",
"pleroma" => %{
"emoji" => nil,
"emoji_url" => nil
}
}
})
end

View file

@ -258,7 +258,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
},
quotes_count: %Schema{
type: :integer,
description: "How many statuses quoted this status"
deprecated: true,
description:
"How many statuses quoted this status. Deprecated, use `quotes_count` from parent object instead."
},
local: %Schema{
type: :boolean,
@ -288,10 +290,20 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
nullable: true,
description:
"A datetime (ISO 8601) that states when the post was pinned or `null` if the post is not pinned"
},
list_id: %Schema{
type: :integer,
nullable: true,
description:
"The ID of the list the post is addressed to (if any, only returned to author)"
}
}
},
poll: %Schema{allOf: [Poll], nullable: true, description: "The poll attached to the status"},
quotes_count: %Schema{
type: :integer,
description: "How many statuses quoted this status."
},
reblog: %Schema{
allOf: [%OpenApiSpex.Reference{"$ref": "#/components/schemas/Status"}],
nullable: true,
@ -418,6 +430,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
"quotes_count" => 0
},
"poll" => nil,
"quotes_count" => 0,
"reblog" => nil,
"reblogged" => false,
"reblogs_count" => 0,

View file

@ -17,11 +17,22 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Tag do
type: :string,
format: :uri,
description: "A link to the hashtag on the instance"
},
following: %Schema{
type: :boolean,
description: "Whether the authenticated user is following the hashtag"
},
history: %Schema{
type: :array,
items: %Schema{type: :string},
description:
"A list of historical uses of the hashtag (not implemented, for compatibility only)"
}
},
example: %{
name: "cofe",
url: "https://lain.com/tag/cofe"
url: "https://lain.com/tag/cofe",
following: false
}
})
end

View file

@ -26,7 +26,11 @@ defmodule Pleroma.Web.ApiSpec.Scopes.Compiler do
end
def extract_all_scopes do
extract_all_scopes_from(Pleroma.Web.ApiSpec.spec())
try do
extract_all_scopes_from(Pleroma.Web.ApiSpec.spec())
catch
_, _ -> []
end
end
def extract_all_scopes_from(specs) do