Create tombstone instead of object deletion
authorMaxim Filippov <colixer@gmail.com>
Sun, 23 Dec 2018 23:25:36 +0000 (02:25 +0300)
committerMaxim Filippov <colixer@gmail.com>
Sun, 23 Dec 2018 23:25:36 +0000 (02:25 +0300)
lib/pleroma/activity.ex
lib/pleroma/object.ex
lib/pleroma/web/common_api/utils.ex
test/activity_test.exs
test/user_test.exs
test/web/activity_pub/activity_pub_test.exs
test/web/activity_pub/transmogrifier_test.exs
test/web/mastodon_api/mastodon_api_controller_test.exs

index 200addd6ebdba96a600c4a46816dd7b7559bb421..0845233ee7109b93ad1ccfdafeb18b7c37d97c40 100644 (file)
@@ -1,7 +1,7 @@
 defmodule Pleroma.Activity do
   use Ecto.Schema
   alias Pleroma.{Repo, Activity, Notification}
-  import Ecto.Query
+  import Ecto.{Query, Changeset}
 
   # https://github.com/tootsuite/mastodon/blob/master/app/models/notification.rb#L19
   @mastodon_notification_types %{
@@ -103,4 +103,22 @@ defmodule Pleroma.Activity do
   end
 
   def mastodon_notification_type(%Activity{}), do: nil
+
+  def get_tombstone(%Activity{data: data}, deleted \\ DateTime.utc_now()) do
+    %{
+      id: data["id"],
+      context: data["context"],
+      type: "tombstone",
+      published: data["published"],
+      deleted: deleted
+    }
+  end
+
+  def swap_data_with_tombstone(activity) do
+    tombstone = get_tombstone(activity)
+
+    activity
+    |> change(%{data: tombstone})
+    |> Repo.update()
+  end
 end
index 31c8dd5bd13cba9913d322729b34621999da9d98..436cf6d5d994e940d35da565b989e2c45659b0c7 100644 (file)
@@ -62,9 +62,27 @@ defmodule Pleroma.Object do
     Object.change(%Object{}, %{data: %{"id" => context}})
   end
 
+  def get_tombstone(%Object{data: data}, deleted \\ DateTime.utc_now()) do
+    %{
+      id: data["id"],
+      type: "tombstone",
+      deleted: deleted
+    }
+  end
+
+  def swap_data_with_tombstone(object) do
+    tombstone = get_tombstone(object)
+
+    object
+    |> Object.change(%{data: tombstone})
+    |> Repo.update()
+  end
+
   def delete(%Object{data: %{"id" => id}} = object) do
-    with Repo.delete(object),
-         Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),
+    with swap_data_with_tombstone(object),
+         Activity.all_non_create_by_object_ap_id_q(id)
+         |> Repo.all()
+         |> Enum.each(&Activity.swap_data_with_tombstone/1),
          {:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do
       {:ok, object}
     end
index 142283684b4d176448edd7605c8bae7eb7b79b0f..d25fef6bce05a5b2091897cbb754e54ce47fe523 100644 (file)
@@ -69,7 +69,12 @@ defmodule Pleroma.Web.CommonAPI.Utils do
     mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)
 
     if inReplyTo do
-      {Enum.uniq([inReplyTo.data["actor"] | mentioned_users]), []}
+      to =
+        [inReplyTo.data["actor"] | mentioned_users]
+        |> Enum.uniq()
+        |> Enum.reject(&is_nil/1)
+
+      {to, []}
     else
       {mentioned_users, []}
     end
index 55849c5221b5c00a84afd53f572bacd72696a64f..87c9ddc50f5139707d6c4700e85268165bf2d80a 100644 (file)
@@ -1,5 +1,6 @@
 defmodule Pleroma.ActivityTest do
   use Pleroma.DataCase
+  alias Pleroma.Activity
   import Pleroma.Factory
 
   test "returns an activity by it's AP id" do
@@ -24,4 +25,28 @@ defmodule Pleroma.ActivityTest do
 
     assert activity == found_activity
   end
+
+  test "returns tombstone" do
+    activity = insert(:note_activity)
+    deleted = DateTime.utc_now()
+
+    assert Pleroma.Activity.get_tombstone(activity, deleted) == %{
+             id: activity.data["object"]["id"],
+             context: activity.data["context"],
+             type: "tombstone",
+             published: activity.data["published"],
+             deleted: deleted
+           }
+  end
+
+  test "swaps data with tombstone" do
+    activity = insert(:note_activity)
+
+    {:ok, deleted} = Pleroma.Activity.swap_data_with_tombstone(activity)
+    assert deleted.data.type == "tombstone"
+
+    found_activity = Repo.get(Activity, activity.id)
+
+    assert deleted.data.type == found_activity.data["type"]
+  end
 end
index b4d8174c67fdcfa560ab59e1394a503b03ec127d..43a3687ecbdec9a859ebd317e8c6d5e4bf46354b 100644 (file)
@@ -625,7 +625,7 @@ defmodule Pleroma.UserTest do
 
     # TODO: Remove favorites, repeats, delete activities.
 
-    refute Repo.get(Activity, activity.id)
+    assert Repo.get(Activity, activity.id).data["type"] == "tombstone"
   end
 
   test "get_public_key_for_ap_id fetches a user that's not in the db" do
index 470ed08b277980ba966da54f8b656fee107b0030..95731a868bcc5382afedf9151a3a952dbef4fe5e 100644 (file)
@@ -478,7 +478,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
       assert Repo.get(Activity, delete.id) != nil
 
-      assert Repo.get(Object, object.id) == nil
+      assert Repo.get(Object, object.id).data["type"] == "tombstone"
     end
   end
 
index 0428e052de9bdca5ccfeb55dae36fa5c3db66cec..18a5ad3d0e7896a8273b3dd7b06e1ef092c0b0e8 100644 (file)
@@ -363,7 +363,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
 
-      refute Repo.get(Activity, activity.id)
+      assert Repo.get(Activity, activity.id).data["type"] == "tombstone"
     end
 
     test "it fails for incoming deletes with spoofed origin" do
index aec0f851cf2717fe1ea35fc0a61553ef9acc44f7..6c6cc2a00eff62d0116ee0b7c4a50a57c4edf3d2 100644 (file)
@@ -292,7 +292,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       assert %{} = json_response(conn, 200)
 
-      assert Repo.get(Activity, activity.id) == nil
+      assert Repo.get(Activity, activity.id).data["type"] == "tombstone"
     end
 
     test "when you didn't create it", %{conn: conn} do