@@ -312,19 +312,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do | |||
|> Map.put("content", emoji) | |||
end | |||
@spec update_element_in_object(String.t(), list(any), Object.t()) :: | |||
@spec update_element_in_object(String.t(), list(any), Object.t(), integer() | nil) :: | |||
{:ok, Object.t()} | {:error, Ecto.Changeset.t()} | |||
def update_element_in_object(property, element, object) do | |||
def update_element_in_object(property, element, object, count \\ nil) do | |||
length = | |||
if is_map(element) do | |||
element | |||
|> Map.values() | |||
|> List.flatten() | |||
|> length() | |||
else | |||
element | |||
|> length() | |||
end | |||
count || | |||
length(element) | |||
data = | |||
Map.merge( | |||
@@ -344,29 +337,52 @@ defmodule Pleroma.Web.ActivityPub.Utils do | |||
%Activity{data: %{"content" => emoji, "actor" => actor}}, | |||
object | |||
) do | |||
reactions = object.data["reactions"] || %{} | |||
emoji_actors = reactions[emoji] || [] | |||
new_emoji_actors = [actor | emoji_actors] |> Enum.uniq() | |||
new_reactions = Map.put(reactions, emoji, new_emoji_actors) | |||
update_element_in_object("reaction", new_reactions, object) | |||
reactions = object.data["reactions"] || [] | |||
new_reactions = | |||
case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do | |||
nil -> | |||
reactions ++ [[emoji, [actor]]] | |||
index -> | |||
List.update_at( | |||
reactions, | |||
index, | |||
fn [emoji, users] -> [emoji, Enum.uniq([actor | users])] end | |||
) | |||
end | |||
count = emoji_count(new_reactions) | |||
update_element_in_object("reaction", new_reactions, object, count) | |||
end | |||
def emoji_count(reactions_list) do | |||
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}}, | |||
object | |||
) do | |||
reactions = object.data["reactions"] || %{} | |||
emoji_actors = reactions[emoji] || [] | |||
new_emoji_actors = List.delete(emoji_actors, actor) | |||
reactions = object.data["reactions"] || [] | |||
new_reactions = | |||
if new_emoji_actors == [] do | |||
Map.delete(reactions, emoji) | |||
else | |||
Map.put(reactions, emoji, new_emoji_actors) | |||
case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do | |||
nil -> | |||
reactions | |||
index -> | |||
List.update_at( | |||
reactions, | |||
index, | |||
fn [emoji, users] -> [emoji, List.delete(users, actor)] end | |||
) | |||
|> Enum.reject(fn [_, users] -> Enum.empty?(users) end) | |||
end | |||
update_element_in_object("reaction", new_reactions, object) | |||
count = emoji_count(new_reactions) | |||
update_element_in_object("reaction", new_reactions, object, count) | |||
end | |||
@spec add_like_to_object(Activity.t(), Object.t()) :: | |||
@@ -255,12 +255,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do | |||
emoji_reactions = | |||
with %{data: %{"reactions" => emoji_reactions}} <- object do | |||
Enum.map(emoji_reactions, fn {emoji, users} -> | |||
{emoji, length(users)} | |||
Enum.map(emoji_reactions, fn [emoji, users] -> | |||
[emoji, length(users)] | |||
end) | |||
|> Enum.into(%{}) | |||
else | |||
_ -> %{} | |||
_ -> [] | |||
end | |||
%{ | |||
@@ -43,21 +43,21 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do | |||
def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do | |||
with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), | |||
%Object{data: %{"reactions" => emoji_reactions}} <- Object.normalize(activity) do | |||
%Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <- | |||
Object.normalize(activity) do | |||
reactions = | |||
emoji_reactions | |||
|> Enum.map(fn {emoji, users} -> | |||
|> Enum.map(fn [emoji, users] -> | |||
users = Enum.map(users, &User.get_cached_by_ap_id/1) | |||
{emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})} | |||
end) | |||
|> Enum.into(%{}) | |||
conn | |||
|> json(reactions) | |||
else | |||
_e -> | |||
conn | |||
|> json(%{}) | |||
|> json([]) | |||
end | |||
end | |||
@@ -867,6 +867,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do | |||
test "adds an emoji reaction activity to the db" do | |||
user = insert(:user) | |||
reactor = insert(:user) | |||
third_user = insert(:user) | |||
fourth_user = insert(:user) | |||
{:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"}) | |||
assert object = Object.normalize(activity) | |||
@@ -881,7 +883,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do | |||
assert reaction_activity.data["to"] == [User.ap_followers(reactor), activity.data["actor"]] | |||
assert reaction_activity.data["context"] == object.data["context"] | |||
assert object.data["reaction_count"] == 1 | |||
assert object.data["reactions"]["🔥"] == [reactor.ap_id] | |||
assert object.data["reactions"] == [["🔥", [reactor.ap_id]]] | |||
{:ok, _reaction_activity, object} = ActivityPub.react_with_emoji(third_user, object, "☕") | |||
assert object.data["reaction_count"] == 2 | |||
assert object.data["reactions"] == [["🔥", [reactor.ap_id]], ["☕", [third_user.ap_id]]] | |||
{:ok, _reaction_activity, object} = ActivityPub.react_with_emoji(fourth_user, object, "🔥") | |||
assert object.data["reaction_count"] == 3 | |||
assert object.data["reactions"] == [ | |||
["🔥", [fourth_user.ap_id, reactor.ap_id]], | |||
["☕", [third_user.ap_id]] | |||
] | |||
end | |||
end | |||
@@ -919,7 +935,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do | |||
object = Object.get_by_ap_id(object.data["id"]) | |||
assert object.data["reaction_count"] == 0 | |||
assert object.data["reactions"] == %{} | |||
assert object.data["reactions"] == [] | |||
end | |||
end | |||
@@ -31,13 +31,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do | |||
{:ok, activity} = CommonAPI.post(user, %{"status" => "dae cofe??"}) | |||
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, user, "☕") | |||
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") | |||
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵") | |||
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") | |||
activity = Repo.get(Activity, activity.id) | |||
status = StatusView.render("show.json", activity: activity) | |||
assert status[:pleroma][:emoji_reactions]["🍵"] == 1 | |||
assert status[:pleroma][:emoji_reactions]["☕"] == 2 | |||
assert status[:pleroma][:emoji_reactions] == [["☕", 2], ["🍵", 1]] | |||
end | |||
test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do | |||
@@ -189,7 +188,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do | |||
expires_at: nil, | |||
direct_conversation_id: nil, | |||
thread_muted: false, | |||
emoji_reactions: %{} | |||
emoji_reactions: [] | |||
} | |||
} | |||
@@ -62,7 +62,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do | |||
|> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") | |||
|> json_response(200) | |||
assert result == %{} | |||
assert result == [] | |||
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") | |||
@@ -71,7 +71,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do | |||
|> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") | |||
|> json_response(200) | |||
[represented_user] = result["🎅"] | |||
[["🎅", [represented_user]]] = result | |||
assert represented_user["id"] == other_user.id | |||
end | |||