aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTusooa Zhu <tusooa@kazv.moe>2022-05-29 22:16:03 -0400
committerTusooa Zhu <tusooa@kazv.moe>2022-05-29 22:16:03 -0400
commit8acfe95f3e9d4183fd513cfe828500c852db4d5f (patch)
tree2be1783225d9500286164231c6db842e62d5cd3c
parent5e8aac0e07cf54d527643e9793b92f3c0b3826e2 (diff)
downloadpleroma-8acfe95f3e9d4183fd513cfe828500c852db4d5f.tar.gz
Allow updating polls
-rw-r--r--lib/pleroma/web/activity_pub/side_effects.ex81
-rw-r--r--test/pleroma/web/activity_pub/side_effects_test.exs64
2 files changed, 125 insertions, 20 deletions
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index c4d56fa20..ac327280c 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -443,14 +443,29 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
"attachment",
"generator"
]
- defp handle_update_object(
- %{data: %{"type" => "Update", "object" => updated_object}} = object,
- meta
- ) do
- orig_object = Object.get_by_ap_id(updated_object["id"])
- orig_object_data = orig_object.data
+ defp update_content_fields(orig_object_data, updated_object) do
+ @updatable_fields
+ |> Enum.reduce(
+ %{data: orig_object_data, updated: false},
+ fn field, %{data: data, updated: updated} ->
+ updated = updated or Map.get(updated_object, field) != Map.get(orig_object_data, field)
+
+ data =
+ if Map.has_key?(updated_object, field) do
+ Map.put(data, field, updated_object[field])
+ else
+ Map.drop(data, [field])
+ end
- if orig_object_data["type"] in @updatable_object_types do
+ %{data: data, updated: updated}
+ end
+ )
+ end
+
+ defp maybe_update_history(updated_object, orig_object_data, updated) do
+ if not updated do
+ updated_object
+ else
# Put edit history
# Note that we may have got the edit history by first fetching the object
history = history_for_object(orig_object_data)
@@ -464,19 +479,47 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|> Map.put("orderedItems", [latest_history_item | history["orderedItems"]])
|> Map.put("totalItems", history["totalItems"] + 1)
+ updated_object
+ |> Map.put("formerRepresentations", new_history)
+ end
+ end
+
+ defp maybe_update_poll(to_be_updated, updated_object) do
+ choice_key = fn data ->
+ if Map.has_key?(data, "anyOf"), do: "anyOf", else: "oneOf"
+ end
+
+ with true <- to_be_updated["type"] == "Question",
+ key <- choice_key.(updated_object),
+ true <- key == choice_key.(to_be_updated),
+ orig_choices <- to_be_updated[key] |> Enum.map(&Map.drop(&1, ["replies"])),
+ new_choices <- updated_object[key] |> Enum.map(&Map.drop(&1, ["replies"])),
+ true <- orig_choices == new_choices do
+ # Choices are the same, but counts are different
+ to_be_updated
+ |> Map.put(key, updated_object[key])
+ else
+ # Choices (or vote type) have changed, do not allow this
+ _ -> to_be_updated
+ end
+ end
+
+ defp handle_update_object(
+ %{data: %{"type" => "Update", "object" => updated_object}} = object,
+ meta
+ ) do
+ orig_object = Object.get_by_ap_id(updated_object["id"])
+ orig_object_data = orig_object.data
+
+ if orig_object_data["type"] in @updatable_object_types do
+ %{data: updated_object_data, updated: updated} =
+ orig_object_data
+ |> update_content_fields(updated_object)
+
updated_object_data =
- @updatable_fields
- |> Enum.reduce(
- orig_object_data,
- fn field, acc ->
- if Map.has_key?(updated_object, field) do
- Map.put(acc, field, updated_object[field])
- else
- Map.drop(acc, [field])
- end
- end
- )
- |> Map.put("formerRepresentations", new_history)
+ updated_object_data
+ |> maybe_update_history(orig_object_data, updated)
+ |> maybe_update_poll(updated_object)
orig_object
|> Object.change(%{data: updated_object_data})
diff --git a/test/pleroma/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs
index 5c60504d4..62394b058 100644
--- a/test/pleroma/web/activity_pub/side_effects_test.exs
+++ b/test/pleroma/web/activity_pub/side_effects_test.exs
@@ -178,15 +178,24 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
end
test "it puts the original note at the front of formerRepresentations", %{
+ user: user,
note: note,
object_id: object_id,
update: update
} do
{:ok, _, _} = SideEffects.handle(update)
%{data: first_edit} = Pleroma.Object.get_by_id(object_id)
+
+ second_updated_note =
+ note.data
+ |> Map.put("summary", "edited summary 2")
+ |> Map.put("content", "edited content 2")
+
+ {:ok, second_update_data, []} = Builder.update(user, second_updated_note)
+ {:ok, update, _meta} = ActivityPub.persist(second_update_data, local: true)
{:ok, _, _} = SideEffects.handle(update)
%{data: new_note} = Pleroma.Object.get_by_id(object_id)
- assert %{"summary" => "edited summary", "content" => "edited content"} = new_note
+ assert %{"summary" => "edited summary 2", "content" => "edited content 2"} = new_note
original_version = Map.drop(note.data, ["id", "formerRepresentations"])
first_edit = Map.drop(first_edit, ["id", "formerRepresentations"])
@@ -196,6 +205,59 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
assert new_note["formerRepresentations"]["totalItems"] == 2
end
+
+ test "it does not prepend to formerRepresentations if no actual changes are made", %{
+ note: note,
+ object_id: object_id,
+ update: update
+ } do
+ {:ok, _, _} = SideEffects.handle(update)
+ %{data: _first_edit} = Pleroma.Object.get_by_id(object_id)
+
+ {:ok, _, _} = SideEffects.handle(update)
+ %{data: new_note} = Pleroma.Object.get_by_id(object_id)
+ assert %{"summary" => "edited summary", "content" => "edited content"} = new_note
+
+ original_version = Map.drop(note.data, ["id", "formerRepresentations"])
+
+ assert [original_version] ==
+ new_note["formerRepresentations"]["orderedItems"]
+
+ assert new_note["formerRepresentations"]["totalItems"] == 1
+ end
+ end
+
+ describe "update questions" do
+ setup do
+ user = insert(:user)
+ question = insert(:question, user: user)
+
+ %{user: user, data: question.data, id: question.id}
+ end
+
+ test "allows updating choice count without generating edit history", %{
+ user: user,
+ data: data,
+ id: id
+ } do
+ new_choices =
+ data["oneOf"]
+ |> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end)
+
+ updated_question = data |> Map.put("oneOf", new_choices)
+
+ {:ok, update_data, []} = Builder.update(user, updated_question)
+ {:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
+
+ {:ok, _, _} = SideEffects.handle(update)
+
+ %{data: new_question} = Pleroma.Object.get_by_id(id)
+
+ assert [%{"replies" => %{"totalItems" => 5}}, %{"replies" => %{"totalItems" => 5}}] =
+ new_question["oneOf"]
+
+ refute Map.has_key?(new_question, "formerRepresentations")
+ end
end
describe "EmojiReact objects" do