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
|> restrict_instance(opts)
|> Activity.restrict_deactivated_users()
|> exclude_poll_votes(opts)
+ |> exclude_chat_messages(opts)
|> exclude_visibility(opts)
end
--- /dev/null
+# 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
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}} <-
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.PleromaAPI.ChatView
+ alias Pleroma.Web.PleromaAPI.ChatMessageView
import Ecto.Query
# - 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
%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
)
|> 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
)
|> 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
--- /dev/null
+# 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
--- /dev/null
+# 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
{: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))
|> 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)
|> 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
--- /dev/null
+# 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