diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 4a56beb73..b6ba91052 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -1207,6 +1207,18 @@ defp exclude_poll_votes(query, _) 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 @@ def fetch_activities_query(recipients, opts \\ %{}) 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
index 000000000..038ebb29d
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/chat_operation.ex
@@ -0,0 +1,81 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# 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
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 2f13daf0c..c306c1e96 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -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}} <-
diff --git a/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex b/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex
index 972330f4e..5ec546847 100644
--- a/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex
@@ -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 @@ def post_chat_message(%{assigns: %{user: %{id: user_id} = user}} = conn, %{
%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 @@ def messages(%{assigns: %{user: %{id: user_id} = user}} = conn, %{"id" => id}) d
)
|> 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 @@ def index(%{assigns: %{user: %{id: user_id}}} = conn, _params) 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
index 000000000..2df591358
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/views/chat_message_view.ex
@@ -0,0 +1,28 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# 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
index 000000000..ee48385bf
--- /dev/null
+++ b/lib/pleroma/web/pleroma_api/views/chat_view.ex
@@ -0,0 +1,21 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# 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
diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/web/mastodon_api/controllers/timeline_controller_test.exs
index 06efdc901..a5c227991 100644
--- a/test/web/mastodon_api/controllers/timeline_controller_test.exs
+++ b/test/web/mastodon_api/controllers/timeline_controller_test.exs
@@ -51,6 +51,9 @@ test "the home timeline", %{user: user, conn: conn} 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))
diff --git a/test/web/pleroma_api/controllers/chat_controller_test.exs b/test/web/pleroma_api/controllers/chat_controller_test.exs
index b4230e5ad..dad37a889 100644
--- a/test/web/pleroma_api/controllers/chat_controller_test.exs
+++ b/test/web/pleroma_api/controllers/chat_controller_test.exs
@@ -23,14 +23,13 @@ test "it posts a message to the chat", %{conn: conn} 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 @@ test "it returns the messages for a given chat", %{conn: conn} 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
index 000000000..e690da022
--- /dev/null
+++ b/test/web/pleroma_api/views/chat_message_view_test.exs
@@ -0,0 +1,42 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors
+# 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