chat_controller.ex 5.19 KB
Newer Older
1
2
3
4
5
6
# 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.ChatController do
  use Pleroma.Web, :controller

7
  alias Pleroma.Activity
8
  alias Pleroma.Chat
9
  alias Pleroma.Chat.MessageReference
10
  alias Pleroma.Object
lain's avatar
lain committed
11
12
  alias Pleroma.Pagination
  alias Pleroma.Plugs.OAuthScopesPlug
13
  alias Pleroma.Repo
lain's avatar
lain committed
14
15
  alias Pleroma.User
  alias Pleroma.Web.CommonAPI
16
  alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView
lain's avatar
lain committed
17
  alias Pleroma.Web.PleromaAPI.ChatView
18
19
20

  import Ecto.Query

21
  action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
lain's avatar
lain committed
22

lain's avatar
lain committed
23
24
  plug(
    OAuthScopesPlug,
25
    %{scopes: ["write:chats"]}
26
27
28
29
30
31
32
    when action in [
           :post_chat_message,
           :create,
           :mark_as_read,
           :mark_message_as_read,
           :delete_message
         ]
lain's avatar
lain committed
33
34
35
36
  )

  plug(
    OAuthScopesPlug,
37
    %{scopes: ["read:chats"]} when action in [:messages, :index, :show]
lain's avatar
lain committed
38
39
  )

40
  plug(OpenApiSpex.Plug.CastAndValidate, render_error: Pleroma.Web.ApiSpec.RenderError)
lain's avatar
lain committed
41

42
43
  defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ChatOperation

44
45
46
  def delete_message(%{assigns: %{user: %{id: user_id} = user}} = conn, %{
        message_id: message_id,
        id: chat_id
47
      }) do
48
49
    with %MessageReference{} = cm_ref <-
           MessageReference.get_by_id(message_id),
50
51
52
         ^chat_id <- cm_ref.chat_id |> to_string(),
         %Chat{user_id: ^user_id} <- Chat.get_by_id(chat_id),
         {: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
58
      _e ->
        {:error, :could_not_delete}
59
60
61
    end
  end

62
63
64
65
66
67
68
69
70
71
72
  defp remove_or_delete(
         %{object: %{data: %{"actor" => actor, "id" => id}}},
         %{ap_id: actor} = user
       ) do
    with %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
      CommonAPI.delete(activity.id, user)
    end
  end

  defp remove_or_delete(cm_ref, _) do
    cm_ref
73
    |> MessageReference.delete()
74
75
  end

lain's avatar
lain committed
76
  def post_chat_message(
77
        %{body_params: params, assigns: %{user: %{id: user_id} = user}} = conn,
lain's avatar
lain committed
78
79
80
81
        %{
          id: id
        }
      ) do
lain's avatar
lain committed
82
83
    with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
         %User{} = recipient <- User.get_cached_by_ap_id(chat.recipient),
lain's avatar
lain committed
84
         {:ok, activity} <-
85
86
87
           CommonAPI.post_chat_message(user, recipient, params[:content],
             media_id: params[:media_id]
           ),
88
         message <- Object.normalize(activity, false),
89
         cm_ref <- MessageReference.for_chat_and_object(chat, message) do
lain's avatar
lain committed
90
      conn
91
      |> put_view(MessageReferenceView)
92
      |> render("show.json", chat_message_reference: cm_ref)
lain's avatar
lain committed
93
94
95
    end
  end

96
  def mark_message_as_read(%{assigns: %{user: %{id: user_id}}} = conn, %{
97
98
99
        id: chat_id,
        message_id: message_id
      }) do
100
101
    with %MessageReference{} = cm_ref <-
           MessageReference.get_by_id(message_id),
102
103
         ^chat_id <- cm_ref.chat_id |> to_string(),
         %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", chat_message_reference: cm_ref)
108
109
110
    end
  end

111
  def mark_as_read(
112
113
114
115
        %{
          body_params: %{last_read_id: last_read_id},
          assigns: %{user: %{id: user_id}}
        } = conn,
116
117
        %{id: id}
      ) do
lain's avatar
lain committed
118
    with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
119
         {_n, _} <-
120
           MessageReference.set_all_seen_for_chat(chat, last_read_id) do
lain's avatar
lain committed
121
122
123
124
125
126
      conn
      |> put_view(ChatView)
      |> render("show.json", chat: chat)
    end
  end

127
  def messages(%{assigns: %{user: %{id: user_id}}} = conn, %{id: id} = params) do
128
    with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id) do
129
      cm_refs =
130
        chat
131
        |> MessageReference.for_chat_query()
132
        |> Pagination.fetch_paginated(params)
133
134

      conn
135
      |> put_view(MessageReferenceView)
136
      |> render("index.json", chat_message_references: cm_refs)
lain's avatar
lain committed
137
138
139
140
141
    else
      _ ->
        conn
        |> put_status(:not_found)
        |> json(%{error: "not found"})
142
143
144
    end
  end

145
  def index(%{assigns: %{user: %{id: user_id} = user}} = conn, _params) do
146
147
    blocked_ap_ids = User.blocked_users_ap_ids(user)

148
149
150
    chats =
      from(c in Chat,
        where: c.user_id == ^user_id,
151
        where: c.recipient not in ^blocked_ap_ids,
152
153
154
        order_by: [desc: c.updated_at],
        inner_join: u in User,
        on: u.ap_id == c.recipient
155
      )
156
      |> Repo.all()
157
158

    conn
159
160
    |> put_view(ChatView)
    |> render("index.json", chats: chats)
161
162
163
  end

  def create(%{assigns: %{user: user}} = conn, params) do
164
165
    with %User{ap_id: recipient} <- User.get_by_id(params[:id]),
         {:ok, %Chat{} = chat} <- Chat.get_or_create(user.id, recipient) do
166
      conn
167
168
      |> put_view(ChatView)
      |> render("show.json", chat: chat)
169
170
    end
  end
lain's avatar
lain committed
171
172
173
174
175
176
177
178

  def show(%{assigns: %{user: user}} = conn, params) do
    with %Chat{} = chat <- Repo.get_by(Chat, user_id: user.id, id: params[:id]) do
      conn
      |> put_view(ChatView)
      |> render("show.json", chat: chat)
    end
  end
179
end