Conversations: Add recipient list to conversation participation.
authorlain <lain@soykaf.club>
Fri, 2 Aug 2019 09:55:41 +0000 (11:55 +0200)
committerlain <lain@soykaf.club>
Fri, 2 Aug 2019 09:55:41 +0000 (11:55 +0200)
This enables to address the same group of people every time.

lib/pleroma/conversation.ex
lib/pleroma/conversation/participation.ex
lib/pleroma/conversation/participation_recipient_ship.ex [new file with mode: 0644]
lib/pleroma/user.ex
priv/repo/migrations/20190205114625_create_thread_mutes.exs
priv/repo/migrations/20190801154554_create_conversation_participation_recipient_ships.exs [new file with mode: 0644]
test/conversation/participation_test.exs

index bc97b39ca6e6229d888f6fd721747e48f3579115..fb0dfedca11aa7b44c4e1e4ea2c65a948b5d8260 100644 (file)
@@ -4,6 +4,7 @@
 
 defmodule Pleroma.Conversation do
   alias Pleroma.Conversation.Participation
+  alias Pleroma.Conversation.Participation.RecipientShip
   alias Pleroma.Repo
   alias Pleroma.User
   use Ecto.Schema
@@ -39,6 +40,15 @@ defmodule Pleroma.Conversation do
     Repo.get_by(__MODULE__, ap_id: ap_id)
   end
 
+  def maybe_set_recipients(participation, activity) do
+    participation = Repo.preload(participation, :recipients)
+
+    if participation.recipients |> Enum.empty?() do
+      recipients = User.get_all_by_ap_id(activity.recipients)
+      RecipientShip.create(recipients, participation)
+    end
+  end
+
   @doc """
   This will
   1. Create a conversation if there isn't one already
@@ -60,6 +70,7 @@ defmodule Pleroma.Conversation do
           {:ok, participation} =
             Participation.create_for_user_and_conversation(user, conversation, opts)
 
+          maybe_set_recipients(participation, activity)
           participation
         end)
 
index 77b3f61e9af95c4b30adfa5822b40683c1282fca..121efb67195444b41c0bfaee3a16d0b1398edda0 100644 (file)
@@ -5,6 +5,7 @@
 defmodule Pleroma.Conversation.Participation do
   use Ecto.Schema
   alias Pleroma.Conversation
+  alias Pleroma.Conversation.Participation.RecipientShip
   alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
@@ -17,6 +18,9 @@ defmodule Pleroma.Conversation.Participation do
     field(:read, :boolean, default: false)
     field(:last_activity_id, Pleroma.FlakeId, virtual: true)
 
+    has_many(:recipient_ships, RecipientShip)
+    has_many(:recipients, through: [:recipient_ships, :user])
+
     timestamps()
   end
 
diff --git a/lib/pleroma/conversation/participation_recipient_ship.ex b/lib/pleroma/conversation/participation_recipient_ship.ex
new file mode 100644 (file)
index 0000000..27c0c89
--- /dev/null
@@ -0,0 +1,34 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Conversation.Participation.RecipientShip do
+  use Ecto.Schema
+
+  alias Pleroma.Conversation.Participation
+  alias Pleroma.User
+  alias Pleroma.Repo
+
+  import Ecto.Changeset
+
+  schema "conversation_participation_recipient_ships" do
+    belongs_to(:user, User, type: Pleroma.FlakeId)
+    belongs_to(:participation, Participation)
+  end
+
+  def creation_cng(struct, params) do
+    struct
+    |> cast(params, [:user_id, :participation_id])
+    |> validate_required([:user_id, :participation_id])
+  end
+
+  def create(%User{} = user, participation), do: create([user], participation)
+
+  def create(users, participation) do
+    Enum.each(users, fn user ->
+      %__MODULE__{}
+      |> creation_cng(%{user_id: user.id, participation_id: participation.id})
+      |> Repo.insert!()
+    end)
+  end
+end
index 6e2fd3af8d4d5030922c460a3c73286e73fce73f..a021e77f010e204237bb3fea4b97b0a1e80e0bb1 100644 (file)
@@ -450,6 +450,13 @@ defmodule Pleroma.User do
     Repo.get_by(User, ap_id: ap_id)
   end
 
+  def get_all_by_ap_id(ap_ids) do
+    from(u in __MODULE__,
+      where: u.ap_id in ^ap_ids
+    )
+    |> Repo.all()
+  end
+
   # This is mostly an SPC migration fix. This guesses the user nickname by taking the last part
   # of the ap_id and the domain and tries to get that user
   def get_by_guessed_nickname(ap_id) do
index 7e44db1214ab8ebefb4cadbed85fb4d68f2fa472..baaf072536cef5e97a41c08e537a9cadde70d65d 100644 (file)
@@ -6,7 +6,7 @@ defmodule Pleroma.Repo.Migrations.CreateThreadMutes do
       add :user_id, references(:users, type: :uuid, on_delete: :delete_all)
       add :context, :string
     end
-    
+
     create_if_not_exists unique_index(:thread_mutes, [:user_id, :context], name: :unique_index)
   end
 end
diff --git a/priv/repo/migrations/20190801154554_create_conversation_participation_recipient_ships.exs b/priv/repo/migrations/20190801154554_create_conversation_participation_recipient_ships.exs
new file mode 100644 (file)
index 0000000..c6e3469
--- /dev/null
@@ -0,0 +1,13 @@
+defmodule Pleroma.Repo.Migrations.CreateConversationParticipationRecipientShips do
+  use Ecto.Migration
+
+  def change do
+    create_if_not_exists table(:conversation_participation_recipient_ships) do
+      add(:user_id, references(:users, type: :uuid, on_delete: :delete_all))
+      add(:participation_id, references(:conversation_participations, on_delete: :delete_all))
+    end
+
+    create_if_not_exists index(:conversation_participation_recipient_ships, [:user_id])
+    create_if_not_exists index(:conversation_participation_recipient_ships, [:participation_id])
+  end
+end
index 2a03e5d67a722f4459fbef1174f6ef8b25a9f920..4a3c397bdc95c44046bcb9d1a84e21c845a70695 100644 (file)
@@ -8,6 +8,36 @@ defmodule Pleroma.Conversation.ParticipationTest do
   alias Pleroma.Conversation.Participation
   alias Pleroma.Web.CommonAPI
 
+  test "for a new conversation, it sets the recipents of the participation" do
+    user = insert(:user)
+    other_user = insert(:user)
+    third_user = insert(:user)
+
+    {:ok, activity} =
+      CommonAPI.post(user, %{"status" => "Hey @#{other_user.nickname}.", "visibility" => "direct"})
+
+    [participation] = Participation.for_user(user)
+    participation = Pleroma.Repo.preload(participation, :recipients)
+
+    assert length(participation.recipients) == 2
+    assert user in participation.recipients
+    assert other_user in participation.recipients
+
+    # Mentioning another user in the same conversation will not add a new recipients.
+
+    {:ok, _activity} =
+      CommonAPI.post(user, %{
+        "in_reply_to_status_id" => activity.id,
+        "status" => "Hey @#{third_user.nickname}.",
+        "visibility" => "direct"
+      })
+
+    [participation] = Participation.for_user(user)
+    participation = Pleroma.Repo.preload(participation, :recipients)
+
+    assert length(participation.recipients) == 2
+  end
+
   test "it creates a participation for a conversation and a user" do
     user = insert(:user)
     conversation = insert(:conversation)