Mastodon API: Add the `recipients` parameter to `GET /api/v1/conversations`
authoreugenijm <eugenijm@protonmail.com>
Thu, 7 Nov 2019 00:00:21 +0000 (03:00 +0300)
committereugenijm <eugenijm@protonmail.com>
Thu, 7 Nov 2019 05:26:24 +0000 (08:26 +0300)
CHANGELOG.md
docs/API/differences_in_mastoapi_responses.md
lib/pleroma/conversation/participation.ex
test/web/mastodon_api/controllers/conversation_controller_test.exs

index 9fd46b6500ffd7193fa0ddfe259c675c030c9897..b33d618193c755fe054ed98b65fe20d8a2e7cd01 100644 (file)
@@ -57,6 +57,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Admin API: Add `GET /api/pleroma/admin/relay` endpoint - lists all followed relays
 - Pleroma API: `POST /api/v1/pleroma/conversations/read` to mark all conversations as read
 - Mastodon API: Add `/api/v1/markers` for managing timeline read markers
+- Mastodon API: Add the `recipients` parameter to `GET /api/v1/conversations`
 </details>
 
 ### Fixed
index aca0f5e0e9d01c1ec43398778a0feaedb1fea72f..7fbe171306f54e41369bea8dc3b9184fcca2d903 100644 (file)
@@ -72,6 +72,12 @@ Has an additional field under the `pleroma` object:
 
 - `recipients`: The list of the recipients of this Conversation. These will be addressed when replying to this conversation.
 
+## GET `/api/v1/conversations`
+
+Accepts additional parameters:
+
+- `recipients`: Only return conversations with the given recipients (a list of user ids). Usage example: `GET /api/v1/conversations?recipients[]=1&recipients[]=2`
+
 ## Account Search
 
 Behavior has changed:
index 176b82a2092e46cd48745c719a5f4c6fd4dd206d..aafe572803f0b99f848c146f50a931c39b4eb447 100644 (file)
@@ -122,9 +122,37 @@ defmodule Pleroma.Conversation.Participation do
       order_by: [desc: p.updated_at],
       preload: [conversation: [:users]]
     )
+    |> restrict_recipients(user, params)
     |> Pleroma.Pagination.fetch_paginated(params)
   end
 
+  def restrict_recipients(query, user, %{"recipients" => user_ids}) do
+    user_ids =
+      [user.id | user_ids]
+      |> Enum.uniq()
+      |> Enum.reduce([], fn user_id, acc ->
+        case FlakeId.Ecto.CompatType.dump(user_id) do
+          {:ok, user_id} -> [user_id | acc]
+          _ -> acc
+        end
+      end)
+
+    conversation_subquery =
+      __MODULE__
+      |> group_by([p], p.conversation_id)
+      |> having(
+        [p],
+        count(p.user_id) == ^length(user_ids) and
+          fragment("array_agg(?) @> ?", p.user_id, ^user_ids)
+      )
+      |> select([p], %{id: p.conversation_id})
+
+    query
+    |> join(:inner, [p], c in subquery(conversation_subquery), on: p.conversation_id == c.id)
+  end
+
+  def restrict_recipients(query, _, _), do: query
+
   def for_user_and_conversation(user, conversation) do
     from(p in __MODULE__,
       where: p.user_id == ^user.id,
index 542af494469575666e17718d1949bc76f43f799a..2a1223b182a9abc4e4426efe355ee5fcf95eab7c 100644 (file)
@@ -59,6 +59,59 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
     assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0
   end
 
+  test "filters conversations by recipients", %{conn: conn} do
+    user_one = insert(:user)
+    user_two = insert(:user)
+    user_three = insert(:user)
+
+    {:ok, direct1} =
+      CommonAPI.post(user_one, %{
+        "status" => "Hi @#{user_two.nickname}!",
+        "visibility" => "direct"
+      })
+
+    {:ok, _direct2} =
+      CommonAPI.post(user_one, %{
+        "status" => "Hi @#{user_three.nickname}!",
+        "visibility" => "direct"
+      })
+
+    {:ok, direct3} =
+      CommonAPI.post(user_one, %{
+        "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
+        "visibility" => "direct"
+      })
+
+    {:ok, _direct4} =
+      CommonAPI.post(user_two, %{
+        "status" => "Hi @#{user_three.nickname}!",
+        "visibility" => "direct"
+      })
+
+    {:ok, direct5} =
+      CommonAPI.post(user_two, %{
+        "status" => "Hi @#{user_one.nickname}!",
+        "visibility" => "direct"
+      })
+
+    [conversation1, conversation2] =
+      conn
+      |> assign(:user, user_one)
+      |> get("/api/v1/conversations", %{"recipients" => [user_two.id]})
+      |> json_response(200)
+
+    assert conversation1["last_status"]["id"] == direct5.id
+    assert conversation2["last_status"]["id"] == direct1.id
+
+    [conversation1] =
+      conn
+      |> assign(:user, user_one)
+      |> get("/api/v1/conversations", %{"recipients" => [user_two.id, user_three.id]})
+      |> json_response(200)
+
+    assert conversation1["last_status"]["id"] == direct3.id
+  end
+
   test "updates the last_status on reply", %{conn: conn} do
     user_one = insert(:user)
     user_two = insert(:user)