logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

chat_controller.ex (6528B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 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. import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
  7. alias Pleroma.Activity
  8. alias Pleroma.Chat
  9. alias Pleroma.Chat.MessageReference
  10. alias Pleroma.Object
  11. alias Pleroma.Pagination
  12. alias Pleroma.Repo
  13. alias Pleroma.User
  14. alias Pleroma.Web.CommonAPI
  15. alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView
  16. alias Pleroma.Web.Plugs.OAuthScopesPlug
  17. import Ecto.Query
  18. action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
  19. plug(
  20. OAuthScopesPlug,
  21. %{scopes: ["write:chats"]}
  22. when action in [
  23. :post_chat_message,
  24. :create,
  25. :mark_as_read,
  26. :mark_message_as_read,
  27. :delete_message
  28. ]
  29. )
  30. plug(
  31. OAuthScopesPlug,
  32. %{scopes: ["read:chats"]} when action in [:messages, :index, :index2, :show]
  33. )
  34. plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
  35. defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ChatOperation
  36. def delete_message(
  37. %{
  38. assigns: %{user: %{id: user_id} = user},
  39. private: %{
  40. open_api_spex: %{
  41. params: %{
  42. message_id: message_id,
  43. id: chat_id
  44. }
  45. }
  46. }
  47. } = conn,
  48. _
  49. ) do
  50. with %MessageReference{} = cm_ref <-
  51. MessageReference.get_by_id(message_id),
  52. ^chat_id <- to_string(cm_ref.chat_id),
  53. %Chat{user_id: ^user_id} <- Chat.get_by_id(chat_id),
  54. {:ok, _} <- remove_or_delete(cm_ref, user) do
  55. conn
  56. |> put_view(MessageReferenceView)
  57. |> render("show.json", chat_message_reference: cm_ref)
  58. else
  59. _e ->
  60. {:error, :could_not_delete}
  61. end
  62. end
  63. defp remove_or_delete(
  64. %{object: %{data: %{"actor" => actor, "id" => id}}},
  65. %{ap_id: actor} = user
  66. ) do
  67. with %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
  68. CommonAPI.delete(activity.id, user)
  69. end
  70. end
  71. defp remove_or_delete(cm_ref, _), do: MessageReference.delete(cm_ref)
  72. def post_chat_message(
  73. %{
  74. private: %{open_api_spex: %{body_params: params, params: %{id: id}}},
  75. assigns: %{user: user}
  76. } = conn,
  77. _
  78. ) do
  79. with {:ok, chat} <- Chat.get_by_user_and_id(user, id),
  80. {_, %User{} = recipient} <- {:user, User.get_cached_by_ap_id(chat.recipient)},
  81. {:ok, activity} <-
  82. CommonAPI.post_chat_message(user, recipient, params[:content],
  83. media_id: params[:media_id],
  84. idempotency_key: idempotency_key(conn)
  85. ),
  86. message <- Object.normalize(activity, fetch: false),
  87. cm_ref <- MessageReference.for_chat_and_object(chat, message) do
  88. conn
  89. |> put_view(MessageReferenceView)
  90. |> render("show.json", chat_message_reference: cm_ref)
  91. else
  92. {:reject, message} ->
  93. conn
  94. |> put_status(:unprocessable_entity)
  95. |> json(%{error: message})
  96. {:error, message} ->
  97. conn
  98. |> put_status(:bad_request)
  99. |> json(%{error: message})
  100. {:user, nil} ->
  101. conn
  102. |> put_status(:bad_request)
  103. |> json(%{error: "Recipient does not exist"})
  104. end
  105. end
  106. def mark_message_as_read(
  107. %{
  108. assigns: %{user: %{id: user_id}},
  109. private: %{open_api_spex: %{params: %{id: chat_id, message_id: message_id}}}
  110. } = conn,
  111. _
  112. ) do
  113. with %MessageReference{} = cm_ref <- MessageReference.get_by_id(message_id),
  114. ^chat_id <- to_string(cm_ref.chat_id),
  115. %Chat{user_id: ^user_id} <- Chat.get_by_id(chat_id),
  116. {:ok, cm_ref} <- MessageReference.mark_as_read(cm_ref) do
  117. conn
  118. |> put_view(MessageReferenceView)
  119. |> render("show.json", chat_message_reference: cm_ref)
  120. end
  121. end
  122. def mark_as_read(
  123. %{
  124. assigns: %{user: user},
  125. private: %{
  126. open_api_spex: %{
  127. body_params: %{last_read_id: last_read_id},
  128. params: %{id: id}
  129. }
  130. }
  131. } = conn,
  132. _
  133. ) do
  134. with {:ok, chat} <- Chat.get_by_user_and_id(user, id),
  135. {_n, _} <- MessageReference.set_all_seen_for_chat(chat, last_read_id) do
  136. render(conn, "show.json", chat: chat)
  137. end
  138. end
  139. def messages(
  140. %{
  141. assigns: %{user: user},
  142. private: %{open_api_spex: %{params: %{id: id} = params}}
  143. } = conn,
  144. _
  145. ) do
  146. with {:ok, chat} <- Chat.get_by_user_and_id(user, id) do
  147. chat_message_refs =
  148. chat
  149. |> MessageReference.for_chat_query()
  150. |> Pagination.fetch_paginated(params)
  151. conn
  152. |> add_link_headers(chat_message_refs)
  153. |> put_view(MessageReferenceView)
  154. |> render("index.json", chat_message_references: chat_message_refs)
  155. end
  156. end
  157. def index(%{assigns: %{user: user}, private: %{open_api_spex: %{params: params}}} = conn, _) do
  158. chats =
  159. index_query(user, params)
  160. |> Repo.all()
  161. render(conn, "index.json", chats: chats)
  162. end
  163. def index2(%{assigns: %{user: user}, private: %{open_api_spex: %{params: params}}} = conn, _) do
  164. chats =
  165. index_query(user, params)
  166. |> Pagination.fetch_paginated(params)
  167. conn
  168. |> add_link_headers(chats)
  169. |> render("index.json", chats: chats)
  170. end
  171. defp index_query(%{id: user_id} = user, params) do
  172. exclude_users =
  173. User.cached_blocked_users_ap_ids(user) ++
  174. if params[:with_muted], do: [], else: User.cached_muted_users_ap_ids(user)
  175. user_id
  176. |> Chat.for_user_query()
  177. |> where([c], c.recipient not in ^exclude_users)
  178. end
  179. def create(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
  180. with %User{ap_id: recipient} <- User.get_cached_by_id(id),
  181. {:ok, %Chat{} = chat} <- Chat.get_or_create(user.id, recipient) do
  182. render(conn, "show.json", chat: chat)
  183. end
  184. end
  185. def show(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
  186. with {:ok, chat} <- Chat.get_by_user_and_id(user, id) do
  187. render(conn, "show.json", chat: chat)
  188. end
  189. end
  190. defp idempotency_key(conn) do
  191. case get_req_header(conn, "idempotency-key") do
  192. [key] -> key
  193. _ -> nil
  194. end
  195. end
  196. end