Allow updating polls
This commit is contained in:
parent
11c7cf3010
commit
c94b86683a
2 changed files with 125 additions and 20 deletions
|
@ -448,14 +448,29 @@ defp history_skeleton do
|
||||||
"attachment",
|
"attachment",
|
||||||
"generator"
|
"generator"
|
||||||
]
|
]
|
||||||
defp handle_update_object(
|
defp update_content_fields(orig_object_data, updated_object) do
|
||||||
%{data: %{"type" => "Update", "object" => updated_object}} = object,
|
@updatable_fields
|
||||||
meta
|
|> Enum.reduce(
|
||||||
) do
|
%{data: orig_object_data, updated: false},
|
||||||
orig_object = Object.get_by_ap_id(updated_object["id"])
|
fn field, %{data: data, updated: updated} ->
|
||||||
orig_object_data = orig_object.data
|
updated = updated or Map.get(updated_object, field) != Map.get(orig_object_data, field)
|
||||||
|
|
||||||
if orig_object_data["type"] in @updatable_object_types do
|
data =
|
||||||
|
if Map.has_key?(updated_object, field) do
|
||||||
|
Map.put(data, field, updated_object[field])
|
||||||
|
else
|
||||||
|
Map.drop(data, [field])
|
||||||
|
end
|
||||||
|
|
||||||
|
%{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
|
# Put edit history
|
||||||
# Note that we may have got the edit history by first fetching the object
|
# Note that we may have got the edit history by first fetching the object
|
||||||
history = history_for_object(orig_object_data)
|
history = history_for_object(orig_object_data)
|
||||||
|
@ -469,19 +484,47 @@ defp handle_update_object(
|
||||||
|> Map.put("orderedItems", [latest_history_item | history["orderedItems"]])
|
|> Map.put("orderedItems", [latest_history_item | history["orderedItems"]])
|
||||||
|> Map.put("totalItems", history["totalItems"] + 1)
|
|> 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 =
|
updated_object_data =
|
||||||
@updatable_fields
|
updated_object_data
|
||||||
|> Enum.reduce(
|
|> maybe_update_history(orig_object_data, updated)
|
||||||
orig_object_data,
|
|> maybe_update_poll(updated_object)
|
||||||
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)
|
|
||||||
|
|
||||||
orig_object
|
orig_object
|
||||||
|> Object.change(%{data: updated_object_data})
|
|> Object.change(%{data: updated_object_data})
|
||||||
|
|
|
@ -183,15 +183,24 @@ test "it records the original note in formerRepresentations", %{
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it puts the original note at the front of formerRepresentations", %{
|
test "it puts the original note at the front of formerRepresentations", %{
|
||||||
|
user: user,
|
||||||
note: note,
|
note: note,
|
||||||
object_id: object_id,
|
object_id: object_id,
|
||||||
update: update
|
update: update
|
||||||
} do
|
} do
|
||||||
{:ok, _, _} = SideEffects.handle(update)
|
{:ok, _, _} = SideEffects.handle(update)
|
||||||
%{data: first_edit} = Pleroma.Object.get_by_id(object_id)
|
%{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)
|
{:ok, _, _} = SideEffects.handle(update)
|
||||||
%{data: new_note} = Pleroma.Object.get_by_id(object_id)
|
%{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"])
|
original_version = Map.drop(note.data, ["id", "formerRepresentations"])
|
||||||
first_edit = Map.drop(first_edit, ["id", "formerRepresentations"])
|
first_edit = Map.drop(first_edit, ["id", "formerRepresentations"])
|
||||||
|
@ -201,6 +210,59 @@ test "it puts the original note at the front of formerRepresentations", %{
|
||||||
|
|
||||||
assert new_note["formerRepresentations"]["totalItems"] == 2
|
assert new_note["formerRepresentations"]["totalItems"] == 2
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
describe "EmojiReact objects" do
|
describe "EmojiReact objects" do
|
||||||
|
|
Loading…
Reference in a new issue