aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r--lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex97
-rw-r--r--lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex102
-rw-r--r--lib/pleroma/web/api_spec/operations/instance_operation.ex7
-rw-r--r--lib/pleroma/web/api_spec/operations/notification_operation.ex2
-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_notification_operation.ex42
-rw-r--r--lib/pleroma/web/mastodon_api/views/instance_view.ex7
-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/notification_controller.ex36
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex220
-rw-r--r--lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex33
-rw-r--r--lib/pleroma/web/router.ex47
15 files changed, 1042 insertions, 293 deletions
diff --git a/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
new file mode 100644
index 000000000..2858af9eb
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
@@ -0,0 +1,97 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
+ require Logger
+
+ alias Pleroma.Config
+
+ @moduledoc "Detect new emojis by their shortcode and steals them"
+ @behaviour Pleroma.Web.ActivityPub.MRF
+
+ defp remote_host?(host), do: host != Config.get([Pleroma.Web.Endpoint, :url, :host])
+
+ defp accept_host?(host), do: host in Config.get([:mrf_steal_emoji, :hosts], [])
+
+ defp steal_emoji({shortcode, url}) do
+ url = Pleroma.Web.MediaProxy.url(url)
+ {:ok, response} = Pleroma.HTTP.get(url)
+ size_limit = Config.get([:mrf_steal_emoji, :size_limit], 50_000)
+
+ if byte_size(response.body) <= size_limit do
+ emoji_dir_path =
+ Config.get(
+ [:mrf_steal_emoji, :path],
+ Path.join(Config.get([:instance, :static_dir]), "emoji/stolen")
+ )
+
+ extension =
+ url
+ |> URI.parse()
+ |> Map.get(:path)
+ |> Path.basename()
+ |> Path.extname()
+
+ file_path = Path.join([emoji_dir_path, shortcode <> (extension || ".png")])
+
+ try do
+ :ok = File.write(file_path, response.body)
+
+ shortcode
+ rescue
+ e ->
+ Logger.warn("MRF.StealEmojiPolicy: Failed to write to #{file_path}: #{inspect(e)}")
+ nil
+ end
+ else
+ Logger.debug(
+ "MRF.StealEmojiPolicy: :#{shortcode}: at #{url} (#{byte_size(response.body)} B) over size limit (#{
+ size_limit
+ } B)"
+ )
+
+ nil
+ end
+ rescue
+ e ->
+ Logger.warn("MRF.StealEmojiPolicy: Failed to fetch #{url}: #{inspect(e)}")
+ nil
+ end
+
+ @impl true
+ def filter(%{"object" => %{"emoji" => foreign_emojis, "actor" => actor}} = message) do
+ host = URI.parse(actor).host
+
+ if remote_host?(host) and accept_host?(host) do
+ installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
+
+ new_emojis =
+ foreign_emojis
+ |> Enum.filter(fn {shortcode, _url} -> shortcode not in installed_emoji end)
+ |> Enum.filter(fn {shortcode, _url} ->
+ reject_emoji? =
+ Config.get([:mrf_steal_emoji, :rejected_shortcodes], [])
+ |> Enum.find(false, fn regex -> String.match?(shortcode, regex) end)
+
+ !reject_emoji?
+ end)
+ |> Enum.map(&steal_emoji(&1))
+ |> Enum.filter(& &1)
+
+ if !Enum.empty?(new_emojis) do
+ Logger.info("Stole new emojis: #{inspect(new_emojis)}")
+ Pleroma.Emoji.reload()
+ end
+ end
+
+ {:ok, message}
+ end
+
+ def filter(message), do: {:ok, message}
+
+ @impl true
+ def describe do
+ {:ok, %{}}
+ end
+end
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/instance_operation.ex b/lib/pleroma/web/api_spec/operations/instance_operation.ex
index 9d189d029..d5c335d0c 100644
--- a/lib/pleroma/web/api_spec/operations/instance_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/instance_operation.ex
@@ -125,7 +125,12 @@ 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,
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_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_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/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex
index 8088306c3..6a630eafa 100644
--- a/lib/pleroma/web/mastodon_api/views/instance_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex
@@ -23,7 +23,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
streaming_api: Pleroma.Web.Endpoint.websocket_url()
},
stats: Pleroma.Stats.get_stats(),
- thumbnail: Pleroma.Web.base_url() <> "/instance/thumbnail.jpeg",
+ thumbnail: instance_thumbnail(),
languages: ["en"],
registrations: Keyword.get(instance, :registrations_open),
# Extra (not present in Mastodon):
@@ -87,4 +87,9 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
end
|> Map.put(:enabled, Config.get([:instance, :federating]))
end
+
+ defp instance_thumbnail do
+ Pleroma.Config.get([:instance, :instance_thumbnail]) ||
+ "#{Pleroma.Web.base_url()}/instance/thumbnail.jpeg"
+ end
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/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 e834133b2..000000000
--- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
+++ /dev/null
@@ -1,220 +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]
-
- 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
- )
- 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}) 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
- )
- end
- end
-end
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/router.ex b/lib/pleroma/web/router.ex
index 369c54cf4..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)