schema "chats" do
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
field(:recipient, :string)
- field(:unread, :integer, default: 0, read_after_writes: true)
timestamps()
end
def creation_cng(struct, params) do
struct
- |> cast(params, [:user_id, :recipient, :unread])
+ |> cast(params, [:user_id, :recipient])
|> validate_change(:recipient, fn
:recipient, recipient ->
case User.get_cached_by_ap_id(recipient) do
def bump_or_create(user_id, recipient) do
%__MODULE__{}
- |> creation_cng(%{user_id: user_id, recipient: recipient, unread: 1})
+ |> creation_cng(%{user_id: user_id, recipient: recipient})
|> Repo.insert(
- on_conflict: [set: [updated_at: NaiveDateTime.utc_now()], inc: [unread: 1]],
+ on_conflict: [set: [updated_at: NaiveDateTime.utc_now()]],
conflict_target: [:user_id, :recipient]
)
end
-
- def mark_as_read(chat) do
- chat
- |> change(%{unread: 0})
- |> Repo.update()
- end
end
|> changeset(params)
|> Repo.insert()
end
+
+ def unread_count_for_chat(chat) do
+ chat
+ |> for_chat_query()
+ |> where([cmr], cmr.seen == false)
+ |> Repo.aggregate(:count)
+ end
+
+ def set_all_seen_for_chat(chat) do
+ chat
+ |> for_chat_query()
+ |> exclude(:order_by)
+ |> exclude(:preload)
+ |> where([cmr], cmr.seen == false)
+ |> Repo.update_all(set: [seen: true])
+ end
end
[[actor, recipient], [recipient, actor]]
|> Enum.each(fn [user, other_user] ->
if user.local do
- if user.ap_id == actor.ap_id do
- {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
- ChatMessageReference.create(chat, object, true)
- else
- {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
- ChatMessageReference.create(chat, object, false)
- end
+ {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
+ ChatMessageReference.create(chat, object, user.ap_id == actor.ap_id)
end
end)
def mark_as_read(%{assigns: %{user: %{id: user_id}}} = conn, %{id: id}) do
with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
- {:ok, chat} <- Chat.mark_as_read(chat) do
+ {_n, _} <- ChatMessageReference.set_all_seen_for_chat(chat) do
conn
|> put_view(ChatView)
|> render("show.json", chat: chat)
%{
id: chat.id |> to_string(),
account: AccountView.render("show.json", Map.put(opts, :user, recipient)),
- unread: chat.unread,
+ unread: ChatMessageReference.unread_count_for_chat(chat),
last_message:
last_message &&
ChatMessageReferenceView.render("show.json", chat_message_reference: last_message),
--- /dev/null
+defmodule Pleroma.Repo.Migrations.RemoveUnreadFromChats do
+ use Ecto.Migration
+
+ def change do
+ alter table(:chats) do
+ remove(:unread, :integer, default: 0)
+ end
+ end
+end
use Pleroma.DataCase, async: true
alias Pleroma.Chat
- alias Pleroma.Web.CommonAPI
import Pleroma.Factory
{:ok, chat_two} = Chat.bump_or_create(user.id, other_user.ap_id)
assert chat.id == chat_two.id
- assert chat_two.unread == 2
end
test "it returns a chat for a user and recipient if it already exists" do
assert chat.id == chat_two.id
end
- test "a returning chat will have an updated `update_at` field and an incremented unread count" do
+ test "a returning chat will have an updated `update_at` field" do
user = insert(:user)
other_user = insert(:user)
{:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
- assert chat.unread == 1
:timer.sleep(1500)
{:ok, chat_two} = Chat.bump_or_create(user.id, other_user.ap_id)
- assert chat_two.unread == 2
assert chat.id == chat_two.id
assert chat.updated_at != chat_two.updated_at
SideEffects.handle(create_activity, local: false, object_data: chat_message_data)
chat = Chat.get(author.id, recipient.ap_id)
- assert chat.unread == 0
[cm_ref] = ChatMessageReference.for_chat_query(chat) |> Repo.all()
assert cm_ref.seen == true
chat = Chat.get(recipient.id, author.ap_id)
- assert chat.unread == 1
[cm_ref] = ChatMessageReference.for_chat_query(chat) |> Repo.all()
test "it marks all messages in a chat as read", %{conn: conn, user: user} do
other_user = insert(:user)
- {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
+ {:ok, create} = CommonAPI.post_chat_message(other_user, user, "sup")
+ {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
+ object = Object.normalize(create, false)
+ cm_ref = ChatMessageReference.for_chat_and_object(chat, object)
- assert chat.unread == 1
+ assert cm_ref.seen == false
result =
conn
assert result["unread"] == 0
- {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
+ cm_ref = ChatMessageReference.for_chat_and_object(chat, object)
- assert chat.unread == 0
+ assert cm_ref.seen == true
end
end