Merge branch 'develop' of https://git.pleroma.social/pleroma/pleroma into develop
[akkoma] / lib / pleroma / conversation / participation.ex
index 41918fa78e4cd21962c902563b95fa004ebe50d9..e5d28ebffdfc786480fc417ff409d116044f76bd 100644 (file)
@@ -32,11 +32,20 @@ defmodule Pleroma.Conversation.Participation do
 
   def create_for_user_and_conversation(user, conversation, opts \\ []) do
     read = !!opts[:read]
+    invisible_conversation = !!opts[:invisible_conversation]
+
+    update_on_conflict =
+      if(invisible_conversation, do: [], else: [read: read])
+      |> Keyword.put(:updated_at, NaiveDateTime.utc_now())
 
     %__MODULE__{}
-    |> creation_cng(%{user_id: user.id, conversation_id: conversation.id, read: read})
+    |> creation_cng(%{
+      user_id: user.id,
+      conversation_id: conversation.id,
+      read: invisible_conversation || read
+    })
     |> Repo.insert(
-      on_conflict: [set: [read: read, updated_at: NaiveDateTime.utc_now()]],
+      on_conflict: [set: update_on_conflict],
       returning: true,
       conflict_target: [:user_id, :conversation_id]
     )
@@ -55,11 +64,13 @@ defmodule Pleroma.Conversation.Participation do
   end
 
   def mark_as_read(participation) do
-    participation
-    |> read_cng(%{read: true})
-    |> Repo.update()
+    __MODULE__
+    |> where(id: ^participation.id)
+    |> update(set: [read: true])
+    |> select([p], p)
+    |> Repo.update_all([])
     |> case do
-      {:ok, participation} ->
+      {1, [participation]} ->
         participation = Repo.preload(participation, :user)
         User.set_unread_conversation_count(participation.user)
         {:ok, participation}
@@ -69,7 +80,26 @@ defmodule Pleroma.Conversation.Participation do
     end
   end
 
-  def mark_all_as_read(user) do
+  def mark_all_as_read(%User{local: true} = user, %User{} = target_user) do
+    target_conversation_ids =
+      __MODULE__
+      |> where([p], p.user_id == ^target_user.id)
+      |> select([p], p.conversation_id)
+      |> Repo.all()
+
+    __MODULE__
+    |> where([p], p.user_id == ^user.id)
+    |> where([p], p.conversation_id in ^target_conversation_ids)
+    |> update([p], set: [read: true])
+    |> Repo.update_all([])
+
+    {:ok, user} = User.set_unread_conversation_count(user)
+    {:ok, user, []}
+  end
+
+  def mark_all_as_read(%User{} = user, %User{}), do: {:ok, user, []}
+
+  def mark_all_as_read(%User{} = user) do
     {_, participations} =
       __MODULE__
       |> where([p], p.user_id == ^user.id)
@@ -78,8 +108,8 @@ defmodule Pleroma.Conversation.Participation do
       |> select([p], p)
       |> Repo.update_all([])
 
-    User.set_unread_conversation_count(user)
-    {:ok, participations}
+    {:ok, user} = User.set_unread_conversation_count(user)
+    {:ok, user, participations}
   end
 
   def mark_as_unread(participation) do
@@ -94,9 +124,37 @@ defmodule Pleroma.Conversation.Participation do
       order_by: [desc: p.updated_at],
       preload: [conversation: [:users]]
     )
+    |> restrict_recipients(user, params)
     |> Pleroma.Pagination.fetch_paginated(params)
   end
 
+  def restrict_recipients(query, user, %{"recipients" => user_ids}) do
+    user_ids =
+      [user.id | user_ids]
+      |> Enum.uniq()
+      |> Enum.reduce([], fn user_id, acc ->
+        case FlakeId.Ecto.CompatType.dump(user_id) do
+          {:ok, user_id} -> [user_id | acc]
+          _ -> acc
+        end
+      end)
+
+    conversation_subquery =
+      __MODULE__
+      |> group_by([p], p.conversation_id)
+      |> having(
+        [p],
+        count(p.user_id) == ^length(user_ids) and
+          fragment("array_agg(?) @> ?", p.user_id, ^user_ids)
+      )
+      |> select([p], %{id: p.conversation_id})
+
+    query
+    |> join(:inner, [p], c in subquery(conversation_subquery), on: p.conversation_id == c.id)
+  end
+
+  def restrict_recipients(query, _, _), do: query
+
   def for_user_and_conversation(user, conversation) do
     from(p in __MODULE__,
       where: p.user_id == ^user.id,