Favorite changes.
authorRoger Braun <roger@rogerbraun.net>
Fri, 14 Apr 2017 13:07:24 +0000 (15:07 +0200)
committerRoger Braun <roger@rogerbraun.net>
Fri, 14 Apr 2017 13:07:24 +0000 (15:07 +0200)
- Add 'likes' to activity, collection of ids of people who liked it.
- show if you favorited something or not.
- Don't allow double favorites
- Address favorites to the followers of the liked activity's author.

TODO.txt
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/twitter_api/representers/activity_representer.ex
test/web/activity_pub/activity_pub_test.exs
test/web/twitter_api/representers/activity_representer_test.exs

index 78cb92e2c757db1acf3291526ba3b695912d5b7d..42501a6374f3ffd33b836bc5ad23db7e1b0a3c67 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,8 +1 @@
 - Add cache for user fetching / representing. (mostly in TwitterAPI.activity_to_status)
-
-Favorites:
-- Add 'likes' to activity, collection of ids of people who liked it.
-- show if you favorited something or not.
-- Don't allow double favorites
-- Address favorites to the followers of the liked activity's author.
-
index 10efa2c9d4ad902709ba42c4e1800684e07e1463..b9ba72b0d14cb467f232d02b51a5010c629fa37b 100644 (file)
@@ -19,28 +19,43 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     Repo.insert(%Activity{data: map})
   end
 
-  def like(%User{ap_id: ap_id}, object = %Object{data: %{ "id" => id}}) do
-    data = %{
-      "type" => "Like",
-      "actor" => ap_id,
-      "object" => id
-    }
-
-    {:ok, activity} = insert(data)
-    like_count = (object.data["like_count"] || 0) + 1
-    new_data = object.data |> Map.put("like_count", like_count)
-    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)
-
-    {:ok, activity, object}
+  def like(%User{ap_id: ap_id} = user, %Object{data: %{ "id" => id}} = object) do
+    cond 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})
+
+        activity = Repo.one(query)
+        {:ok, activity, object}
+      true ->
+        data = %{
+          "type" => "Like",
+          "actor" => ap_id,
+          "object" => id,
+          "to" => [User.ap_followers(user)]
+        }
+
+        {:ok, activity} = insert(data)
+
+        likes = [ap_id | (object.data["likes"] || [])] |> Enum.uniq
+
+        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 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)
+        {:ok, activity, object}
+    end
   end
 
   def generate_activity_id do
index ed86559057be31b353896e6abda799c908ca101c..e69a63e1de8b4d55a2f097aaa9fbe6f5f9d2e49f 100644 (file)
@@ -45,6 +45,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
     created_at = get_in(activity.data, ["object", "published"])
     |> date_to_asctime
     like_count = get_in(activity.data, ["object", "like_count"]) || 0
+    favorited = opts[:for] && opts[:for].ap_id in (activity.data["object"]["likes"] || [])
 
     mentions = opts[:mentioned] || []
 
@@ -66,7 +67,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
       "statusnet_conversation_id" => activity.data["object"]["statusnetConversationId"],
       "attachments" => (activity.data["object"]["attachment"] || []) |> ObjectRepresenter.enum_to_list(opts),
       "attentions" => attentions,
-      "fave_num" => like_count
+      "fave_num" => like_count,
+      "favorited" => !!favorited
     }
   end
 
index 2bdd439b022e9ec0d8eb10f94b289b5205cb1a41..5701204840330f70076729e2dcd47b17c9a7ee7a 100644 (file)
@@ -1,7 +1,7 @@
 defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
   use Pleroma.DataCase
   alias Pleroma.Web.ActivityPub.ActivityPub
-  alias Pleroma.{Activity, Object}
+  alias Pleroma.{Activity, Object, User}
   alias Pleroma.Builders.ActivityBuilder
 
   import Pleroma.Factory
@@ -124,7 +124,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert like_activity.data["actor"] == user.ap_id
       assert like_activity.data["type"] == "Like"
       assert like_activity.data["object"] == object.data["id"]
+      assert like_activity.data["to"] == [User.ap_followers(user)]
       assert object.data["like_count"] == 1
+      assert object.data["likes"] == [user.ap_id]
+
+      # Just return the original activity if the user already liked it.
+      {:ok, same_like_activity, object} = ActivityPub.like(user, object)
+
+      assert like_activity == same_like_activity
+      assert object.data["likes"] == [user.ap_id]
 
       [note_activity] = Activity.all_by_object_ap_id(object.data["id"])
       assert note_activity.data["object"]["like_count"] == 1
index 5673c1f0ddbc0a1fde007937eaec76bd9285af81..d1f9e00c8c7b2cf8d1ed8497c6d34728b5764e2e 100644 (file)
@@ -11,11 +11,16 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
     note_activity = insert(:note_activity)
     object = Object.get_by_ap_id(note_activity.data["object"]["id"])
 
-    {:ok, like_activity, object} = ActivityPub.like(user, object)
+    {:ok, like_activity, _object} = ActivityPub.like(user, object)
     status = ActivityRepresenter.to_map(like_activity, %{user: user, liked_activity: note_activity})
 
     assert status["id"] == like_activity.id
     assert status["in_reply_to_status_id"] == note_activity.id
+
+    note_activity = Activity.get_by_ap_id(note_activity.data["id"])
+    activity_actor = Repo.get_by(User, ap_id: note_activity.data["actor"])
+    liked_status = ActivityRepresenter.to_map(note_activity, %{user: activity_actor, for: user})
+    assert liked_status["favorited"] == true
   end
 
   test "an activity" do
@@ -84,7 +89,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
       "attentions" => [
         UserRepresenter.to_map(mentioned_user, %{for: follower})
       ],
-      "fave_num" => 5
+      "fave_num" => 5,
+      "favorited" => false
     }
 
     assert ActivityRepresenter.to_map(activity, %{user: user, for: follower, mentioned: [mentioned_user]}) == expected_status