forked from AkkomaGang/akkoma
Allow reacting with remote emoji when they exist on the post (#200)
Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk> Reviewed-on: AkkomaGang/akkoma#200
This commit is contained in:
parent
7a90d71e8d
commit
1b826eea54
8 changed files with 211 additions and 47 deletions
|
@ -55,37 +55,84 @@ def follow(follower, followed) do
|
||||||
{:ok, data, []}
|
{:ok, data, []}
|
||||||
end
|
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
|
||||||
|
data
|
||||||
|
|> Map.put("content", Emoji.maybe_quote(emoji))
|
||||||
|
|> Map.put("type", "EmojiReact")
|
||||||
|
|> Map.put("tag", [
|
||||||
|
%{}
|
||||||
|
|> Map.put("id", url)
|
||||||
|
|> Map.put("type", "Emoji")
|
||||||
|
|> Map.put("name", Emoji.maybe_quote(emoji))
|
||||||
|
|> Map.put(
|
||||||
|
"icon",
|
||||||
|
%{}
|
||||||
|
|> Map.put("type", "Image")
|
||||||
|
|> Map.put("url", url)
|
||||||
|
)
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp remote_custom_emoji_react(
|
||||||
|
%{data: %{"reactions" => existing_reactions}} = object,
|
||||||
|
data,
|
||||||
|
emoji
|
||||||
|
) do
|
||||||
|
[emoji_code, instance] = String.split(Emoji.stripped_name(emoji), "@")
|
||||||
|
|
||||||
|
matching_reaction =
|
||||||
|
Enum.find(
|
||||||
|
existing_reactions,
|
||||||
|
fn [name, _, url] ->
|
||||||
|
url = URI.parse(url)
|
||||||
|
url.host == instance && name == emoji_code
|
||||||
|
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 %{} = emojo <- Emoji.get(emoji) do
|
||||||
|
path = emojo |> Map.get(:file)
|
||||||
|
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()}
|
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
|
||||||
def emoji_react(actor, object, emoji) do
|
def emoji_react(actor, object, emoji) do
|
||||||
with {:ok, data, meta} <- object_action(actor, object) do
|
with {:ok, data, meta} <- object_action(actor, object) do
|
||||||
data =
|
data =
|
||||||
if Emoji.is_unicode_emoji?(emoji) do
|
if Emoji.is_unicode_emoji?(emoji) do
|
||||||
data
|
unicode_emoji_react(object, data, emoji)
|
||||||
|> Map.put("content", emoji)
|
|
||||||
|> Map.put("type", "EmojiReact")
|
|
||||||
else
|
else
|
||||||
with %{} = emojo <- Emoji.get(emoji) do
|
custom_emoji_react(object, data, emoji)
|
||||||
path = emojo |> Map.get(:file)
|
|
||||||
url = "#{Endpoint.url()}#{path}"
|
|
||||||
|
|
||||||
data
|
|
||||||
|> Map.put("content", emoji)
|
|
||||||
|> Map.put("type", "EmojiReact")
|
|
||||||
|> Map.put("tag", [
|
|
||||||
%{}
|
|
||||||
|> Map.put("id", url)
|
|
||||||
|> Map.put("type", "Emoji")
|
|
||||||
|> Map.put("name", emojo.code)
|
|
||||||
|> Map.put(
|
|
||||||
"icon",
|
|
||||||
%{}
|
|
||||||
|> Map.put("type", "Image")
|
|
||||||
|> Map.put("url", url)
|
|
||||||
)
|
|
||||||
])
|
|
||||||
else
|
|
||||||
_ -> {:error, "Emoji does not exist"}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, data, meta}
|
{:ok, data, meta}
|
||||||
|
|
|
@ -13,7 +13,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
||||||
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
|
||||||
@primary_key false
|
@primary_key false
|
||||||
@emoji_regex ~r/:[A-Za-z0-9_-]+:/
|
@emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
quote do
|
quote do
|
||||||
|
|
|
@ -329,7 +329,7 @@ def add_emoji_reaction_to_object(
|
||||||
object
|
object
|
||||||
) do
|
) do
|
||||||
reactions = get_cached_emoji_reactions(object)
|
reactions = get_cached_emoji_reactions(object)
|
||||||
emoji = stripped_emoji_name(emoji)
|
emoji = Pleroma.Emoji.stripped_name(emoji)
|
||||||
url = emoji_url(emoji, activity)
|
url = emoji_url(emoji, activity)
|
||||||
|
|
||||||
new_reactions =
|
new_reactions =
|
||||||
|
@ -356,12 +356,6 @@ def add_emoji_reaction_to_object(
|
||||||
update_element_in_object("reaction", new_reactions, object, count)
|
update_element_in_object("reaction", new_reactions, object, count)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp stripped_emoji_name(name) do
|
|
||||||
name
|
|
||||||
|> String.replace_leading(":", "")
|
|
||||||
|> String.replace_trailing(":", "")
|
|
||||||
end
|
|
||||||
|
|
||||||
defp emoji_url(
|
defp emoji_url(
|
||||||
name,
|
name,
|
||||||
%Activity{
|
%Activity{
|
||||||
|
@ -384,7 +378,7 @@ def remove_emoji_reaction_from_object(
|
||||||
%Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
|
%Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
|
||||||
object
|
object
|
||||||
) do
|
) do
|
||||||
emoji = stripped_emoji_name(emoji)
|
emoji = Pleroma.Emoji.stripped_name(emoji)
|
||||||
reactions = get_cached_emoji_reactions(object)
|
reactions = get_cached_emoji_reactions(object)
|
||||||
url = emoji_url(emoji, activity)
|
url = emoji_url(emoji, activity)
|
||||||
|
|
||||||
|
@ -513,19 +507,37 @@ def fetch_latest_undo(%User{ap_id: ap_id}) do
|
||||||
|
|
||||||
def get_latest_reaction(internal_activity_id, %{ap_id: ap_id}, emoji) 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)
|
%{data: %{"object" => object_ap_id}} = Activity.get_by_id(internal_activity_id)
|
||||||
|
|
||||||
emoji = Pleroma.Emoji.maybe_quote(emoji)
|
emoji = Pleroma.Emoji.maybe_quote(emoji)
|
||||||
|
|
||||||
"EmojiReact"
|
"EmojiReact"
|
||||||
|> Activity.Queries.by_type()
|
|> Activity.Queries.by_type()
|
||||||
|> where(actor: ^ap_id)
|
|> where(actor: ^ap_id)
|
||||||
|> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
|
|> custom_emoji_discriminator(emoji)
|
||||||
|> Activity.Queries.by_object_id(object_ap_id)
|
|> Activity.Queries.by_object_id(object_ap_id)
|
||||||
|> order_by([activity], fragment("? desc nulls last", activity.id))
|
|> order_by([activity], fragment("? desc nulls last", activity.id))
|
||||||
|> limit(1)
|
|> limit(1)
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp custom_emoji_discriminator(query, emoji) do
|
||||||
|
if String.contains?(emoji, "@") do
|
||||||
|
stripped = Pleroma.Emoji.stripped_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
|
#### Announce-related helpers
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
|
|
@ -209,7 +209,8 @@ def react_with_emoji(id, user, emoji) do
|
||||||
{:ok, activity, _} <- Pipeline.common_pipeline(emoji_react, local: true) do
|
{:ok, activity, _} <- Pipeline.common_pipeline(emoji_react, local: true) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
_ -> {:error, dgettext("errors", "Could not add reaction emoji")}
|
_ ->
|
||||||
|
{:error, dgettext("errors", "Could not add reaction emoji")}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -587,7 +587,7 @@ defp pin_data(%Object{data: %{"id" => object_id}}, %User{pinned_objects: pinned_
|
||||||
|
|
||||||
defp build_emoji_map(emoji, users, url, 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),
|
count: length(users),
|
||||||
url: MediaProxy.url(url),
|
url: MediaProxy.url(url),
|
||||||
me: !!(current_user && current_user.ap_id in users),
|
me: !!(current_user && current_user.ap_id in users),
|
||||||
|
|
|
@ -74,7 +74,10 @@ defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do
|
||||||
defp filter(reactions, _), do: reactions
|
defp filter(reactions, _), do: reactions
|
||||||
|
|
||||||
def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
|
def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
|
||||||
emoji = Pleroma.Emoji.maybe_quote(emoji)
|
emoji =
|
||||||
|
emoji
|
||||||
|
|> Pleroma.Emoji.fully_qualify_emoji()
|
||||||
|
|> Pleroma.Emoji.maybe_quote()
|
||||||
|
|
||||||
with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do
|
with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do
|
||||||
activity = Activity.get_by_id(activity_id)
|
activity = Activity.get_by_id(activity_id)
|
||||||
|
@ -86,6 +89,11 @@ def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) d
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
|
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
|
with {:ok, _activity} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji) do
|
||||||
activity = Activity.get_by_id(activity_id)
|
activity = Activity.get_by_id(activity_id)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,18 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionView do
|
||||||
alias Pleroma.Web.MastodonAPI.AccountView
|
alias Pleroma.Web.MastodonAPI.AccountView
|
||||||
alias Pleroma.Web.MediaProxy
|
alias Pleroma.Web.MediaProxy
|
||||||
|
|
||||||
|
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
|
def render("index.json", %{emoji_reactions: emoji_reactions} = opts) do
|
||||||
render_many(emoji_reactions, __MODULE__, "show.json", opts)
|
render_many(emoji_reactions, __MODULE__, "show.json", opts)
|
||||||
end
|
end
|
||||||
|
@ -16,7 +28,7 @@ def render("show.json", %{emoji_reaction: {emoji, user_ap_ids, url}, user: user}
|
||||||
users = fetch_users(user_ap_ids)
|
users = fetch_users(user_ap_ids)
|
||||||
|
|
||||||
%{
|
%{
|
||||||
name: emoji,
|
name: emoji_name(emoji, url),
|
||||||
count: length(users),
|
count: length(users),
|
||||||
accounts: render(AccountView, "index.json", users: users, for: user),
|
accounts: render(AccountView, "index.json", users: users, for: user),
|
||||||
url: MediaProxy.url(url),
|
url: MediaProxy.url(url),
|
||||||
|
|
|
@ -17,22 +17,29 @@ test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
|
note = insert(:note, user: user, data: %{"reactions" => [["👍", [other_user.ap_id], nil]]})
|
||||||
|
activity = insert(:note_activity, note: note, user: user)
|
||||||
|
|
||||||
result =
|
result =
|
||||||
conn
|
conn
|
||||||
|> assign(:user, other_user)
|
|> assign(:user, other_user)
|
||||||
|> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
|
|> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
|
||||||
|> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕")
|
|> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/\u26A0")
|
||||||
|> json_response_and_validate_schema(200)
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
# We return the status, but this our implementation detail.
|
|
||||||
assert %{"id" => id} = result
|
assert %{"id" => id} = result
|
||||||
assert to_string(activity.id) == id
|
assert to_string(activity.id) == id
|
||||||
|
|
||||||
assert result["pleroma"]["emoji_reactions"] == [
|
assert result["pleroma"]["emoji_reactions"] == [
|
||||||
%{
|
%{
|
||||||
"name" => "☕",
|
"name" => "👍",
|
||||||
|
"count" => 1,
|
||||||
|
"me" => true,
|
||||||
|
"url" => nil,
|
||||||
|
"account_ids" => [other_user.id]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"name" => "\u26A0\uFE0F",
|
||||||
"count" => 1,
|
"count" => 1,
|
||||||
"me" => true,
|
"me" => true,
|
||||||
"url" => nil,
|
"url" => nil,
|
||||||
|
@ -43,6 +50,7 @@ test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
|
||||||
|
|
||||||
ObanHelpers.perform_all()
|
ObanHelpers.perform_all()
|
||||||
|
|
||||||
# Reacting with a custom emoji
|
# Reacting with a custom emoji
|
||||||
result =
|
result =
|
||||||
conn
|
conn
|
||||||
|
@ -51,7 +59,6 @@ test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
|
||||||
|> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:dinosaur:")
|
|> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:dinosaur:")
|
||||||
|> json_response_and_validate_schema(200)
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
# We return the status, but this our implementation detail.
|
|
||||||
assert %{"id" => id} = result
|
assert %{"id" => id} = result
|
||||||
assert to_string(activity.id) == id
|
assert to_string(activity.id) == id
|
||||||
|
|
||||||
|
@ -65,6 +72,46 @@ test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Reacting with a remote emoji
|
||||||
|
note =
|
||||||
|
insert(:note,
|
||||||
|
user: user,
|
||||||
|
data: %{"reactions" => [["wow", [other_user.ap_id], "https://remote/emoji/wow"]]}
|
||||||
|
)
|
||||||
|
|
||||||
|
activity = insert(:note_activity, note: note, user: user)
|
||||||
|
|
||||||
|
result =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:statuses"]))
|
||||||
|
|> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:wow@remote:")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert result["pleroma"]["emoji_reactions"] == [
|
||||||
|
%{
|
||||||
|
"name" => "wow@remote",
|
||||||
|
"count" => 2,
|
||||||
|
"me" => true,
|
||||||
|
"url" => "https://remote/emoji/wow",
|
||||||
|
"account_ids" => [user.id, other_user.id]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Reacting with a remote custom emoji that hasn't been reacted with yet
|
||||||
|
note =
|
||||||
|
insert(:note,
|
||||||
|
user: user
|
||||||
|
)
|
||||||
|
|
||||||
|
activity = insert(:note_activity, note: note, user: user)
|
||||||
|
|
||||||
|
assert conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:statuses"]))
|
||||||
|
|> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:wow@remote:")
|
||||||
|
|> json_response(400)
|
||||||
|
|
||||||
# Reacting with a non-emoji
|
# Reacting with a non-emoji
|
||||||
assert conn
|
assert conn
|
||||||
|> assign(:user, other_user)
|
|> assign(:user, other_user)
|
||||||
|
@ -77,10 +124,22 @@ test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
|
note =
|
||||||
|
insert(:note,
|
||||||
|
user: user,
|
||||||
|
data: %{"reactions" => [["wow", [user.ap_id], "https://remote/emoji/wow"]]}
|
||||||
|
)
|
||||||
|
|
||||||
|
activity = insert(:note_activity, note: note, user: user)
|
||||||
|
|
||||||
|
ObanHelpers.perform_all()
|
||||||
|
|
||||||
{:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
|
{:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
|
||||||
{:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, ":dinosaur:")
|
{:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, ":dinosaur:")
|
||||||
|
|
||||||
|
{:ok, _reaction_activity} =
|
||||||
|
CommonAPI.react_with_emoji(activity.id, other_user, ":wow@remote:")
|
||||||
|
|
||||||
ObanHelpers.perform_all()
|
ObanHelpers.perform_all()
|
||||||
|
|
||||||
result =
|
result =
|
||||||
|
@ -107,7 +166,32 @@ test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
|
||||||
|
|
||||||
object = Object.get_by_ap_id(activity.data["object"])
|
object = Object.get_by_ap_id(activity.data["object"])
|
||||||
|
|
||||||
assert object.data["reaction_count"] == 0
|
assert object.data["reaction_count"] == 2
|
||||||
|
|
||||||
|
# Remove custom remote emoji
|
||||||
|
result =
|
||||||
|
conn
|
||||||
|
|> assign(:user, other_user)
|
||||||
|
|> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
|
||||||
|
|> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/:wow@remote:")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
assert result["pleroma"]["emoji_reactions"] == [
|
||||||
|
%{
|
||||||
|
"name" => "wow@remote",
|
||||||
|
"count" => 1,
|
||||||
|
"me" => false,
|
||||||
|
"url" => "https://remote/emoji/wow",
|
||||||
|
"account_ids" => [user.id]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# Remove custom remote emoji that hasn't been reacted with yet
|
||||||
|
assert conn
|
||||||
|
|> assign(:user, other_user)
|
||||||
|
|> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
|
||||||
|
|> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/:zoop@remote:")
|
||||||
|
|> json_response(400)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do
|
test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do
|
||||||
|
|
Loading…
Reference in a new issue