Mark the conversations with the blocked user as read and update the blocking user...
authoreugenijm <eugenijm@protonmail.com>
Fri, 25 Oct 2019 18:29:23 +0000 (21:29 +0300)
committereugenijm <eugenijm@protonmail.com>
Fri, 25 Oct 2019 23:29:18 +0000 (02:29 +0300)
Since the conversations with the blocked user are invisible, they are excluded
from the blocking user's `unread_conversation_count`.

lib/pleroma/conversation.ex
lib/pleroma/conversation/participation.ex
lib/pleroma/user.ex
lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
test/conversation/participation_test.exs

index 098016af28c7b839bd6f019d4d61ea6e59ab3c7a..ade3a526a57e52b1f69006eb383dd438c03f2df6 100644 (file)
@@ -67,7 +67,13 @@ defmodule Pleroma.Conversation do
 
       participations =
         Enum.map(users, fn user ->
-          User.increment_unread_conversation_count(conversation, user)
+          invisible_conversation = Enum.any?(users, &User.blocks?(user, &1))
+
+          unless invisible_conversation do
+            User.increment_unread_conversation_count(conversation, user)
+          end
+
+          opts = Keyword.put(opts, :invisible_conversation, invisible_conversation)
 
           {:ok, participation} =
             Participation.create_for_user_and_conversation(user, conversation, opts)
index 41918fa78e4cd21962c902563b95fa004ebe50d9..176b82a2092e46cd48745c719a5f4c6fd4dd206d 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]
     )
@@ -69,7 +78,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 +106,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
index b99e236a4790ac2dc29f3a17c5d5d1adc5671e0d..5d3f5572192966b7fff3d0c99a678e25b3058c2d 100644 (file)
@@ -971,7 +971,7 @@ defmodule Pleroma.User do
     end
   end
 
-  def set_unread_conversation_count(_), do: :noop
+  def set_unread_conversation_count(user), do: {:ok, user}
 
   def increment_unread_conversation_count(conversation, %User{local: true} = user) do
     unread_query =
@@ -993,7 +993,7 @@ defmodule Pleroma.User do
     end
   end
 
-  def increment_unread_conversation_count(_, _), do: :noop
+  def increment_unread_conversation_count(_, user), do: {:ok, user}
 
   def remove_duplicated_following(%User{following: following} = user) do
     uniq_following = Enum.uniq(following)
@@ -1077,7 +1077,7 @@ defmodule Pleroma.User do
     if following?(blocked, blocker), do: unfollow(blocked, blocker)
 
     {:ok, blocker} = update_follower_count(blocker)
-
+    {:ok, blocker, _} = Participation.mark_all_as_read(blocker, blocked)
     add_to_block(blocker, ap_id)
   end
 
index fc39abf053ee658b90b846e708bebf080636e79e..651a9942382355871610cc687cb7dec48ab20199 100644 (file)
@@ -80,7 +80,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
   end
 
   def read_conversations(%{assigns: %{user: user}} = conn, _params) do
-    with {:ok, participations} <- Participation.mark_all_as_read(user) do
+    with {:ok, _, participations} <- Participation.mark_all_as_read(user) do
       conn
       |> add_link_headers(participations)
       |> put_view(ConversationView)
index 91867bf7047341a066b7a2f810de305edc4e3021..863270022e8c0f8ac8675277114642cc46498598 100644 (file)
@@ -140,7 +140,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
     participation2 = insert(:participation, %{read: false, user: user})
     participation3 = insert(:participation, %{read: false, user: other_user})
 
-    {:ok, [%{read: true}, %{read: true}]} = Participation.mark_all_as_read(user)
+    {:ok, _, [%{read: true}, %{read: true}]} = Participation.mark_all_as_read(user)
 
     assert Participation.get(participation1.id).read == true
     assert Participation.get(participation2.id).read == true
@@ -216,4 +216,134 @@ defmodule Pleroma.Conversation.ParticipationTest do
     assert user in participation.recipients
     assert other_user in participation.recipients
   end
