Emoji reactions: Change cache and reply format

This commit is contained in:
lain 2020-01-22 13:57:42 +01:00
parent 04c9ca5d68
commit dd3fc50ea4
6 changed files with 70 additions and 40 deletions

View file

@ -312,19 +312,12 @@ def make_emoji_reaction_data(user, object, emoji, activity_id) do
|> Map.put("content", emoji) |> Map.put("content", emoji)
end 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()} {: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 = length =
if is_map(element) do count ||
element length(element)
|> Map.values()
|> List.flatten()
|> length()
else
element
|> length()
end
data = data =
Map.merge( Map.merge(
@ -344,29 +337,52 @@ def add_emoji_reaction_to_object(
%Activity{data: %{"content" => emoji, "actor" => actor}}, %Activity{data: %{"content" => emoji, "actor" => actor}},
object object
) do ) do
reactions = object.data["reactions"] || %{} reactions = object.data["reactions"] || []
emoji_actors = reactions[emoji] || []
new_emoji_actors = [actor | emoji_actors] |> Enum.uniq() new_reactions =
new_reactions = Map.put(reactions, emoji, new_emoji_actors) case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
update_element_in_object("reaction", new_reactions, object) 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 end
def remove_emoji_reaction_from_object( def remove_emoji_reaction_from_object(
%Activity{data: %{"content" => emoji, "actor" => actor}}, %Activity{data: %{"content" => emoji, "actor" => actor}},
object object
) do ) do
reactions = object.data["reactions"] || %{} reactions = object.data["reactions"] || []
emoji_actors = reactions[emoji] || []
new_emoji_actors = List.delete(emoji_actors, actor)
new_reactions = new_reactions =
if new_emoji_actors == [] do case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
Map.delete(reactions, emoji) nil ->
else reactions
Map.put(reactions, emoji, new_emoji_actors)
index ->
List.update_at(
reactions,
index,
fn [emoji, users] -> [emoji, List.delete(users, actor)] end
)
|> Enum.reject(fn [_, users] -> Enum.empty?(users) end)
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 end
@spec add_like_to_object(Activity.t(), Object.t()) :: @spec add_like_to_object(Activity.t(), Object.t()) ::

View file

@ -255,12 +255,11 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
emoji_reactions = emoji_reactions =
with %{data: %{"reactions" => emoji_reactions}} <- object do with %{data: %{"reactions" => emoji_reactions}} <- object do
Enum.map(emoji_reactions, fn {emoji, users} -> Enum.map(emoji_reactions, fn [emoji, users] ->
{emoji, length(users)} [emoji, length(users)]
end) end)
|> Enum.into(%{})
else else
_ -> %{} _ -> []
end end
%{ %{

View file

@ -43,21 +43,21 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), 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 = reactions =
emoji_reactions emoji_reactions
|> Enum.map(fn {emoji, users} -> |> Enum.map(fn [emoji, users] ->
users = Enum.map(users, &User.get_cached_by_ap_id/1) users = Enum.map(users, &User.get_cached_by_ap_id/1)
{emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})} {emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})}
end) end)
|> Enum.into(%{})
conn conn
|> json(reactions) |> json(reactions)
else else
_e -> _e ->
conn conn
|> json(%{}) |> json([])
end end
end end

View file

@ -867,6 +867,8 @@ test "returns reblogs for users for whom reblogs have not been muted" do
test "adds an emoji reaction activity to the db" do test "adds an emoji reaction activity to the db" do
user = insert(:user) user = insert(:user)
reactor = insert(:user) reactor = insert(:user)
third_user = insert(:user)
fourth_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"}) {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
assert object = Object.normalize(activity) assert object = Object.normalize(activity)
@ -881,7 +883,21 @@ test "adds an emoji reaction activity to the db" do
assert reaction_activity.data["to"] == [User.ap_followers(reactor), activity.data["actor"]] assert reaction_activity.data["to"] == [User.ap_followers(reactor), activity.data["actor"]]
assert reaction_activity.data["context"] == object.data["context"] assert reaction_activity.data["context"] == object.data["context"]
assert object.data["reaction_count"] == 1 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
end end
@ -919,7 +935,7 @@ test "adds an undo activity to the db" do
object = Object.get_by_ap_id(object.data["id"]) object = Object.get_by_ap_id(object.data["id"])
assert object.data["reaction_count"] == 0 assert object.data["reaction_count"] == 0
assert object.data["reactions"] == %{} assert object.data["reactions"] == []
end end
end end

View file

@ -31,13 +31,12 @@ test "has an emoji reaction list" do
{:ok, activity} = CommonAPI.post(user, %{"status" => "dae cofe??"}) {:ok, activity} = CommonAPI.post(user, %{"status" => "dae cofe??"})
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, user, "") {: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, third_user, "🍵")
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "")
activity = Repo.get(Activity, activity.id) activity = Repo.get(Activity, activity.id)
status = StatusView.render("show.json", activity: activity) status = StatusView.render("show.json", activity: activity)
assert status[:pleroma][:emoji_reactions]["🍵"] == 1 assert status[:pleroma][:emoji_reactions] == [["", 2], ["🍵", 1]]
assert status[:pleroma][:emoji_reactions][""] == 2
end end
test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do
@ -189,7 +188,7 @@ test "a note activity" do
expires_at: nil, expires_at: nil,
direct_conversation_id: nil, direct_conversation_id: nil,
thread_muted: false, thread_muted: false,
emoji_reactions: %{} emoji_reactions: []
} }
} }

View file

@ -62,7 +62,7 @@ test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do
|> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")
|> json_response(200) |> json_response(200)
assert result == %{} assert result == []
{:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") {:ok, _, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
@ -71,7 +71,7 @@ test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do
|> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")
|> json_response(200) |> json_response(200)
[represented_user] = result["🎅"] [["🎅", [represented_user]]] = result
assert represented_user["id"] == other_user.id assert represented_user["id"] == other_user.id
end end