aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTusooa Zhu <tusooa@kazv.moe>2022-06-25 00:32:22 -0400
committerTusooa Zhu <tusooa@kazv.moe>2022-06-25 00:32:22 -0400
commit99a6f5031638da2eed237f91c6dded9e25717599 (patch)
treecb4cbdcdf7b5be34fda50642fe9600c98ba79eff
parente0d6da4e7d52e2cdd0fc5290e4ff3a23da7398f6 (diff)
downloadpleroma-99a6f5031638da2eed237f91c6dded9e25717599.tar.gz
Unify the logic of updating objects
-rw-r--r--lib/pleroma/object.ex42
-rw-r--r--lib/pleroma/object/fetcher.ex9
-rw-r--r--lib/pleroma/object/updater.ex157
-rw-r--r--lib/pleroma/web/activity_pub/side_effects.ex62
-rw-r--r--lib/pleroma/web/common_api.ex10
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex4
6 files changed, 183 insertions, 101 deletions
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 670ab8743..fe264b5e0 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -425,46 +425,4 @@ defmodule Pleroma.Object do
end
def object_data_hashtags(_), do: []
-
- def history_for(object) do
- with history <- Map.get(object, "formerRepresentations"),
- true <- is_map(history),
- "OrderedCollection" <- Map.get(history, "type"),
- true <- is_list(Map.get(history, "orderedItems")),
- true <- is_integer(Map.get(history, "totalItems")) do
- history
- else
- _ -> history_skeleton()
- end
- end
-
- defp history_skeleton do
- %{
- "type" => "OrderedCollection",
- "totalItems" => 0,
- "orderedItems" => []
- }
- end
-
- def 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 = Object.history_for(orig_object_data)
-
- latest_history_item =
- orig_object_data
- |> Map.drop(["id", "formerRepresentations"])
-
- new_history =
- history
- |> Map.put("orderedItems", [latest_history_item | history["orderedItems"]])
- |> Map.put("totalItems", history["totalItems"] + 1)
-
- updated_object
- |> Map.put("formerRepresentations", new_history)
- end
- end
end
diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index ce816c1fc..d81fdcf24 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -50,7 +50,14 @@ defmodule Pleroma.Object.Fetcher do
Pleroma.Constants.status_updatable_fields()
|> Enum.any?(fn field -> Map.get(old_data, field) != Map.get(new_data, field) end)
- new_data |> Object.maybe_update_history(old_data, changed?)
+ %{updated_object: updated_object} =
+ new_data
+ |> Object.Updater.maybe_update_history(old_data,
+ updated: changed?,
+ use_history_in_new_object?: false
+ )
+
+ updated_object
else
new_data
end
diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex
new file mode 100644
index 000000000..03136c38e
--- /dev/null
+++ b/lib/pleroma/object/updater.ex
@@ -0,0 +1,157 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Object.Updater do
+ require Pleroma.Constants
+
+ def update_content_fields(orig_object_data, updated_object) do
+ Pleroma.Constants.status_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
+
+ %{data: data, updated: updated}
+ end
+ )
+ end
+
+ def maybe_history(object) do
+ with history <- Map.get(object, "formerRepresentations"),
+ true <- is_map(history),
+ "OrderedCollection" <- Map.get(history, "type"),
+ true <- is_list(Map.get(history, "orderedItems")),
+ true <- is_integer(Map.get(history, "totalItems")) do
+ history
+ else
+ _ -> nil
+ end
+ end
+
+ def history_for(object) do
+ with history when not is_nil(history) <- maybe_history(object) do
+ history
+ else
+ _ -> history_skeleton()
+ end
+ end
+
+ defp history_skeleton do
+ %{
+ "type" => "OrderedCollection",
+ "totalItems" => 0,
+ "orderedItems" => []
+ }
+ end
+
+ def maybe_update_history(
+ updated_object,
+ orig_object_data,
+ opts
+ ) do
+ updated = opts[:updated]
+ use_history_in_new_object? = opts[:use_history_in_new_object?]
+
+ if not updated do
+ %{updated_object: updated_object, used_history_in_new_object?: false}
+ else
+ # Put edit history
+ # Note that we may have got the edit history by first fetching the object
+ {new_history, used_history_in_new_object?} =
+ with true <- use_history_in_new_object?,
+ updated_history when not is_nil(updated_history) <- maybe_history(updated_object) do
+ {updated_history, true}
+ else
+ _ ->
+ history = history_for(orig_object_data)
+
+ latest_history_item =
+ orig_object_data
+ |> Map.drop(["id", "formerRepresentations"])
+
+ updated_history =
+ history
+ |> Map.put("orderedItems", [latest_history_item | history["orderedItems"]])
+ |> Map.put("totalItems", history["totalItems"] + 1)
+
+ {updated_history, false}
+ end
+
+ updated_object =
+ updated_object
+ |> Map.put("formerRepresentations", new_history)
+
+ %{updated_object: updated_object, used_history_in_new_object?: used_history_in_new_object?}
+ 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
+
+ # This calculates the data to be sent as the object of an Update.
+ # new_data's formerRepresentations is not considered.
+ # formerRepresentations is added to the returned data.
+ def make_update_object_data(original_data, new_data, date) do
+ %{data: updated_data, updated: updated} =
+ original_data
+ |> update_content_fields(new_data)
+
+ if not updated do
+ updated_data
+ else
+ %{updated_object: updated_data} =
+ updated_data
+ |> maybe_update_history(original_data, updated: updated, use_history_in_new_object?: false)
+
+ updated_data
+ |> Map.put("updated", date)
+ end
+ end
+
+ # 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)
+
+ %{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?: false)
+
+ updated_data =
+ updated_data
+ |> maybe_update_poll(new_data)
+
+ %{
+ updated_data: updated_data,
+ updated: updated,
+ used_history_in_new_object?: used_history_in_new_object?
+ }
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index aa4183bf6..7345a6904 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -412,45 +412,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end
@updatable_object_types ["Note", "Question"]
- defp update_content_fields(orig_object_data, updated_object) do
- Pleroma.Constants.status_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
-
- %{data: data, updated: updated}
- 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
@@ -462,14 +423,11 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
updated_object = meta[: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
- |> Object.maybe_update_history(orig_object_data, updated)
- |> maybe_update_poll(updated_object)
+ %{
+ updated_data: updated_object_data,
+ updated: updated,
+ used_history_in_new_object?: used_history_in_new_object?
+ } = Object.Updater.make_new_object_data_from_update_object(orig_object_data, updated_object)
changeset =
orig_object
@@ -481,6 +439,16 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
{:ok, _} <- Object.set_cache(new_object),
# The metadata/utils.ex uses the object id for the cache.
{:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(new_object.id) do
+ if used_history_in_new_object? do
+ with create_activity when not is_nil(create_activity) <-
+ Pleroma.Activity.get_create_by_object_ap_id(orig_object_ap_id),
+ {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(create_activity.id) do
+ nil
+ else
+ _ -> nil
+ end
+ end
+
if updated do
object
|> Activity.normalize()
diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex
index e60c26053..e5a78c102 100644
--- a/lib/pleroma/web/common_api.ex
+++ b/lib/pleroma/web/common_api.ex
@@ -422,15 +422,7 @@ defmodule Pleroma.Web.CommonAPI do
with {:ok, draft} <- ActivityDraft.create(user, params) do
change =
- Pleroma.Constants.status_updatable_fields()
- |> Enum.reduce(orig_object.data, fn key, acc ->
- if Map.has_key?(draft.object, key) do
- acc |> Map.put(key, Map.get(draft.object, key))
- else
- acc |> Map.drop([key])
- end
- end)
- |> Map.put("updated", Utils.make_date())
+ Object.Updater.make_update_object_data(orig_object.data, draft.object, Utils.make_date())
{:ok, change}
else
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 8439431eb..54e025aae 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -274,7 +274,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
history_len =
1 +
- (Object.history_for(object.data)
+ (Object.Updater.history_for(object.data)
|> Map.get("orderedItems")
|> length())
@@ -413,7 +413,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
user = CommonAPI.get_user(activity.data["actor"])
past_history =
- Object.history_for(object.data)
+ Object.Updater.history_for(object.data)
|> Map.get("orderedItems")
|> Enum.map(&Map.put(&1, "id", object.data["id"]))
|> Enum.map(&%Object{data: &1, id: object.id})