aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex53
-rw-r--r--lib/pleroma/web/admin_api/views/account_view.ex9
-rw-r--r--lib/pleroma/web/admin_api/views/report_view.ex13
-rw-r--r--lib/pleroma/web/admin_api/views/status_view.ex17
-rw-r--r--lib/pleroma/web/api_spec/helpers.ex14
-rw-r--r--lib/pleroma/web/api_spec/operations/account_operation.ex90
-rw-r--r--lib/pleroma/web/api_spec/operations/app_operation.ex6
-rw-r--r--lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex102
-rw-r--r--lib/pleroma/web/api_spec/operations/filter_operation.ex9
-rw-r--r--lib/pleroma/web/api_spec/operations/instance_operation.ex8
-rw-r--r--lib/pleroma/web/api_spec/operations/marker_operation.ex6
-rw-r--r--lib/pleroma/web/api_spec/operations/media_operation.ex132
-rw-r--r--lib/pleroma/web/api_spec/operations/notification_operation.ex2
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex187
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex106
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex390
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex79
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex42
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex102
-rw-r--r--lib/pleroma/web/api_spec/operations/report_operation.ex6
-rw-r--r--lib/pleroma/web/api_spec/operations/search_operation.ex9
-rw-r--r--lib/pleroma/web/api_spec/operations/status_operation.ex39
-rw-r--r--lib/pleroma/web/api_spec/operations/subscription_operation.ex59
-rw-r--r--lib/pleroma/web/api_spec/operations/timeline_operation.ex18
-rw-r--r--lib/pleroma/web/api_spec/schemas/attachment.ex2
-rw-r--r--lib/pleroma/web/auth/pleroma_authenticator.ex3
-rw-r--r--lib/pleroma/web/auth/totp_authenticator.ex5
-rw-r--r--lib/pleroma/web/chat_channel.ex1
-rw-r--r--lib/pleroma/web/common_api/common_api.ex24
-rw-r--r--lib/pleroma/web/controller_helper.ex21
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex27
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex4
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/media_controller.ex49
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/notification_controller.ex5
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/search_controller.ex16
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/status_controller.ex13
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex17
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex9
-rw-r--r--lib/pleroma/web/mastodon_api/views/instance_view.ex1
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex23
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex33
-rw-r--r--lib/pleroma/web/media_proxy/invalidation.ex26
-rw-r--r--lib/pleroma/web/media_proxy/invalidations/http.ex40
-rw-r--r--lib/pleroma/web/media_proxy/invalidations/script.ex41
-rw-r--r--lib/pleroma/web/mongooseim/mongoose_im_controller.ex3
-rw-r--r--lib/pleroma/web/oauth/mfa_controller.ex2
-rw-r--r--lib/pleroma/web/oauth/mfa_view.ex2
-rw-r--r--lib/pleroma/web/oauth/token/clean_worker.ex2
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/account_controller.ex31
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex95
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex (renamed from lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex)90
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex61
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex5
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/notification_controller.ex36
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex217
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex35
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex2
-rw-r--r--lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex33
-rw-r--r--lib/pleroma/web/pleroma_api/views/scrobble_view.ex37
-rw-r--r--lib/pleroma/web/router.ex54
60 files changed, 2022 insertions, 541 deletions
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 9821173d0..647ceb3ba 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -22,6 +22,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.AdminAPI.ConfigView
alias Pleroma.Web.AdminAPI.ModerationLogView
@@ -30,14 +31,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
alias Pleroma.Web.AdminAPI.Search
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Endpoint
+ alias Pleroma.Web.MastodonAPI
alias Pleroma.Web.MastodonAPI.AppView
- alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.Router
require Logger
- @descriptions_json Pleroma.Docs.JSON.compile()
+ @descriptions Pleroma.Docs.JSON.compile()
@users_page_size 50
plug(
@@ -280,8 +281,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
})
conn
- |> put_view(Pleroma.Web.AdminAPI.StatusView)
- |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
+ |> put_view(AdminAPI.StatusView)
+ |> render("index.json", %{activities: activities, as: :activity})
end
def list_user_statuses(conn, %{"nickname" => nickname} = params) do
@@ -299,8 +300,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
})
conn
- |> put_view(StatusView)
- |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
+ |> put_view(MastodonAPI.StatusView)
+ |> render("index.json", %{activities: activities, as: :activity})
else
_ -> {:error, :not_found}
end
@@ -829,14 +830,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
})
conn
- |> put_view(Pleroma.Web.AdminAPI.StatusView)
- |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
+ |> put_view(AdminAPI.StatusView)
+ |> render("index.json", %{activities: activities, as: :activity})
end
def status_show(conn, %{"id" => id}) do
with %Activity{} = activity <- Activity.get_by_id(id) do
conn
- |> put_view(StatusView)
+ |> put_view(MastodonAPI.StatusView)
|> render("show.json", %{activity: activity})
else
_ -> errors(conn, {:error, :not_found})
@@ -861,7 +862,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
})
conn
- |> put_view(StatusView)
+ |> put_view(MastodonAPI.StatusView)
|> render("show.json", %{activity: activity})
end
end
@@ -897,9 +898,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
def config_descriptions(conn, _params) do
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.send_resp(200, @descriptions_json)
+ descriptions = Enum.filter(@descriptions, &whitelisted_config?/1)
+
+ json(conn, descriptions)
end
def config_show(conn, %{"only_db" => true}) do
@@ -954,7 +955,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
def config_update(conn, %{"configs" => configs}) do
with :ok <- configurable_from_database(conn) do
{_errors, results} =
- Enum.map(configs, fn
+ configs
+ |> Enum.filter(&whitelisted_config?/1)
+ |> Enum.map(fn
%{"group" => group, "key" => key, "delete" => true} = params ->
ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]})
@@ -1016,6 +1019,28 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
end
+ defp whitelisted_config?(group, key) do
+ if whitelisted_configs = Config.get(:database_config_whitelist) do
+ Enum.any?(whitelisted_configs, fn
+ {whitelisted_group} ->
+ group == inspect(whitelisted_group)
+
+ {whitelisted_group, whitelisted_key} ->
+ group == inspect(whitelisted_group) && key == inspect(whitelisted_key)
+ end)
+ else
+ true
+ end
+ end
+
+ defp whitelisted_config?(%{"group" => group, "key" => key}) do
+ whitelisted_config?(group, key)
+ end
+
+ defp whitelisted_config?(%{:group => group} = config) do
+ whitelisted_config?(group, config[:key])
+ end
+
def reload_emoji(conn, _params) do
Pleroma.Emoji.reload()
diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex
index a16a3ebf0..46dadb5ee 100644
--- a/lib/pleroma/web/admin_api/views/account_view.ex
+++ b/lib/pleroma/web/admin_api/views/account_view.ex
@@ -6,7 +6,9 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
use Pleroma.Web, :view
alias Pleroma.User
+ alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.AccountView
+ alias Pleroma.Web.MastodonAPI
alias Pleroma.Web.MediaProxy
def render("index.json", %{users: users, count: count, page_size: page_size}) do
@@ -119,6 +121,13 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
}
end
+ def merge_account_views(%User{} = user) do
+ MastodonAPI.AccountView.render("show.json", %{user: user})
+ |> Map.merge(AdminAPI.AccountView.render("show.json", %{user: user}))
+ end
+
+ def merge_account_views(_), do: %{}
+
defp parse_error([]), do: ""
defp parse_error(errors) do
diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex
index d50969b2a..f432b8c2c 100644
--- a/lib/pleroma/web/admin_api/views/report_view.ex
+++ b/lib/pleroma/web/admin_api/views/report_view.ex
@@ -7,10 +7,13 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
alias Pleroma.HTML
alias Pleroma.User
+ alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.Report
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.StatusView
+ defdelegate merge_account_views(user), to: AdminAPI.AccountView
+
def render("index.json", %{reports: reports}) do
%{
reports:
@@ -41,8 +44,7 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
statuses:
StatusView.render("index.json", %{
activities: statuses,
- as: :activity,
- skip_relationships: false
+ as: :activity
}),
state: report.data["state"],
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
@@ -70,11 +72,4 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
created_at: Utils.to_masto_date(inserted_at)
}
end
-
- defp merge_account_views(%User{} = user) do
- Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
- |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
- end
-
- defp merge_account_views(_), do: %{}
end
diff --git a/lib/pleroma/web/admin_api/views/status_view.ex b/lib/pleroma/web/admin_api/views/status_view.ex
index 3637dee24..500800be2 100644
--- a/lib/pleroma/web/admin_api/views/status_view.ex
+++ b/lib/pleroma/web/admin_api/views/status_view.ex
@@ -7,24 +7,19 @@ defmodule Pleroma.Web.AdminAPI.StatusView do
require Pleroma.Constants
- alias Pleroma.User
- alias Pleroma.Web.MastodonAPI.StatusView
+ alias Pleroma.Web.AdminAPI
+ alias Pleroma.Web.MastodonAPI
+
+ defdelegate merge_account_views(user), to: AdminAPI.AccountView
def render("index.json", opts) do
safe_render_many(opts.activities, __MODULE__, "show.json", opts)
end
def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
- user = StatusView.get_user(activity.data["actor"])
+ user = MastodonAPI.StatusView.get_user(activity.data["actor"])
- StatusView.render("show.json", opts)
+ MastodonAPI.StatusView.render("show.json", opts)
|> Map.merge(%{account: merge_account_views(user)})
end
-
- defp merge_account_views(%User{} = user) do
- Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
- |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
- end
-
- defp merge_account_views(_), do: %{}
end
diff --git a/lib/pleroma/web/api_spec/helpers.ex b/lib/pleroma/web/api_spec/helpers.ex
index 183df43ee..a9cfe0fed 100644
--- a/lib/pleroma/web/api_spec/helpers.ex
+++ b/lib/pleroma/web/api_spec/helpers.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.ApiSpec.Helpers do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
def request_body(description, schema_ref, opts \\ []) do
media_types = ["application/json", "multipart/form-data", "application/x-www-form-urlencoded"]
@@ -47,6 +48,15 @@ defmodule Pleroma.Web.ApiSpec.Helpers do
]
end
+ def with_relationships_param do
+ Operation.parameter(
+ :with_relationships,
+ :query,
+ BooleanLike,
+ "Embed relationships into accounts."
+ )
+ end
+
def empty_object_response do
Operation.response("Empty object", "application/json", %Schema{type: :object, example: %{}})
end
@@ -54,4 +64,8 @@ defmodule Pleroma.Web.ApiSpec.Helpers do
def empty_array_response do
Operation.response("Empty array", "application/json", %Schema{type: :array, example: []})
end
+
+ def no_content_response do
+ Operation.response("No Content", "application/json", %Schema{type: :string, example: ""})
+ end
end
diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex
index 70069d6f9..20572f8ea 100644
--- a/lib/pleroma/web/api_spec/operations/account_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/account_operation.ex
@@ -155,8 +155,10 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
security: [%{"oAuth" => ["read:accounts"]}],
description:
"Accounts which follow the given account, if network is not hidden by the account owner.",
- parameters:
- [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
+ parameters: [
+ %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
+ with_relationships_param() | pagination_params()
+ ],
responses: %{
200 => Operation.response("Accounts", "application/json", array_of_accounts())
}
@@ -171,8 +173,10 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
security: [%{"oAuth" => ["read:accounts"]}],
description:
"Accounts which the given account is following, if network is not hidden by the account owner.",
- parameters:
- [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
+ parameters: [
+ %Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
+ with_relationships_param() | pagination_params()
+ ],
responses: %{200 => Operation.response("Accounts", "application/json", array_of_accounts())}
}
end
@@ -367,15 +371,18 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
title: "AccountCreateRequest",
description: "POST body for creating an account",
type: :object,
+ required: [:username, :password, :agreement],
properties: %{
reason: %Schema{
type: :string,
+ nullable: true,
description:
"Text that will be reviewed by moderators if registrations require manual approval"
},
username: %Schema{type: :string, description: "The desired username for the account"},
email: %Schema{
type: :string,
+ nullable: true,
description:
"The email address to be used for login. Required when `account_activation_required` is enabled.",
format: :email
@@ -386,29 +393,39 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
format: :password
},
agreement: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
description:
"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."
},
locale: %Schema{
type: :string,
+ nullable: true,
description: "The language of the confirmation email that will be sent"
},
# Pleroma-specific properties:
- fullname: %Schema{type: :string, description: "Full name"},
- bio: %Schema{type: :string, description: "Bio", default: ""},
+ fullname: %Schema{type: :string, nullable: true, description: "Full name"},
+ bio: %Schema{type: :string, description: "Bio", nullable: true, default: ""},
captcha_solution: %Schema{
type: :string,
+ nullable: true,
description: "Provider-specific captcha solution"
},
- captcha_token: %Schema{type: :string, description: "Provider-specific captcha token"},
- captcha_answer_data: %Schema{type: :string, description: "Provider-specific captcha data"},
+ captcha_token: %Schema{
+ type: :string,
+ nullable: true,
+ description: "Provider-specific captcha token"
+ },
+ captcha_answer_data: %Schema{
+ type: :string,
+ nullable: true,
+ description: "Provider-specific captcha data"
+ },
token: %Schema{
type: :string,
+ nullable: true,
description: "Invite token required when the registrations aren't public"
}
},
- required: [:username, :password, :agreement],
example: %{
"username" => "cofe",
"email" => "cofe@example.com",
@@ -446,29 +463,35 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
type: :object,
properties: %{
bot: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Whether the account has a bot flag."
},
display_name: %Schema{
type: :string,
+ nullable: true,
description: "The display name to use for the profile."
},
note: %Schema{type: :string, description: "The account bio."},
avatar: %Schema{
type: :string,
+ nullable: true,
description: "Avatar image encoded using multipart/form-data",
format: :binary
},
header: %Schema{
type: :string,
+ nullable: true,
description: "Header image encoded using multipart/form-data",
format: :binary
},
locked: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Whether manual approval of follow requests is required."
},
fields_attributes: %Schema{
+ nullable: true,
oneOf: [
%Schema{type: :array, items: attribute_field()},
%Schema{type: :object, additionalProperties: %Schema{type: attribute_field()}}
@@ -487,48 +510,66 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
# Pleroma-specific fields
no_rich_text: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "html tags are stripped from all statuses requested from the API"
},
- hide_followers: %Schema{type: :boolean, description: "user's followers will be hidden"},
- hide_follows: %Schema{type: :boolean, description: "user's follows will be hidden"},
+ hide_followers: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "user's followers will be hidden"
+ },
+ hide_follows: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "user's follows will be hidden"
+ },
hide_followers_count: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "user's follower count will be hidden"
},
hide_follows_count: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "user's follow count will be hidden"
},
hide_favorites: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "user's favorites timeline will be hidden"
},
show_role: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "user's role (e.g admin, moderator) will be exposed to anyone in the
API"
},
default_scope: VisibilityScope,
pleroma_settings_store: %Schema{
type: :object,
+ nullable: true,
description: "Opaque user settings to be saved on the backend."
},
skip_thread_containment: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Skip filtering out broken threads"
},
allow_following_move: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Allows automatically follow moved following accounts"
},
pleroma_background_image: %Schema{
type: :string,
+ nullable: true,
description: "Sets the background image of the user.",
format: :binary
},
discoverable: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description:
"Discovery of this account in search results and other services is allowed."
},
@@ -624,7 +665,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
description: "POST body for muting an account",
type: :object,
properties: %{
- uri: %Schema{type: :string, format: :uri}
+ uri: %Schema{type: :string, nullable: true, format: :uri}
},
required: [:uri]
}
@@ -637,7 +678,8 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
type: :object,
properties: %{
notifications: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Mute notifications in addition to statuses? Defaults to true.",
default: true
}
diff --git a/lib/pleroma/web/api_spec/operations/app_operation.ex b/lib/pleroma/web/api_spec/operations/app_operation.ex
index f6ccd073f..ae01cbbec 100644
--- a/lib/pleroma/web/api_spec/operations/app_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/app_operation.ex
@@ -105,7 +105,11 @@ defmodule Pleroma.Web.ApiSpec.AppOperation do
description: "Space separated list of scopes",
default: "read"
},
- website: %Schema{type: :string, description: "A URL to the homepage of your app"}
+ website: %Schema{
+ type: :string,
+ nullable: true,
+ description: "A URL to the homepage of your app"
+ }
},
required: [:client_name, :redirect_uris],
example: %{
diff --git a/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex b/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex
new file mode 100644
index 000000000..7c08fbaa7
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex
@@ -0,0 +1,102 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.Account
+ alias Pleroma.Web.ApiSpec.Schemas.FlakeID
+ alias Pleroma.Web.ApiSpec.Schemas.Status
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def index_operation do
+ %Operation{
+ tags: ["Emoji Reactions"],
+ summary:
+ "Get an object of emoji to account mappings with accounts that reacted to the post",
+ parameters: [
+ Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
+ Operation.parameter(:emoji, :path, :string, "Filter by a single unicode emoji",
+ required: false
+ )
+ ],
+ security: [%{"oAuth" => ["read:statuses"]}],
+ operationId: "EmojiReactionController.index",
+ responses: %{
+ 200 => array_of_reactions_response()
+ }
+ }
+ end
+
+ def create_operation do
+ %Operation{
+ tags: ["Emoji Reactions"],
+ summary: "React to a post with a unicode emoji",
+ parameters: [
+ Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
+ Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
+ required: true
+ )
+ ],
+ security: [%{"oAuth" => ["write:statuses"]}],
+ operationId: "EmojiReactionController.create",
+ responses: %{
+ 200 => Operation.response("Status", "application/json", Status)
+ }
+ }
+ end
+
+ def delete_operation do
+ %Operation{
+ tags: ["Emoji Reactions"],
+ summary: "Remove a reaction to a post with a unicode emoji",
+ parameters: [
+ Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
+ Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
+ required: true
+ )
+ ],
+ security: [%{"oAuth" => ["write:statuses"]}],
+ operationId: "EmojiReactionController.delete",
+ responses: %{
+ 200 => Operation.response("Status", "application/json", Status)
+ }
+ }
+ end
+
+ defp array_of_reactions_response do
+ Operation.response("Array of Emoji Reactions", "application/json", %Schema{
+ type: :array,
+ items: emoji_reaction(),
+ example: [emoji_reaction().example]
+ })
+ end
+
+ defp emoji_reaction do
+ %Schema{
+ title: "EmojiReaction",
+ type: :object,
+ properties: %{
+ name: %Schema{type: :string, description: "Emoji"},
+ count: %Schema{type: :integer, description: "Count of reactions with this emoji"},
+ me: %Schema{type: :boolean, description: "Did I react with this emoji?"},
+ accounts: %Schema{
+ type: :array,
+ items: Account,
+ description: "Array of accounts reacted with this emoji"
+ }
+ },
+ example: %{
+ "name" => "😱",
+ "count" => 1,
+ "me" => false,
+ "accounts" => [Account.schema().example]
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/filter_operation.ex b/lib/pleroma/web/api_spec/operations/filter_operation.ex
index 53e57b46b..31e576f99 100644
--- a/lib/pleroma/web/api_spec/operations/filter_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/filter_operation.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.ApiSpec.FilterOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers
+ alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
@@ -171,7 +172,7 @@ defmodule Pleroma.Web.ApiSpec.FilterOperation do
type: :object,
properties: %{
irreversible: %Schema{
- type: :bolean,
+ allOf: [BooleanLike],
description:
"Should the server irreversibly drop matching entities from home and notifications?",
default: false
@@ -199,12 +200,14 @@ defmodule Pleroma.Web.ApiSpec.FilterOperation do
"Array of enumerable strings `home`, `notifications`, `public`, `thread`. At least one context must be specified."
},
irreversible: %Schema{
- type: :bolean,
+ allOf: [BooleanLike],
+ nullable: true,
description:
"Should the server irreversibly drop matching entities from home and notifications?"
},
whole_word: %Schema{
- type: :bolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Consider word boundaries?",
default: true
}
diff --git a/lib/pleroma/web/api_spec/operations/instance_operation.ex b/lib/pleroma/web/api_spec/operations/instance_operation.ex
index 880bd3f1b..d5c335d0c 100644
--- a/lib/pleroma/web/api_spec/operations/instance_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/instance_operation.ex
@@ -125,11 +125,17 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
},
avatar_upload_limit: %Schema{type: :integer, description: "The title of the website"},
background_upload_limit: %Schema{type: :integer, description: "The title of the website"},
- banner_upload_limit: %Schema{type: :integer, description: "The title of the website"}
+ banner_upload_limit: %Schema{type: :integer, description: "The title of the website"},
+ background_image: %Schema{
+ type: :string,
+ format: :uri,
+ description: "The background image for the website"
+ }
},
example: %{
"avatar_upload_limit" => 2_000_000,
"background_upload_limit" => 4_000_000,
+ "background_image" => "/static/image.png",
"banner_upload_limit" => 4_000_000,
"description" => "A Pleroma instance, an alternative fediverse server",
"email" => "lain@lain.com",
diff --git a/lib/pleroma/web/api_spec/operations/marker_operation.ex b/lib/pleroma/web/api_spec/operations/marker_operation.ex
index 06620492a..714ef1f99 100644
--- a/lib/pleroma/web/api_spec/operations/marker_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/marker_operation.ex
@@ -110,14 +110,16 @@ defmodule Pleroma.Web.ApiSpec.MarkerOperation do
properties: %{
notifications: %Schema{
type: :object,
+ nullable: true,
properties: %{
- last_read_id: %Schema{type: :string}
+ last_read_id: %Schema{nullable: true, type: :string}
}
},
home: %Schema{
type: :object,
+ nullable: true,
properties: %{
- last_read_id: %Schema{type: :string}
+ last_read_id: %Schema{nullable: true, type: :string}
}
}
},
diff --git a/lib/pleroma/web/api_spec/operations/media_operation.ex b/lib/pleroma/web/api_spec/operations/media_operation.ex
new file mode 100644
index 000000000..d9c3c42db
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/media_operation.ex
@@ -0,0 +1,132 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.MediaOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Helpers
+ alias Pleroma.Web.ApiSpec.Schemas.ApiError
+ alias Pleroma.Web.ApiSpec.Schemas.Attachment
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def create_operation do
+ %Operation{
+ tags: ["media"],
+ summary: "Upload media as attachment",
+ description: "Creates an attachment to be used with a new status.",
+ operationId: "MediaController.create",
+ security: [%{"oAuth" => ["write:media"]}],
+ requestBody: Helpers.request_body("Parameters", create_request()),
+ responses: %{
+ 200 => Operation.response("Media", "application/json", Attachment),
+ 401 => Operation.response("Media", "application/json", ApiError),
+ 422 => Operation.response("Media", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp create_request do
+ %Schema{
+ title: "MediaCreateRequest",
+ description: "POST body for creating an attachment",
+ type: :object,
+ required: [:file],
+ properties: %{
+ file: %Schema{
+ type: :string,
+ format: :binary,
+ description: "The file to be attached, using multipart form data."
+ },
+ description: %Schema{
+ type: :string,
+ description: "A plain-text description of the media, for accessibility purposes."
+ },
+ focus: %Schema{
+ type: :string,
+ description: "Two floating points (x,y), comma-delimited, ranging from -1.0 to 1.0."
+ }
+ }
+ }
+ end
+
+ def update_operation do
+ %Operation{
+ tags: ["media"],
+ summary: "Upload media as attachment",
+ description: "Creates an attachment to be used with a new status.",
+ operationId: "MediaController.update",
+ security: [%{"oAuth" => ["write:media"]}],
+ parameters: [id_param()],
+ requestBody: Helpers.request_body("Parameters", update_request()),
+ responses: %{
+ 200 => Operation.response("Media", "application/json", Attachment),
+ 400 => Operation.response("Media", "application/json", ApiError),
+ 401 => Operation.response("Media", "application/json", ApiError),
+ 422 => Operation.response("Media", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp update_request do
+ %Schema{
+ title: "MediaUpdateRequest",
+ description: "POST body for updating an attachment",
+ type: :object,
+ properties: %{
+ file: %Schema{
+ type: :string,
+ format: :binary,
+ description: "The file to be attached, using multipart form data."
+ },
+ description: %Schema{
+ type: :string,
+ description: "A plain-text description of the media, for accessibility purposes."
+ },
+ focus: %Schema{
+ type: :string,
+ description: "Two floating points (x,y), comma-delimited, ranging from -1.0 to 1.0."
+ }
+ }
+ }
+ end
+
+ def show_operation do
+ %Operation{
+ tags: ["media"],
+ summary: "Show Uploaded media attachment",
+ operationId: "MediaController.show",
+ parameters: [id_param()],
+ security: [%{"oAuth" => ["read:media"]}],
+ responses: %{
+ 200 => Operation.response("Media", "application/json", Attachment),
+ 401 => Operation.response("Media", "application/json", ApiError),
+ 422 => Operation.response("Media", "application/json", ApiError)
+ }
+ }
+ end
+
+ def create2_operation do
+ %Operation{
+ tags: ["media"],
+ summary: "Upload media as attachment",
+ description: "Creates an attachment to be used with a new status.",
+ operationId: "MediaController.create2",
+ security: [%{"oAuth" => ["write:media"]}],
+ requestBody: Helpers.request_body("Parameters", create_request()),
+ responses: %{
+ 202 => Operation.response("Media", "application/json", Attachment),
+ 422 => Operation.response("Media", "application/json", ApiError),
+ 500 => Operation.response("Media", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp id_param do
+ Operation.parameter(:id, :path, :string, "The ID of the Attachment entity")
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/notification_operation.ex b/lib/pleroma/web/api_spec/operations/notification_operation.ex
index 64adc5319..46e72f8bf 100644
--- a/lib/pleroma/web/api_spec/operations/notification_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/notification_operation.ex
@@ -145,7 +145,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
}
end
- defp notification do
+ def notification do
%Schema{
title: "Notification",
description: "Response schema for a notification",
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex
new file mode 100644
index 000000000..90922c064
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex
@@ -0,0 +1,187 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.AccountRelationship
+ alias Pleroma.Web.ApiSpec.Schemas.ApiError
+ alias Pleroma.Web.ApiSpec.Schemas.FlakeID
+ alias Pleroma.Web.ApiSpec.StatusOperation
+
+ import Pleroma.Web.ApiSpec.Helpers
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def confirmation_resend_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Resend confirmation email. Expects `email` or `nickname`",
+ operationId: "PleromaAPI.AccountController.confirmation_resend",
+ parameters: [
+ Operation.parameter(:email, :query, :string, "Email of that needs to be verified",
+ example: "cofe@cofe.io"
+ ),
+ Operation.parameter(
+ :nickname,
+ :query,
+ :string,
+ "Nickname of user that needs to be verified",
+ example: "cofefe"
+ )
+ ],
+ responses: %{
+ 204 => no_content_response()
+ }
+ }
+ end
+
+ def update_avatar_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Set/clear user avatar image",
+ operationId: "PleromaAPI.AccountController.update_avatar",
+ requestBody:
+ request_body("Parameters", update_avatar_or_background_request(), required: true),
+ security: [%{"oAuth" => ["write:accounts"]}],
+ responses: %{
+ 200 => update_response(),
+ 403 => Operation.response("Forbidden", "application/json", ApiError)
+ }
+ }
+ end
+
+ def update_banner_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Set/clear user banner image",
+ operationId: "PleromaAPI.AccountController.update_banner",
+ requestBody: request_body("Parameters", update_banner_request(), required: true),
+ security: [%{"oAuth" => ["write:accounts"]}],
+ responses: %{
+ 200 => update_response()
+ }
+ }
+ end
+
+ def update_background_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Set/clear user background image",
+ operationId: "PleromaAPI.AccountController.update_background",
+ security: [%{"oAuth" => ["write:accounts"]}],
+ requestBody:
+ request_body("Parameters", update_avatar_or_background_request(), required: true),
+ responses: %{
+ 200 => update_response()
+ }
+ }
+ end
+
+ def favourites_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Returns favorites timeline of any user",
+ operationId: "PleromaAPI.AccountController.favourites",
+ parameters: [id_param() | pagination_params()],
+ security: [%{"oAuth" => ["read:favourites"]}],
+ responses: %{
+ 200 =>
+ Operation.response(
+ "Array of Statuses",
+ "application/json",
+ StatusOperation.array_of_statuses()
+ ),
+ 403 => Operation.response("Forbidden", "application/json", ApiError),
+ 404 => Operation.response("Not Found", "application/json", ApiError)
+ }
+ }
+ end
+
+ def subscribe_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Subscribe to receive notifications for all statuses posted by a user",
+ operationId: "PleromaAPI.AccountController.subscribe",
+ parameters: [id_param()],
+ security: [%{"oAuth" => ["follow", "write:follows"]}],
+ responses: %{
+ 200 => Operation.response("Relationship", "application/json", AccountRelationship),
+ 404 => Operation.response("Not Found", "application/json", ApiError)
+ }
+ }
+ end
+
+ def unsubscribe_operation do
+ %Operation{
+ tags: ["Accounts"],
+ summary: "Unsubscribe to stop receiving notifications from user statuses",
+ operationId: "PleromaAPI.AccountController.unsubscribe",
+ parameters: [id_param()],
+ security: [%{"oAuth" => ["follow", "write:follows"]}],
+ responses: %{
+ 200 => Operation.response("Relationship", "application/json", AccountRelationship),
+ 404 => Operation.response("Not Found", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp id_param do
+ Operation.parameter(:id, :path, FlakeID, "Account ID",
+ example: "9umDrYheeY451cQnEe",
+ required: true
+ )
+ end
+
+ defp update_avatar_or_background_request do
+ %Schema{
+ title: "PleromaAccountUpdateAvatarOrBackgroundRequest",
+ type: :object,
+ properties: %{
+ img: %Schema{
+ nullable: true,
+ type: :string,
+ format: :binary,
+ description: "Image encoded using `multipart/form-data` or an empty string to clear"
+ }
+ }
+ }
+ end
+
+ defp update_banner_request do
+ %Schema{
+ title: "PleromaAccountUpdateBannerRequest",
+ type: :object,
+ properties: %{
+ banner: %Schema{
+ type: :string,
+ nullable: true,
+ format: :binary,
+ description: "Image encoded using `multipart/form-data` or an empty string to clear"
+ }
+ }
+ }
+ end
+
+ defp update_response do
+ Operation.response("PleromaAccountUpdateResponse", "application/json", %Schema{
+ type: :object,
+ properties: %{
+ url: %Schema{
+ type: :string,
+ format: :uri,
+ nullable: true,
+ description: "Image URL"
+ }
+ },
+ example: %{
+ "url" =>
+ "https://cofe.party/media/9d0add56-bcb6-4c0f-8225-cbbd0b6dd773/13eadb6972c9ccd3f4ffa3b8196f0e0d38b4d2f27594457c52e52946c054cd9a.gif"
+ }
+ })
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex
new file mode 100644
index 000000000..e885eab20
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex
@@ -0,0 +1,106 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaConversationOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.Conversation
+ alias Pleroma.Web.ApiSpec.Schemas.FlakeID
+ alias Pleroma.Web.ApiSpec.StatusOperation
+
+ import Pleroma.Web.ApiSpec.Helpers
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def show_operation do
+ %Operation{
+ tags: ["Conversations"],
+ summary: "The conversation with the given ID",
+ parameters: [
+ Operation.parameter(:id, :path, :string, "Conversation ID",
+ example: "123",
+ required: true
+ )
+ ],
+ security: [%{"oAuth" => ["read:statuses"]}],
+ operationId: "PleromaAPI.ConversationController.show",
+ responses: %{
+ 200 => Operation.response("Conversation", "application/json", Conversation)
+ }
+ }
+ end
+
+ def statuses_operation do
+ %Operation{
+ tags: ["Conversations"],
+ summary: "Timeline for a given conversation",
+ parameters: [
+ Operation.parameter(:id, :path, :string, "Conversation ID",
+ example: "123",
+ required: true
+ )
+ | pagination_params()
+ ],
+ security: [%{"oAuth" => ["read:statuses"]}],
+ operationId: "PleromaAPI.ConversationController.statuses",
+ responses: %{
+ 200 =>
+ Operation.response(
+ "Array of Statuses",
+ "application/json",
+ StatusOperation.array_of_statuses()
+ )
+ }
+ }
+ end
+
+ def update_operation do
+ %Operation{
+ tags: ["Conversations"],
+ summary: "Update a conversation. Used to change the set of recipients.",
+ parameters: [
+ Operation.parameter(:id, :path, :string, "Conversation ID",
+ example: "123",
+ required: true
+ ),
+ Operation.parameter(
+ :recipients,
+ :query,
+ %Schema{type: :array, items: FlakeID},
+ "A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though.",
+ required: true
+ )
+ ],
+ security: [%{"oAuth" => ["write:conversations"]}],
+ operationId: "PleromaAPI.ConversationController.update",
+ responses: %{
+ 200 => Operation.response("Conversation", "application/json", Conversation)
+ }
+ }
+ end
+
+ def mark_as_read_operation do
+ %Operation{
+ tags: ["Conversations"],
+ summary: "Marks all user's conversations as read",
+ security: [%{"oAuth" => ["write:conversations"]}],
+ operationId: "PleromaAPI.ConversationController.mark_as_read",
+ responses: %{
+ 200 =>
+ Operation.response(
+ "Array of Conversations that were marked as read",
+ "application/json",
+ %Schema{
+ type: :array,
+ items: Conversation,
+ example: [Conversation.schema().example]
+ }
+ )
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
new file mode 100644
index 000000000..567688ff5
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
@@ -0,0 +1,390 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.ApiError
+
+ import Pleroma.Web.ApiSpec.Helpers
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def remote_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Make request to another instance for emoji packs list",
+ security: [%{"oAuth" => ["write"]}],
+ parameters: [url_param()],
+ operationId: "PleromaAPI.EmojiPackController.remote",
+ responses: %{
+ 200 => emoji_packs_response(),
+ 500 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ def index_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Lists local custom emoji packs",
+ operationId: "PleromaAPI.EmojiPackController.index",
+ responses: %{
+ 200 => emoji_packs_response()
+ }
+ }
+ end
+
+ def show_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Show emoji pack",
+ operationId: "PleromaAPI.EmojiPackController.show",
+ parameters: [name_param()],
+ responses: %{
+ 200 => Operation.response("Emoji Pack", "application/json", emoji_pack()),
+ 400 => Operation.response("Bad Request", "application/json", ApiError),
+ 404 => Operation.response("Not Found", "application/json", ApiError)
+ }
+ }
+ end
+
+ def archive_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Requests a local pack archive from the instance",
+ operationId: "PleromaAPI.EmojiPackController.archive",
+ parameters: [name_param()],
+ responses: %{
+ 200 =>
+ Operation.response("Archive file", "application/octet-stream", %Schema{
+ type: :string,
+ format: :binary
+ }),
+ 403 => Operation.response("Forbidden", "application/json", ApiError),
+ 404 => Operation.response("Not Found", "application/json", ApiError)
+ }
+ }
+ end
+
+ def download_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Download pack from another instance",
+ operationId: "PleromaAPI.EmojiPackController.download",
+ security: [%{"oAuth" => ["write"]}],
+ requestBody: request_body("Parameters", download_request(), required: true),
+ responses: %{
+ 200 => ok_response(),
+ 500 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp download_request do
+ %Schema{
+ type: :object,
+ required: [:url, :name],
+ properties: %{
+ url: %Schema{
+ type: :string,
+ format: :uri,
+ description: "URL of the instance to download from"
+ },
+ name: %Schema{type: :string, format: :uri, description: "Pack Name"},
+ as: %Schema{type: :string, format: :uri, description: "Save as"}
+ }
+ }
+ end
+
+ def create_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Create an empty pack",
+ operationId: "PleromaAPI.EmojiPackController.create",
+ security: [%{"oAuth" => ["write"]}],
+ parameters: [name_param()],
+ responses: %{
+ 200 => ok_response(),
+ 400 => Operation.response("Not Found", "application/json", ApiError),
+ 409 => Operation.response("Conflict", "application/json", ApiError),
+ 500 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ def delete_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Delete a custom emoji pack",
+ operationId: "PleromaAPI.EmojiPackController.delete",
+ security: [%{"oAuth" => ["write"]}],
+ parameters: [name_param()],
+ responses: %{
+ 200 => ok_response(),
+ 400 => Operation.response("Bad Request", "application/json", ApiError),
+ 404 => Operation.response("Not Found", "application/json", ApiError)
+ }
+ }
+ end
+
+ def update_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Updates (replaces) pack metadata",
+ operationId: "PleromaAPI.EmojiPackController.update",
+ security: [%{"oAuth" => ["write"]}],
+ requestBody: request_body("Parameters", update_request(), required: true),
+ parameters: [name_param()],
+ responses: %{
+ 200 => Operation.response("Metadata", "application/json", metadata()),
+ 400 => Operation.response("Bad Request", "application/json", ApiError)
+ }
+ }
+ end
+
+ def add_file_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Add new file to the pack",
+ operationId: "PleromaAPI.EmojiPackController.add_file",
+ security: [%{"oAuth" => ["write"]}],
+ requestBody: request_body("Parameters", add_file_request(), required: true),
+ parameters: [name_param()],
+ responses: %{
+ 200 => Operation.response("Files Object", "application/json", files_object()),
+ 400 => Operation.response("Bad Request", "application/json", ApiError),
+ 409 => Operation.response("Conflict", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp add_file_request do
+ %Schema{
+ type: :object,
+ required: [:file],
+ properties: %{
+ file: %Schema{
+ description:
+ "File needs to be uploaded with the multipart request or link to remote file",
+ anyOf: [
+ %Schema{type: :string, format: :binary},
+ %Schema{type: :string, format: :uri}
+ ]
+ },
+ shortcode: %Schema{
+ type: :string,
+ description:
+ "Shortcode for new emoji, must be unique for all emoji. If not sended, shortcode will be taken from original filename."
+ },
+ filename: %Schema{
+ type: :string,
+ description:
+ "New emoji file name. If not specified will be taken from original filename."
+ }
+ }
+ }
+ end
+
+ def update_file_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Add new file to the pack",
+ operationId: "PleromaAPI.EmojiPackController.update_file",
+ security: [%{"oAuth" => ["write"]}],
+ requestBody: request_body("Parameters", update_file_request(), required: true),
+ parameters: [name_param()],
+ responses: %{
+ 200 => Operation.response("Files Object", "application/json", files_object()),
+ 400 => Operation.response("Bad Request", "application/json", ApiError),
+ 409 => Operation.response("Conflict", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp update_file_request do
+ %Schema{
+ type: :object,
+ required: [:shortcode, :new_shortcode, :new_filename],
+ properties: %{
+ shortcode: %Schema{
+ type: :string,
+ description: "Emoji file shortcode"
+ },
+ new_shortcode: %Schema{
+ type: :string,
+ description: "New emoji file shortcode"
+ },
+ new_filename: %Schema{
+ type: :string,
+ description: "New filename for emoji file"
+ },
+ force: %Schema{
+ type: :boolean,
+ description: "With true value to overwrite existing emoji with new shortcode",
+ default: false
+ }
+ }
+ }
+ end
+
+ def delete_file_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Delete emoji file from pack",
+ operationId: "PleromaAPI.EmojiPackController.delete_file",
+ security: [%{"oAuth" => ["write"]}],
+ parameters: [
+ name_param(),
+ Operation.parameter(:shortcode, :query, :string, "File shortcode",
+ example: "cofe",
+ required: true
+ )
+ ],
+ responses: %{
+ 200 => Operation.response("Files Object", "application/json", files_object()),
+ 400 => Operation.response("Bad Request", "application/json", ApiError)
+ }
+ }
+ end
+
+ def import_from_filesystem_operation do
+ %Operation{
+ tags: ["Emoji Packs"],
+ summary: "Imports packs from filesystem",
+ operationId: "PleromaAPI.EmojiPackController.import",
+ security: [%{"oAuth" => ["write"]}],
+ responses: %{
+ 200 =>
+ Operation.response("Array of imported pack names", "application/json", %Schema{
+ type: :array,
+ items: %Schema{type: :string}
+ })
+ }
+ }
+ end
+
+ defp name_param do
+ Operation.parameter(:name, :path, :string, "Pack Name", example: "cofe", required: true)
+ end
+
+ defp url_param do
+ Operation.parameter(
+ :url,
+ :query,
+ %Schema{type: :string, format: :uri},
+ "URL of the instance",
+ required: true
+ )
+ end
+
+ defp ok_response do
+ Operation.response("Ok", "application/json", %Schema{type: :string, example: "ok"})
+ end
+
+ defp emoji_packs_response do
+ Operation.response(
+ "Object with pack names as keys and pack contents as values",
+ "application/json",
+ %Schema{
+ type: :object,
+ additionalProperties: emoji_pack(),
+ example: %{
+ "emojos" => emoji_pack().example
+ }
+ }
+ )
+ end
+
+ defp emoji_pack do
+ %Schema{
+ title: "EmojiPack",
+ type: :object,
+ properties: %{
+ files: files_object(),
+ pack: %Schema{
+ type: :object,
+ properties: %{
+ license: %Schema{type: :string},
+ homepage: %Schema{type: :string, format: :uri},
+ description: %Schema{type: :string},
+ "can-download": %Schema{type: :boolean},
+ "share-files": %Schema{type: :boolean},
+ "download-sha256": %Schema{type: :string}
+ }
+ }
+ },
+ example: %{
+ "files" => %{"emacs" => "emacs.png", "guix" => "guix.png"},
+ "pack" => %{
+ "license" => "Test license",
+ "homepage" => "https://pleroma.social",
+ "description" => "Test description",
+ "can-download" => true,
+ "share-files" => true,
+ "download-sha256" => "57482F30674FD3DE821FF48C81C00DA4D4AF1F300209253684ABA7075E5FC238"
+ }
+ }
+ }
+ end
+
+ defp files_object do
+ %Schema{
+ type: :object,
+ additionalProperties: %Schema{type: :string},
+ description: "Object with emoji names as keys and filenames as values"
+ }
+ end
+
+ defp update_request do
+ %Schema{
+ type: :object,
+ properties: %{
+ metadata: %Schema{
+ type: :object,
+ description: "Metadata to replace the old one",
+ properties: %{
+ license: %Schema{type: :string},
+ homepage: %Schema{type: :string, format: :uri},
+ description: %Schema{type: :string},
+ "fallback-src": %Schema{
+ type: :string,
+ format: :uri,
+ description: "Fallback url to download pack from"
+ },
+ "fallback-src-sha256": %Schema{
+ type: :string,
+ description: "SHA256 encoded for fallback pack archive"
+ },
+ "share-files": %Schema{type: :boolean, description: "Is pack allowed for sharing?"}
+ }
+ }
+ }
+ }
+ end
+
+ defp metadata do
+ %Schema{
+ type: :object,
+ properties: %{
+ license: %Schema{type: :string},
+ homepage: %Schema{type: :string, format: :uri},
+ description: %Schema{type: :string},
+ "fallback-src": %Schema{
+ type: :string,
+ format: :uri,
+ description: "Fallback url to download pack from"
+ },
+ "fallback-src-sha256": %Schema{
+ type: :string,
+ description: "SHA256 encoded for fallback pack archive"
+ },
+ "share-files": %Schema{type: :boolean, description: "Is pack allowed for sharing?"}
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex
new file mode 100644
index 000000000..8c5f37ea6
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex
@@ -0,0 +1,79 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaMascotOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.ApiError
+
+ import Pleroma.Web.ApiSpec.Helpers
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def show_operation do
+ %Operation{
+ tags: ["Mascot"],
+ summary: "Gets user mascot image",
+ security: [%{"oAuth" => ["read:accounts"]}],
+ operationId: "PleromaAPI.MascotController.show",
+ responses: %{
+ 200 => Operation.response("Mascot", "application/json", mascot())
+ }
+ }
+ end
+
+ def update_operation do
+ %Operation{
+ tags: ["Mascot"],
+ summary: "Set/clear user avatar image",
+ description:
+ "Behaves exactly the same as `POST /api/v1/upload`. Can only accept images - any attempt to upload non-image files will be met with `HTTP 415 Unsupported Media Type`.",
+ operationId: "PleromaAPI.MascotController.update",
+ requestBody:
+ request_body(
+ "Parameters",
+ %Schema{
+ type: :object,
+ properties: %{
+ file: %Schema{type: :string, format: :binary}
+ }
+ },
+ required: true
+ ),
+ security: [%{"oAuth" => ["write:accounts"]}],
+ responses: %{
+ 200 => Operation.response("Mascot", "application/json", mascot()),
+ 415 => Operation.response("Unsupported Media Type", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp mascot do
+ %Schema{
+ type: :object,
+ properties: %{
+ id: %Schema{type: :string},
+ url: %Schema{type: :string, format: :uri},
+ type: %Schema{type: :string},
+ pleroma: %Schema{
+ type: :object,
+ properties: %{
+ mime_type: %Schema{type: :string}
+ }
+ }
+ },
+ example: %{
+ "id" => "abcdefg",
+ "url" => "https://pleroma.example.org/media/abcdefg.png",
+ "type" => "image",
+ "pleroma" => %{
+ "mime_type" => "image/png"
+ }
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex
new file mode 100644
index 000000000..636c39a15
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex
@@ -0,0 +1,42 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaNotificationOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.NotificationOperation
+ alias Pleroma.Web.ApiSpec.Schemas.ApiError
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def mark_as_read_operation do
+ %Operation{
+ tags: ["Notifications"],
+ summary: "Mark notifications as read. Query parameters are mutually exclusive.",
+ parameters: [
+ Operation.parameter(:id, :query, :string, "A single notification ID to read"),
+ Operation.parameter(:max_id, :query, :string, "Read all notifications up to this id")
+ ],
+ security: [%{"oAuth" => ["write:notifications"]}],
+ operationId: "PleromaAPI.NotificationController.mark_as_read",
+ responses: %{
+ 200 =>
+ Operation.response(
+ "A Notification or array of Motifications",
+ "application/json",
+ %Schema{
+ anyOf: [
+ %Schema{type: :array, items: NotificationOperation.notification()},
+ NotificationOperation.notification()
+ ]
+ }
+ ),
+ 400 => Operation.response("Bad Request", "application/json", ApiError)
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex
new file mode 100644
index 000000000..85a22aa0b
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex
@@ -0,0 +1,102 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Reference
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.Account
+ alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
+
+ import Pleroma.Web.ApiSpec.Helpers
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def create_operation do
+ %Operation{
+ tags: ["Scrobbles"],
+ summary: "Creates a new Listen activity for an account",
+ security: [%{"oAuth" => ["write"]}],
+ operationId: "PleromaAPI.ScrobbleController.create",
+ requestBody: request_body("Parameters", create_request(), requried: true),
+ responses: %{
+ 200 => Operation.response("Scrobble", "application/json", scrobble())
+ }
+ }
+ end
+
+ def index_operation do
+ %Operation{
+ tags: ["Scrobbles"],
+ summary: "Requests a list of current and recent Listen activities for an account",
+ operationId: "PleromaAPI.ScrobbleController.index",
+ parameters: [
+ %Reference{"$ref": "#/components/parameters/accountIdOrNickname"} | pagination_params()
+ ],
+ security: [%{"oAuth" => ["read"]}],
+ responses: %{
+ 200 =>
+ Operation.response("Array of Scrobble", "application/json", %Schema{
+ type: :array,
+ items: scrobble()
+ })
+ }
+ }
+ end
+
+ defp create_request do
+ %Schema{
+ type: :object,
+ required: [:title],
+ properties: %{
+ 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"},
+ length: %Schema{type: :integer, description: "The length of the media playing"},
+ visibility: %Schema{
+ allOf: [VisibilityScope],
+ default: "public",
+ description: "Scrobble visibility"
+ }
+ },
+ example: %{
+ "title" => "Some Title",
+ "artist" => "Some Artist",
+ "album" => "Some Album",
+ "length" => 180_000
+ }
+ }
+ end
+
+ defp scrobble do
+ %Schema{
+ type: :object,
+ properties: %{
+ id: %Schema{type: :string},
+ account: Account,
+ 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"},
+ length: %Schema{
+ type: :integer,
+ description: "The length of the media playing",
+ nullable: true
+ },
+ created_at: %Schema{type: :string, format: :"date-time"}
+ },
+ example: %{
+ "id" => "1234",
+ "account" => Account.schema().example,
+ "title" => "Some Title",
+ "artist" => "Some Artist",
+ "album" => "Some Album",
+ "length" => 180_000,
+ "created_at" => "2019-09-28T12:40:45.000Z"
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/report_operation.ex b/lib/pleroma/web/api_spec/operations/report_operation.ex
index da4d50703..b9b4c4f79 100644
--- a/lib/pleroma/web/api_spec/operations/report_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/report_operation.ex
@@ -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.BooleanLike
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
@@ -37,15 +38,18 @@ defmodule Pleroma.Web.ApiSpec.ReportOperation do
account_id: %Schema{type: :string, description: "ID of the account to report"},
status_ids: %Schema{
type: :array,
+ nullable: true,
items: %Schema{type: :string},
description: "Array of Statuses to attach to the report, for context"
},
comment: %Schema{
type: :string,
+ nullable: true,
description: "Reason for the report"
},
forward: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
default: false,
description:
"If the account is remote, should the report be forwarded to the remote admin?"
diff --git a/lib/pleroma/web/api_spec/operations/search_operation.ex b/lib/pleroma/web/api_spec/operations/search_operation.ex
index 6ea00a9a8..169c36d87 100644
--- a/lib/pleroma/web/api_spec/operations/search_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/search_operation.ex
@@ -19,6 +19,7 @@ defmodule Pleroma.Web.ApiSpec.SearchOperation do
apply(__MODULE__, operation, [])
end
+ # Note: `with_relationships` param is not supported (PleromaFE uses this op for autocomplete)
def account_search_operation do
%Operation{
tags: ["Search"],
@@ -96,8 +97,8 @@ defmodule Pleroma.Web.ApiSpec.SearchOperation do
:query,
%Schema{type: :integer},
"Offset"
- )
- | pagination_params()
+ ),
+ with_relationships_param() | pagination_params()
],
responses: %{
200 => Operation.response("Results", "application/json", results())
@@ -138,8 +139,8 @@ defmodule Pleroma.Web.ApiSpec.SearchOperation do
:query,
%Schema{allOf: [BooleanLike], default: false},
"Only include accounts that the user is following"
- )
- | pagination_params()
+ ),
+ with_relationships_param() | pagination_params()
],
responses: %{
200 => Operation.response("Results", "application/json", results2())
diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex
index a6bb87560..0682ca6e5 100644
--- a/lib/pleroma/web/api_spec/operations/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/status_operation.ex
@@ -349,10 +349,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
summary: "Bookmarked statuses",
description: "Statuses the user has bookmarked",
operationId: "StatusController.bookmarks",
- parameters: [
- Operation.parameter(:with_relationships, :query, BooleanLike, "Include relationships")
- | pagination_params()
- ],
+ parameters: pagination_params(),
security: [%{"oAuth" => ["read:bookmarks"]}],
responses: %{
200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
@@ -360,7 +357,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
}
end
- defp array_of_statuses do
+ def array_of_statuses do
%Schema{type: :array, items: Status, example: [Status.schema().example]}
end
@@ -371,15 +368,18 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
properties: %{
status: %Schema{
type: :string,
+ nullable: true,
description:
"Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided."
},
media_ids: %Schema{
+ nullable: true,
type: :array,
items: %Schema{type: :string},
description: "Array of Attachment ids to be attached as media."
},
poll: %Schema{
+ nullable: true,
type: :object,
required: [:options],
properties: %{
@@ -390,26 +390,35 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
},
expires_in: %Schema{
type: :integer,
+ nullable: true,
description:
"Duration the poll should be open, in seconds. Must be provided with `poll[options]`"
},
- multiple: %Schema{type: :boolean, description: "Allow multiple choices?"},
+ multiple: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Allow multiple choices?"
+ },
hide_totals: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Hide vote counts until the poll ends?"
}
}
},
in_reply_to_id: %Schema{
+ nullable: true,
allOf: [FlakeID],
description: "ID of the status being replied to, if status is a reply"
},
sensitive: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Mark status and attached media as sensitive?"
},
spoiler_text: %Schema{
type: :string,
+ nullable: true,
description:
"Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field."
},
@@ -420,25 +429,33 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
description:
"ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future."
},
- language: %Schema{type: :string, description: "ISO 639 language code for this status."},
+ language: %Schema{
+ type: :string,
+ nullable: true,
+ description: "ISO 639 language code for this status."
+ },
# Pleroma-specific properties:
preview: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description:
"If set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example"
},
content_type: %Schema{
type: :string,
+ nullable: true,
description:
"The MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint."
},
to: %Schema{
type: :array,
+ nullable: true,
items: %Schema{type: :string},
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"}
@@ -447,11 +464,13 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
"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,
description:
"The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour."
},
in_reply_to_conversation_id: %Schema{
+ nullable: true,
type: :string,
description:
"Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`."
diff --git a/lib/pleroma/web/api_spec/operations/subscription_operation.ex b/lib/pleroma/web/api_spec/operations/subscription_operation.ex
index 663b8fa11..c575a87e6 100644
--- a/lib/pleroma/web/api_spec/operations/subscription_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/subscription_operation.ex
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.SubscriptionOperation do
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.ApiError
+ alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
alias Pleroma.Web.ApiSpec.Schemas.PushSubscription
def open_api_operation(action) do
@@ -109,19 +110,38 @@ defmodule Pleroma.Web.ApiSpec.SubscriptionOperation do
required: [:endpoint, :keys]
},
data: %Schema{
+ nullable: true,
type: :object,
properties: %{
alerts: %Schema{
+ nullable: true,
type: :object,
properties: %{
- follow: %Schema{type: :boolean, description: "Receive follow notifications?"},
+ follow: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Receive follow notifications?"
+ },
favourite: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Receive favourite notifications?"
},
- reblog: %Schema{type: :boolean, description: "Receive reblog notifications?"},
- mention: %Schema{type: :boolean, description: "Receive mention notifications?"},
- poll: %Schema{type: :boolean, description: "Receive poll notifications?"}
+ reblog: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Receive reblog notifications?"
+ },
+ mention: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Receive mention notifications?"
+ },
+ poll: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Receive poll notifications?"
+ }
}
}
}
@@ -154,19 +174,38 @@ defmodule Pleroma.Web.ApiSpec.SubscriptionOperation do
type: :object,
properties: %{
data: %Schema{
+ nullable: true,
type: :object,
properties: %{
alerts: %Schema{
+ nullable: true,
type: :object,
properties: %{
- follow: %Schema{type: :boolean, description: "Receive follow notifications?"},
+ follow: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Receive follow notifications?"
+ },
favourite: %Schema{
- type: :boolean,
+ allOf: [BooleanLike],
+ nullable: true,
description: "Receive favourite notifications?"
},
- reblog: %Schema{type: :boolean, description: "Receive reblog notifications?"},
- mention: %Schema{type: :boolean, description: "Receive mention notifications?"},
- poll: %Schema{type: :boolean, description: "Receive poll notifications?"}
+ reblog: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Receive reblog notifications?"
+ },
+ mention: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Receive mention notifications?"
+ },
+ poll: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Receive poll notifications?"
+ }
}
}
}
diff --git a/lib/pleroma/web/api_spec/operations/timeline_operation.ex b/lib/pleroma/web/api_spec/operations/timeline_operation.ex
index 1b89035d4..8e19bace7 100644
--- a/lib/pleroma/web/api_spec/operations/timeline_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/timeline_operation.ex
@@ -27,8 +27,7 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
local_param(),
with_muted_param(),
exclude_visibilities_param(),
- reply_visibility_param(),
- with_relationships_param() | pagination_params()
+ reply_visibility_param() | pagination_params()
],
operationId: "TimelineController.home",
responses: %{
@@ -44,7 +43,7 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
description:
"View statuses with a “direct” privacy, from your account or in your notifications",
deprecated: true,
- parameters: pagination_params(),
+ parameters: [with_muted_param() | pagination_params()],
security: [%{"oAuth" => ["read:statuses"]}],
operationId: "TimelineController.direct",
responses: %{
@@ -63,8 +62,7 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
only_media_param(),
with_muted_param(),
exclude_visibilities_param(),
- reply_visibility_param(),
- with_relationships_param() | pagination_params()
+ reply_visibility_param() | pagination_params()
],
operationId: "TimelineController.public",
responses: %{
@@ -109,8 +107,7 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
local_param(),
only_media_param(),
with_muted_param(),
- exclude_visibilities_param(),
- with_relationships_param() | pagination_params()
+ exclude_visibilities_param() | pagination_params()
],
operationId: "TimelineController.hashtag",
responses: %{
@@ -134,8 +131,7 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
required: true
),
with_muted_param(),
- exclude_visibilities_param(),
- with_relationships_param() | pagination_params()
+ exclude_visibilities_param() | pagination_params()
],
operationId: "TimelineController.list",
responses: %{
@@ -153,10 +149,6 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
}
end
- defp with_relationships_param do
- Operation.parameter(:with_relationships, :query, BooleanLike, "Include relationships")
- end
-
defp local_param do
Operation.parameter(
:local,
diff --git a/lib/pleroma/web/api_spec/schemas/attachment.ex b/lib/pleroma/web/api_spec/schemas/attachment.ex
index c146c416e..c6edf6d36 100644
--- a/lib/pleroma/web/api_spec/schemas/attachment.ex
+++ b/lib/pleroma/web/api_spec/schemas/attachment.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Attachment do
type: :object,
requried: [:id, :url, :preview_url],
properties: %{
- id: %Schema{type: :string},
+ id: %Schema{type: :string, description: "The ID of the attachment in the database."},
url: %Schema{
type: :string,
format: :uri,
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index a8f554aa3..200ca03dc 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -16,7 +16,8 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
def get_user(%Plug.Conn{} = conn) do
with {:ok, {name, password}} <- fetch_credentials(conn),
{_, %User{} = user} <- {:user, fetch_user(name)},
- {_, true} <- {:checkpw, AuthenticationPlug.checkpw(password, user.password_hash)} do
+ {_, true} <- {:checkpw, AuthenticationPlug.checkpw(password, user.password_hash)},
+ {:ok, user} <- AuthenticationPlug.maybe_update_password(user, password) do
{:ok, user}
else
{:error, _reason} = error -> error
diff --git a/lib/pleroma/web/auth/totp_authenticator.ex b/lib/pleroma/web/auth/totp_authenticator.ex
index 04e489c83..1794e407c 100644
--- a/lib/pleroma/web/auth/totp_authenticator.ex
+++ b/lib/pleroma/web/auth/totp_authenticator.ex
@@ -1,10 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.TOTPAuthenticator do
alias Pleroma.MFA
alias Pleroma.MFA.TOTP
+ alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.User
@doc "Verify code or check backup code."
@@ -30,7 +31,7 @@ defmodule Pleroma.Web.Auth.TOTPAuthenticator do
code
)
when is_list(codes) and is_binary(code) do
- hash_code = Enum.find(codes, fn hash -> Pbkdf2.verify_pass(code, hash) end)
+ hash_code = Enum.find(codes, fn hash -> AuthenticationPlug.checkpw(code, hash) end)
if hash_code do
MFA.invalidate_backup_code(user, hash_code)
diff --git a/lib/pleroma/web/chat_channel.ex b/lib/pleroma/web/chat_channel.ex
index 38ec774f7..bce27897f 100644
--- a/lib/pleroma/web/chat_channel.ex
+++ b/lib/pleroma/web/chat_channel.ex
@@ -23,6 +23,7 @@ defmodule Pleroma.Web.ChatChannel do
if String.length(text) in 1..Pleroma.Config.get([:instance, :chat_limit]) do
author = User.get_cached_by_nickname(user_name)
author = Pleroma.Web.MastodonAPI.AccountView.render("show.json", user: author)
+
message = ChatChannelState.add_message(%{text: text, author: author})
broadcast!(socket, "new_msg", message)
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 601caeb46..447dbe4e6 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -25,10 +25,21 @@ defmodule Pleroma.Web.CommonAPI do
require Logger
def unblock(blocker, blocked) do
- with %Activity{} = block <- Utils.fetch_latest_block(blocker, blocked),
+ with {_, %Activity{} = block} <- {:fetch_block, Utils.fetch_latest_block(blocker, blocked)},
{:ok, unblock_data, _} <- Builder.undo(blocker, block),
{:ok, unblock, _} <- Pipeline.common_pipeline(unblock_data, local: true) do
{:ok, unblock}
+ else
+ {:fetch_block, nil} ->
+ if User.blocks?(blocker, blocked) do
+ User.unblock(blocker, blocked)
+ {:ok, :no_activity}
+ else
+ {:error, :not_blocking}
+ end
+
+ e ->
+ e
end
end
@@ -336,11 +347,14 @@ defmodule Pleroma.Web.CommonAPI do
|> check_expiry_date()
end
- def listen(user, %{"title" => _} = data) do
- with visibility <- data["visibility"] || "public",
- {to, cc} <- get_to_and_cc(user, [], nil, visibility, nil),
+ def listen(user, data) do
+ visibility = Map.get(data, :visibility, "public")
+
+ with {to, cc} <- get_to_and_cc(user, [], nil, visibility, nil),
listen_data <-
- Map.take(data, ["album", "artist", "title", "length"])
+ data
+ |> Map.take([:album, :artist, :title, :length])
+ |> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("type", "Audio")
|> Map.put("to", to)
|> Map.put("cc", cc)
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
index eb97ae975..5a1316a5f 100644
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -5,8 +5,6 @@
defmodule Pleroma.Web.ControllerHelper do
use Pleroma.Web, :controller
- alias Pleroma.Config
-
# As in Mastodon API, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
@falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
@@ -106,13 +104,16 @@ defmodule Pleroma.Web.ControllerHelper do
def put_if_exist(map, key, value), do: Map.put(map, key, value)
- @doc "Whether to skip rendering `[:account][:pleroma][:relationship]`for statuses/notifications"
- def skip_relationships?(params) do
- if Config.get([:extensions, :output_relationships_in_statuses_by_default]) do
- false
- else
- # BREAKING: older PleromaFE versions do not send this param but _do_ expect relationships.
- not truthy_param?(params["with_relationships"])
- end
+ @doc """
+ Returns true if request specifies to include embedded relationships in account objects.
+ May only be used in selected account-related endpoints; has no effect for status- or
+ notification-related endpoints.
+ """
+ # Intended for PleromaFE: https://git.pleroma.social/pleroma/pleroma-fe/-/issues/838
+ def embed_relationships?(params) do
+ # To do once OpenAPI transition mess is over: just `truthy_param?(params[:with_relationships])`
+ params
+ |> Map.get(:with_relationships, params["with_relationships"])
+ |> truthy_param?()
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index b9ed2d7b2..75512442d 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -10,8 +10,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
add_link_headers: 2,
truthy_param?: 1,
assign_account_by_id: 2,
- json_response: 3,
- skip_relationships?: 1
+ embed_relationships?: 1,
+ json_response: 3
]
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
@@ -177,6 +177,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
)
|> add_if_present(params, :pleroma_settings_store, :pleroma_settings_store)
|> add_if_present(params, :default_scope, :default_scope)
+ |> add_if_present(params["source"], "privacy", :default_scope)
|> add_if_present(params, :actor_type, :actor_type)
changeset = User.update_changeset(user, user_params)
@@ -189,7 +190,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
defp add_if_present(map, params, params_field, map_field, value_function \\ &{:ok, &1}) do
- with true <- Map.has_key?(params, params_field),
+ with true <- is_map(params),
+ true <- Map.has_key?(params, params_field),
{:ok, new_value} <- value_function.(Map.get(params, params_field)) do
Map.put(map, map_field, new_value)
else
@@ -247,8 +249,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|> render("index.json",
activities: activities,
for: reading_user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
else
_e -> render_error(conn, :not_found, "Can't find user")
@@ -271,7 +272,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
conn
|> add_link_headers(followers)
- |> render("index.json", for: for_user, users: followers, as: :user)
+ # https://git.pleroma.social/pleroma/pleroma-fe/-/issues/838#note_59223
+ |> render("index.json",
+ for: for_user,
+ users: followers,
+ as: :user,
+ embed_relationships: embed_relationships?(params)
+ )
end
@doc "GET /api/v1/accounts/:id/following"
@@ -290,7 +297,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
conn
|> add_link_headers(followers)
- |> render("index.json", for: for_user, users: followers, as: :user)
+ # https://git.pleroma.social/pleroma/pleroma-fe/-/issues/838#note_59223
+ |> render("index.json",
+ for: for_user,
+ users: followers,
+ as: :user,
+ embed_relationships: embed_relationships?(params)
+ )
end
@doc "GET /api/v1/accounts/:id/lists"
diff --git a/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex b/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex
index 0a257f604..8af557b61 100644
--- a/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex
@@ -20,6 +20,10 @@ defmodule Pleroma.Web.MastodonAPI.FallbackController do
render_error(conn, :not_found, "Record not found")
end
+ def call(conn, {:error, :forbidden}) do
+ render_error(conn, :forbidden, "Access denied")
+ end
+
def call(conn, {:error, error_message}) do
conn
|> put_status(:bad_request)
diff --git a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
index e36751220..513de279f 100644
--- a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
@@ -11,17 +11,21 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
alias Pleroma.Web.ActivityPub.ActivityPub
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)
- plug(OAuthScopesPlug, %{scopes: ["write:media"]})
+ plug(OAuthScopesPlug, %{scopes: ["read:media"]} when action == :show)
+ plug(OAuthScopesPlug, %{scopes: ["write:media"]} when action != :show)
+
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.MediaOperation
@doc "POST /api/v1/media"
- def create(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
+ def create(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
with {:ok, object} <-
ActivityPub.upload(
file,
actor: User.ap_id(user),
- description: Map.get(data, "description")
+ description: Map.get(data, :description)
) do
attachment_data = Map.put(object.data, "id", object.id)
@@ -29,11 +33,30 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
end
end
+ def create(_conn, _data), do: {:error, :bad_request}
+
+ @doc "POST /api/v2/media"
+ def create2(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
+ with {:ok, object} <-
+ ActivityPub.upload(
+ file,
+ actor: User.ap_id(user),
+ description: Map.get(data, :description)
+ ) do
+ attachment_data = Map.put(object.data, "id", object.id)
+
+ conn
+ |> put_status(202)
+ |> render("attachment.json", %{attachment: attachment_data})
+ end
+ end
+
+ def create2(_conn, _data), do: {:error, :bad_request}
+
@doc "PUT /api/v1/media/:id"
- def update(%{assigns: %{user: user}} = conn, %{"id" => id, "description" => description})
- when is_binary(description) do
+ def update(%{assigns: %{user: user}, body_params: %{description: description}} = conn, %{id: id}) do
with %Object{} = object <- Object.get_by_id(id),
- true <- Object.authorize_mutation(object, user),
+ :ok <- Object.authorize_access(object, user),
{:ok, %Object{data: data}} <- Object.update_data(object, %{"name" => description}) do
attachment_data = Map.put(data, "id", object.id)
@@ -41,5 +64,17 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
end
end
- def update(_conn, _data), do: {:error, :bad_request}
+ def update(conn, data), do: show(conn, data)
+
+ @doc "GET /api/v1/media/:id"
+ def show(%{assigns: %{user: user}} = conn, %{id: id}) do
+ with %Object{data: data, id: object_id} = object <- Object.get_by_id(id),
+ :ok <- Object.authorize_access(object, user) do
+ attachment_data = Map.put(data, "id", object_id)
+
+ render(conn, "attachment.json", %{attachment: attachment_data})
+ end
+ end
+
+ def show(_conn, _data), do: {:error, :bad_request}
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
index 596b85617..bcd12c73f 100644
--- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
@@ -5,7 +5,7 @@
defmodule Pleroma.Web.MastodonAPI.NotificationController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
+ import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
alias Pleroma.Notification
alias Pleroma.Plugs.OAuthScopesPlug
@@ -50,8 +50,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
|> add_link_headers(notifications)
|> render("index.json",
notifications: notifications,
- for: user,
- skip_relationships: skip_relationships?(params)
+ for: user
)
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
index 0e0d54ba4..77e2224e4 100644
--- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
@@ -5,14 +5,13 @@
defmodule Pleroma.Web.MastodonAPI.SearchController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [skip_relationships?: 1]
-
alias Pleroma.Activity
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.RateLimiter
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
+ alias Pleroma.Web.ControllerHelper
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.StatusView
@@ -34,7 +33,11 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
conn
|> put_view(AccountView)
- |> render("index.json", users: accounts, for: user, as: :user)
+ |> render("index.json",
+ users: accounts,
+ for: user,
+ as: :user
+ )
end
def search2(conn, params), do: do_search(:v2, conn, params)
@@ -71,13 +74,13 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
defp search_options(params, user) do
[
- skip_relationships: skip_relationships?(params),
resolve: params[:resolve],
following: params[:following],
limit: params[:limit],
offset: params[:offset],
type: params[:type],
author: get_author(params),
+ embed_relationships: ControllerHelper.embed_relationships?(params),
for_user: user
]
|> Enum.filter(&elem(&1, 1))
@@ -90,7 +93,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
users: accounts,
for: options[:for_user],
as: :user,
- skip_relationships: false
+ embed_relationships: options[:embed_relationships]
)
end
@@ -100,8 +103,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
StatusView.render("index.json",
activities: statuses,
for: options[:for_user],
- as: :activity,
- skip_relationships: options[:skip_relationships]
+ as: :activity
)
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
index 25e499a77..9dbf4f33c 100644
--- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
- only: [try_render: 3, add_link_headers: 2, skip_relationships?: 1]
+ only: [try_render: 3, add_link_headers: 2]
require Ecto.Query
@@ -105,7 +105,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
`ids` query param is required
"""
- def index(%{assigns: %{user: user}} = conn, %{ids: ids} = params) do
+ def index(%{assigns: %{user: user}} = conn, %{ids: ids} = _params) do
limit = 100
activities =
@@ -117,8 +117,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
render(conn, "index.json",
activities: activities,
for: user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
end
@@ -383,8 +382,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|> render("index.json",
activities: activities,
for: user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
end
@@ -406,8 +404,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|> render("index.json",
activities: activities,
for: user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
index bbd576ffd..958567510 100644
--- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
- only: [add_link_headers: 2, add_link_headers: 3, skip_relationships?: 1]
+ only: [add_link_headers: 2, add_link_headers: 3]
alias Pleroma.Pagination
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
@@ -63,8 +63,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> render("index.json",
activities: activities,
for: user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
end
@@ -88,8 +87,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> render("index.json",
activities: activities,
for: user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
end
@@ -125,8 +123,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> render("index.json",
activities: activities,
for: user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
end
end
@@ -173,8 +170,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> render("index.json",
activities: activities,
for: user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
end
@@ -203,8 +199,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
render(conn, "index.json",
activities: activities,
for: user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
else
_e -> render_error(conn, :forbidden, "Error.")
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 835dfe9f4..45fffaad2 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -15,13 +15,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
def render("index.json", %{users: users} = opts) do
reading_user = opts[:for]
- # Note: :skip_relationships option is currently intentionally not supported for accounts
relationships_opt =
cond do
Map.has_key?(opts, :relationships) ->
opts[:relationships]
- is_nil(reading_user) ->
+ is_nil(reading_user) || !opts[:embed_relationships] ->
UserRelationship.view_relationships_option(nil, [])
true ->
@@ -193,14 +192,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
end)
relationship =
- if opts[:skip_relationships] do
- %{}
- else
+ if opts[:embed_relationships] do
render("relationship.json", %{
user: opts[:for],
target: user,
relationships: opts[:relationships]
})
+ else
+ %{}
end
%{
diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex
index a329ffc28..8088306c3 100644
--- a/lib/pleroma/web/mastodon_api/views/instance_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex
@@ -33,6 +33,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
avatar_upload_limit: Keyword.get(instance, :avatar_upload_limit),
background_upload_limit: Keyword.get(instance, :background_upload_limit),
banner_upload_limit: Keyword.get(instance, :banner_upload_limit),
+ background_image: Keyword.get(instance, :background_image),
pleroma: %{
metadata: %{
features: features(),
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index 4da1ab67f..c46ddcf55 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -51,9 +51,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|> Enum.filter(& &1)
|> Kernel.++(move_activities_targets)
- UserRelationship.view_relationships_option(reading_user, actors,
- source_mutes_only: opts[:skip_relationships]
- )
+ UserRelationship.view_relationships_option(reading_user, actors, subset: :source_mutes)
end
opts =
@@ -83,15 +81,13 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
mastodon_type = Activity.mastodon_notification_type(activity)
- render_opts = %{
- relationships: opts[:relationships],
- skip_relationships: opts[:skip_relationships]
- }
+ # Note: :relationships contain user mutes (needed for :muted flag in :status)
+ status_render_opts = %{relationships: opts[:relationships]}
with %{id: _} = account <-
AccountView.render(
"show.json",
- Map.merge(render_opts, %{user: actor, for: reading_user})
+ %{user: actor, for: reading_user}
) do
response = %{
id: to_string(notification.id),
@@ -105,21 +101,20 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
case mastodon_type do
"mention" ->
- put_status(response, activity, reading_user, render_opts)
+ put_status(response, activity, reading_user, status_render_opts)
"favourite" ->
- put_status(response, parent_activity_fn.(), reading_user, render_opts)
+ put_status(response, parent_activity_fn.(), reading_user, status_render_opts)
"reblog" ->
- put_status(response, parent_activity_fn.(), reading_user, render_opts)
+ put_status(response, parent_activity_fn.(), reading_user, status_render_opts)
"move" ->
- # Note: :skip_relationships option being applied to _account_ rendering (here)
- put_target(response, activity, reading_user, render_opts)
+ put_target(response, activity, reading_user, %{})
"pleroma:emoji_reaction" ->
response
- |> put_status(parent_activity_fn.(), reading_user, render_opts)
+ |> put_status(parent_activity_fn.(), reading_user, status_render_opts)
|> put_emoji(activity)
type when type in ["follow", "follow_request"] ->
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 24167f66f..8e3715093 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -107,9 +107,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|> Enum.map(&get_user(&1.data["actor"], false))
|> Enum.filter(& &1)
- UserRelationship.view_relationships_option(reading_user, actors,
- source_mutes_only: opts[:skip_relationships]
- )
+ UserRelationship.view_relationships_option(reading_user, actors, subset: :source_mutes)
end
opts =
@@ -162,9 +160,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
account:
AccountView.render("show.json", %{
user: user,
- for: opts[:for],
- relationships: opts[:relationships],
- skip_relationships: opts[:skip_relationships]
+ for: opts[:for]
}),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
@@ -330,9 +326,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
account:
AccountView.render("show.json", %{
user: user,
- for: opts[:for],
- relationships: opts[:relationships],
- skip_relationships: opts[:skip_relationships]
+ for: opts[:for]
}),
in_reply_to_id: reply_to && to_string(reply_to.id),
in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
@@ -442,27 +436,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
}
end
- def render("listen.json", %{activity: %Activity{data: %{"type" => "Listen"}} = activity} = opts) do
- object = Object.normalize(activity)
-
- user = get_user(activity.data["actor"])
- created_at = Utils.to_masto_date(activity.data["published"])
-
- %{
- id: activity.id,
- account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
- created_at: created_at,
- title: object.data["title"] |> HTML.strip_tags(),
- artist: object.data["artist"] |> HTML.strip_tags(),
- album: object.data["album"] |> HTML.strip_tags(),
- length: object.data["length"]
- }
- end
-
- def render("listens.json", opts) do
- safe_render_many(opts.activities, StatusView, "listen.json", opts)
- end
-
def render("context.json", %{activity: activity, activities: activities, user: user}) do
%{ancestors: ancestors, descendants: descendants} =
activities
diff --git a/lib/pleroma/web/media_proxy/invalidation.ex b/lib/pleroma/web/media_proxy/invalidation.ex
new file mode 100644
index 000000000..c037ff13e
--- /dev/null
+++ b/lib/pleroma/web/media_proxy/invalidation.ex
@@ -0,0 +1,26 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MediaProxy.Invalidation do
+ @moduledoc false
+
+ @callback purge(list(String.t()), map()) :: {:ok, String.t()} | {:error, String.t()}
+
+ alias Pleroma.Config
+
+ @spec purge(list(String.t())) :: {:ok, String.t()} | {:error, String.t()}
+ def purge(urls) do
+ [:media_proxy, :invalidation, :enabled]
+ |> Config.get()
+ |> do_purge(urls)
+ end
+
+ defp do_purge(true, urls) do
+ provider = Config.get([:media_proxy, :invalidation, :provider])
+ options = Config.get(provider)
+ provider.purge(urls, options)
+ end
+
+ defp do_purge(_, _), do: :ok
+end
diff --git a/lib/pleroma/web/media_proxy/invalidations/http.ex b/lib/pleroma/web/media_proxy/invalidations/http.ex
new file mode 100644
index 000000000..07248df6e
--- /dev/null
+++ b/lib/pleroma/web/media_proxy/invalidations/http.ex
@@ -0,0 +1,40 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MediaProxy.Invalidation.Http do
+ @moduledoc false
+ @behaviour Pleroma.Web.MediaProxy.Invalidation
+
+ require Logger
+
+ @impl Pleroma.Web.MediaProxy.Invalidation
+ def purge(urls, opts) do
+ method = Map.get(opts, :method, :purge)
+ headers = Map.get(opts, :headers, [])
+ options = Map.get(opts, :options, [])
+
+ Logger.debug("Running cache purge: #{inspect(urls)}")
+
+ Enum.each(urls, fn url ->
+ with {:error, error} <- do_purge(method, url, headers, options) do
+ Logger.error("Error while cache purge: url - #{url}, error: #{inspect(error)}")
+ end
+ end)
+
+ {:ok, "success"}
+ end
+
+ defp do_purge(method, url, headers, options) do
+ case Pleroma.HTTP.request(method, url, "", headers, options) do
+ {:ok, %{status: status} = env} when 400 <= status and status < 500 ->
+ {:error, env}
+
+ {:error, error} = error ->
+ error
+
+ _ ->
+ {:ok, "success"}
+ end
+ end
+end
diff --git a/lib/pleroma/web/media_proxy/invalidations/script.ex b/lib/pleroma/web/media_proxy/invalidations/script.ex
new file mode 100644
index 000000000..6be782132
--- /dev/null
+++ b/lib/pleroma/web/media_proxy/invalidations/script.ex
@@ -0,0 +1,41 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MediaProxy.Invalidation.Script do
+ @moduledoc false
+
+ @behaviour Pleroma.Web.MediaProxy.Invalidation
+
+ require Logger
+
+ @impl Pleroma.Web.MediaProxy.Invalidation
+ def purge(urls, %{script_path: script_path} = _options) do
+ args =
+ urls
+ |> List.wrap()
+ |> Enum.uniq()
+ |> Enum.join(" ")
+
+ path = Path.expand(script_path)
+
+ Logger.debug("Running cache purge: #{inspect(urls)}, #{path}")
+
+ case do_purge(path, [args]) do
+ {result, exit_status} when exit_status > 0 ->
+ Logger.error("Error while cache purge: #{inspect(result)}")
+ {:error, inspect(result)}
+
+ _ ->
+ {:ok, "success"}
+ end
+ end
+
+ def purge(_, _), do: {:error, "not found script path"}
+
+ defp do_purge(path, args) do
+ System.cmd(path, args)
+ rescue
+ error -> {inspect(error), 1}
+ end
+end
diff --git a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex
index 0814b3bc3..6cbbe8fd8 100644
--- a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex
+++ b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.MongooseIM.MongooseIMController do
use Pleroma.Web, :controller
+ alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.Plugs.RateLimiter
alias Pleroma.Repo
alias Pleroma.User
@@ -27,7 +28,7 @@ defmodule Pleroma.Web.MongooseIM.MongooseIMController do
def check_password(conn, %{"user" => username, "pass" => password}) do
with %User{password_hash: password_hash, deactivated: false} <-
Repo.get_by(User, nickname: username, local: true),
- true <- Pbkdf2.verify_pass(password, password_hash) do
+ true <- AuthenticationPlug.checkpw(password, password_hash) do
conn
|> json(true)
else
diff --git a/lib/pleroma/web/oauth/mfa_controller.ex b/lib/pleroma/web/oauth/mfa_controller.ex
index e52cccd85..53e19f82e 100644
--- a/lib/pleroma/web/oauth/mfa_controller.ex
+++ b/lib/pleroma/web/oauth/mfa_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.MFAController do
diff --git a/lib/pleroma/web/oauth/mfa_view.ex b/lib/pleroma/web/oauth/mfa_view.ex
index e88e7066b..41d5578dc 100644
--- a/lib/pleroma/web/oauth/mfa_view.ex
+++ b/lib/pleroma/web/oauth/mfa_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.MFAView do
diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex
index 2c3bb9ded..e3aa4eb7e 100644
--- a/lib/pleroma/web/oauth/token/clean_worker.ex
+++ b/lib/pleroma/web/oauth/token/clean_worker.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Token.CleanWorker do
diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex
index be7477867..0a3f45620 100644
--- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
- only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2, skip_relationships?: 1]
+ only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2]
alias Ecto.Changeset
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
@@ -19,6 +19,13 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
require Pleroma.Constants
plug(
+ OpenApiSpex.Plug.PutApiSpec,
+ [module: Pleroma.Web.ApiSpec] when action == :confirmation_resend
+ )
+
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
+
+ plug(
:skip_plug,
[OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :confirmation_resend
)
@@ -49,9 +56,11 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
plug(:assign_account_by_id when action in [:favourites, :subscribe, :unsubscribe])
plug(:put_view, Pleroma.Web.MastodonAPI.AccountView)
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaAccountOperation
+
@doc "POST /api/v1/pleroma/accounts/confirmation_resend"
def confirmation_resend(conn, params) do
- nickname_or_email = params["email"] || params["nickname"]
+ nickname_or_email = params[:email] || params[:nickname]
with %User{} = user <- User.get_by_nickname_or_email(nickname_or_email),
{:ok, _} <- User.try_send_confirmation_email(user) do
@@ -60,7 +69,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
end
@doc "PATCH /api/v1/pleroma/accounts/update_avatar"
- def update_avatar(%{assigns: %{user: user}} = conn, %{"img" => ""}) do
+ def update_avatar(%{assigns: %{user: user}, body_params: %{img: ""}} = conn, _) do
{:ok, _user} =
user
|> Changeset.change(%{avatar: nil})
@@ -69,7 +78,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
json(conn, %{url: nil})
end
- def update_avatar(%{assigns: %{user: user}} = conn, params) do
+ def update_avatar(%{assigns: %{user: user}, body_params: params} = conn, _params) do
{:ok, %{data: data}} = ActivityPub.upload(params, type: :avatar)
{:ok, _user} = user |> Changeset.change(%{avatar: data}) |> User.update_and_set_cache()
%{"url" => [%{"href" => href} | _]} = data
@@ -78,14 +87,14 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
end
@doc "PATCH /api/v1/pleroma/accounts/update_banner"
- def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do
+ def update_banner(%{assigns: %{user: user}, body_params: %{banner: ""}} = conn, _) do
with {:ok, _user} <- User.update_banner(user, %{}) do
json(conn, %{url: nil})
end
end
- def update_banner(%{assigns: %{user: user}} = conn, params) do
- with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner),
+ def update_banner(%{assigns: %{user: user}, body_params: params} = conn, _) do
+ with {:ok, object} <- ActivityPub.upload(%{img: params[:banner]}, type: :banner),
{:ok, _user} <- User.update_banner(user, object.data) do
%{"url" => [%{"href" => href} | _]} = object.data
@@ -94,13 +103,13 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
end
@doc "PATCH /api/v1/pleroma/accounts/update_background"
- def update_background(%{assigns: %{user: user}} = conn, %{"img" => ""}) do
+ def update_background(%{assigns: %{user: user}, body_params: %{img: ""}} = conn, _) do
with {:ok, _user} <- User.update_background(user, %{}) do
json(conn, %{url: nil})
end
end
- def update_background(%{assigns: %{user: user}} = conn, params) do
+ def update_background(%{assigns: %{user: user}, body_params: params} = conn, _) do
with {:ok, object} <- ActivityPub.upload(params, type: :background),
{:ok, _user} <- User.update_background(user, object.data) do
%{"url" => [%{"href" => href} | _]} = object.data
@@ -117,6 +126,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
def favourites(%{assigns: %{user: for_user, account: user}} = conn, params) do
params =
params
+ |> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("type", "Create")
|> Map.put("favorited_by", user.ap_id)
|> Map.put("blocking_user", for_user)
@@ -139,8 +149,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
|> render("index.json",
activities: activities,
for: for_user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
+ as: :activity
)
end
diff --git a/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex b/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex
new file mode 100644
index 000000000..21d5eb8d5
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex
@@ -0,0 +1,95 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ConversationController do
+ use Pleroma.Web, :controller
+
+ import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
+
+ alias Pleroma.Conversation.Participation
+ alias Pleroma.Plugs.OAuthScopesPlug
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.MastodonAPI.StatusView
+
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(:put_view, Pleroma.Web.MastodonAPI.ConversationView)
+ plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:show, :statuses])
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["write:conversations"]} when action in [:update, :mark_as_read]
+ )
+
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaConversationOperation
+
+ def show(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: participation_id}) do
+ with %Participation{user_id: ^user_id} = participation <- Participation.get(participation_id) do
+ render(conn, "participation.json", participation: participation, for: user)
+ else
+ _error ->
+ conn
+ |> put_status(:not_found)
+ |> json(%{"error" => "Unknown conversation id"})
+ end
+ end
+
+ def statuses(
+ %{assigns: %{user: %{id: user_id} = user}} = conn,
+ %{id: participation_id} = params
+ ) do
+ with %Participation{user_id: ^user_id} = participation <-
+ Participation.get(participation_id, preload: [:conversation]) do
+ params =
+ params
+ |> Map.new(fn {key, value} -> {to_string(key), value} end)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+
+ activities =
+ participation.conversation.ap_id
+ |> ActivityPub.fetch_activities_for_context_query(params)
+ |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
+ |> Enum.reverse()
+
+ conn
+ |> add_link_headers(activities)
+ |> put_view(StatusView)
+ |> render("index.json", activities: activities, for: user, as: :activity)
+ else
+ _error ->
+ conn
+ |> put_status(:not_found)
+ |> json(%{"error" => "Unknown conversation id"})
+ end
+ end
+
+ def update(
+ %{assigns: %{user: %{id: user_id} = user}} = conn,
+ %{id: participation_id, recipients: recipients}
+ ) do
+ with %Participation{user_id: ^user_id} = participation <- Participation.get(participation_id),
+ {:ok, participation} <- Participation.set_recipients(participation, recipients) do
+ render(conn, "participation.json", participation: participation, for: user)
+ else
+ {:error, message} ->
+ conn
+ |> put_status(:bad_request)
+ |> json(%{"error" => message})
+
+ _error ->
+ conn
+ |> put_status(:not_found)
+ |> json(%{"error" => "Unknown conversation id"})
+ end
+ end
+
+ def mark_as_read(%{assigns: %{user: user}} = conn, _params) do
+ with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
+ conn
+ |> add_link_headers(participations)
+ |> render("participations.json", participations: participations, for: user)
+ end
+ end
+end
diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex
index d276b96a4..2c53dcde1 100644
--- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex
@@ -1,8 +1,10 @@
-defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
+defmodule Pleroma.Web.PleromaAPI.EmojiPackController do
use Pleroma.Web, :controller
alias Pleroma.Emoji.Pack
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
+
plug(
Pleroma.Plugs.OAuthScopesPlug,
%{scopes: ["write"], admin: true}
@@ -19,39 +21,37 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
]
)
- plug(
- :skip_plug,
- [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug]
- when action in [:archive, :show, :list]
- )
+ @skip_plugs [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug]
+ plug(:skip_plug, @skip_plugs when action in [:archive, :show, :list])
+
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiPackOperation
- def remote(conn, %{"url" => url}) do
+ def remote(conn, %{url: url}) do
with {:ok, packs} <- Pack.list_remote(url) do
json(conn, packs)
else
- {:shareable, _} ->
+ {:error, :not_shareable} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "The requested instance does not support sharing emoji packs"})
end
end
- def list(conn, _params) do
+ def index(conn, _params) do
emoji_path =
- Path.join(
- Pleroma.Config.get!([:instance, :static_dir]),
- "emoji"
- )
+ [:instance, :static_dir]
+ |> Pleroma.Config.get!()
+ |> Path.join("emoji")
with {:ok, packs} <- Pack.list_local() do
json(conn, packs)
else
- {:create_dir, {:error, e}} ->
+ {:error, :create_dir, e} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "Failed to create the emoji pack directory at #{emoji_path}: #{e}"})
- {:ls, {:error, e}} ->
+ {:error, :ls, e} ->
conn
|> put_status(:internal_server_error)
|> json(%{
@@ -60,13 +60,13 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end
- def show(conn, %{"name" => name}) do
+ def show(conn, %{name: name}) do
name = String.trim(name)
with {:ok, pack} <- Pack.show(name) do
json(conn, pack)
else
- {:loaded, _} ->
+ {:error, :not_found} ->
conn
|> put_status(:not_found)
|> json(%{error: "Pack #{name} does not exist"})
@@ -78,11 +78,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end
- def archive(conn, %{"name" => name}) do
+ def archive(conn, %{name: name}) do
with {:ok, archive} <- Pack.get_archive(name) do
send_download(conn, {:binary, archive}, filename: "#{name}.zip")
else
- {:can_download?, _} ->
+ {:error, :cant_download} ->
conn
|> put_status(:forbidden)
|> json(%{
@@ -90,23 +90,23 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
"Pack #{name} cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing"
})
- {:exists?, _} ->
+ {:error, :not_found} ->
conn
|> put_status(:not_found)
|> json(%{error: "Pack #{name} does not exist"})
end
end
- def download(conn, %{"url" => url, "name" => name} = params) do
- with :ok <- Pack.download(name, url, params["as"]) do
+ def download(%{body_params: %{url: url, name: name} = params} = conn, _) do
+ with {:ok, _pack} <- Pack.download(name, url, params[:as]) do
json(conn, "ok")
else
- {:shareable, _} ->
+ {:error, :not_shareable} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "The requested instance does not support sharing emoji packs"})
- {:checksum, _} ->
+ {:error, :imvalid_checksum} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "SHA256 for the pack doesn't match the one sent by the server"})
@@ -118,10 +118,10 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end
- def create(conn, %{"name" => name}) do
+ def create(conn, %{name: name}) do
name = String.trim(name)
- with :ok <- Pack.create(name) do
+ with {:ok, _pack} <- Pack.create(name) do
json(conn, "ok")
else
{:error, :eexist} ->
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end
- def delete(conn, %{"name" => name}) do
+ def delete(conn, %{name: name}) do
name = String.trim(name)
with {:ok, deleted} when deleted != [] <- Pack.delete(name) do
@@ -166,11 +166,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end
- def update(conn, %{"name" => name, "metadata" => metadata}) do
+ def update(%{body_params: %{metadata: metadata}} = conn, %{name: name}) do
with {:ok, pack} <- Pack.update_metadata(name, metadata) do
json(conn, pack.pack)
else
- {:has_all_files?, _} ->
+ {:error, :incomplete} ->
conn
|> put_status(:bad_request)
|> json(%{error: "The fallback archive does not have all files specified in pack.json"})
@@ -184,19 +184,19 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end
- def add_file(conn, %{"name" => name} = params) do
- filename = params["filename"] || get_filename(params["file"])
- shortcode = params["shortcode"] || Path.basename(filename, Path.extname(filename))
+ def add_file(%{body_params: params} = conn, %{name: name}) do
+ filename = params[:filename] || get_filename(params[:file])
+ shortcode = params[:shortcode] || Path.basename(filename, Path.extname(filename))
- with {:ok, pack} <- Pack.add_file(name, shortcode, filename, params["file"]) do
+ with {:ok, pack} <- Pack.add_file(name, shortcode, filename, params[:file]) do
json(conn, pack.files)
else
- {:exists, _} ->
+ {:error, :already_exists} ->
conn
|> put_status(:conflict)
|> json(%{error: "An emoji with the \"#{shortcode}\" shortcode already exists"})
- {:loaded, _} ->
+ {:error, :not_found} ->
conn
|> put_status(:bad_request)
|> json(%{error: "pack \"#{name}\" is not found"})
@@ -215,20 +215,20 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end
- def update_file(conn, %{"name" => name, "shortcode" => shortcode} = params) do
- new_shortcode = params["new_shortcode"]
- new_filename = params["new_filename"]
- force = params["force"] == true
+ def update_file(%{body_params: %{shortcode: shortcode} = params} = conn, %{name: name}) do
+ new_shortcode = params[:new_shortcode]
+ new_filename = params[:new_filename]
+ force = params[:force]
with {:ok, pack} <- Pack.update_file(name, shortcode, new_shortcode, new_filename, force) do
json(conn, pack.files)
else
- {:exists, _} ->
+ {:error, :doesnt_exist} ->
conn
|> put_status(:bad_request)
|> json(%{error: "Emoji \"#{shortcode}\" does not exist"})
- {:not_used, _} ->
+ {:error, :already_exists} ->
conn
|> put_status(:conflict)
|> json(%{
@@ -236,7 +236,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
"New shortcode \"#{new_shortcode}\" is already used. If you want to override emoji use 'force' option"
})
- {:loaded, _} ->
+ {:error, :not_found} ->
conn
|> put_status(:bad_request)
|> json(%{error: "pack \"#{name}\" is not found"})
@@ -255,16 +255,16 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
end
end
- def delete_file(conn, %{"name" => name, "shortcode" => shortcode}) do
+ def delete_file(conn, %{name: name, shortcode: shortcode}) do
with {:ok, pack} <- Pack.delete_file(name, shortcode) do
json(conn, pack.files)
else
- {:exists, _} ->
+ {:error, :doesnt_exist} ->
conn
|> put_status(:bad_request)
|> json(%{error: "Emoji \"#{shortcode}\" does not exist"})
- {:loaded, _} ->
+ {:error, :not_found} ->
conn
|> put_status(:bad_request)
|> json(%{error: "pack \"#{name}\" is not found"})
diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
new file mode 100644
index 000000000..a002912f3
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
@@ -0,0 +1,61 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
+ use Pleroma.Web, :controller
+
+ alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.Plugs.OAuthScopesPlug
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.MastodonAPI.StatusView
+
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(OAuthScopesPlug, %{scopes: ["write:statuses"]} when action in [:create, :delete])
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["read:statuses"], fallback: :proceed_unauthenticated}
+ when action == :index
+ )
+
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.EmojiReactionOperation
+
+ def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do
+ with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
+ %Object{data: %{"reactions" => reactions}} when is_list(reactions) <-
+ Object.normalize(activity) do
+ reactions = filter(reactions, params)
+ render(conn, "index.json", emoji_reactions: reactions, user: user)
+ else
+ _e -> json(conn, [])
+ end
+ end
+
+ defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do
+ Enum.filter(reactions, fn [e, _] -> e == emoji end)
+ end
+
+ defp filter(reactions, _), do: reactions
+
+ def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
+ with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do
+ activity = Activity.get_by_id(activity_id)
+
+ conn
+ |> put_view(StatusView)
+ |> render("show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+
+ def delete(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
+ with {:ok, _activity} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji) do
+ activity = Activity.get_by_id(activity_id)
+
+ conn
+ |> put_view(StatusView)
+ |> render("show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+end
diff --git a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex
index d4e0d8b7c..df6c50ca5 100644
--- a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex
@@ -9,16 +9,19 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(OAuthScopesPlug, %{scopes: ["read:accounts"]} when action == :show)
plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action != :show)
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaMascotOperation
+
@doc "GET /api/v1/pleroma/mascot"
def show(%{assigns: %{user: user}} = conn, _params) do
json(conn, User.get_mascot(user))
end
@doc "PUT /api/v1/pleroma/mascot"
- def update(%{assigns: %{user: user}} = conn, %{"file" => file}) do
+ def update(%{assigns: %{user: user}, body_params: %{file: file}} = conn, _) do
with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)),
# Reject if not an image
%{type: "image"} = attachment <- render_attachment(object) do
diff --git a/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex b/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex
new file mode 100644
index 000000000..0b2f678c5
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/controllers/notification_controller.ex
@@ -0,0 +1,36 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.NotificationController do
+ use Pleroma.Web, :controller
+
+ alias Pleroma.Notification
+ alias Pleroma.Plugs.OAuthScopesPlug
+
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :mark_as_read)
+ plug(:put_view, Pleroma.Web.MastodonAPI.NotificationView)
+
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaNotificationOperation
+
+ def mark_as_read(%{assigns: %{user: user}} = conn, %{id: notification_id}) do
+ with {:ok, notification} <- Notification.read_one(user, notification_id) do
+ render(conn, "show.json", notification: notification, for: user)
+ else
+ {:error, message} ->
+ conn
+ |> put_status(:bad_request)
+ |> json(%{"error" => message})
+ end
+ end
+
+ def mark_as_read(%{assigns: %{user: user}} = conn, %{max_id: max_id}) do
+ notifications =
+ user
+ |> Notification.set_read_up_to(max_id)
+ |> Enum.take(80)
+
+ render(conn, "index.json", notifications: notifications, for: user)
+ end
+end
diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
deleted file mode 100644
index 8bc77b75e..000000000
--- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
+++ /dev/null
@@ -1,217 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
- use Pleroma.Web, :controller
-
- import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
-
- alias Pleroma.Activity
- alias Pleroma.Conversation.Participation
- alias Pleroma.Notification
- alias Pleroma.Object
- alias Pleroma.Plugs.OAuthScopesPlug
- alias Pleroma.User
- alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.CommonAPI
- alias Pleroma.Web.MastodonAPI.AccountView
- alias Pleroma.Web.MastodonAPI.ConversationView
- alias Pleroma.Web.MastodonAPI.NotificationView
- alias Pleroma.Web.MastodonAPI.StatusView
-
- plug(
- OAuthScopesPlug,
- %{scopes: ["read:statuses"]}
- when action in [:conversation, :conversation_statuses]
- )
-
- plug(
- OAuthScopesPlug,
- %{scopes: ["read:statuses"], fallback: :proceed_unauthenticated}
- when action == :emoji_reactions_by
- )
-
- plug(
- OAuthScopesPlug,
- %{scopes: ["write:statuses"]}
- when action in [:react_with_emoji, :unreact_with_emoji]
- )
-
- plug(
- OAuthScopesPlug,
- %{scopes: ["write:conversations"]}
- when action in [:update_conversation, :mark_conversations_as_read]
- )
-
- plug(
- OAuthScopesPlug,
- %{scopes: ["write:notifications"]} when action == :mark_notifications_as_read
- )
-
- def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id} = params) do
- with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
- %Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
- Object.normalize(activity) do
- reactions =
- emoji_reactions
- |> Enum.map(fn [emoji, user_ap_ids] ->
- if params["emoji"] && params["emoji"] != emoji do
- nil
- else
- users =
- Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
- |> Enum.filter(fn
- %{deactivated: false} -> true
- _ -> false
- end)
-
- %{
- name: emoji,
- count: length(users),
- accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
- me: !!(user && user.ap_id in user_ap_ids)
- }
- end
- end)
- |> Enum.filter(& &1)
-
- conn
- |> json(reactions)
- else
- _e ->
- conn
- |> json([])
- end
- end
-
- def react_with_emoji(%{assigns: %{user: user}} = conn, %{"id" => activity_id, "emoji" => emoji}) do
- with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji),
- activity <- Activity.get_by_id(activity_id) do
- conn
- |> put_view(StatusView)
- |> render("show.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def unreact_with_emoji(%{assigns: %{user: user}} = conn, %{
- "id" => activity_id,
- "emoji" => emoji
- }) do
- with {:ok, _activity} <-
- CommonAPI.unreact_with_emoji(activity_id, user, emoji),
- activity <- Activity.get_by_id(activity_id) do
- conn
- |> put_view(StatusView)
- |> render("show.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
- with %Participation{} = participation <- Participation.get(participation_id),
- true <- user.id == participation.user_id do
- conn
- |> put_view(ConversationView)
- |> render("participation.json", %{participation: participation, for: user})
- else
- _error ->
- conn
- |> put_status(404)
- |> json(%{"error" => "Unknown conversation id"})
- end
- end
-
- def conversation_statuses(
- %{assigns: %{user: %{id: user_id} = user}} = conn,
- %{"id" => participation_id} = params
- ) do
- with %Participation{user_id: ^user_id} = participation <-
- Participation.get(participation_id, preload: [:conversation]) do
- params =
- params
- |> Map.put("blocking_user", user)
- |> Map.put("muting_user", user)
- |> Map.put("user", user)
-
- activities =
- participation.conversation.ap_id
- |> ActivityPub.fetch_activities_for_context_query(params)
- |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
- |> Enum.reverse()
-
- conn
- |> add_link_headers(activities)
- |> put_view(StatusView)
- |> render("index.json",
- activities: activities,
- for: user,
- as: :activity,
- skip_relationships: skip_relationships?(params)
- )
- else
- _error ->
- conn
- |> put_status(404)
- |> json(%{"error" => "Unknown conversation id"})
- end
- end
-
- def update_conversation(
- %{assigns: %{user: user}} = conn,
- %{"id" => participation_id, "recipients" => recipients}
- ) do
- with %Participation{} = participation <- Participation.get(participation_id),
- true <- user.id == participation.user_id,
- {:ok, participation} <- Participation.set_recipients(participation, recipients) do
- conn
- |> put_view(ConversationView)
- |> render("participation.json", %{participation: participation, for: user})
- else
- {:error, message} ->
- conn
- |> put_status(:bad_request)
- |> json(%{"error" => message})
-
- _error ->
- conn
- |> put_status(404)
- |> json(%{"error" => "Unknown conversation id"})
- end
- end
-
- def mark_conversations_as_read(%{assigns: %{user: user}} = conn, _params) do
- with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
- conn
- |> add_link_headers(participations)
- |> put_view(ConversationView)
- |> render("participations.json", participations: participations, for: user)
- end
- end
-
- def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
- with {:ok, notification} <- Notification.read_one(user, notification_id) do
- conn
- |> put_view(NotificationView)
- |> render("show.json", %{notification: notification, for: user})
- else
- {:error, message} ->
- conn
- |> put_status(:bad_request)
- |> json(%{"error" => message})
- end
- end
-
- def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"max_id" => max_id} = params) do
- with notifications <- Notification.set_read_up_to(user, max_id) do
- notifications = Enum.take(notifications, 80)
-
- conn
- |> put_view(NotificationView)
- |> render("index.json",
- notifications: notifications,
- for: user,
- skip_relationships: skip_relationships?(params)
- )
- end
- end
-end
diff --git a/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
index 22da6c0ad..8665ca56c 100644
--- a/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
@@ -5,34 +5,27 @@
defmodule Pleroma.Web.PleromaAPI.ScrobbleController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, fetch_integer_param: 2]
+ import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
- alias Pleroma.Web.MastodonAPI.StatusView
+
+ plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(
OAuthScopesPlug,
- %{scopes: ["read"], fallback: :proceed_unauthenticated} when action == :user_scrobbles
+ %{scopes: ["read"], fallback: :proceed_unauthenticated} when action == :index
)
- plug(OAuthScopesPlug, %{scopes: ["write"]} when action != :user_scrobbles)
+ plug(OAuthScopesPlug, %{scopes: ["write"]} when action == :create)
- def new_scrobble(%{assigns: %{user: user}} = conn, %{"title" => _} = params) do
- params =
- if !params["length"] do
- params
- else
- params
- |> Map.put("length", fetch_integer_param(params, "length"))
- end
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaScrobbleOperation
+ def create(%{assigns: %{user: user}, body_params: params} = conn, _) do
with {:ok, activity} <- CommonAPI.listen(user, params) do
- conn
- |> put_view(StatusView)
- |> render("listen.json", %{activity: activity, for: user})
+ render(conn, "show.json", activity: activity, for: user)
else
{:error, message} ->
conn
@@ -41,16 +34,18 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleController do
end
end
- def user_scrobbles(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do
- params = Map.put(params, "type", ["Listen"])
+ def index(%{assigns: %{user: reading_user}} = conn, %{id: id} = params) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(id, for: reading_user) do
+ params =
+ params
+ |> Map.new(fn {key, value} -> {to_string(key), value} end)
+ |> Map.put("type", ["Listen"])
activities = ActivityPub.fetch_user_abstract_activities(user, reading_user, params)
conn
|> add_link_headers(activities)
- |> put_view(StatusView)
- |> render("listens.json", %{
+ |> render("index.json", %{
activities: activities,
for: reading_user,
as: :activity
diff --git a/lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex b/lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex
index eb9989cdf..b86791d09 100644
--- a/lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationController do
diff --git a/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
new file mode 100644
index 000000000..84d2d303d
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.EmojiReactionView do
+ use Pleroma.Web, :view
+
+ alias Pleroma.Web.MastodonAPI.AccountView
+
+ def render("index.json", %{emoji_reactions: emoji_reactions} = opts) do
+ render_many(emoji_reactions, __MODULE__, "show.json", opts)
+ end
+
+ def render("show.json", %{emoji_reaction: [emoji, user_ap_ids], user: user}) do
+ users = fetch_users(user_ap_ids)
+
+ %{
+ name: emoji,
+ count: length(users),
+ accounts: render(AccountView, "index.json", users: users, for: user, as: :user),
+ me: !!(user && user.ap_id in user_ap_ids)
+ }
+ end
+
+ defp fetch_users(user_ap_ids) do
+ user_ap_ids
+ |> Enum.map(&Pleroma.User.get_cached_by_ap_id/1)
+ |> Enum.filter(fn
+ %{deactivated: false} -> true
+ _ -> false
+ end)
+ end
+end
diff --git a/lib/pleroma/web/pleroma_api/views/scrobble_view.ex b/lib/pleroma/web/pleroma_api/views/scrobble_view.ex
new file mode 100644
index 000000000..bbff93abe
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/views/scrobble_view.ex
@@ -0,0 +1,37 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ScrobbleView do
+ use Pleroma.Web, :view
+
+ require Pleroma.Constants
+
+ alias Pleroma.Activity
+ alias Pleroma.HTML
+ alias Pleroma.Object
+ alias Pleroma.Web.CommonAPI.Utils
+ alias Pleroma.Web.MastodonAPI.AccountView
+ alias Pleroma.Web.MastodonAPI.StatusView
+
+ def render("show.json", %{activity: %Activity{data: %{"type" => "Listen"}} = activity} = opts) do
+ object = Object.normalize(activity)
+
+ user = StatusView.get_user(activity.data["actor"])
+ created_at = Utils.to_masto_date(activity.data["published"])
+
+ %{
+ id: activity.id,
+ account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
+ created_at: created_at,
+ title: object.data["title"] |> HTML.strip_tags(),
+ artist: object.data["artist"] |> HTML.strip_tags(),
+ album: object.data["album"] |> HTML.strip_tags(),
+ length: object.data["length"]
+ }
+ end
+
+ def render("index.json", opts) do
+ safe_render_many(opts.activities, __MODULE__, "show.json", opts)
+ end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 7a171f9fb..cbe320746 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -216,24 +216,25 @@ defmodule Pleroma.Web.Router do
scope "/packs" do
pipe_through(:admin_api)
- get("/import", EmojiAPIController, :import_from_filesystem)
- get("/remote", EmojiAPIController, :remote)
- post("/download", EmojiAPIController, :download)
+ get("/import", EmojiPackController, :import_from_filesystem)
+ get("/remote", EmojiPackController, :remote)
+ post("/download", EmojiPackController, :download)
- post("/:name", EmojiAPIController, :create)
- patch("/:name", EmojiAPIController, :update)
- delete("/:name", EmojiAPIController, :delete)
+ post("/:name", EmojiPackController, :create)
+ patch("/:name", EmojiPackController, :update)
+ delete("/:name", EmojiPackController, :delete)
- post("/:name/files", EmojiAPIController, :add_file)
- patch("/:name/files", EmojiAPIController, :update_file)
- delete("/:name/files", EmojiAPIController, :delete_file)
+ post("/:name/files", EmojiPackController, :add_file)
+ patch("/:name/files", EmojiPackController, :update_file)
+ delete("/:name/files", EmojiPackController, :delete_file)
end
# Pack info / downloading
scope "/packs" do
- get("/", EmojiAPIController, :list)
- get("/:name", EmojiAPIController, :show)
- get("/:name/archive", EmojiAPIController, :archive)
+ pipe_through(:api)
+ get("/", EmojiPackController, :index)
+ get("/:name", EmojiPackController, :show)
+ get("/:name/archive", EmojiPackController, :archive)
end
end
@@ -297,26 +298,22 @@ defmodule Pleroma.Web.Router do
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:api)
- get("/statuses/:id/reactions/:emoji", PleromaAPIController, :emoji_reactions_by)
- get("/statuses/:id/reactions", PleromaAPIController, :emoji_reactions_by)
+ get("/statuses/:id/reactions/:emoji", EmojiReactionController, :index)
+ get("/statuses/:id/reactions", EmojiReactionController, :index)
end
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
scope [] do
pipe_through(:authenticated_api)
- get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses)
- get("/conversations/:id", PleromaAPIController, :conversation)
- post("/conversations/read", PleromaAPIController, :mark_conversations_as_read)
- end
-
- scope [] do
- pipe_through(:authenticated_api)
+ get("/conversations/:id/statuses", ConversationController, :statuses)
+ get("/conversations/:id", ConversationController, :show)
+ post("/conversations/read", ConversationController, :mark_as_read)
+ patch("/conversations/:id", ConversationController, :update)
- patch("/conversations/:id", PleromaAPIController, :update_conversation)
- put("/statuses/:id/reactions/:emoji", PleromaAPIController, :react_with_emoji)
- delete("/statuses/:id/reactions/:emoji", PleromaAPIController, :unreact_with_emoji)
- post("/notifications/read", PleromaAPIController, :mark_notifications_as_read)
+ put("/statuses/:id/reactions/:emoji", EmojiReactionController, :create)
+ delete("/statuses/:id/reactions/:emoji", EmojiReactionController, :delete)
+ post("/notifications/read", NotificationController, :mark_as_read)
patch("/accounts/update_avatar", AccountController, :update_avatar)
patch("/accounts/update_banner", AccountController, :update_banner)
@@ -325,7 +322,7 @@ defmodule Pleroma.Web.Router do
get("/mascot", MascotController, :show)
put("/mascot", MascotController, :update)
- post("/scrobble", ScrobbleController, :new_scrobble)
+ post("/scrobble", ScrobbleController, :create)
end
scope [] do
@@ -345,7 +342,7 @@ defmodule Pleroma.Web.Router do
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:api)
- get("/accounts/:id/scrobbles", ScrobbleController, :user_scrobbles)
+ get("/accounts/:id/scrobbles", ScrobbleController, :index)
end
scope "/api/v1", Pleroma.Web.MastodonAPI do
@@ -403,6 +400,7 @@ defmodule Pleroma.Web.Router do
post("/markers", MarkerController, :upsert)
post("/media", MediaController, :create)
+ get("/media/:id", MediaController, :show)
put("/media/:id", MediaController, :update)
get("/notifications", NotificationController, :index)
@@ -497,6 +495,8 @@ defmodule Pleroma.Web.Router do
scope "/api/v2", Pleroma.Web.MastodonAPI do
pipe_through(:api)
get("/search", SearchController, :search2)
+
+ post("/media", MediaController, :create2)
end
scope "/api", Pleroma.Web do