Merge remote-tracking branch 'tusooa/from/upstream-develop/tusooa/edits' into emr_develop
This commit is contained in:
commit
6c86ad31ec
|
@ -10,7 +10,10 @@ defmodule Pleroma.Object.Updater do
|
|||
|> 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)
|
||||
updated =
|
||||
updated or
|
||||
(field != "updated" and
|
||||
Map.get(updated_object, field) != Map.get(orig_object_data, field))
|
||||
|
||||
data =
|
||||
if Map.has_key?(updated_object, field) do
|
||||
|
@ -136,21 +139,57 @@ defmodule Pleroma.Object.Updater do
|
|||
# This calculates the data of the new Object from an Update.
|
||||
# new_data's formerRepresentations is considered.
|
||||
def make_new_object_data_from_update_object(original_data, new_data) do
|
||||
%{data: updated_data, updated: updated} =
|
||||
original_data
|
||||
|> update_content_fields(new_data)
|
||||
update_is_reasonable =
|
||||
with {_, updated} when not is_nil(updated) <- {:cur_updated, new_data["updated"]},
|
||||
{_, {:ok, updated_time, _}} <- {:cur_updated, DateTime.from_iso8601(updated)},
|
||||
{_, last_updated} when not is_nil(last_updated) <-
|
||||
{:last_updated, original_data["updated"] || original_data["published"]},
|
||||
{_, {:ok, last_updated_time, _}} <-
|
||||
{:last_updated, DateTime.from_iso8601(last_updated)},
|
||||
:gt <- DateTime.compare(updated_time, last_updated_time) do
|
||||
:update_everything
|
||||
else
|
||||
# only allow poll updates
|
||||
{:cur_updated, _} -> :no_content_update
|
||||
:eq -> :no_content_update
|
||||
# allow all updates
|
||||
{:last_updated, _} -> :update_everything
|
||||
# allow no updates
|
||||
_ -> false
|
||||
end
|
||||
|
||||
%{updated_object: updated_data, used_history_in_new_object?: used_history_in_new_object?} =
|
||||
updated_data
|
||||
|> maybe_update_history(original_data,
|
||||
updated: updated,
|
||||
use_history_in_new_object?: true,
|
||||
new_data: new_data
|
||||
)
|
||||
%{
|
||||
updated_object: updated_data,
|
||||
used_history_in_new_object?: used_history_in_new_object?,
|
||||
updated: updated
|
||||
} =
|
||||
if update_is_reasonable == :update_everything do
|
||||
%{data: updated_data, updated: updated} =
|
||||
original_data
|
||||
|> update_content_fields(new_data)
|
||||
|
||||
updated_data
|
||||
|> maybe_update_history(original_data,
|
||||
updated: updated,
|
||||
use_history_in_new_object?: true,
|
||||
new_data: new_data
|
||||
)
|
||||
|> Map.put(:updated, updated)
|
||||
else
|
||||
%{
|
||||
updated_object: original_data,
|
||||
used_history_in_new_object?: false,
|
||||
updated: false
|
||||
}
|
||||
end
|
||||
|
||||
updated_data =
|
||||
updated_data
|
||||
|> maybe_update_poll(new_data)
|
||||
if update_is_reasonable != false do
|
||||
updated_data
|
||||
|> maybe_update_poll(new_data)
|
||||
else
|
||||
updated_data
|
||||
end
|
||||
|
||||
%{
|
||||
updated_data: updated_data,
|
||||
|
|
|
@ -103,8 +103,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
meta
|
||||
)
|
||||
when objtype in ~w[Question Answer Audio Video Event Article Note Page] do
|
||||
with {:ok, object_data} <- cast_and_apply(object),
|
||||
meta = Keyword.put(meta, :object_data, object_data |> stringify_keys),
|
||||
with {:ok, object_data} <- cast_and_apply_and_stringify_with_history(object),
|
||||
meta = Keyword.put(meta, :object_data, object_data),
|
||||
{:ok, create_activity} <-
|
||||
create_activity
|
||||
|> CreateGenericValidator.cast_and_validate(meta)
|
||||
|
@ -228,6 +228,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
|
||||
def validate(o, m), do: {:error, {:validator_not_set, {o, m}}}
|
||||
|
||||
def cast_and_apply_and_stringify_with_history(object) do
|
||||
do_separate_with_history(object, fn object ->
|
||||
with {:ok, object_data} <- cast_and_apply(object),
|
||||
object_data <- object_data |> stringify_keys() do
|
||||
{:ok, object_data}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
def cast_and_apply(%{"type" => "ChatMessage"} = object) do
|
||||
ChatMessageValidator.cast_and_apply(object)
|
||||
end
|
||||
|
|
|
@ -415,7 +415,14 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
|
||||
defp make_update_data(user, orig_object, changes) do
|
||||
kept_params = %{
|
||||
visibility: Visibility.get_visibility(orig_object)
|
||||
visibility: Visibility.get_visibility(orig_object),
|
||||
in_reply_to_id:
|
||||
with replied_id when is_binary(replied_id) <- orig_object.data["inReplyTo"],
|
||||
%Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(replied_id) do
|
||||
activity_id
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
}
|
||||
|
||||
params = Map.merge(changes, kept_params)
|
||||
|
|
|
@ -456,4 +456,84 @@ defmodule Pleroma.Object.FetcherTest do
|
|||
} = refetched.data
|
||||
end
|
||||
end
|
||||
|
||||
describe "fetch with history" do
|
||||
setup do
|
||||
object2 = %{
|
||||
"id" => "https://mastodon.social/2",
|
||||
"actor" => "https://mastodon.social/users/emelie",
|
||||
"attributedTo" => "https://mastodon.social/users/emelie",
|
||||
"type" => "Note",
|
||||
"content" => "test 2",
|
||||
"bcc" => [],
|
||||
"bto" => [],
|
||||
"cc" => ["https://mastodon.social/users/emelie/followers"],
|
||||
"to" => [],
|
||||
"summary" => "",
|
||||
"formerRepresentations" => %{
|
||||
"type" => "OrderedCollection",
|
||||
"orderedItems" => [
|
||||
%{
|
||||
"type" => "Note",
|
||||
"content" => "orig 2",
|
||||
"actor" => "https://mastodon.social/users/emelie",
|
||||
"attributedTo" => "https://mastodon.social/users/emelie",
|
||||
"bcc" => [],
|
||||
"bto" => [],
|
||||
"cc" => ["https://mastodon.social/users/emelie/followers"],
|
||||
"to" => [],
|
||||
"summary" => ""
|
||||
}
|
||||
],
|
||||
"totalItems" => 1
|
||||
}
|
||||
}
|
||||
|
||||
mock(fn
|
||||
%{
|
||||
method: :get,
|
||||
url: "https://mastodon.social/2"
|
||||
} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
headers: [{"content-type", "application/activity+json"}],
|
||||
body: Jason.encode!(object2)
|
||||
}
|
||||
|
||||
%{
|
||||
method: :get,
|
||||
url: "https://mastodon.social/users/emelie/collections/featured"
|
||||
} ->
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
headers: [{"content-type", "application/activity+json"}],
|
||||
body:
|
||||
Jason.encode!(%{
|
||||
"id" => "https://mastodon.social/users/emelie/collections/featured",
|
||||
"type" => "OrderedCollection",
|
||||
"actor" => "https://mastodon.social/users/emelie",
|
||||
"attributedTo" => "https://mastodon.social/users/emelie",
|
||||
"orderedItems" => [],
|
||||
"totalItems" => 0
|
||||
})
|
||||
}
|
||||
|
||||
env ->
|
||||
apply(HttpRequestMock, :request, [env])
|
||||
end)
|
||||
|
||||
%{object2: object2}
|
||||
end
|
||||
|
||||
test "it gets history", %{object2: object2} do
|
||||
{:ok, object} = Fetcher.fetch_object_from_id(object2["id"])
|
||||
|
||||
assert %{
|
||||
"formerRepresentations" => %{
|
||||
"type" => "OrderedCollection",
|
||||
"orderedItems" => [%{}]
|
||||
}
|
||||
} = object.data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -142,14 +142,19 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
|||
|
||||
describe "update notes" do
|
||||
setup do
|
||||
make_time = fn ->
|
||||
Pleroma.Web.ActivityPub.Utils.make_date()
|
||||
end
|
||||
|
||||
user = insert(:user)
|
||||
note = insert(:note, user: user)
|
||||
note = insert(:note, user: user, data: %{"published" => make_time.()})
|
||||
_note_activity = insert(:note_activity, note: note)
|
||||
|
||||
updated_note =
|
||||
note.data
|
||||
|> Map.put("summary", "edited summary")
|
||||
|> Map.put("content", "edited content")
|
||||
|> Map.put("updated", make_time.())
|
||||
|
||||
{:ok, update_data, []} = Builder.update(user, updated_note)
|
||||
{:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
|
||||
|
@ -170,8 +175,69 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
|||
updated_note: updated_note
|
||||
} do
|
||||
{:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
|
||||
updated_time = updated_note["updated"]
|
||||
|
||||
new_note = Pleroma.Object.get_by_id(object_id)
|
||||
assert %{"summary" => "edited summary", "content" => "edited content"} = new_note.data
|
||||
|
||||
assert %{
|
||||
"summary" => "edited summary",
|
||||
"content" => "edited content",
|
||||
"updated" => ^updated_time
|
||||
} = new_note.data
|
||||
end
|
||||
|
||||
test "it rejects updates with no updated attribute in object", %{
|
||||
object_id: object_id,
|
||||
update: update,
|
||||
updated_note: updated_note
|
||||
} do
|
||||
old_note = Pleroma.Object.get_by_id(object_id)
|
||||
updated_note = Map.drop(updated_note, ["updated"])
|
||||
{:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
|
||||
new_note = Pleroma.Object.get_by_id(object_id)
|
||||
assert old_note.data == new_note.data
|
||||
end
|
||||
|
||||
test "it rejects updates with updated attribute older than what we have in the original object",
|
||||
%{
|
||||
object_id: object_id,
|
||||
update: update,
|
||||
updated_note: updated_note
|
||||
} do
|
||||
old_note = Pleroma.Object.get_by_id(object_id)
|
||||
{:ok, creation_time, _} = DateTime.from_iso8601(old_note.data["published"])
|
||||
|
||||
updated_note =
|
||||
Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(creation_time, -10)))
|
||||
|
||||
{:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
|
||||
new_note = Pleroma.Object.get_by_id(object_id)
|
||||
assert old_note.data == new_note.data
|
||||
end
|
||||
|
||||
test "it rejects updates with updated attribute older than the last Update", %{
|
||||
object_id: object_id,
|
||||
update: update,
|
||||
updated_note: updated_note
|
||||
} do
|
||||
old_note = Pleroma.Object.get_by_id(object_id)
|
||||
{:ok, creation_time, _} = DateTime.from_iso8601(old_note.data["published"])
|
||||
|
||||
updated_note =
|
||||
Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(creation_time, +10)))
|
||||
|
||||
{:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
|
||||
|
||||
old_note = Pleroma.Object.get_by_id(object_id)
|
||||
{:ok, update_time, _} = DateTime.from_iso8601(old_note.data["updated"])
|
||||
|
||||
updated_note =
|
||||
Map.put(updated_note, "updated", DateTime.to_iso8601(DateTime.add(update_time, -5)))
|
||||
|
||||
{:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
|
||||
|
||||
new_note = Pleroma.Object.get_by_id(object_id)
|
||||
assert old_note.data == new_note.data
|
||||
end
|
||||
|
||||
test "it updates using object_data", %{
|
||||
|
@ -215,6 +281,14 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
|||
note.data
|
||||
|> Map.put("summary", "edited summary 2")
|
||||
|> Map.put("content", "edited content 2")
|
||||
|> Map.put(
|
||||
"updated",
|
||||
first_edit["updated"]
|
||||
|> DateTime.from_iso8601()
|
||||
|> elem(1)
|
||||
|> DateTime.add(10)
|
||||
|> DateTime.to_iso8601()
|
||||
)
|
||||
|
||||
{:ok, second_update_data, []} = Builder.update(user, second_updated_note)
|
||||
{:ok, update, _meta} = ActivityPub.persist(second_update_data, local: true)
|
||||
|
@ -238,7 +312,18 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
|||
updated_note: updated_note
|
||||
} do
|
||||
{:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
|
||||
%{data: _first_edit} = Pleroma.Object.get_by_id(object_id)
|
||||
%{data: first_edit} = Pleroma.Object.get_by_id(object_id)
|
||||
|
||||
updated_note =
|
||||
updated_note
|
||||
|> Map.put(
|
||||
"updated",
|
||||
first_edit["updated"]
|
||||
|> DateTime.from_iso8601()
|
||||
|> elem(1)
|
||||
|> DateTime.add(10)
|
||||
|> DateTime.to_iso8601()
|
||||
)
|
||||
|
||||
{:ok, _, _} = SideEffects.handle(update, object_data: updated_note)
|
||||
%{data: new_note} = Pleroma.Object.get_by_id(object_id)
|
||||
|
@ -256,7 +341,12 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
|||
describe "update questions" do
|
||||
setup do
|
||||
user = insert(:user)
|
||||
question = insert(:question, user: user)
|
||||
|
||||
question =
|
||||
insert(:question,
|
||||
user: user,
|
||||
data: %{"published" => Pleroma.Web.ActivityPub.Utils.make_date()}
|
||||
)
|
||||
|
||||
%{user: user, data: question.data, id: question.id}
|
||||
end
|
||||
|
@ -270,7 +360,63 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
|||
data["oneOf"]
|
||||
|> Enum.map(fn choice -> put_in(choice, ["replies", "totalItems"], 5) end)
|
||||
|
||||
updated_question = data |> Map.put("oneOf", new_choices)
|
||||
updated_question =
|
||||
data
|
||||
|> Map.put("oneOf", new_choices)
|
||||
|> Map.put("updated", Pleroma.Web.ActivityPub.Utils.make_date())
|
||||
|
||||
{:ok, update_data, []} = Builder.update(user, updated_question)
|
||||
{:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
|
||||
|
||||
{:ok, _, _} = SideEffects.handle(update, object_data: updated_question)
|
||||
|
||||
%{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
|
||||
|
||||
test "allows updating choice count without updated field", %{
|
||||
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, object_data: updated_question)
|
||||
|
||||
%{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
|
||||
|
||||
test "allows updating choice count with updated field same as the creation date", %{
|
||||
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)
|
||||
|> Map.put("updated", data["published"])
|
||||
|
||||
{:ok, update_data, []} = Builder.update(user, updated_question)
|
||||
{:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
|
||||
|
|
|
@ -1596,7 +1596,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
clear_config([:instance, :federating], true)
|
||||
|
||||
with_mock Pleroma.Web.Federator,
|
||||
publish: fn p -> nil end do
|
||||
publish: fn _p -> nil end do
|
||||
{:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2 :#{emoji2}:"})
|
||||
|
||||
assert updated.data["object"]["content"] == "updated 2 :#{emoji2}:"
|
||||
|
@ -1605,5 +1605,47 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
assert called(Pleroma.Web.Federator.publish(updated))
|
||||
end
|
||||
end
|
||||
|
||||
test "editing a post that copied a remote title with remote emoji should keep that emoji" do
|
||||
remote_emoji_uri = "https://remote.org/emoji.png"
|
||||
|
||||
note =
|
||||
insert(
|
||||
:note,
|
||||
data: %{
|
||||
"summary" => ":remoteemoji:",
|
||||
"emoji" => %{
|
||||
"remoteemoji" => remote_emoji_uri
|
||||
},
|
||||
"tag" => [
|
||||
%{
|
||||
"type" => "Emoji",
|
||||
"name" => "remoteemoji",
|
||||
"icon" => %{"url" => remote_emoji_uri}
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
note_activity = insert(:note_activity, note: note)
|
||||
|
||||
user = insert(:user)
|
||||
|
||||
{:ok, reply} =
|
||||
CommonAPI.post(user, %{
|
||||
status: "reply",
|
||||
spoiler_text: ":remoteemoji:",
|
||||
in_reply_to_id: note_activity.id
|
||||
})
|
||||
|
||||
assert reply.object.data["emoji"]["remoteemoji"] == remote_emoji_uri
|
||||
|
||||
{:ok, edit} =
|
||||
CommonAPI.update(user, reply, %{status: "reply mew mew", spoiler_text: ":remoteemoji:"})
|
||||
|
||||
edited_note = Pleroma.Object.normalize(edit)
|
||||
|
||||
assert edited_note.data["emoji"]["remoteemoji"] == remote_emoji_uri
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue