Chat: Add views, don't return them in timeline queries.
authorlain <lain@soykaf.club>
Wed, 15 Apr 2020 16:23:16 +0000 (18:23 +0200)
committerlain <lain@soykaf.club>
Wed, 15 Apr 2020 16:23:16 +0000 (18:23 +0200)
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/api_spec/operations/chat_operation.ex [new file with mode: 0644]
lib/pleroma/web/common_api/common_api.ex
lib/pleroma/web/pleroma_api/controllers/chat_controller.ex
lib/pleroma/web/pleroma_api/views/chat_message_view.ex [new file with mode: 0644]
lib/pleroma/web/pleroma_api/views/chat_view.ex [new file with mode: 0644]
test/web/mastodon_api/controllers/timeline_controller_test.exs
test/web/pleroma_api/controllers/chat_controller_test.exs
test/web/pleroma_api/views/chat_message_view_test.exs [new file with mode: 0644]

index 4a56beb7372fb433cd50eb44f8d5f5e963479a3c..b6ba9105263e690c09afaa71278744694398e0de 100644 (file)
@@ -1207,6 +1207,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     end
   end
 
+  defp exclude_chat_messages(query, %{"include_chat_messages" => true}), do: query
+
+  defp exclude_chat_messages(query, _) do
+    if has_named_binding?(query, :object) do
+      from([activity, object: o] in query,
+        where: fragment("not(?->>'type' = ?)", o.data, "ChatMessage")
+      )
+    else
+      query
+    end
+  end
+
   defp exclude_id(query, %{"exclude_id" => id}) when is_binary(id) do
     from(activity in query, where: activity.id != ^id)
   end
@@ -1312,6 +1324,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> restrict_instance(opts)
     |> Activity.restrict_deactivated_users()
     |> exclude_poll_votes(opts)
+    |> exclude_chat_messages(opts)
     |> exclude_visibility(opts)
   end
 
diff --git a/lib/pleroma/web/api_spec/operations/chat_operation.ex b/lib/pleroma/web/api_spec/operations/chat_operation.ex
new file mode 100644 (file)
index 0000000..038ebb2
--- /dev/null
@@ -0,0 +1,81 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.ChatOperation do
+  alias OpenApiSpex.Operation
+  alias OpenApiSpex.Schema
+
+  @spec open_api_operation(atom) :: Operation.t()
+  def open_api_operation(action) do
+    operation = String.to_existing_atom("#{action}_operation")
+    apply(__MODULE__, operation, [])
+  end
+
+  def create_operation do
+    %Operation{
+      tags: ["chat"],
+      summary: "Create a chat",
+      responses: %{
+        200 =>
+          Operation.response("Chat", "application/json", %Schema{
+            type: :object,
+            description: "A created chat is returned",
+            properties: %{
+              id: %Schema{type: :integer}
+            }
+          })
+      }
+    }
+  end
+
+  def index_operation do
+    %Operation{
+      tags: ["chat"],
+      summary: "Get a list of chats that you participated in",
+      responses: %{
+        200 =>
+          Operation.response("Chats", "application/json", %Schema{
+            type: :array,
+            description: "A list of chats",
+            items: %Schema{
+              type: :object,
+              description: "A chat"
+            }
+          })
+      }
+    }
+  end
+
+  def messages_operation do
+    %Operation{
+      tags: ["chat"],
+      summary: "Get the most recent messages of the chat",
+      responses: %{
+        200 =>
+          Operation.response("Messages", "application/json", %Schema{
+            type: :array,
+            description: "A list of chat messages",
+            items: %Schema{
+              type: :object,
+              description: "A chat message"
+            }
+          })
+      }
+    }
+  end
+
+  def post_chat_message_operation do
+    %Operation{
+      tags: ["chat"],
+      summary: "Post a message to the chat",
+      responses: %{
+        200 =>
+          Operation.response("Message", "application/json", %Schema{
+            type: :object,
+            description: "A chat message"
+          })
+      }
+    }
+  end
+end
index 2f13daf0ccbd899e2de3f0028bc9b5843f056932..c306c1e96c8086411cbd376624e8b16162a6bdee 100644 (file)
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.CommonAPI do
   require Pleroma.Constants
   require Logger
 
-  def post_chat_message(user, recipient, content) do
+  def post_chat_message(%User{} = user, %User{} = recipient, content) do
     transaction =
       Repo.transaction(fn ->
         with {_, {:ok, chat_message_data, _meta}} <-
index 972330f4e0c4f7dfaedf604e352528d86e90b359..5ec54684796ecbffebbd350a7e4ad748d3464f20 100644 (file)
@@ -9,6 +9,8 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
   alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.PleromaAPI.ChatView
+  alias Pleroma.Web.PleromaAPI.ChatMessageView
 
   import Ecto.Query
 
@@ -17,6 +19,8 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
   # - Views / Representers
   # - Error handling
 
+  defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ChatOperation
+
   def post_chat_message(%{assigns: %{user: %{id: user_id} = user}} = conn, %{
         "id" => id,
         "content" => content
@@ -25,14 +29,9 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
          %User{} = recipient <- User.get_cached_by_ap_id(chat.recipient),
          {:ok, activity} <- CommonAPI.post_chat_message(user, recipient, content),
          message <- Object.normalize(activity) do
-      represented_message = %{
-        actor: message.data["actor"],
-        id: message.id,
-        content: message.data["content"]
-      }
-
       conn
-      |> json(represented_message)
+      |> put_view(ChatMessageView)
+      |> render("show.json", for: user, object: message, chat: chat)
     end
   end
 
@@ -60,18 +59,9 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
         )
         |> Repo.all()
 
-      represented_messages =
-        messages
-        |> Enum.map(fn message ->
-          %{
-            actor: message.data["actor"],
-            id: message.id,
-            content: message.data["content"]
-          }
-        end)
-
       conn
-      |> json(represented_messages)
+      |> put_view(ChatMessageView)
+      |> render("index.json", for: user, objects: messages, chat: chat)
     end
   end
 
@@ -83,31 +73,18 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
       )
       |> Repo.all()
 
-    represented_chats =
-      Enum.map(chats, fn chat ->
-        %{
-          id: chat.id,
-          recipient: chat.recipient,
-          unread: chat.unread
-        }
-      end)
-
     conn
-    |> json(represented_chats)
+    |> put_view(ChatView)
+    |> render("index.json", chats: chats)
   end
 
   def create(%{assigns: %{user: user}} = conn, params) do
     recipient = params["ap_id"] |> URI.decode_www_form()
 
     with {:ok, %Chat{} = chat} <- Chat.get_or_create(user.id, recipient) do
-      represented_chat = %{
-        id: chat.id,
-        recipient: chat.recipient,
-        unread: chat.unread
-      }
-
       conn
-      |> json(represented_chat)
+      |> put_view(ChatView)
+      |> render("show.json", chat: chat)
     end
   end
 end
diff --git a/lib/pleroma/web/pleroma_api/views/chat_message_view.ex b/lib/pleroma/web/pleroma_api/views/chat_message_view.ex
new file mode 100644 (file)
index 0000000..2df5913
--- /dev/null
@@ -0,0 +1,28 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ChatMessageView do
+  use Pleroma.Web, :view
+
+  alias Pleroma.Chat
+
+  def render(
+        "show.json",
+        %{
+          object: %{id: id, data: %{"type" => "ChatMessage"} = chat_message},
+          chat: %Chat{id: chat_id}
+        }
+      ) do
+    %{
+      id: id,
+      content: chat_message["content"],
+      chat_id: chat_id,
+      actor: chat_message["actor"]
+    }
+  end
+
+  def render("index.json", opts) do
+    render_many(opts[:objects], __MODULE__, "show.json", Map.put(opts, :as, :object))
+  end
+end
diff --git a/lib/pleroma/web/pleroma_api/views/chat_view.ex b/lib/pleroma/web/pleroma_api/views/chat_view.ex
new file mode 100644 (file)
index 0000000..ee48385
--- /dev/null
@@ -0,0 +1,21 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ChatView do
+  use Pleroma.Web, :view
+
+  alias Pleroma.Chat
+
+  def render("show.json", %{chat: %Chat{} = chat}) do
+    %{
+      id: chat.id,
+      recipient: chat.recipient,
+      unread: chat.unread
+    }
+  end
+
+  def render("index.json", %{chats: chats}) do
+    render_many(chats, __MODULE__, "show.json")
+  end
+end
index 06efdc901aa763ae6dd58a7628b544f5a06c0a43..a5c227991ebb0cf6eba00e30184d3f991946adcd 100644 (file)
@@ -51,6 +51,9 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
       {:ok, activity} = CommonAPI.post(third_user, %{"status" => "repeated post"})
       {:ok, _, _} = CommonAPI.repeat(activity.id, following)
 
+      # This one should not show up in the TL
+      {:ok, _activity} = CommonAPI.post_chat_message(third_user, user, ":gun:")
+
       ret_conn = get(conn, uri)
 
       assert Enum.empty?(json_response(ret_conn, :ok))
index b4230e5ade4d92b50c3a08edcc0b68a620cdfd80..dad37a889b57ec967664eb1a86bee0c743c067b6 100644 (file)
@@ -23,14 +23,13 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
         |> json_response(200)
 
       assert result["content"] == "Hallo!!"
+      assert result["chat_id"] == chat.id
     end
   end
 
   describe "GET /api/v1/pleroma/chats/:id/messages" do
     # TODO
-    # - Test that statuses don't show
     # - Test the case where it's not the user's chat
-    # - Test the returned data
     test "it returns the messages for a given chat", %{conn: conn} do
       user = insert(:user)
       other_user = insert(:user)
@@ -49,6 +48,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
         |> get("/api/v1/pleroma/chats/#{chat.id}/messages")
         |> json_response(200)
 
+      result
+      |> Enum.each(fn message ->
+        assert message["chat_id"] == chat.id
+      end)
+
       assert length(result) == 3
     end
   end
diff --git a/test/web/pleroma_api/views/chat_message_view_test.exs b/test/web/pleroma_api/views/chat_message_view_test.exs
new file mode 100644 (file)
index 0000000..e690da0
--- /dev/null
@@ -0,0 +1,42 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ChatMessageViewTest do
+  use Pleroma.DataCase
+
+  alias Pleroma.Chat
+  alias Pleroma.Object
+  alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.PleromaAPI.ChatMessageView
+
+  import Pleroma.Factory
+
+  test "it displays a chat message" do
+    user = insert(:user)
+    recipient = insert(:user)
+    {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "kippis")
+
+    chat = Chat.get(user.id, recipient.ap_id)
+
+    object = Object.normalize(activity)
+
+    chat_message = ChatMessageView.render("show.json", object: object, for: user, chat: chat)
+
+    assert chat_message[:id] == object.id
+    assert chat_message[:content] == "kippis"
+    assert chat_message[:actor] == user.ap_id
+    assert chat_message[:chat_id]
+
+    {:ok, activity} = CommonAPI.post_chat_message(recipient, user, "gkgkgk")
+
+    object = Object.normalize(activity)
+
+    chat_message_two = ChatMessageView.render("show.json", object: object, for: user, chat: chat)
+
+    assert chat_message_two[:id] == object.id
+    assert chat_message_two[:content] == "gkgkgk"
+    assert chat_message_two[:actor] == recipient.ap_id
+    assert chat_message_two[:chat_id] == chat_message[:chat_id]
+  end
+end