First
[anni] / lib / pleroma / chat / message_reference.ex
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
5 defmodule Pleroma.Chat.MessageReference do
6   @moduledoc """
7   A reference that builds a relation between an AP chat message that a user can see and whether it has been seen
8   by them, or should be displayed to them. Used to build the chat view that is presented to the user.
9   """
10
11   use Ecto.Schema
12
13   alias Pleroma.Chat
14   alias Pleroma.Object
15   alias Pleroma.Repo
16
17   import Ecto.Changeset
18   import Ecto.Query
19
20   @primary_key {:id, FlakeId.Ecto.Type, autogenerate: true}
21
22   schema "chat_message_references" do
23     belongs_to(:object, Object)
24     belongs_to(:chat, Chat, type: FlakeId.Ecto.CompatType)
25
26     field(:unread, :boolean, default: true)
27
28     timestamps()
29   end
30
31   def changeset(struct, params) do
32     struct
33     |> cast(params, [:object_id, :chat_id, :unread])
34     |> validate_required([:object_id, :chat_id, :unread])
35   end
36
37   def get_by_id(id) do
38     __MODULE__
39     |> Repo.get(id)
40     |> Repo.preload(:object)
41   end
42
43   def delete(cm_ref) do
44     cm_ref
45     |> Repo.delete()
46   end
47
48   def delete_for_object(%{id: object_id}) do
49     from(cr in __MODULE__,
50       where: cr.object_id == ^object_id
51     )
52     |> Repo.delete_all()
53   end
54
55   def for_chat_and_object(%{id: chat_id}, %{id: object_id}) do
56     __MODULE__
57     |> Repo.get_by(chat_id: chat_id, object_id: object_id)
58     |> Repo.preload(:object)
59   end
60
61   def for_chat_query(chat) do
62     from(cr in __MODULE__,
63       where: cr.chat_id == ^chat.id,
64       order_by: [desc: :id],
65       preload: [:object]
66     )
67   end
68
69   def last_message_for_chat(chat) do
70     chat
71     |> for_chat_query()
72     |> limit(1)
73     |> Repo.one()
74   end
75
76   def create(chat, object, unread) do
77     params = %{
78       chat_id: chat.id,
79       object_id: object.id,
80       unread: unread
81     }
82
83     %__MODULE__{}
84     |> changeset(params)
85     |> Repo.insert()
86   end
87
88   def unread_count_for_chat(chat) do
89     chat
90     |> for_chat_query()
91     |> where([cmr], cmr.unread == true)
92     |> Repo.aggregate(:count)
93   end
94
95   def mark_as_read(cm_ref) do
96     cm_ref
97     |> changeset(%{unread: false})
98     |> Repo.update()
99   end
100
101   def set_all_seen_for_chat(chat, last_read_id \\ nil) do
102     query =
103       chat
104       |> for_chat_query()
105       |> exclude(:order_by)
106       |> exclude(:preload)
107       |> where([cmr], cmr.unread == true)
108
109     if last_read_id do
110       query
111       |> where([cmr], cmr.id <= ^last_read_id)
112     else
113       query
114     end
115     |> Repo.update_all(set: [unread: false])
116   end
117 end