logo

pleroma

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

chat_controller.ex (7294B)


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