Merge branch 'feature/create-tombstone-instead-of-delete' into 'develop'
authorkaniini <nenolod@gmail.com>
Thu, 27 Dec 2018 19:37:55 +0000 (19:37 +0000)
committerkaniini <nenolod@gmail.com>
Thu, 27 Dec 2018 19:37:55 +0000 (19:37 +0000)
Create tombstone instead of object deletion

See merge request pleroma/pleroma!593

lib/pleroma/notification.ex
lib/pleroma/object.ex
lib/pleroma/object_tombstone.ex [new file with mode: 0644]
test/activity_test.exs
test/object_test.exs
test/web/activity_pub/activity_pub_test.exs
test/web/mastodon_api/mastodon_api_controller_test.exs
test/web/ostatus/incoming_documents/delete_handling_test.exs
test/web/ostatus/ostatus_controller_test.exs

index 301cfd1346d946f7ea0a370955531ae331f30873..b5aadfd17eee840293be7fffeb0f326b01ec5bd8 100644 (file)
@@ -80,9 +80,8 @@ defmodule Pleroma.Notification do
   end
 
   def clear(user) do
-    query = from(n in Notification, where: n.user_id == ^user.id)
-
-    Repo.delete_all(query)
+    from(n in Notification, where: n.user_id == ^user.id)
+    |> Repo.delete_all()
   end
 
   def dismiss(%{id: user_id} = _user, id) do
index cc4a2181a060c5d5c9e965bce9b4cebd34b5e4fc..e2b64872785dfca64084526243028e235951d97d 100644 (file)
@@ -4,7 +4,7 @@
 
 defmodule Pleroma.Object do
   use Ecto.Schema
-  alias Pleroma.{Repo, Object, User, Activity}
+  alias Pleroma.{Repo, Object, User, Activity, ObjectTombstone}
   import Ecto.{Query, Changeset}
 
   schema "objects" do
@@ -66,8 +66,25 @@ defmodule Pleroma.Object do
     Object.change(%Object{}, %{data: %{"id" => context}})
   end
 
+  def make_tombstone(%Object{data: %{"id" => id, "type" => type}}, deleted \\ DateTime.utc_now()) do
+    %ObjectTombstone{
+      id: id,
+      formerType: type,
+      deleted: deleted
+    }
+    |> Map.from_struct()
+  end
+
+  def swap_object_with_tombstone(object) do
+    tombstone = make_tombstone(object)
+
+    object
+    |> Object.change(%{data: tombstone})
+    |> Repo.update()
+  end
+
   def delete(%Object{data: %{"id" => id}} = object) do
-    with Repo.delete(object),
+    with {:ok, _obj} = swap_object_with_tombstone(object),
          Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),
          {:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do
       {:ok, object}
diff --git a/lib/pleroma/object_tombstone.ex b/lib/pleroma/object_tombstone.ex
new file mode 100644 (file)
index 0000000..64d836d
--- /dev/null
@@ -0,0 +1,4 @@
+defmodule Pleroma.ObjectTombstone do
+  @enforce_keys [:id, :formerType, :deleted]
+  defstruct [:id, :formerType, :deleted, type: "Tombstone"]
+end
index cf27fbbc50bf4e054675ee210c6136d709b3761a..36c718869cc5acde56ac301ec69066faba1e2bff 100644 (file)
@@ -4,18 +4,19 @@
 
 defmodule Pleroma.ActivityTest do
   use Pleroma.DataCase
+  alias Pleroma.Activity
   import Pleroma.Factory
 
   test "returns an activity by it's AP id" do
     activity = insert(:note_activity)
-    found_activity = Pleroma.Activity.get_by_ap_id(activity.data["id"])
+    found_activity = Activity.get_by_ap_id(activity.data["id"])
 
     assert activity == found_activity
   end
 
   test "returns activities by it's objects AP ids" do
     activity = insert(:note_activity)
-    [found_activity] = Pleroma.Activity.all_by_object_ap_id(activity.data["object"]["id"])
+    [found_activity] = Activity.all_by_object_ap_id(activity.data["object"]["id"])
 
     assert activity == found_activity
   end
@@ -23,8 +24,7 @@ defmodule Pleroma.ActivityTest do
   test "returns the activity that created an object" do
     activity = insert(:note_activity)
 
-    found_activity =
-      Pleroma.Activity.get_create_activity_by_object_ap_id(activity.data["object"]["id"])
+    found_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"]["id"])
 
     assert activity == found_activity
   end
index 0effb9505767d68b251b31f29b2423858184e3c9..72194975d7b25405bae21fedb1c7d9e93d0dedda 100644 (file)
@@ -36,6 +36,8 @@ defmodule Pleroma.ObjectTest do
       found_object = Object.get_by_ap_id(object.data["id"])
 
       refute object == found_object
+
+      assert found_object.data["type"] == "Tombstone"
     end
 
     test "ensures cache is cleared for the object" do
@@ -51,6 +53,8 @@ defmodule Pleroma.ObjectTest do
       cached_object = Object.get_cached_by_ap_id(object.data["id"])
 
       refute object == cached_object
+
+      assert cached_object.data["type"] == "Tombstone"
     end
   end
 end
index f7c66038d900d98f244aed36669c03d4684b5e5c..7bccd7500d91e913a166129871b4ba1e316ff6b8 100644 (file)
@@ -492,7 +492,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 1737a5ebe07fd65644ab14145264d5a818cf1e9e..0136acf8cdfcdfe5e12152c1075d5152be6ce020 100644 (file)
@@ -296,7 +296,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       assert %{} = json_response(conn, 200)
 
-      assert Repo.get(Activity, activity.id) == nil
+      refute Repo.get(Activity, activity.id)
     end
 
     test "when you didn't create it", %{conn: conn} do
index 1e041e5b091b026260159e0a65193f21d1d54274..c8fbff6cc7741e3298185ca551d1dbee0eac1cec 100644 (file)
@@ -25,7 +25,7 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
 
       refute Repo.get(Activity, note.id)
       refute Repo.get(Activity, like.id)
-      refute Object.get_by_ap_id(note.data["object"]["id"])
+      assert Object.get_by_ap_id(note.data["object"]["id"]).data["type"] == "Tombstone"
       assert Repo.get(Activity, second_note.id)
       assert Object.get_by_ap_id(second_note.data["object"]["id"])
 
index 6b535a1a9537b6691258a182e9560230885d7d88..995cc00d6359973393a0c1f6f5dd9a684d6d0498 100644 (file)
@@ -5,7 +5,7 @@
 defmodule Pleroma.Web.OStatus.OStatusControllerTest do
   use Pleroma.Web.ConnCase
   import Pleroma.Factory
-  alias Pleroma.{User, Repo}
+  alias Pleroma.{User, Repo, Object}
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.OStatus.ActivityRepresenter
 
@@ -114,6 +114,22 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
     |> response(404)
   end
 
+  test "404s on deleted objects", %{conn: conn} do
+    note_activity = insert(:note_activity)
+    [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["object"]["id"]))
+    object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+
+    conn
+    |> get("/objects/#{uuid}")
+    |> response(200)
+
+    Object.delete(object)
+
+    conn
+    |> get("/objects/#{uuid}")
+    |> response(404)
+  end
+
   test "gets an activity", %{conn: conn} do
     note_activity = insert(:note_activity)
     [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))