summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/tasks/pleroma/openapi_spec.ex67
-rw-r--r--lib/pleroma/bbs/authenticator.ex20
-rw-r--r--lib/pleroma/bbs/handler.ex246
-rw-r--r--lib/pleroma/emoji.ex53
-rw-r--r--lib/pleroma/object.ex26
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex2
-rw-r--r--lib/pleroma/web/activity_pub/builder.ex81
-rw-r--r--lib/pleroma/web/activity_pub/object_validator.ex15
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex (renamed from lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex)15
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex47
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/tag_validator.ex6
-rw-r--r--lib/pleroma/web/activity_pub/side_effects.ex2
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex2
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex79
-rw-r--r--lib/pleroma/web/admin_api/controllers/frontend_controller.ex25
-rw-r--r--lib/pleroma/web/admin_api/views/frontend_view.ex3
-rw-r--r--lib/pleroma/web/api_spec.ex24
-rw-r--r--lib/pleroma/web/api_spec/operations/account_operation.ex4
-rw-r--r--lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex10
-rw-r--r--lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex5
-rw-r--r--lib/pleroma/web/api_spec/operations/admin/status_operation.ex8
-rw-r--r--lib/pleroma/web/api_spec/operations/announcement_operation.ex4
-rw-r--r--lib/pleroma/web/api_spec/operations/directory_operation.ex2
-rw-r--r--lib/pleroma/web/api_spec/operations/instance_operation.ex4
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex6
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex28
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex2
-rw-r--r--lib/pleroma/web/api_spec/operations/status_operation.ex6
-rw-r--r--lib/pleroma/web/api_spec/operations/twitter_util_operation.ex25
-rw-r--r--lib/pleroma/web/api_spec/schemas/status.ex12
-rw-r--r--lib/pleroma/web/api_spec/scopes/compiler.ex82
-rw-r--r--lib/pleroma/web/api_spec/scopes/translator.ex10
-rw-r--r--lib/pleroma/web/common_api/utils.ex15
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex20
-rw-r--r--lib/pleroma/web/mastodon_api/views/instance_view.ex1
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex5
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex16
-rw-r--r--lib/pleroma/web/metadata/providers/rel_me.ex14
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex24
-rw-r--r--lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex17
-rw-r--r--lib/pleroma/web/plugs/uploaded_media.ex4
-rw-r--r--lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex2
42 files changed, 644 insertions, 395 deletions
diff --git a/lib/mix/tasks/pleroma/openapi_spec.ex b/lib/mix/tasks/pleroma/openapi_spec.ex
index 884f931f8..1ea468476 100644
--- a/lib/mix/tasks/pleroma/openapi_spec.ex
+++ b/lib/mix/tasks/pleroma/openapi_spec.ex
@@ -6,7 +6,70 @@ defmodule Mix.Tasks.Pleroma.OpenapiSpec do
def run([path]) do
# Load Pleroma application to get version info
Application.load(:pleroma)
- spec = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
- File.write(path, spec)
+
+ spec_json = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
+ # to get rid of the structs
+ spec_regened = spec_json |> Jason.decode!()
+
+ check_specs!(spec_regened)
+
+ File.write(path, spec_json)
+ end
+
+ defp check_specs!(spec) do
+ with :ok <- check_specs(spec) do
+ :ok
+ else
+ {_, errors} ->
+ IO.puts(IO.ANSI.format([:red, :bright, "Spec check failed, errors:"]))
+ Enum.map(errors, &IO.puts/1)
+
+ raise "Spec check failed"
+ end
+ end
+
+ def check_specs(spec) do
+ errors =
+ spec["paths"]
+ |> Enum.flat_map(fn {path, %{} = endpoints} ->
+ Enum.map(
+ endpoints,
+ fn {method, endpoint} ->
+ with :ok <- check_endpoint(spec, endpoint) do
+ :ok
+ else
+ error ->
+ "#{endpoint["operationId"]} (#{method} #{path}): #{error}"
+ end
+ end
+ )
+ |> Enum.reject(fn res -> res == :ok end)
+ end)
+
+ if errors == [] do
+ :ok
+ else
+ {:error, errors}
+ end
+ end
+
+ defp check_endpoint(spec, endpoint) do
+ valid_tags = available_tags(spec)
+
+ with {_, [_ | _] = tags} <- {:tags, endpoint["tags"]},
+ {_, []} <- {:unavailable, Enum.reject(tags, &(&1 in valid_tags))} do
+ :ok
+ else
+ {:tags, _} ->
+ "No tags specified"
+
+ {:unavailable, tags} ->
+ "Tags #{inspect(tags)} not available. Please add it in \"x-tagGroups\" in Pleroma.Web.ApiSpec"
+ end
+ end
+
+ defp available_tags(spec) do
+ spec["x-tagGroups"]
+ |> Enum.flat_map(fn %{"tags" => tags} -> tags end)
end
end
diff --git a/lib/pleroma/bbs/authenticator.ex b/lib/pleroma/bbs/authenticator.ex
deleted file mode 100644
index 0f7543ff5..000000000
--- a/lib/pleroma/bbs/authenticator.ex
+++ /dev/null
@@ -1,20 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.BBS.Authenticator do
- use Sshd.PasswordAuthenticator
- alias Pleroma.User
- alias Pleroma.Web.Plugs.AuthenticationPlug
-
- def authenticate(username, password) do
- username = to_string(username)
- password = to_string(password)
-
- with %User{} = user <- User.get_by_nickname(username) do
- AuthenticationPlug.checkpw(password, user.password_hash)
- else
- _e -> false
- end
- end
-end
diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex
deleted file mode 100644
index 27799338f..000000000
--- a/lib/pleroma/bbs/handler.ex
+++ /dev/null
@@ -1,246 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.BBS.Handler do
- use Sshd.ShellHandler
- alias Pleroma.Activity
- alias Pleroma.HTML
- alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.CommonAPI
-
- def on_shell(username, _pubkey, _ip, _port) do
- :ok = IO.puts("Welcome to #{Pleroma.Config.get([:instance, :name])}!")
- user = Pleroma.User.get_cached_by_nickname(to_string(username))
- Logger.debug("#{inspect(user)}")
- loop(run_state(user: user))
- end
-
- def on_connect(username, ip, port, method) do
- Logger.debug(fn ->
- """
- Incoming SSH shell #{inspect(self())} requested for #{username} from #{inspect(ip)}:#{inspect(port)} using #{inspect(method)}
- """
- end)
- end
-
- def on_disconnect(username, ip, port) do
- Logger.debug(fn ->
- "Disconnecting SSH shell for #{username} from #{inspect(ip)}:#{inspect(port)}"
- end)
- end
-
- defp loop(state) do
- self_pid = self()
- counter = state.counter
- prefix = state.prefix
- user = state.user
-
- input = spawn(fn -> io_get(self_pid, prefix, counter, user.nickname) end)
- wait_input(state, input)
- end
-
- def puts_activity(activity) do
- status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity})
-
- IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})")
-
- status.content
- |> String.split("<br/>")
- |> Enum.map(&HTML.strip_tags/1)
- |> Enum.map(&HtmlEntities.decode/1)
- |> Enum.map(&IO.puts/1)
- end
-
- def puts_notification(activity, user) do
- notification =
- Pleroma.Web.MastodonAPI.NotificationView.render("show.json", %{
- notification: activity,
- for: user
- })
-
- IO.puts(
- "== (#{notification.type}) #{notification.status.id} by #{notification.account.display_name} (#{notification.account.acct})"
- )
-
- notification.status.content
- |> String.split("<br/>")
- |> Enum.map(&HTML.strip_tags/1)
- |> Enum.map(&HtmlEntities.decode/1)
- |> (fn x ->
- case x do
- [content] ->
- "> " <> content
-
- [head | _tail] ->
- # "> " <> hd <> "..."
- head
- |> String.slice(1, 80)
- |> (fn x -> "> " <> x <> "..." end).()
- end
- end).()
- |> IO.puts()
-
- IO.puts("")
- end
-
- def handle_command(state, "help") do
- IO.puts("Available commands:")
- IO.puts("help - This help")
- IO.puts("home - Show the home timeline")
- IO.puts("p <text> - Post the given text")
- IO.puts("r <id> <text> - Reply to the post with the given id")
- IO.puts("t <id> - Show a thread from the given id")
- IO.puts("n - Show notifications")
- IO.puts("n read - Mark all notifactions as read")
- IO.puts("f <id> - Favourites the post with the given id")
- IO.puts("R <id> - Repeat the post with the given id")
- IO.puts("quit - Quit")
-
- state
- end
-
- def handle_command(%{user: user} = state, "r " <> text) do
- text = String.trim(text)
- [activity_id, rest] = String.split(text, " ", parts: 2)
-
- with %Activity{} <- Activity.get_by_id(activity_id),
- {:ok, _activity} <-
- CommonAPI.post(user, %{status: rest, in_reply_to_status_id: activity_id}) do
- IO.puts("Replied!")
- else
- _e -> IO.puts("Could not reply...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "t " <> activity_id) do
- with %Activity{} = activity <- Activity.get_by_id(activity_id) do
- activities =
- ActivityPub.fetch_activities_for_context(activity.data["context"], %{
- blocking_user: user,
- user: user,
- exclude_id: activity.id
- })
-
- case activities do
- [] ->
- activity_id
- |> Activity.get_by_id()
- |> puts_activity()
-
- _ ->
- activities
- |> Enum.reverse()
- |> Enum.each(&puts_activity/1)
- end
- else
- _e -> IO.puts("Could not show this thread...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "n read") do
- Pleroma.Notification.clear(user)
- IO.puts("All notifications were marked as read")
-
- state
- end
-
- def handle_command(%{user: user} = state, "n") do
- user
- |> Pleroma.Web.MastodonAPI.MastodonAPI.get_notifications(%{})
- |> Enum.each(&puts_notification(&1, user))
-
- state
- end
-
- def handle_command(%{user: user} = state, "p " <> text) do
- text = String.trim(text)
-
- with {:ok, activity} <- CommonAPI.post(user, %{status: text}) do
- IO.puts("Posted! ID: #{activity.id}")
- else
- _e -> IO.puts("Could not post...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "f " <> id) do
- id = String.trim(id)
-
- with %Activity{} = activity <- Activity.get_by_id(id),
- {:ok, _activity} <- CommonAPI.favorite(user, activity) do
- IO.puts("Favourited!")
- else
- _e -> IO.puts("Could not Favourite...")
- end
-
- state
- end
-
- def handle_command(state, "home") do
- user = state.user
-
- params =
- %{}
- |> Map.put(:type, ["Create"])
- |> Map.put(:blocking_user, user)
- |> Map.put(:muting_user, user)
- |> Map.put(:user, user)
-
- activities =
- [user.ap_id | Pleroma.User.following(user)]
- |> ActivityPub.fetch_activities(params)
-
- Enum.each(activities, fn activity ->
- puts_activity(activity)
- end)
-
- state
- end
-
- def handle_command(state, command) do
- IO.puts("Unknown command '#{command}'")
- state
- end
-
- defp wait_input(state, input) do
- receive do
- {:input, ^input, "quit\n"} ->
- IO.puts("Exiting...")
-
- {:input, ^input, code} when is_binary(code) ->
- code = String.trim(code)
-
- state = handle_command(state, code)
-
- loop(%{state | counter: state.counter + 1})
-
- {:input, ^input, {:error, :interrupted}} ->
- IO.puts("Caught Ctrl+C...")
- loop(%{state | counter: state.counter + 1})
-
- {:input, ^input, msg} ->
- :ok = Logger.warn("received unknown message: #{inspect(msg)}")
- loop(%{state | counter: state.counter + 1})
- end
- end
-
- defp run_state(opts) do
- %{prefix: "pleroma", counter: 1, user: opts[:user]}
- end
-
- defp io_get(pid, prefix, counter, username) do
- prompt = prompt(prefix, counter, username)
- send(pid, {:input, self(), IO.gets(:stdio, prompt)})
- end
-
- defp prompt(prefix, counter, username) do
- prompt = "#{username}@#{prefix}:#{counter}>"
- prompt <> " "
- end
-end
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index dd65d56ae..43a3447c3 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -51,6 +51,8 @@ defmodule Pleroma.Emoji do
@doc "Returns the path of the emoji `name`."
@spec get(String.t()) :: String.t() | nil
def get(name) do
+ name = maybe_strip_name(name)
+
case :ets.lookup(@ets, name) do
[{_, path}] -> path
_ -> nil
@@ -139,6 +141,57 @@ defmodule Pleroma.Emoji do
def is_unicode_emoji?(_), do: false
+ @emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/
+
+ def is_custom_emoji?(s) when is_binary(s), do: Regex.match?(@emoji_regex, s)
+
+ def is_custom_emoji?(_), do: false
+
+ def maybe_strip_name(name) when is_binary(name), do: String.trim(name, ":")
+
+ def maybe_strip_name(name), do: name
+
+ def maybe_quote(name) when is_binary(name) do
+ if is_unicode_emoji?(name) do
+ name
+ else
+ if String.starts_with?(name, ":") do
+ name
+ else
+ ":#{name}:"
+ end
+ end
+ end
+
+ def maybe_quote(name), do: name
+
+ def emoji_url(%{"type" => "EmojiReact", "content" => _, "tag" => []}), do: nil
+
+ def emoji_url(%{"type" => "EmojiReact", "content" => emoji, "tag" => tags}) do
+ emoji = maybe_strip_name(emoji)
+
+ tag =
+ tags
+ |> Enum.find(fn tag ->
+ tag["type"] == "Emoji" && !is_nil(tag["name"]) && tag["name"] == emoji
+ end)
+
+ if is_nil(tag) do
+ nil
+ else
+ tag
+ |> Map.get("icon")
+ |> Map.get("url")
+ end
+ end
+
+ def emoji_url(_), do: nil
+
+ def emoji_name_with_instance(name, url) do
+ url = url |> URI.parse() |> Map.get(:host)
+ "#{name}@#{url}"
+ end
+
emoji_qualification_map =
emojis
|> Enum.filter(&String.contains?(&1, "\uFE0F"))
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 38accae5d..aa137d250 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -425,4 +425,30 @@ defmodule Pleroma.Object do
end
def object_data_hashtags(_), do: []
+
+ def get_emoji_reactions(object) do
+ reactions = object.data["reactions"]
+
+ if is_list(reactions) or is_map(reactions) do
+ reactions
+ |> Enum.map(fn
+ [_emoji, users, _maybe_url] = item when is_list(users) ->
+ item
+
+ [emoji, users] when is_list(users) ->
+ [emoji, users, nil]
+
+ # This case is here to process the Map situation, which will happen
+ # only with the legacy two-value format.
+ {emoji, users} when is_list(users) ->
+ [emoji, users, nil]
+
+ _ ->
+ nil
+ end)
+ |> Enum.reject(&is_nil/1)
+ else
+ []
+ end
+ end
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 1ab2db94a..f22756015 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -96,7 +96,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp increase_replies_count_if_reply(_create_data), do: :noop
- @object_types ~w[ChatMessage Question Answer Audio Video Event Article Note Page]
+ @object_types ~w[ChatMessage Question Answer Audio Video Image Event Article Note Page]
@impl true
def persist(%{"type" => type} = object, meta) when type in @object_types do
with {:ok, object} <- Object.create(object) do
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
index 532047599..8eab3a241 100644
--- a/lib/pleroma/web/activity_pub/builder.ex
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -16,6 +16,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI.ActivityDraft
+ alias Pleroma.Web.Endpoint
require Pleroma.Constants
@@ -54,13 +55,87 @@ defmodule Pleroma.Web.ActivityPub.Builder do
{:ok, data, []}
end
+ defp unicode_emoji_react(_object, data, emoji) do
+ data
+ |> Map.put("content", emoji)
+ |> Map.put("type", "EmojiReact")
+ end
+
+ defp add_emoji_content(data, emoji, url) do
+ tag = [
+ %{
+ "id" => url,
+ "type" => "Emoji",
+ "name" => Emoji.maybe_quote(emoji),
+ "icon" => %{
+ "type" => "Image",
+ "url" => url
+ }
+ }
+ ]
+
+ data
+ |> Map.put("content", Emoji.maybe_quote(emoji))
+ |> Map.put("type", "EmojiReact")
+ |> Map.put("tag", tag)
+ end
+
+ defp remote_custom_emoji_react(
+ %{data: %{"reactions" => existing_reactions}},
+ data,
+ emoji
+ ) do
+ [emoji_code, instance] = String.split(Emoji.maybe_strip_name(emoji), "@")
+
+ matching_reaction =
+ Enum.find(
+ existing_reactions,
+ fn [name, _, url] ->
+ if url != nil do
+ url = URI.parse(url)
+ url.host == instance && name == emoji_code
+ end
+ end
+ )
+
+ if matching_reaction do
+ [name, _, url] = matching_reaction
+ add_emoji_content(data, name, url)
+ else
+ {:error, "Could not react"}
+ end
+ end
+
+ defp remote_custom_emoji_react(_object, _data, _emoji) do
+ {:error, "Could not react"}
+ end
+
+ defp local_custom_emoji_react(data, emoji) do
+ with %{file: path} = emojo <- Emoji.get(emoji) do
+ url = "#{Endpoint.url()}#{path}"
+ add_emoji_content(data, emojo.code, url)
+ else
+ _ -> {:error, "Emoji does not exist"}
+ end
+ end
+
+ defp custom_emoji_react(object, data, emoji) do
+ if String.contains?(emoji, "@") do
+ remote_custom_emoji_react(object, data, emoji)
+ else
+ local_custom_emoji_react(data, emoji)
+ end
+ end
+
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do
data =
- data
- |> Map.put("content", emoji)
- |> Map.put("type", "EmojiReact")
+ if Emoji.is_unicode_emoji?(emoji) do
+ unicode_emoji_react(object, data, emoji)
+ else
+ custom_emoji_react(object, data, emoji)
+ end
{:ok, data, meta}
end
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 5bcd6da46..5e0d1aa8e 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator
- alias Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
@@ -102,7 +102,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
%{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,
meta
)
- when objtype in ~w[Question Answer Audio Video Event Article Note Page] do
+ when objtype in ~w[Question Answer Audio Video Image Event Article Note Page] do
with {:ok, object_data} <- cast_and_apply_and_stringify_with_history(object),
meta = Keyword.put(meta, :object_data, object_data),
{:ok, create_activity} <-
@@ -115,13 +115,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end
def validate(%{"type" => type} = object, meta)
- when type in ~w[Event Question Audio Video Article Note Page] do
+ when type in ~w[Event Question Audio Video Image Article Note Page] do
validator =
case type do
"Event" -> EventValidator
"Question" -> QuestionValidator
- "Audio" -> AudioVideoValidator
- "Video" -> AudioVideoValidator
+ "Audio" -> AudioImageVideoValidator
+ "Video" -> AudioImageVideoValidator
+ "Image" -> AudioImageVideoValidator
"Article" -> ArticleNotePageValidator
"Note" -> ArticleNotePageValidator
"Page" -> ArticleNotePageValidator
@@ -233,8 +234,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
AnswerValidator.cast_and_apply(object)
end
- def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Video] do
- AudioVideoValidator.cast_and_apply(object)
+ def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Image Video] do
+ AudioImageVideoValidator.cast_and_apply(object)
end
def cast_and_apply(%{"type" => "Event"} = object) do
diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
index 671a7ef0c..79ff76104 100644
--- a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
@@ -2,7 +2,7 @@
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator do
use Ecto.Schema
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
@@ -55,9 +55,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
url
|> Enum.concat(mpeg_url["tag"] || [])
|> Enum.find(fn
- %{"mediaType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
- %{"mimeType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
- _ -> false
+ %{"mediaType" => mime_type} ->
+ String.starts_with?(mime_type, ["video/", "audio/", "image/"])
+
+ %{"mimeType" => mime_type} ->
+ String.starts_with?(mime_type, ["video/", "audio/", "image/"])
+
+ _ ->
+ false
end)
end
@@ -110,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
defp validate_data(data_cng) do
data_cng
- |> validate_inclusion(:type, ["Audio", "Video"])
+ |> validate_inclusion(:type, ~w[Audio Image Video])
|> validate_required([:id, :actor, :attributedTo, :type, :context])
|> CommonValidations.validate_any_presence([:cc, :to])
|> CommonValidations.validate_fields_match([:actor, :attributedTo])
diff --git a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
index 0858281e5..a0b82b325 100644
--- a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
@@ -5,8 +5,10 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
use Ecto.Schema
+ alias Pleroma.Emoji
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
+ alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@@ -19,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
message_fields()
activity_fields()
+ embeds_many(:tag, TagValidator)
end
end
@@ -43,7 +46,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
def changeset(struct, data) do
struct
- |> cast(data, __schema__(:fields))
+ |> cast(data, __schema__(:fields) -- [:tag])
+ |> cast_embed(:tag)
end
defp fix(data) do
@@ -53,12 +57,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|> CommonFixes.fix_actor()
|> CommonFixes.fix_activity_addressing()
- with %Object{} = object <- Object.normalize(data["object"]) do
- data
- |> CommonFixes.fix_activity_context(object)
- |> CommonFixes.fix_object_action_recipients(object)
- else
- _ -> data
+ data = Map.put_new(data, "tag", [])
+
+ case Object.normalize(data["object"]) do
+ %Object{} = object ->
+ data
+ |> CommonFixes.fix_activity_context(object)
+ |> CommonFixes.fix_object_action_recipients(object)
+
+ _ ->
+ data
end
end
@@ -82,11 +90,31 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
defp validate_emoji(cng) do
content = get_field(cng, :content)
- if Pleroma.Emoji.is_unicode_emoji?(content) do
+ if Emoji.is_unicode_emoji?(content) || Emoji.is_custom_emoji?(content) do
cng
else
cng
- |> add_error(:content, "must be a single character emoji")
+ |> add_error(:content, "is not a valid emoji")
+ end
+ end
+
+ defp maybe_validate_tag_presence(cng) do
+ content = get_field(cng, :content)
+
+ if Emoji.is_unicode_emoji?(content) do
+ cng
+ else
+ tag = get_field(cng, :tag)
+ emoji_name = Emoji.maybe_strip_name(content)
+
+ case tag do
+ [%{name: ^emoji_name, type: "Emoji", icon: %{url: _}}] ->
+ cng
+
+ _ ->
+ cng
+ |> add_error(:tag, "does not contain an Emoji tag")
+ end
end
end
@@ -97,5 +125,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|> validate_actor_presence()
|> validate_object_presence()
|> validate_emoji()
+ |> maybe_validate_tag_presence()
end
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
index 9f15f1981..cfd510c19 100644
--- a/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
@@ -68,6 +68,12 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|> validate_required([:type, :name, :icon])
end
+ def changeset(struct, %{"type" => _} = data) do
+ struct
+ |> cast(data, [])
+ |> Map.put(:action, :ignore)
+ end
+
def icon_changeset(struct, data) do
struct
|> cast(data, [:type, :url])
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index fc5dec362..098c177c7 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -496,7 +496,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end
def handle_object_creation(%{"type" => objtype} = object, _activity, meta)
- when objtype in ~w[Audio Video Event Article Note Page] do
+ when objtype in ~w[Audio Video Image Event Article Note Page] do
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
{:ok, object, meta}
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index e4c04da0d..3141f8437 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -447,7 +447,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data,
options
)
- when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page} do
+ when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page Image} do
fetch_options = Keyword.put(options, :depth, (options[:depth] || 0) + 1)
object =
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index b898d6fe8..437220077 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -31,7 +31,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"Page",
"Question",
"Answer",
- "Audio"
+ "Audio",
+ "Image"
]
@strip_status_report_states ~w(closed resolved)
@supported_report_states ~w(open closed resolved)
@@ -325,21 +326,29 @@ defmodule Pleroma.Web.ActivityPub.Utils do
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
def add_emoji_reaction_to_object(
- %Activity{data: %{"content" => emoji, "actor" => actor}},
+ %Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
reactions = get_cached_emoji_reactions(object)
+ emoji = Pleroma.Emoji.maybe_strip_name(emoji)
+ url = maybe_emoji_url(emoji, activity)
new_reactions =
- case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+ case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
+ if is_nil(candidate_url) do
+ emoji == candidate
+ else
+ url == candidate_url
+ end
+ end) do
nil ->
- reactions ++ [[emoji, [actor]]]
+ reactions ++ [[emoji, [actor], url]]
index ->
List.update_at(
reactions,
index,
- fn [emoji, users] -> [emoji, Enum.uniq([actor | users])] end
+ fn [emoji, users, url] -> [emoji, Enum.uniq([actor | users]), url] end
)
end
@@ -348,18 +357,40 @@ defmodule Pleroma.Web.ActivityPub.Utils do
update_element_in_object("reaction", new_reactions, object, count)
end
+ defp maybe_emoji_url(
+ name,
+ %Activity{
+ data: %{
+ "tag" => [
+ %{"type" => "Emoji", "name" => name, "icon" => %{"url" => url}}
+ ]
+ }
+ }
+ ),
+ do: url
+
+ defp maybe_emoji_url(_, _), do: nil
+
def emoji_count(reactions_list) do
- Enum.reduce(reactions_list, 0, fn [_, users], acc -> acc + length(users) end)
+ Enum.reduce(reactions_list, 0, fn [_, users, _], acc -> acc + length(users) end)
end
def remove_emoji_reaction_from_object(
- %Activity{data: %{"content" => emoji, "actor" => actor}},
+ %Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
+ emoji = Pleroma.Emoji.maybe_strip_name(emoji)
reactions = get_cached_emoji_reactions(object)
+ url = maybe_emoji_url(emoji, activity)
new_reactions =
- case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+ case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
+ if is_nil(candidate_url) do
+ emoji == candidate
+ else
+ url == candidate_url
+ end
+ end) do
nil ->
reactions
@@ -367,9 +398,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do
List.update_at(
reactions,
index,
- fn [emoji, users] -> [emoji, List.delete(users, actor)] end
+ fn [emoji, users, url] -> [emoji, List.delete(users, actor), url] end
)
- |> Enum.reject(fn [_, users] -> Enum.empty?(users) end)
+ |> Enum.reject(fn [_, users, _] -> Enum.empty?(users) end)
end
count = emoji_count(new_reactions)
@@ -377,11 +408,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
end
def get_cached_emoji_reactions(object) do
- if is_list(object.data["reactions"]) do
- object.data["reactions"]
- else
- []
- end
+ Object.get_emoji_reactions(object)
end
@spec add_like_to_object(Activity.t(), Object.t()) ::
@@ -489,17 +516,37 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def get_latest_reaction(internal_activity_id, %{ap_id: ap_id}, emoji) do
%{data: %{"object" => object_ap_id}} = Activity.get_by_id(internal_activity_id)
+ emoji = Pleroma.Emoji.maybe_quote(emoji)
"EmojiReact"
|> Activity.Queries.by_type()
|> where(actor: ^ap_id)
- |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
+ |> custom_emoji_discriminator(emoji)
|> Activity.Queries.by_object_id(object_ap_id)
|> order_by([activity], fragment("? desc nulls last", activity.id))
|> limit(1)
|> Repo.one()
end
+ defp custom_emoji_discriminator(query, emoji) do
+ if String.contains?(emoji, "@") do
+ stripped = Pleroma.Emoji.maybe_strip_name(emoji)
+ [name, domain] = String.split(stripped, "@")
+ domain_pattern = "%/" <> domain <> "/%"
+ emoji_pattern = Pleroma.Emoji.maybe_quote(name)
+
+ query
+ |> where([activity], fragment("?->>'content' = ?
+ AND EXISTS (
+ SELECT FROM jsonb_array_elements(?->'tag') elem
+ WHERE elem->>'id' ILIKE ?
+ )", activity.data, ^emoji_pattern, activity.data, ^domain_pattern))
+ else
+ query
+ |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
+ end
+ end
+
#### Announce-related helpers
@doc """
diff --git a/lib/pleroma/web/admin_api/controllers/frontend_controller.ex b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
index b4dbb82fe..9e2ed4aac 100644
--- a/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
@@ -18,13 +18,24 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
def index(conn, _params) do
installed = installed()
+ # FIrst get frontends from config,
+ # then add frontends that are installed but not in the config
frontends =
- [:frontends, :available]
- |> Config.get([])
+ Config.get([:frontends, :available], [])
|> Enum.map(fn {name, desc} ->
- Map.put(desc, "installed", name in installed)
+ desc
+ |> Map.put("installed", name in installed)
+ |> Map.put("installed_refs", installed_refs(name))
end)
+ frontends =
+ frontends ++
+ (installed
+ |> Enum.filter(fn n -> not Enum.any?(frontends, fn f -> f["name"] == n end) end)
+ |> Enum.map(fn name ->
+ %{"name" => name, "installed" => true, "installed_refs" => installed_refs(name)}
+ end))
+
render(conn, "index.json", frontends: frontends)
end
@@ -43,4 +54,12 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
[]
end
end
+
+ def installed_refs(name) do
+ if name in installed() do
+ File.ls!(Path.join(Pleroma.Frontend.dir(), name))
+ else
+ []
+ end
+ end
end
diff --git a/lib/pleroma/web/admin_api/views/frontend_view.ex b/lib/pleroma/web/admin_api/views/frontend_view.ex
index 0ca3d67cb..ae4016581 100644
--- a/lib/pleroma/web/admin_api/views/frontend_view.ex
+++ b/lib/pleroma/web/admin_api/views/frontend_view.ex
@@ -15,7 +15,8 @@ defmodule Pleroma.Web.AdminAPI.FrontendView do
git: frontend["git"],
build_url: frontend["build_url"],
ref: frontend["ref"],
- installed: frontend["installed"]
+ installed: frontend["installed"],
+ installed_refs: frontend["installed_refs"]
}
end
end
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
index cae4241ff..2d56dc643 100644
--- a/lib/pleroma/web/api_spec.ex
+++ b/lib/pleroma/web/api_spec.ex
@@ -95,7 +95,8 @@ defmodule Pleroma.Web.ApiSpec do
"Relays",
"Report managment",
"Status administration",
- "User administration"
+ "User administration",
+ "Announcement management"
]
},
%{"name" => "Applications", "tags" => ["Applications", "Push subscriptions"]},
@@ -110,10 +111,12 @@ defmodule Pleroma.Web.ApiSpec do
"Follow requests",
"Mascot",
"Markers",
- "Notifications"
+ "Notifications",
+ "Filters",
+ "Settings"
]
},
- %{"name" => "Instance", "tags" => ["Custom emojis"]},
+ %{"name" => "Instance", "tags" => ["Custom emojis", "Instance misc"]},
%{"name" => "Messaging", "tags" => ["Chats", "Conversations"]},
%{
"name" => "Statuses",
@@ -125,10 +128,21 @@ defmodule Pleroma.Web.ApiSpec do
"Retrieve status information",
"Scheduled statuses",
"Search",
- "Status actions"
+ "Status actions",
+ "Media attachments"
]
},
- %{"name" => "Miscellaneous", "tags" => ["Emoji packs", "Reports", "Suggestions"]}
+ %{
+ "name" => "Miscellaneous",
+ "tags" => [
+ "Emoji packs",
+ "Reports",
+ "Suggestions",
+ "Announcements",
+ "Remote interaction",
+ "Others"
+ ]
+ }
]
}
}
diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex
index aabe988f7..f2897a3a3 100644
--- a/lib/pleroma/web/api_spec/operations/account_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/account_operation.ex
@@ -452,7 +452,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
operationId: "AccountController.blocks",
description: "View your blocks. See also accounts/:id/{block,unblock}",
security: [%{"oAuth" => ["read:blocks"]}],
- parameters: pagination_params(),
+ parameters: [with_relationships_param() | pagination_params()],
responses: %{
200 => Operation.response("Accounts", "application/json", array_of_accounts())
}
@@ -461,7 +461,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
def lookup_operation do
%Operation{
- tags: ["Account lookup"],
+ tags: ["Retrieve account information"],
summary: "Find a user by nickname",
operationId: "AccountController.lookup",
parameters: [
diff --git a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
index 58a039e72..49850e5d2 100644
--- a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def index_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Retrieve a list of announcements",
operationId: "AdminAPI.AnnouncementController.index",
security: [%{"oAuth" => ["admin:read"]}],
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def show_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Display one announcement",
operationId: "AdminAPI.AnnouncementController.show",
security: [%{"oAuth" => ["admin:read"]}],
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def delete_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Delete one announcement",
operationId: "AdminAPI.AnnouncementController.delete",
security: [%{"oAuth" => ["admin:write"]}],
@@ -92,7 +92,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def create_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Create one announcement",
operationId: "AdminAPI.AnnouncementController.create",
security: [%{"oAuth" => ["admin:write"]}],
@@ -107,7 +107,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def change_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Change one announcement",
operationId: "AdminAPI.AnnouncementController.change",
security: [%{"oAuth" => ["admin:write"]}],
diff --git a/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex b/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
index 4bfe5ac5a..3e85c44d2 100644
--- a/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
@@ -51,8 +51,9 @@ defmodule Pleroma.Web.ApiSpec.Admin.FrontendOperation do
name: %Schema{type: :string},
git: %Schema{type: :string, format: :uri, nullable: true},
build_url: %Schema{type: :string, format: :uri, nullable: true},
- ref: %Schema{type: :string},
- installed: %Schema{type: :boolean}
+ ref: %Schema{type: :string, nullable: true},
+ installed: %Schema{type: :boolean},
+ installed_refs: %Schema{type: :array, items: %Schema{type: :string}}
}
}
}
diff --git a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
index 229912dd7..17383f1d0 100644
--- a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
@@ -70,7 +70,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def show_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Get status",
operationId: "AdminAPI.StatusController.show",
parameters: [id_param() | admin_api_params()],
@@ -84,7 +84,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def update_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Change the scope of a status",
operationId: "AdminAPI.StatusController.update",
parameters: [id_param() | admin_api_params()],
@@ -99,7 +99,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def delete_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Delete status",
operationId: "AdminAPI.StatusController.delete",
parameters: [id_param() | admin_api_params()],
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
}
},
tags: %Schema{type: :string},
- is_confirmed: %Schema{type: :string}
+ is_confirmed: %Schema{type: :boolean}
}
}
end
diff --git a/lib/pleroma/web/api_spec/operations/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/announcement_operation.ex
index 71be0002a..6f7031962 100644
--- a/lib/pleroma/web/api_spec/operations/announcement_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/announcement_operation.ex
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do
def index_operation do
%Operation{
- tags: ["Announcement"],
+ tags: ["Announcements"],
summary: "Retrieve a list of announcements",
operationId: "MastodonAPI.AnnouncementController.index",
security: [%{"oAuth" => []}],
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do
def mark_read_operation do
%Operation{
- tags: ["Announcement"],
+ tags: ["Announcements"],
summary: "Mark one announcement as read",
operationId: "MastodonAPI.AnnouncementController.mark_read",
security: [%{"oAuth" => ["write:accounts"]}],
diff --git a/lib/pleroma/web/api_spec/operations/directory_operation.ex b/lib/pleroma/web/api_spec/operations/directory_operation.ex
index 55752fa62..23fa84dff 100644
--- a/lib/pleroma/web/api_spec/operations/directory_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/directory_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.DirectoryOperation do
def index_operation do
%Operation{
- tags: ["Directory"],
+ tags: ["Others"],
summary: "Profile directory",
operationId: "DirectoryController.index",
parameters:
diff --git a/lib/pleroma/web/api_spec/operations/instance_operation.ex b/lib/pleroma/web/api_spec/operations/instance_operation.ex
index 3c4b504fe..a07be7e40 100644
--- a/lib/pleroma/web/api_spec/operations/instance_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/instance_operation.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
def show_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve instance information",
description: "Information about the server",
operationId: "InstanceController.show",
@@ -25,7 +25,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
def peers_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve list of known instances",
operationId: "InstanceController.peers",
responses: %{
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
index d09c1c10e..b05bad197 100644
--- a/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
@@ -133,7 +133,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiFileOperation do
defp files_object do
%Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Filename of the emoji",
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
+ },
description: "Object with emoji names as keys and filenames as values"
}
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
index 6add3ff33..efa36ffdc 100644
--- a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
@@ -227,13 +227,29 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
defp emoji_packs_response do
Operation.response(
- "Object with pack names as keys and pack contents as values",
+ "Emoji packs and the count",
"application/json",
%Schema{
type: :object,
- additionalProperties: emoji_pack(),
+ properties: %{
+ packs: %Schema{
+ type: :object,
+ description: "Object with pack names as keys and pack contents as values",
+ additionalProperties: %Schema{
+ emoji_pack()
+ | extensions: %{"x-additionalPropertiesName": "Pack name"}
+ }
+ },
+ count: %Schema{
+ type: :integer,
+ description: "Number of emoji packs"
+ }
+ },
example: %{
- "emojos" => emoji_pack().example
+ "packs" => %{
+ "emojos" => emoji_pack().example
+ },
+ "count" => 1
}
}
)
@@ -274,7 +290,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
defp files_object do
%Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Filename",
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
+ },
description: "Object with emoji names as keys and filenames as values"
}
end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
index 82db4e1a8..e9319f3fb 100644
--- a/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaInstancesOperation do
def show_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve federation status",
description: "Information about instances deemed unreachable by the server",
operationId: "PleromaInstances.show",
diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex
index e921128c7..5d6e82f3c 100644
--- a/lib/pleroma/web/api_spec/operations/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/status_operation.ex
@@ -440,7 +440,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def show_history_operation do
%Operation{
- tags: ["Retrieve status history"],
+ tags: ["Retrieve status information"],
summary: "Status history",
description: "View history of a status",
operationId: "StatusController.show_history",
@@ -457,7 +457,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def show_source_operation do
%Operation{
- tags: ["Retrieve status source"],
+ tags: ["Retrieve status information"],
summary: "Status source",
description: "View source of a status",
operationId: "StatusController.show_source",
@@ -474,7 +474,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def update_operation do
%Operation{
- tags: ["Update status"],
+ tags: ["Status actions"],
summary: "Update status",
description: "Change the content of a status",
operationId: "StatusController.update",
diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
index 29df03e34..084329ad7 100644
--- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def emoji_operation do
%Operation{
- tags: ["Emojis"],
+ tags: ["Custom emojis"],
summary: "List all custom emojis",
operationId: "UtilController.emoji",
parameters: [],
@@ -30,7 +30,8 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
properties: %{
image_url: %Schema{type: :string},
tags: %Schema{type: :array, items: %Schema{type: :string}}
- }
+ },
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
},
example: %{
"firefox" => %{
@@ -45,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def frontend_configurations_operation do
%Operation{
- tags: ["Configuration"],
+ tags: ["Others"],
summary: "Dump frontend configurations",
operationId: "UtilController.frontend_configurations",
parameters: [],
@@ -53,7 +54,12 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
200 =>
Operation.response("List", "application/json", %Schema{
type: :object,
- additionalProperties: %Schema{type: :object}
+ additionalProperties: %Schema{
+ type: :object,
+ description:
+ "Opaque object representing the instance-wide configuration for the frontend",
+ extensions: %{"x-additionalPropertiesName": "Frontend name"}
+ }
})
}
}
@@ -132,7 +138,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def update_notificaton_settings_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Settings"],
summary: "Update Notification Settings",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.update_notificaton_settings",
@@ -207,6 +213,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
%Operation{
summary: "Get a captcha",
operationId: "UtilController.captcha",
+ tags: ["Others"],
parameters: [],
responses: %{
200 => Operation.response("Success", "application/json", %Schema{type: :object})
@@ -356,7 +363,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def healthcheck_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Others"],
summary: "Quick status check on the instance",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.healthcheck",
@@ -371,7 +378,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def remote_subscribe_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Remote Subscribe",
operationId: "UtilController.remote_subscribe",
parameters: [],
@@ -381,7 +388,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def remote_interaction_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Remote interaction",
operationId: "UtilController.remote_interaction",
requestBody: request_body("Parameters", remote_interaction_request(), required: true),
@@ -407,7 +414,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def show_subscribe_form_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Show remote subscribe form",
operationId: "UtilController.show_subscribe_form",
parameters: [],
diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex
index 698f11794..bc29cf4a6 100644
--- a/lib/pleroma/web/api_spec/schemas/status.ex
+++ b/lib/pleroma/web/api_spec/schemas/status.ex
@@ -144,7 +144,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
properties: %{
content: %Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Alternate representation in the MIME type specified",
+ extensions: %{"x-additionalPropertiesName": "MIME type"}
+ },
description:
"A map consisting of alternate representations of the `content` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`"
},
@@ -195,7 +199,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
},
spoiler_text: %Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Alternate representation in the MIME type specified",
+ extensions: %{"x-additionalPropertiesName": "MIME type"}
+ },
description:
"A map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`."
},
diff --git a/lib/pleroma/web/api_spec/scopes/compiler.ex b/lib/pleroma/web/api_spec/scopes/compiler.ex
new file mode 100644
index 000000000..162edc9a3
--- /dev/null
+++ b/lib/pleroma/web/api_spec/scopes/compiler.ex
@@ -0,0 +1,82 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Scopes.Compiler do
+ defmacro __before_compile__(_env) do
+ strings = __MODULE__.extract_all_scopes()
+
+ quote do
+ def placeholder do
+ unquote do
+ Enum.map(
+ strings,
+ fn string ->
+ quote do
+ Pleroma.Web.Gettext.dgettext_noop(
+ "oauth_scopes",
+ unquote(string)
+ )
+ end
+ end
+ )
+ end
+ end
+ end
+ end
+
+ def extract_all_scopes do
+ extract_all_scopes_from(Pleroma.Web.ApiSpec.spec())
+ end
+
+ def extract_all_scopes_from(specs) do
+ specs.paths
+ |> Enum.reduce([], fn
+ {_path, %{} = path_item}, acc ->
+ extract_routes(path_item)
+ |> Enum.flat_map(fn operation -> process_operation(operation) end)
+ |> Kernel.++(acc)
+
+ {_, _}, acc ->
+ acc
+ end)
+ |> Enum.uniq()
+ end
+
+ defp extract_routes(path_item) do
+ path_item
+ |> Map.from_struct()
+ |> Enum.map(fn {_method, path_item} -> path_item end)
+ |> Enum.filter(fn
+ %OpenApiSpex.Operation{} = _operation -> true
+ _ -> false
+ end)
+ end
+
+ defp process_operation(operation) do
+ operation.security
+ |> Kernel.||([])
+ |> Enum.flat_map(fn
+ %{"oAuth" => scopes} -> process_scopes(scopes)
+ _ -> []
+ end)
+ end
+
+ defp process_scopes(scopes) do
+ scopes
+ |> Enum.flat_map(fn scope ->
+ process_scope(scope)
+ end)
+ end
+
+ def process_scope(scope) do
+ hierarchy = String.split(scope, ":")
+
+ {_, list} =
+ Enum.reduce(hierarchy, {"", []}, fn comp, {cur, list} ->
+ {cur <> comp <> ":", [cur <> comp | list]}
+ end)
+
+ list
+ end
+end
diff --git a/lib/pleroma/web/api_spec/scopes/translator.ex b/lib/pleroma/web/api_spec/scopes/translator.ex
new file mode 100644
index 000000000..54eea3593
--- /dev/null
+++ b/lib/pleroma/web/api_spec/scopes/translator.ex
@@ -0,0 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Scopes.Translator do
+ require Pleroma.Web.ApiSpec.Scopes.Compiler
+ require Pleroma.Web.Gettext
+
+ @before_compile Pleroma.Web.ApiSpec.Scopes.Compiler
+end
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index ff0814329..a93c97e1e 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -145,6 +145,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
when is_list(options) do
limits = Config.get([:instance, :poll_limits])
+ options = options |> Enum.uniq()
+
with :ok <- validate_poll_expiration(expires_in, limits),
:ok <- validate_poll_options_amount(options, limits),
:ok <- validate_poll_options_length(options, limits) do
@@ -180,10 +182,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
defp validate_poll_options_amount(options, %{max_options: max_options}) do
- if Enum.count(options) > max_options do
- {:error, "Poll can't contain more than #{max_options} options"}
- else
- :ok
+ cond do
+ Enum.count(options) < 2 ->
+ {:error, "Poll must contain at least 2 options"}
+
+ Enum.count(options) > max_options ->
+ {:error, "Poll can't contain more than #{max_options} options"}
+
+ true ->
+ :ok
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 ea6e593d9..c313a0e97 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -269,14 +269,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
defp normalize_fields_attributes(fields) do
- if Enum.all?(fields, &is_tuple/1) do
- Enum.map(fields, fn {_, v} -> v end)
- else
- Enum.map(fields, fn
- %{} = field -> %{"name" => field.name, "value" => field.value}
- field -> field
- end)
- end
+ if(Enum.all?(fields, &is_tuple/1), do: Enum.map(fields, fn {_, v} -> v end), else: fields)
+ |> Enum.map(fn
+ %{} = field -> %{"name" => field.name, "value" => field.value}
+ field -> field
+ end)
end
@doc "GET /api/v1/accounts/relationships"
@@ -543,7 +540,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
conn
|> add_link_headers(users)
- |> render("index.json", users: users, for: user, as: :user)
+ |> render("index.json",
+ users: users,
+ for: user,
+ as: :user,
+ embed_relationships: embed_relationships?(params)
+ )
end
@doc "GET /api/v1/accounts/lookup"
diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex
index abf7f29ab..efd2a0af6 100644
--- a/lib/pleroma/web/mastodon_api/views/instance_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex
@@ -92,6 +92,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
"safe_dm_mentions"
end,
"pleroma_emoji_reactions",
+ "pleroma_custom_emoji_reactions",
"pleroma_chat_messages",
if Config.get([:instance, :show_reactions]) do
"exposable_reactions"
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index b5b5b2376..2a51f3755 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -17,6 +17,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView
+ alias Pleroma.Web.MediaProxy
alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView
defp object_id_for(%{data: %{"object" => %{"id" => id}}}) when is_binary(id), do: id
@@ -145,7 +146,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
end
defp put_emoji(response, activity) do
- Map.put(response, :emoji, activity.data["content"])
+ response
+ |> Map.put(:emoji, activity.data["content"])
+ |> Map.put(:emoji_url, MediaProxy.url(Pleroma.Emoji.emoji_url(activity.data)))
end
defp put_chat_message(response, activity, reading_user, opts) do
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 0a8c98b44..dea22f9c2 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -334,14 +334,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
emoji_reactions =
- object.data
- |> Map.get("reactions", [])
+ object
+ |> Object.get_emoji_reactions()
|> EmojiReactionController.filter_allowed_users(
opts[:for],
Map.get(opts, :with_muted, false)
)
- |> Stream.map(fn {emoji, users} ->
- build_emoji_map(emoji, users, opts[:for])
+ |> Stream.map(fn {emoji, users, url} ->
+ build_emoji_map(emoji, users, url, opts[:for])
end)
|> Enum.to_list()
@@ -702,11 +702,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
end
- defp build_emoji_map(emoji, users, current_user) do
+ defp build_emoji_map(emoji, users, url, current_user) do
%{
- name: emoji,
+ name: Pleroma.Web.PleromaAPI.EmojiReactionView.emoji_name(emoji, url),
count: length(users),
- me: !!(current_user && current_user.ap_id in users)
+ url: MediaProxy.url(url),
+ me: !!(current_user && current_user.ap_id in users),
+ account_ids: Enum.map(users, fn user -> User.get_cached_by_ap_id(user).id end)
}
end
diff --git a/lib/pleroma/web/metadata/providers/rel_me.ex b/lib/pleroma/web/metadata/providers/rel_me.ex
index f0bee85c8..eabd8cb00 100644
--- a/lib/pleroma/web/metadata/providers/rel_me.ex
+++ b/lib/pleroma/web/metadata/providers/rel_me.ex
@@ -8,12 +8,20 @@ defmodule Pleroma.Web.Metadata.Providers.RelMe do
@impl Provider
def build_tags(%{user: user}) do
- bio_tree = Floki.parse_fragment!(user.bio)
+ profile_tree =
+ user.bio
+ |> append_fields_tag(user.fields)
+ |> Floki.parse_fragment!()
- (Floki.attribute(bio_tree, "link[rel~=me]", "href") ++
- Floki.attribute(bio_tree, "a[rel~=me]", "href"))
+ (Floki.attribute(profile_tree, "link[rel~=me]", "href") ++
+ Floki.attribute(profile_tree, "a[rel~=me]", "href"))
|> Enum.map(fn link ->
{:link, [rel: "me", href: link], []}
end)
end
+
+ defp append_fields_tag(bio, fields) do
+ fields
+ |> Enum.reduce(bio, fn %{"value" => v}, res -> res <> v end)
+ end
end
diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
index 78fd0b219..662cc15d6 100644
--- a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
@@ -28,8 +28,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do
with true <- Pleroma.Config.get([:instance, :show_reactions]),
%Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
- %Object{data: %{"reactions" => reactions}} when is_list(reactions) <-
- Object.normalize(activity, fetch: false) do
+ %Object{} = object <- Object.normalize(activity, fetch: false),
+ reactions <- Object.get_emoji_reactions(object) do
reactions =
reactions
|> filter(params)
@@ -50,29 +50,32 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
if not with_muted, do: User.cached_muted_users_ap_ids(user), else: []
end
- filter_emoji = fn emoji, users ->
+ filter_emoji = fn emoji, users, url ->
case Enum.reject(users, &(&1 in exclude_ap_ids)) do
[] -> nil
- users -> {emoji, users}
+ users -> {emoji, users, url}
end
end
reactions
|> Stream.map(fn
- [emoji, users] when is_list(users) -> filter_emoji.(emoji, users)
- {emoji, users} when is_list(users) -> filter_emoji.(emoji, users)
- _ -> nil
+ [emoji, users, url] when is_list(users) -> filter_emoji.(emoji, users, url)
end)
|> Stream.reject(&is_nil/1)
end
defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do
- Enum.filter(reactions, fn [e, _] -> e == emoji end)
+ 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
+ emoji =
+ emoji
+ |> Pleroma.Emoji.fully_qualify_emoji()
+ |> Pleroma.Emoji.maybe_quote()
+
with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do
activity = Activity.get_by_id(activity_id)
@@ -83,6 +86,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
end
def delete(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
+ emoji =
+ emoji
+ |> Pleroma.Emoji.fully_qualify_emoji()
+ |> Pleroma.Emoji.maybe_quote()
+
with {:ok, _activity} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji) do
activity = Activity.get_by_id(activity_id)
diff --git a/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
index 68ebd8292..6df4ab9d0 100644
--- a/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
+++ b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
@@ -7,17 +7,30 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionView do
alias Pleroma.Web.MastodonAPI.AccountView
+ def emoji_name(emoji, nil), do: emoji
+
+ def emoji_name(emoji, url) do
+ url = URI.parse(url)
+
+ if url.host == Pleroma.Web.Endpoint.host() do
+ emoji
+ else
+ "#{emoji}@#{url.host}"
+ end
+ end
+
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
+ def render("show.json", %{emoji_reaction: {emoji, user_ap_ids, url}, user: user}) do
users = fetch_users(user_ap_ids)
%{
- name: emoji,
+ name: emoji_name(emoji, url),
count: length(users),
accounts: render(AccountView, "index.json", users: users, for: user),
+ url: Pleroma.Web.MediaProxy.url(url),
me: !!(user && user.ap_id in user_ap_ids)
}
end
diff --git a/lib/pleroma/web/plugs/uploaded_media.ex b/lib/pleroma/web/plugs/uploaded_media.ex
index ad8143234..8b3bc9acb 100644
--- a/lib/pleroma/web/plugs/uploaded_media.ex
+++ b/lib/pleroma/web/plugs/uploaded_media.ex
@@ -35,9 +35,9 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
conn =
case fetch_query_params(conn) do
%{query_params: %{"name" => name}} = conn ->
- name = String.replace(name, "\"", "\\\"")
+ name = String.replace(name, ~s["], ~s[\\"])
- put_resp_header(conn, "content-disposition", "filename=\"#{name}\"")
+ put_resp_header(conn, "content-disposition", ~s[inline; filename="#{name}"])
conn ->
conn
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
index 73115e92a..7585c4d3e 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
@@ -8,7 +8,7 @@
<%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
<%= label @form, :"scope_#{scope}", String.capitalize(scope) %>
<%= if scope in @scopes && scope do %>
- <%= String.capitalize(scope) %>
+ <code><%= scope %></code> <%= :"Elixir.Gettext".dgettext(Gettext, "oauth_scopes", scope) %>
<% end %>
</div>
<% else %>