transmogrifier: gracefully ignore duplicated object deletes
The object lookup is later repeated in the validator, but due to caching shouldn't incur any noticeable performance impact. It’s actually preferable to check here, since it avoids the otherwise occuring user lookup and overhead from starting and aborting a transaction
This commit is contained in:
parent
d7ab4d9b0b
commit
14bda007ae
2 changed files with 19 additions and 4 deletions
|
@ -216,6 +216,11 @@ def get_cached_by_ap_id(ap_id) do
|
|||
end
|
||||
end
|
||||
|
||||
# Intentionally accepts non-Object arguments!
|
||||
@spec is_tombstone_object?(term()) :: boolean()
|
||||
def is_tombstone_object?(%Object{data: %{"type" => "Tombstone"}}), do: true
|
||||
def is_tombstone_object?(_), do: false
|
||||
|
||||
def make_tombstone(%Object{data: %{"id" => id, "type" => type}}, deleted \\ DateTime.utc_now()) do
|
||||
%ObjectTombstone{
|
||||
id: id,
|
||||
|
|
|
@ -556,19 +556,29 @@ defp handle_incoming_normalised(
|
|||
%{"type" => "Delete"} = data,
|
||||
_options
|
||||
) do
|
||||
with {:ok, activity, _} <-
|
||||
Pipeline.common_pipeline(data, local: false) do
|
||||
oid_result = ObjectValidators.ObjectID.cast(data["object"])
|
||||
|
||||
with {_, {:ok, object_id}} <- {:object_id, oid_result},
|
||||
object <- Object.get_cached_by_ap_id(object_id),
|
||||
{_, false} <- {:tombstone, Object.is_tombstone_object?(object) && !data["actor"]},
|
||||
{:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:object_id, _} ->
|
||||
{:error, {:validate, "Invalid object id: #{data["object"]}"}}
|
||||
|
||||
{:tombstone, true} ->
|
||||
{:error, :ignore}
|
||||
|
||||
{:error, {:validate, {:error, %Ecto.Changeset{errors: errors}}}} = e ->
|
||||
if errors[:object] == {"can't find object", []} do
|
||||
# Check if we have a create activity for this
|
||||
# (e.g. from a db prune without --prune-activities)
|
||||
# We'd still like to process side effects so insert a tombstone and retry
|
||||
# We'd still like to process side effects so insert a fake tombstone and retry
|
||||
# (real tombstones from Object.delete do not have an actor field)
|
||||
with {:ok, object_id} <- ObjectValidators.ObjectID.cast(data["object"]),
|
||||
%Activity{data: %{"actor" => actor}} <-
|
||||
Activity.create_by_object_ap_id(object_id) |> Repo.one(),
|
||||
# We have one, insert a tombstone and retry
|
||||
{:ok, tombstone_data, _} <- Builder.tombstone(actor, object_id),
|
||||
{:ok, _tombstone} <- Object.create(tombstone_data) do
|
||||
handle_incoming(data)
|
||||
|
|
Loading…
Reference in a new issue