ChatController: Support deletion of chat messages.
[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 # TODO
22 # - Error handling
23
24 plug(
25 OAuthScopesPlug,
26 %{scopes: ["write:statuses"]}
27 when action in [:post_chat_message, :create, :mark_as_read, :delete_message]
28 )
29
30 plug(
31 OAuthScopesPlug,
32 %{scopes: ["read:statuses"]} when action in [:messages, :index, :show]
33 )
34
35 plug(OpenApiSpex.Plug.CastAndValidate, render_error: Pleroma.Web.ApiSpec.RenderError)
36
37 defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ChatOperation
38
39 def delete_message(%{assigns: %{user: %{ap_id: actor} = user}} = conn, %{
40 message_id: id
41 }) do
42 with %Object{
43 data: %{
44 "actor" => ^actor,
45 "id" => object,
46 "to" => [recipient],
47 "type" => "ChatMessage"
48 }
49 } = message <- Object.get_by_id(id),
50 %Chat{} = chat <- Chat.get(user.id, recipient),
51 %Activity{} = activity <- Activity.get_create_by_object_ap_id(object),
52 {:ok, _delete} <- CommonAPI.delete(activity.id, user) do
53 conn
54 |> put_view(ChatMessageView)
55 |> render("show.json", for: user, object: message, chat: chat)
56 end
57 end
58
59 def post_chat_message(
60 %{body_params: %{content: content} = params, assigns: %{user: %{id: user_id} = user}} =
61 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, content, media_id: params[:media_id]),
70 message <- Object.normalize(activity) do
71 conn
72 |> put_view(ChatMessageView)
73 |> render("show.json", for: user, object: message, chat: chat)
74 end
75 end
76
77 def mark_as_read(%{assigns: %{user: %{id: user_id}}} = conn, %{id: id}) do
78 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
79 {:ok, chat} <- Chat.mark_as_read(chat) do
80 conn
81 |> put_view(ChatView)
82 |> render("show.json", chat: chat)
83 end
84 end
85
86 def messages(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: id} = params) do
87 with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id) do
88 messages =
89 chat
90 |> Chat.messages_for_chat_query()
91 |> Pagination.fetch_paginated(params |> stringify_keys())
92
93 conn
94 |> put_view(ChatMessageView)
95 |> render("index.json", for: user, objects: messages, chat: chat)
96 else
97 _ ->
98 conn
99 |> put_status(:not_found)
100 |> json(%{error: "not found"})
101 end
102 end
103
104 def index(%{assigns: %{user: %{id: user_id}}} = conn, params) do
105 chats =
106 from(c in Chat,
107 where: c.user_id == ^user_id,
108 order_by: [desc: c.updated_at]
109 )
110 |> Pagination.fetch_paginated(params |> stringify_keys)
111
112 conn
113 |> put_view(ChatView)
114 |> render("index.json", chats: chats)
115 end
116
117 def create(%{assigns: %{user: user}} = conn, params) do
118 with %User{ap_id: recipient} <- User.get_by_id(params[:id]),
119 {:ok, %Chat{} = chat} <- Chat.get_or_create(user.id, recipient) do
120 conn
121 |> put_view(ChatView)
122 |> render("show.json", chat: chat)
123 end
124 end
125
126 def show(%{assigns: %{user: user}} = conn, params) do
127 with %Chat{} = chat <- Repo.get_by(Chat, user_id: user.id, id: params[:id]) do
128 conn
129 |> put_view(ChatView)
130 |> render("show.json", chat: chat)
131 end
132 end
133 end