+
+  describe "blocking" do
+    test "when the user blocks a recipient, the existing conversations with them are marked as read" do
+      blocker = insert(:user)
+      blocked = insert(:user)
+      third_user = insert(:user)
+
+      {:ok, _direct1} =
+        CommonAPI.post(third_user, %{
+          "status" => "Hi @#{blocker.nickname}",
+          "visibility" => "direct"
+        })
+
+      {:ok, _direct2} =
+        CommonAPI.post(third_user, %{
+          "status" => "Hi @#{blocker.nickname}, @#{blocked.nickname}",
+          "visibility" => "direct"
+        })
+
+      {:ok, _direct3} =
+        CommonAPI.post(blocked, %{
+          "status" => "Hi @#{blocker.nickname}",
+          "visibility" => "direct"
+        })
+
+      {:ok, _direct4} =
+        CommonAPI.post(blocked, %{
+          "status" => "Hi @#{blocker.nickname}, @#{third_user.nickname}",
+          "visibility" => "direct"
+        })
+
+      assert [%{read: false}, %{read: false}, %{read: false}, %{read: false}] =
+               Participation.for_user(blocker)
+
+      assert User.get_cached_by_id(blocker.id).unread_conversation_count == 4
+
+      {:ok, blocker} = User.block(blocker, blocked)
+
+      # The conversations with the blocked user are marked as read
+      assert [%{read: true}, %{read: true}, %{read: true}, %{read: false}] =
+               Participation.for_user(blocker)
+
+      assert User.get_cached_by_id(blocker.id).unread_conversation_count == 1
+
+      # The conversation is not marked as read for the blocked user
+      assert [_, _, %{read: false}] = Participation.for_user(blocked)
+      assert User.get_cached_by_id(blocked.id).unread_conversation_count == 1
+
+      # The conversation is not marked as read for the third user
+      assert [%{read: false}, _, _] = Participation.for_user(third_user)
+      assert User.get_cached_by_id(third_user.id).unread_conversation_count == 1
+    end
+
+    test "the new conversation with the blocked user is not marked as unread " do
+      blocker = insert(:user)
+      blocked = insert(:user)
+      third_user = insert(:user)
+
+      {:ok, blocker} = User.block(blocker, blocked)
+
+      # When the blocked user is the author
+      {:ok, _direct1} =
+        CommonAPI.post(blocked, %{
+          "status" => "Hi @#{blocker.nickname}",
+          "visibility" => "direct"
+        })
+
+      assert [%{read: true}] = Participation.for_user(blocker)
+      assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+
+      # When the blocked user is a recipient
+      {:ok, _direct2} =
+        CommonAPI.post(third_user, %{
+          "status" => "Hi @#{blocker.nickname}, @#{blocked.nickname}",
+          "visibility" => "direct"
+        })
+
+      assert [%{read: true}, %{read: true}] = Participation.for_user(blocker)
+      assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+
+      assert [%{read: false}, _] = Participation.for_user(blocked)
+      assert User.get_cached_by_id(blocked.id).unread_conversation_count == 1
+    end
+
+    test "the conversation with the blocked user is not marked as unread on a reply" do
+      blocker = insert(:user)
+      blocked = insert(:user)
+      third_user = insert(:user)
+
+      {:ok, _direct1} =
+        CommonAPI.post(blocker, %{
+          "status" => "Hi @#{third_user.nickname}, @#{blocked.nickname}",
+          "visibility" => "direct"
+        })
+
+      {:ok, blocker} = User.block(blocker, blocked)
+      assert [%{read: true}] = Participation.for_user(blocker)
+      assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+
+      assert [blocked_participation] = Participation.for_user(blocked)
+
+      # When it's a reply from the blocked user
+      {:ok, _direct2} =
+        CommonAPI.post(blocked, %{
+          "status" => "reply",
+          "visibility" => "direct",
+          "in_reply_to_conversation_id" => blocked_participation.id
+        })
+
+      assert [%{read: true}] = Participation.for_user(blocker)
+      assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+
+      assert [third_user_participation] = Participation.for_user(third_user)
+
+      # When it's a reply from the third user
+      {:ok, _direct3} =
+        CommonAPI.post(third_user, %{
+          "status" => "reply",
+          "visibility" => "direct",
+          "in_reply_to_conversation_id" => third_user_participation.id
+        })
+
+      assert [%{read: true}] = Participation.for_user(blocker)
+      assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+
+      # Marked as unread for the blocked user
+      assert [%{read: false}] = Participation.for_user(blocked)
+      assert User.get_cached_by_id(blocked.id).unread_conversation_count == 1
+    end
+  end
 end