Add route to get object like activities
authorsxsdv1 <sxsdv1@gmail.com>
Fri, 11 Jan 2019 22:34:32 +0000 (23:34 +0100)
committersxsdv1 <sxsdv1@gmail.com>
Sat, 12 Jan 2019 19:24:38 +0000 (20:24 +0100)
lib/pleroma/web/activity_pub/activity_pub_controller.ex
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/activity_pub/views/object_view.ex
lib/pleroma/web/router.ex
test/web/activity_pub/activity_pub_controller_test.exs

index 6bc8b7195c720a167a21699cb66e668f6b4afe4e..7eed0a6006d86154400cfb50b69978ae281d1ac5 100644 (file)
@@ -54,6 +54,36 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
     end
   end
 
+  def object_likes(conn, %{"uuid" => uuid, "page" => page}) do
+    with ap_id <- o_status_url(conn, :object, uuid),
+         %Object{} = object <- Object.get_cached_by_ap_id(ap_id),
+         {_, true} <- {:public?, ActivityPub.is_public?(object)},
+         likes <- Utils.get_object_likes(object) do
+      {page, _} = Integer.parse(page)
+
+      conn
+      |> put_resp_header("content-type", "application/activity+json")
+      |> json(ObjectView.render("likes.json", ap_id, likes, page))
+    else
+      {:public?, false} ->
+        {:error, :not_found}
+    end
+  end
+
+  def object_likes(conn, %{"uuid" => uuid}) do
+    with ap_id <- o_status_url(conn, :object, uuid),
+         %Object{} = object <- Object.get_cached_by_ap_id(ap_id),
+         {_, true} <- {:public?, ActivityPub.is_public?(object)},
+         likes <- Utils.get_object_likes(object) do
+      conn
+      |> put_resp_header("content-type", "application/activity+json")
+      |> json(ObjectView.render("likes.json", ap_id, likes))
+    else
+      {:public?, false} ->
+        {:error, :not_found}
+    end
+  end
+
   def activity(conn, %{"uuid" => uuid}) do
     with ap_id <- o_status_url(conn, :activity, uuid),
          %Activity{} = activity <- Activity.normalize(ap_id),
index b313996db79cfcc1c920b1e7b063a175d9d1aaf9..6ecab773c7db314a6c9424016099499f27e10dd8 100644 (file)
@@ -231,6 +231,27 @@ defmodule Pleroma.Web.ActivityPub.Utils do
     Repo.one(query)
   end
 
+  @doc """
+  Returns like activities targeting an object
+  """
+  def get_object_likes(%{data: %{"id" => id}}) do
+    query =
+      from(
+        activity in Activity,
+        # this is to use the index
+        where:
+          fragment(
+            "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
+            activity.data,
+            activity.data,
+            ^id
+          ),
+        where: fragment("(?)->>'type' = 'Like'", activity.data)
+      )
+
+    Repo.all(query)
+  end
+
   def make_like_data(%User{ap_id: ap_id} = actor, %{data: %{"id" => id}} = object, activity_id) do
     data = %{
       "type" => "Like",
index b5c9bf8d089537e18fe49f2c7b36714c963f5b98..1930420562b28b470de6fc1dad058a63d83154fa 100644 (file)
@@ -35,4 +35,38 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
 
     Map.merge(base, additional)
   end
+
+  def render("likes.json", ap_id, likes, page) do
+    collection(likes, "#{ap_id}/likes", page)
+    |> Map.merge(Pleroma.Web.ActivityPub.Utils.make_json_ld_header())
+  end
+
+  def render("likes.json", ap_id, likes) do
+    %{
+      "id" => "#{ap_id}/likes",
+      "type" => "OrderedCollection",
+      "totalItems" => length(likes),
+      "first" => collection(likes, "#{ap_id}/followers", 1)
+    }
+    |> Map.merge(Pleroma.Web.ActivityPub.Utils.make_json_ld_header())
+  end
+
+  def collection(collection, iri, page) do
+    offset = (page - 1) * 10
+    items = Enum.slice(collection, offset, 10)
+    items = Enum.map(items, fn object -> Transmogrifier.prepare_object(object.data) end)
+    total = length(collection)
+
+    map = %{
+      "id" => "#{iri}?page=#{page}",
+      "type" => "OrderedCollectionPage",
+      "partOf" => iri,
+      "totalItems" => total,
+      "orderedItems" => items
+    }
+
+    if offset < total do
+      Map.put(map, "next", "#{iri}?page=#{page + 1}")
+    end
+  end
 end
index a5f4d812681ce08dba458301b0b6dbb1e8669222..7a0c9fd25d33de7451160465599af45a7b339b3f 100644 (file)
@@ -421,6 +421,7 @@ defmodule Pleroma.Web.Router do
     get("/users/:nickname/followers", ActivityPubController, :followers)
     get("/users/:nickname/following", ActivityPubController, :following)
     get("/users/:nickname/outbox", ActivityPubController, :outbox)
+    get("/objects/:uuid/likes", ActivityPubController, :object_likes)
   end
 
   pipeline :activitypub_client do
index 82ad4214454ee142384f4d794cee4dcce6932ff6..52e67f0467d0bf27e843ae65fa1fa46436a9e873 100644 (file)
@@ -89,6 +89,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
     end
   end
 
+  describe "/object/:uuid/likes" do
+    test "it returns the like activities in a collection", %{conn: conn} do
+      like = insert(:like_activity)
+      uuid = String.split(like.data["object"], "/") |> List.last()
+
+      result =
+        conn
+        |> put_req_header("accept", "application/activity+json")
+        |> get("/objects/#{uuid}/likes")
+        |> json_response(200)
+
+      assert List.first(result["first"]["orderedItems"])["id"] == like.data["id"]
+    end
+  end
+
   describe "/activities/:uuid" do
     test "it returns a json representation of the activity", %{conn: conn} do
       activity = insert(:note_activity)