Page MenuHomePhorge

No OneTemporary

Size
11 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
index 2d56dc643..163226ce5 100644
--- a/lib/pleroma/web/api_spec.ex
+++ b/lib/pleroma/web/api_spec.ex
@@ -1,152 +1,160 @@
# 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 do
alias OpenApiSpex.OpenApi
alias OpenApiSpex.Operation
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Router
@behaviour OpenApi
+ defp streaming_paths do
+ %{
+ "/api/v1/streaming" => %OpenApiSpex.PathItem{
+ get: Pleroma.Web.ApiSpec.StreamingOperation.streaming_operation()
+ }
+ }
+ end
+
@impl OpenApi
def spec(opts \\ []) do
%OpenApi{
servers:
if opts[:server_specific] do
[
# Populate the Server info from a phoenix endpoint
OpenApiSpex.Server.from_endpoint(Endpoint)
]
else
[]
end,
info: %OpenApiSpex.Info{
title: "Pleroma API",
description: """
This is documentation for client Pleroma API. Most of the endpoints and entities come
from Mastodon API and have custom extensions on top.
While this document aims to be a complete guide to the client API Pleroma exposes,
the details are still being worked out. Some endpoints may have incomplete or poorly worded documentation.
You might want to check the following resources if something is not clear:
- [Legacy Pleroma-specific endpoint documentation](https://docs-develop.pleroma.social/backend/development/API/pleroma_api/)
- [Mastodon API documentation](https://docs.joinmastodon.org/client/intro/)
- [Differences in Mastodon API responses from vanilla Mastodon](https://docs-develop.pleroma.social/backend/development/API/differences_in_mastoapi_responses/)
Please report such occurences on our [issue tracker](https://git.pleroma.social/pleroma/pleroma/-/issues). Feel free to submit API questions or proposals there too!
""",
# Strip environment from the version
version: Application.spec(:pleroma, :vsn) |> to_string() |> String.replace(~r/\+.*$/, ""),
extensions: %{
# Logo path should be picked so that the path exists both on Pleroma instances and on api.pleroma.social
"x-logo": %{"url" => "/static/logo.svg", "altText" => "Pleroma logo"}
}
},
# populate the paths from a phoenix router
- paths: OpenApiSpex.Paths.from_router(Router),
+ paths: Map.merge(streaming_paths(), OpenApiSpex.Paths.from_router(Router)),
components: %OpenApiSpex.Components{
parameters: %{
"accountIdOrNickname" =>
Operation.parameter(:id, :path, :string, "Account ID or nickname",
example: "123",
required: true
)
},
securitySchemes: %{
"oAuth" => %OpenApiSpex.SecurityScheme{
type: "oauth2",
flows: %OpenApiSpex.OAuthFlows{
password: %OpenApiSpex.OAuthFlow{
authorizationUrl: "/oauth/authorize",
tokenUrl: "/oauth/token",
scopes: %{
# TODO: Document granular scopes
"read" => "Read everything",
"write" => "Write everything",
"follow" => "Manage relationships",
"push" => "Web Push API subscriptions"
}
}
}
}
}
},
extensions: %{
# Redoc-specific extension, every time a new tag is added it should be reflected here,
# otherwise it won't be shown.
"x-tagGroups": [
%{
"name" => "Accounts",
"tags" => ["Account actions", "Retrieve account information", "Scrobbles"]
},
%{
"name" => "Administration",
"tags" => [
"Chat administration",
"Emoji pack administration",
"Frontend managment",
"Instance configuration",
"Instance documents",
"Invites",
"MediaProxy cache",
"OAuth application managment",
"Relays",
"Report managment",
"Status administration",
"User administration",
"Announcement management"
]
},
%{"name" => "Applications", "tags" => ["Applications", "Push subscriptions"]},
%{
"name" => "Current account",
"tags" => [
"Account credentials",
"Backups",
"Blocks and mutes",
"Data import",
"Domain blocks",
"Follow requests",
"Mascot",
"Markers",
"Notifications",
"Filters",
"Settings"
]
},
%{"name" => "Instance", "tags" => ["Custom emojis", "Instance misc"]},
%{"name" => "Messaging", "tags" => ["Chats", "Conversations"]},
%{
"name" => "Statuses",
"tags" => [
"Emoji reactions",
"Lists",
"Polls",
"Timelines",
"Retrieve status information",
"Scheduled statuses",
"Search",
"Status actions",
"Media attachments"
]
},
%{
"name" => "Miscellaneous",
"tags" => [
"Emoji packs",
"Reports",
"Suggestions",
"Announcements",
"Remote interaction",
"Others"
]
}
]
}
}
# discover request/response schemas from path specs
|> OpenApiSpex.resolve_schema_modules()
end
end
diff --git a/lib/pleroma/web/api_spec/operations/streaming_operation.ex b/lib/pleroma/web/api_spec/operations/streaming_operation.ex
new file mode 100644
index 000000000..1ef7d72ef
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/streaming_operation.ex
@@ -0,0 +1,186 @@
+# 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.StreamingOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Response
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Helpers
+ alias Pleroma.Web.ApiSpec.Schemas.Status
+
+ @spec open_api_operation(atom) :: Operation.t()
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ @spec streaming_operation() :: Operation.t()
+ def streaming_operation do
+ %Operation{
+ tags: ["Timelines"],
+ summary: "Establish streaming connection",
+ description: "Receive statuses in real-time via WebSocket.",
+ security: [%{"oAuth" => ["read:statuses", "read:notifications"]}],
+ parameters: [
+ Operation.parameter(:connection, :header, %Schema{type: :string}, "connection header",
+ required: true
+ ),
+ Operation.parameter(:upgrade, :header, %Schema{type: :string}, "upgrade header",
+ required: true
+ ),
+ Operation.parameter(
+ :"sec-websocket-key",
+ :header,
+ %Schema{type: :string},
+ "sec-websocket-key header",
+ required: true
+ ),
+ Operation.parameter(
+ :"sec-websocket-version",
+ :header,
+ %Schema{type: :string},
+ "sec-websocket-version header",
+ required: true
+ )
+ ],
+ responses: %{
+ 101 => switching_protocols_response(),
+ 200 =>
+ Operation.response(
+ "Server-sent events",
+ "application/json",
+ server_sent_events()
+ )
+ }
+ }
+ end
+
+ defp switching_protocols_response do
+ %Response{
+ description: "Switching protocols",
+ headers: %{
+ "connection" => %OpenApiSpex.Header{required: true},
+ "upgrade" => %OpenApiSpex.Header{required: true},
+ "sec-websocket-accept" => %OpenApiSpex.Header{required: true}
+ }
+ }
+ end
+
+ defp server_sent_events do
+ %Schema{
+ oneOf: [
+ update_event(),
+ status_update_event(),
+ pleroma_respond_event()
+ ]
+ }
+ end
+
+ defp stream do
+ %Schema{
+ type: :array,
+ title: "Stream",
+ description: """
+ The stream identifier.
+ The first item is the name of the stream. If the stream needs a differentiator, the second item will be the corresponding identifier.
+ Currently, for the following stream types, there is a second element in the array:
+
+ - `list`: The second element is the id of the list, as a string.
+ - `hashtag`: The second element is the name of the hashtag.
+ - `public:remote:media` and `public:remote`: The second element is the domain of the corresponding instance.
+ """,
+ maxItems: 2,
+ minItems: 1,
+ items: %Schema{type: :string},
+ example: ["hashtag", "mew"]
+ }
+ end
+
+ defp get_schema(%Schema{} = schema), do: schema
+ defp get_schema(schema), do: schema.schema
+
+ defp server_sent_event_helper(name, description, type, payload, opts \\ []) do
+ payload_type = opts[:payload_type] || :json
+ has_stream = opts[:has_stream] || true
+
+ stream_properties =
+ if has_stream do
+ %{stream: stream()}
+ else
+ %{}
+ end
+
+ stream_example = if has_stream, do: %{"stream" => get_schema(stream()).example}, else: %{}
+
+ stream_required = if has_stream, do: [:stream], else: []
+
+ %Schema{
+ type: :object,
+ title: name,
+ description: description,
+ required: [:event, :payload] ++ stream_required,
+ properties:
+ %{
+ event: %Schema{
+ title: "Event type",
+ description: "Type of the event.",
+ type: :string,
+ required: true,
+ enum: [type]
+ },
+ payload:
+ if payload_type == :json do
+ %Schema{
+ title: "Event payload",
+ description: "JSON-encoded string of #{get_schema(payload).title}",
+ allOf: [payload]
+ }
+ else
+ payload
+ end
+ }
+ |> Map.merge(stream_properties),
+ example:
+ %{
+ "event" => type,
+ "payload" => get_schema(payload).example |> Jason.encode!()
+ }
+ |> Map.merge(stream_example)
+ }
+ end
+
+ defp update_event do
+ server_sent_event_helper("New status", "A newly-posted status.", "update", Status)
+ end
+
+ defp status_update_event do
+ server_sent_event_helper("Edit", "A status that was just edited", "status.update", Status)
+ end
+
+ defp pleroma_respond_event do
+ server_sent_event_helper(
+ "Server response",
+ "A response to a client-sent event.",
+ "pleroma:respond",
+ %Schema{
+ type: :object,
+ title: "Results",
+ required: [:result],
+ properties: %{
+ result: %Schema{
+ type: :string,
+ title: "Result of the request",
+ enum: ["success", "error", "ignored"]
+ },
+ error: %Schema{
+ type: :string,
+ title: "Error code",
+ description: "An error identifier. Only appears if `result` is `error`."
+ }
+ },
+ example: %{"result" => "success"}
+ }
+ )
+ end
+end

File Metadata

Mime Type
text/x-diff
Expires
Mon, Oct 12, 1:28 PM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1786284
Default Alt Text
(11 KB)

Event Timeline