Add unliking to activitypub.
authorRoger Braun <roger@rogerbraun.net>
Fri, 14 Apr 2017 16:08:47 +0000 (18:08 +0200)
committerRoger Braun <roger@rogerbraun.net>
Fri, 14 Apr 2017 16:09:30 +0000 (18:09 +0200)
TODO.txt
lib/pleroma/web/activity_pub/activity_pub.ex
test/support/factory.ex
test/web/activity_pub/activity_pub_test.exs

index 42501a6374f3ffd33b836bc5ad23db7e1b0a3c67..dd85c52392f0b001ff946b65a2e101579aad6410 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -1 +1,5 @@
 - Add cache for user fetching / representing. (mostly in TwitterAPI.activity_to_status)
+
+Unliking:
+
+- Add a proper undo activity, find out how to ignore those in twitter api.
index b9ba72b0d14cb467f232d02b51a5010c629fa37b..75de2e43c65625b2bce975ec471fdaab9ff6fcad 100644 (file)
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
       # There's already a like here, so return the original activity.
       ap_id in (object.data["likes"] || []) ->
         query = from activity in Activity,
-          where: fragment("? @> ?", activity.data, ^%{actor: ap_id, object: id})
+          where: fragment("? @> ?", activity.data, ^%{actor: ap_id, object: id, type: "Like"})
 
         activity = Repo.one(query)
         {:ok, activity, object}
@@ -47,17 +47,49 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
         changeset = Ecto.Changeset.change(object, data: new_data)
         {:ok, object} = Repo.update(changeset)
 
-        # Update activities that already had this. Could be done in a seperate process.
-        relevant_activities = Activity.all_by_object_ap_id(id)
-        Enum.map(relevant_activities, fn (activity) ->
-          new_activity_data = activity.data |> Map.put("object", new_data)
-          changeset = Ecto.Changeset.change(activity, data: new_activity_data)
-          Repo.update(changeset)
-        end)
+        update_object_in_activities(object)
+
         {:ok, activity, object}
     end
   end
 
+  defp update_object_in_activities(%{data: %{"id" => id}} = object) do
+    # Update activities that already had this. Could be done in a seperate process.
+    relevant_activities = Activity.all_by_object_ap_id(id)
+    Enum.map(relevant_activities, fn (activity) ->
+      new_activity_data = activity.data |> Map.put("object", object.data)
+      changeset = Ecto.Changeset.change(activity, data: new_activity_data)
+      Repo.update(changeset)
+    end)
+  end
+
+  def unlike(%User{ap_id: ap_id} = user, %Object{data: %{ "id" => id}} = object) do
+    query = from activity in Activity,
+      where: fragment("? @> ?", activity.data, ^%{actor: ap_id, object: id, type: "Like"})
+
+    activity = Repo.one(query)
+
+    if activity do
+      # just delete for now...
+      {:ok, _activity} = Repo.delete(activity)
+
+      likes = (object.data["likes"] || []) |> List.delete(ap_id)
+
+      new_data = object.data
+      |> Map.put("like_count", length(likes))
+      |> Map.put("likes", likes)
+
+      changeset = Ecto.Changeset.change(object, data: new_data)
+      {:ok, object} = Repo.update(changeset)
+
+      update_object_in_activities(object)
+
+      {:ok, object}
+    else
+      {:ok, object}
+    end
+  end
+
   def generate_activity_id do
     generate_id("activities")
   end
index af8e58bd1a6bdf23d39c084a775625c180c97b3f..3fc9cf710e5b8b117329b229ff38f3fc89e8bb09 100644 (file)
@@ -22,7 +22,9 @@ defmodule Pleroma.Factory do
       "id" => Pleroma.Web.ActivityPub.ActivityPub.generate_object_id,
       "actor" => user.ap_id,
       "to" => ["https://www.w3.org/ns/activitystreams#Public"],
-      "published_at" => DateTime.utc_now() |> DateTime.to_iso8601
+      "published_at" => DateTime.utc_now() |> DateTime.to_iso8601,
+      "likes" => [],
+      "like_count" => 0
     }
 
     %Pleroma.Object{
index 5701204840330f70076729e2dcd47b17c9a7ee7a..203dcaec29fc6ef4ed7b2e97d4aa6d36bb4a19e7 100644 (file)
@@ -142,6 +142,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     end
   end
 
+  describe "unliking" do
+    test "unliking a previously liked object" do
+      note_activity = insert(:note_activity)
+      object = Object.get_by_ap_id(note_activity.data["object"]["id"])
+      user = insert(:user)
+
+      # Unliking something that hasn't been liked does nothing
+      {:ok, object} = ActivityPub.unlike(user, object)
+      assert object.data["like_count"] == 0
+
+      {:ok, like_activity, object} = ActivityPub.like(user, object)
+      assert object.data["like_count"] == 1
+
+      {:ok, object} = ActivityPub.unlike(user, object)
+      assert object.data["like_count"] == 0
+
+      assert Repo.get(Activity, like_activity.id) == nil
+    end
+  end
+
   describe "uploading files" do
     test "copies the file to the configured folder" do
       file = %Plug.Upload{content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg"}