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: params, assigns: %{user: %{id: user_id} = user}} = conn,
62 %{
63 id: id
64 }
65 ) do
66 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
67 %User{} = recipient <- User.get_cached_by_ap_id(chat.recipient),
68 {:ok, activity} <-
69 CommonAPI.post_chat_message(user, recipient, params[:content],
70 media_id: params[:media_id]
71 ),
72 message <- Object.normalize(activity) do
73 conn
74 |> put_view(ChatMessageView)
75 |> render("show.json", for: user, object: message, chat: chat)
76 end
77 end
78
79 def mark_as_read(%{assigns: %{user: %{id: user_id}}} = conn, %{id: id}) do
80 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
81 {:ok, chat} <- Chat.mark_as_read(chat) do
82 conn
83 |> put_view(ChatView)
84 |> render("show.json", chat: chat)
85 end
86 end
87
88 def messages(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: id} = params) do
89 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id) do
90 messages =
91 chat
92 |> Chat.messages_for_chat_query()
93 |> Pagination.fetch_paginated(params |> stringify_keys())
94
95 conn
96 |> put_view(ChatMessageView)
97 |> render("index.json", for: user, objects: messages, chat: chat)
98 else
99 _ ->
100 conn
101 |> put_status(:not_found)
102 |> json(%{error: "not found"})
103 end
104 end
105
106 def index(%{assigns: %{user: %{id: user_id} = user}} = conn, params) do
107 blocked_ap_ids = User.blocked_users_ap_ids(user)
108
109 chats =
110 from(c in Chat,
111 where: c.user_id == ^user_id,
112 where: c.recipient not in ^blocked_ap_ids,
113 order_by: [desc: c.updated_at]
114 )
115 |> Pagination.fetch_paginated(params |> stringify_keys)
116
117 conn
118 |> put_view(ChatView)
119 |> render("index.json", chats: chats)
120 end
121
122 def create(%{assigns: %{user: user}} = conn, params) do
123 with %User{ap_id: recipient} <- User.get_by_id(params[:id]),
124 {:ok, %Chat{} = chat} <- Chat.get_or_create(user.id, recipient) do
125 conn
126 |> put_view(ChatView)
127 |> render("show.json", chat: chat)
128 end
129 end
130
131 def show(%{assigns: %{user: user}} = conn, params) do
132 with %Chat{} = chat <- Repo.get_by(Chat, user_id: user.id, id: params[:id]) do
133 conn
134 |> put_view(ChatView)
135 |> render("show.json", chat: chat)
136 end
137 end
138 end