ChatMessageReference: Introduce and switch in chat controller.

This commit is contained in:
lain 2020-06-03 12:30:12 +02:00
commit aa22fce8f4
9 changed files with 205 additions and 45 deletions

View file

@ -72,6 +72,11 @@ defmodule Pleroma.Chat do
|> unique_constraint(:user_id, name: :chats_user_id_recipient_index)
end
def get_by_id(id) do
__MODULE__
|> Repo.get(id)
end
def get(user_id, recipient) do
__MODULE__
|> Repo.get_by(user_id: user_id, recipient: recipient)

View file

@ -0,0 +1,80 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ChatMessageReference do
@moduledoc """
A reference that builds a relation between an AP chat message that a user can see and whether it has been seen
by them, or should be displayed to them. Used to build the chat view that is presented to the user.
"""
use Ecto.Schema
alias Pleroma.Chat
alias Pleroma.Object
alias Pleroma.Repo
import Ecto.Changeset
import Ecto.Query
@primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
schema "chat_message_references" do
belongs_to(:object, Object)
belongs_to(:chat, Chat)
field(:seen, :boolean, default: false)
timestamps()
end
def changeset(struct, params) do
struct
|> cast(params, [:object_id, :chat_id, :seen])
|> validate_required([:object_id, :chat_id, :seen])
end
def get_by_id(id) do
__MODULE__
|> Repo.get(id)
|> Repo.preload(:object)
end
def delete(cm_ref) do
cm_ref
|> Repo.delete()
end
def delete_for_object(%{id: object_id}) do
from(cr in __MODULE__,
where: cr.object_id == ^object_id
)
|> Repo.delete_all()
end
def for_chat_and_object(%{id: chat_id}, %{id: object_id}) do
__MODULE__
|> Repo.get_by(chat_id: chat_id, object_id: object_id)
|> Repo.preload(:object)
end
def for_chat_query(chat) do
from(cr in __MODULE__,
where: cr.chat_id == ^chat.id,
order_by: [desc: :id],
preload: [:object]
)
end
def create(chat, object, seen) do
params = %{
chat_id: chat.id,
object_id: object.id,
seen: seen
}
%__MODULE__{}
|> changeset(params)
|> Repo.insert()
end
end

View file

@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
"""
alias Pleroma.Activity
alias Pleroma.Chat
alias Pleroma.ChatMessageReference
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
@ -104,6 +105,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
Object.decrease_replies_count(in_reply_to)
end
ChatMessageReference.delete_for_object(deleted_object)
ActivityPub.stream_out(object)
ActivityPub.stream_out_participations(deleted_object, user)
:ok
@ -137,9 +140,11 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|> Enum.each(fn [user, other_user] ->
if user.local do
if user.ap_id == actor.ap_id do
Chat.get_or_create(user.id, other_user.ap_id)
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
ChatMessageReference.create(chat, object, true)
else
Chat.bump_or_create(user.id, other_user.ap_id)
{:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
ChatMessageReference.create(chat, object, false)
end
end
end)

View file

@ -6,14 +6,15 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
alias Pleroma.Activity
alias Pleroma.Chat
alias Pleroma.ChatMessageReference
alias Pleroma.Object
alias Pleroma.Pagination
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.PleromaAPI.ChatMessageView
alias Pleroma.Web.PleromaAPI.ChatView
alias Pleroma.Web.PleromaAPI.ChatMessageReferenceView
import Ecto.Query
import Pleroma.Web.ActivityPub.ObjectValidator, only: [stringify_keys: 1]
@ -35,28 +36,38 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ChatOperation
def delete_message(%{assigns: %{user: %{ap_id: actor} = user}} = conn, %{
message_id: id
def delete_message(%{assigns: %{user: %{id: user_id} = user}} = conn, %{
message_id: message_id,
id: chat_id
}) do
with %Object{
data: %{
"actor" => ^actor,
"id" => object,
"to" => [recipient],
"type" => "ChatMessage"
}
} = message <- Object.get_by_id(id),
%Chat{} = chat <- Chat.get(user.id, recipient),
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object),
{:ok, _delete} <- CommonAPI.delete(activity.id, user) do
with %ChatMessageReference{} = cm_ref <-
ChatMessageReference.get_by_id(message_id),
^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
conn
|> put_view(ChatMessageView)
|> render("show.json", for: user, object: message, chat: chat)
|> put_view(ChatMessageReferenceView)
|> render("show.json", chat_message_reference: cm_ref)
else
_e -> {:error, :could_not_delete}
_e ->
{:error, :could_not_delete}
end
end
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
|> ChatMessageReference.delete()
end
def post_chat_message(
%{body_params: params, assigns: %{user: %{id: user_id} = user}} = conn,
%{
@ -69,10 +80,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
CommonAPI.post_chat_message(user, recipient, params[:content],
media_id: params[:media_id]
),
message <- Object.normalize(activity) do
message <- Object.normalize(activity, false),
cm_ref <- ChatMessageReference.for_chat_and_object(chat, message) do
conn
|> put_view(ChatMessageView)
|> render("show.json", for: user, object: message, chat: chat)
|> put_view(ChatMessageReferenceView)
|> render("show.json", for: user, chat_message_reference: cm_ref)
end
end
@ -87,14 +99,14 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
def messages(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: id} = params) do
with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id) do
messages =
cm_refs =
chat
|> Chat.messages_for_chat_query()
|> ChatMessageReference.for_chat_query()
|> Pagination.fetch_paginated(params |> stringify_keys())
conn
|> put_view(ChatMessageView)
|> render("index.json", for: user, objects: messages, chat: chat)
|> put_view(ChatMessageReferenceView)
|> render("index.json", for: user, chat_message_references: cm_refs)
else
_ ->
conn

View file

@ -2,10 +2,9 @@
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.ChatMessageView do
defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceView do
use Pleroma.Web, :view
alias Pleroma.Chat
alias Pleroma.User
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.StatusView
@ -13,8 +12,12 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageView do
def render(
"show.json",
%{
object: %{id: id, data: %{"type" => "ChatMessage"} = chat_message},
chat: %Chat{id: chat_id}
chat_message_reference: %{
id: id,
object: %{data: chat_message},
chat_id: chat_id,
seen: seen
}
}
) do
%{
@ -26,11 +29,17 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageView do
emojis: StatusView.build_emojis(chat_message["emoji"]),
attachment:
chat_message["attachment"] &&
StatusView.render("attachment.json", attachment: chat_message["attachment"])
StatusView.render("attachment.json", attachment: chat_message["attachment"]),
seen: seen
}
end
def render("index.json", opts) do
render_many(opts[:objects], __MODULE__, "show.json", Map.put(opts, :as, :object))
render_many(
opts[:chat_message_references],
__MODULE__,
"show.json",
Map.put(opts, :as, :chat_message_reference)
)
end
end