Check if mogrify available before calling it
[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.Chat.MessageReference
10 alias Pleroma.Object
11 alias Pleroma.Pagination
12 alias Pleroma.Plugs.OAuthScopesPlug
13 alias Pleroma.Repo
14 alias Pleroma.User
15 alias Pleroma.Web.CommonAPI
16 alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView
17 alias Pleroma.Web.PleromaAPI.ChatView
18
19 import Ecto.Query
20
21 action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
22
23 plug(
24 OAuthScopesPlug,
25 %{scopes: ["write:chats"]}
26 when action in [
27 :post_chat_message,
28 :create,
29 :mark_as_read,
30 :mark_message_as_read,
31 :delete_message
32 ]
33 )
34
35 plug(
36 OAuthScopesPlug,
37 %{scopes: ["read:chats"]} when action in [:messages, :index, :show]
38 )
39
40 plug(OpenApiSpex.Plug.CastAndValidate, render_error: Pleroma.Web.ApiSpec.RenderError)
41
42 defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ChatOperation
43
44 def delete_message(%{assigns: %{user: %{id: user_id} = user}} = conn, %{
45 message_id: message_id,
46 id: chat_id
47 }) do
48 with %MessageReference{} = cm_ref <-
49 MessageReference.get_by_id(message_id),
50 ^chat_id <- cm_ref.chat_id |> to_string(),
51 %Chat{user_id: ^user_id} <- Chat.get_by_id(chat_id),
52 {:ok, _} <- remove_or_delete(cm_ref, user) do
53 conn
54 |> put_view(MessageReferenceView)
55 |> render("show.json", chat_message_reference: cm_ref)
56 else
57 _e ->
58 {:error, :could_not_delete}
59 end
60 end
61
62 defp remove_or_delete(
63 %{object: %{data: %{"actor" => actor, "id" => id}}},
64 %{ap_id: actor} = user
65 ) do
66 with %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
67 CommonAPI.delete(activity.id, user)
68 end
69 end
70
71 defp remove_or_delete(cm_ref, _) do
72 cm_ref
73 |> MessageReference.delete()
74 end
75
76 def post_chat_message(
77 %{body_params: params, assigns: %{user: %{id: user_id} = user}} = conn,
78 %{
79 id: id
80 }
81 ) do
82 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
83 %User{} = recipient <- User.get_cached_by_ap_id(chat.recipient),
84 {:ok, activity} <-
85 CommonAPI.post_chat_message(user, recipient, params[:content],
86 media_id: params[:media_id]
87 ),
88 message <- Object.normalize(activity, false),
89 cm_ref <- MessageReference.for_chat_and_object(chat, message) do
90 conn
91 |> put_view(MessageReferenceView)
92 |> render("show.json", for: user, chat_message_reference: cm_ref)
93 end
94 end
95
96 def mark_message_as_read(%{assigns: %{user: %{id: user_id} = user}} = conn, %{
97 id: chat_id,
98 message_id: message_id
99 }) do
100 with %MessageReference{} = cm_ref <-
101 MessageReference.get_by_id(message_id),
102 ^chat_id <- cm_ref.chat_id |> to_string(),
103 %Chat{user_id: ^user_id} <- Chat.get_by_id(chat_id),
104 {:ok, cm_ref} <- MessageReference.mark_as_read(cm_ref) do
105 conn
106 |> put_view(MessageReferenceView)
107 |> render("show.json", for: user, chat_message_reference: cm_ref)
108 end
109 end
110
111 def mark_as_read(
112 %{body_params: %{last_read_id: last_read_id}, assigns: %{user: %{id: user_id}}} = conn,
113 %{id: id}
114 ) do
115 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
116 {_n, _} <-
117 MessageReference.set_all_seen_for_chat(chat, last_read_id) do
118 conn
119 |> put_view(ChatView)
120 |> render("show.json", chat: chat)
121 end
122 end
123
124 def messages(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: id} = params) do
125 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id) do
126 cm_refs =
127 chat
128 |> MessageReference.for_chat_query()
129 |> Pagination.fetch_paginated(params)
130
131 conn
132 |> put_view(MessageReferenceView)
133 |> render("index.json", for: user, chat_message_references: cm_refs)
134 else
135 _ ->
136 conn
137 |> put_status(:not_found)
138 |> json(%{error: "not found"})
139 end
140 end
141
142 def index(%{assigns: %{user: %{id: user_id} = user}} = conn, _params) do
143 blocked_ap_ids = User.blocked_users_ap_ids(user)
144
145 chats =
146 from(c in Chat,
147 where: c.user_id == ^user_id,
148 where: c.recipient not in ^blocked_ap_ids,
149 order_by: [desc: c.updated_at]
150 )
151 |> Repo.all()
152
153 conn
154 |> put_view(ChatView)
155 |> render("index.json", chats: chats)
156 end
157
158 def create(%{assigns: %{user: user}} = conn, params) do
159 with %User{ap_id: recipient} <- User.get_by_id(params[:id]),
160 {:ok, %Chat{} = chat} <- Chat.get_or_create(user.id, recipient) do
161 conn
162 |> put_view(ChatView)
163 |> render("show.json", chat: chat)
164 end
165 end
166
167 def show(%{assigns: %{user: user}} = conn, params) do
168 with %Chat{} = chat <- Repo.get_by(Chat, user_id: user.id, id: params[:id]) do
169 conn
170 |> put_view(ChatView)
171 |> render("show.json", chat: chat)
172 end
173 end
174 end