Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remake-remodel-dms
[akkoma] / lib / pleroma / web / pleroma_api / controllers / chat_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4 defmodule Pleroma.Web.PleromaAPI.ChatController do
5 use Pleroma.Web, :controller
6
7 alias Pleroma.Activity
8 alias Pleroma.Chat
9 alias Pleroma.Object
10 alias Pleroma.Pagination
11 alias Pleroma.Plugs.OAuthScopesPlug
12 alias Pleroma.Repo
13 alias Pleroma.User
14 alias Pleroma.Web.CommonAPI
15 alias Pleroma.Web.PleromaAPI.ChatMessageView
16 alias Pleroma.Web.PleromaAPI.ChatView
17
18 import Ecto.Query
19 import Pleroma.Web.ActivityPub.ObjectValidator, only: [stringify_keys: 1]
20
21 action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
22
23 plug(
24 OAuthScopesPlug,
25 %{scopes: ["write:statuses"]}
26 when action in [:post_chat_message, :create, :mark_as_read, :delete_message]
27 )
28
29 plug(
30 OAuthScopesPlug,
31 %{scopes: ["read:statuses"]} when action in [:messages, :index, :show]
32 )
33
34 plug(OpenApiSpex.Plug.CastAndValidate, render_error: Pleroma.Web.ApiSpec.RenderError)
35
36 defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ChatOperation
37
38 def delete_message(%{assigns: %{user: %{ap_id: actor} = user}} = conn, %{
39 message_id: id
40 }) do
41 with %Object{
42 data: %{
43 "actor" => ^actor,
44 "id" => object,
45 "to" => [recipient],
46 "type" => "ChatMessage"
47 }
48 } = message <- Object.get_by_id(id),
49 %Chat{} = chat <- Chat.get(user.id, recipient),
50 %Activity{} = activity <- Activity.get_create_by_object_ap_id(object),
51 {:ok, _delete} <- CommonAPI.delete(activity.id, user) do
52 conn
53 |> put_view(ChatMessageView)
54 |> render("show.json", for: user, object: message, chat: chat)
55 else
56 _e -> {:error, :could_not_delete}
57 end
58 end
59
60 def post_chat_message(
61 %{body_params: %{content: content} = params, assigns: %{user: %{id: user_id} = user}} =
62 conn,
63 %{
64 id: id
65 }
66 ) do
67 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
68 %User{} = recipient <- User.get_cached_by_ap_id(chat.recipient),
69 {:ok, activity} <-
70 CommonAPI.post_chat_message(user, recipient, content, media_id: params[:media_id]),
71 message <- Object.normalize(activity) do
72 conn
73 |> put_view(ChatMessageView)
74 |> render("show.json", for: user, object: message, chat: chat)
75 end
76 end
77
78 def mark_as_read(%{assigns: %{user: %{id: user_id}}} = conn, %{id: id}) do
79 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
80 {:ok, chat} <- Chat.mark_as_read(chat) do
81 conn
82 |> put_view(ChatView)
83 |> render("show.json", chat: chat)
84 end
85 end
86
87 def messages(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: id} = params) do
88 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id) do
89 messages =
90 chat
91 |> Chat.messages_for_chat_query()
92 |> Pagination.fetch_paginated(params |> stringify_keys())
93
94 conn
95 |> put_view(ChatMessageView)
96 |> render("index.json", for: user, objects: messages, chat: chat)
97 else
98 _ ->
99 conn
100 |> put_status(:not_found)
101 |> json(%{error: "not found"})
102 end
103 end
104
105 def index(%{assigns: %{user: %{id: user_id} = user}} = conn, params) do
106 blocked_ap_ids = User.blocked_users_ap_ids(user)
107
108 chats =
109 from(c in Chat,
110 where: c.user_id == ^user_id,
111 where: c.recipient not in ^blocked_ap_ids,
112 order_by: [desc: c.updated_at]
113 )
114 |> Pagination.fetch_paginated(params |> stringify_keys)
115
116 conn
117 |> put_view(ChatView)
118 |> render("index.json", chats: chats)
119 end
120
121 def create(%{assigns: %{user: user}} = conn, params) do
122 with %User{ap_id: recipient} <- User.get_by_id(params[:id]),
123 {:ok, %Chat{} = chat} <- Chat.get_or_create(user.id, recipient) do
124 conn
125 |> put_view(ChatView)
126 |> render("show.json", chat: chat)
127 end
128 end
129
130 def show(%{assigns: %{user: user}} = conn, params) do
131 with %Chat{} = chat <- Repo.get_by(Chat, user_id: user.id, id: params[:id]) do
132 conn
133 |> put_view(ChatView)
134 |> render("show.json", chat: chat)
135 end
136 end
137 end