SideEffects: Handle ChatMessage creation.
authorlain <lain@soykaf.club>
Thu, 9 Apr 2020 10:44:20 +0000 (12:44 +0200)
committerlain <lain@soykaf.club>
Thu, 9 Apr 2020 10:44:20 +0000 (12:44 +0200)
lib/pleroma/chat.ex
lib/pleroma/web/activity_pub/builder.ex
lib/pleroma/web/activity_pub/side_effects.ex
test/chat_test.exs
test/web/activity_pub/side_effects_test.exs

index 07ad62b97fbc63c0d63d782f7117800f1facc3cb..b61bc4c0e741b8eacfa7df5106b721572c902a5d 100644 (file)
@@ -18,23 +18,28 @@ defmodule Pleroma.Chat do
   schema "chats" do
     belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
     field(:recipient, :string)
-    field(:unread, :integer, default: 0)
+    field(:unread, :integer, default: 0, read_after_writes: true)
 
     timestamps()
   end
 
   def creation_cng(struct, params) do
     struct
-    |> cast(params, [:user_id, :recipient])
+    |> cast(params, [:user_id, :recipient, :unread])
     |> validate_required([:user_id, :recipient])
     |> unique_constraint(:user_id, name: :chats_user_id_recipient_index)
   end
 
-  def get_or_create(user_id, recipient) do
+  def get(user_id, recipient) do
+    __MODULE__
+    |> Repo.get_by(user_id: user_id, recipient: recipient)
+  end
+
+  def bump_or_create(user_id, recipient) do
     %__MODULE__{}
-    |> creation_cng(%{user_id: user_id, recipient: recipient})
+    |> creation_cng(%{user_id: user_id, recipient: recipient, unread: 1})
     |> Repo.insert(
-      on_conflict: [set: [updated_at: NaiveDateTime.utc_now()]],
+      on_conflict: [set: [updated_at: NaiveDateTime.utc_now()], inc: [unread: 1]],
       conflict_target: [:user_id, :recipient]
     )
   end
index 429a510b8118df4f136f614de281131fd5dd78b8..f0a6c1e1b8eca57fa1a6f4b7eb0ce13413bf705e 100644 (file)
@@ -10,6 +10,28 @@ defmodule Pleroma.Web.ActivityPub.Builder do
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.ActivityPub.Visibility
 
+  def create(actor, object_id, recipients) do
+    {:ok,
+     %{
+       "id" => Utils.generate_activity_id(),
+       "actor" => actor.ap_id,
+       "to" => recipients,
+       "object" => object_id,
+       "type" => "Create"
+     }, []}
+  end
+
+  def chat_message(actor, recipient, content) do
+    {:ok,
+     %{
+       "id" => Utils.generate_object_id(),
+       "actor" => actor.ap_id,
+       "type" => "ChatMessage",
+       "to" => [recipient],
+       "content" => content
+     }, []}
+  end
+
   @spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
   def like(actor, object) do
     object_actor = User.get_cached_by_ap_id(object.data["actor"])
index 666a4e310a6a116c1f68e0dafc6fd30686f0bd2f..594f327009f828cf43da74349724202434b8bdeb 100644 (file)
@@ -5,8 +5,10 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
   liked object, a `Follow` activity will add the user to the follower
   collection, and so on.
   """
+  alias Pleroma.Chat
   alias Pleroma.Notification
   alias Pleroma.Object
+  alias Pleroma.User
   alias Pleroma.Web.ActivityPub.Utils
 
   def handle(object, meta \\ [])
@@ -21,8 +23,35 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
     {:ok, object, meta}
   end
 
+  def handle(%{data: %{"type" => "Create", "object" => object_id}} = activity, meta) do
+    object = Object.get_by_ap_id(object_id)
+
+    {:ok, _object} = handle_object_creation(object)
+
+    {:ok, activity, meta}
+  end
+
   # Nothing to do
   def handle(object, meta) do
     {:ok, object, meta}
   end
+
+  def handle_object_creation(%{data: %{"type" => "ChatMessage"}} = object) do
+    actor = User.get_cached_by_ap_id(object.data["actor"])
+    recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
+
+    [[actor, recipient], [recipient, actor]]
+    |> Enum.each(fn [user, other_user] ->
+      if user.local do
+        Chat.bump_or_create(user.id, other_user.ap_id)
+      end
+    end)
+
+    {:ok, object}
+  end
+
+  # Nothing to do
+  def handle_object_creation(object) do
+    {:ok, object}
+  end
 end
index ca92068027e10fbb27c4c90866ddcb76b59853ca..bb2b46d5184d8124a7cbb25245facd31e4082efe 100644 (file)
@@ -14,7 +14,7 @@ defmodule Pleroma.ChatTest do
       user = insert(:user)
       other_user = insert(:user)
 
-      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
+      {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
 
       assert chat.id
     end
@@ -23,19 +23,21 @@ defmodule Pleroma.ChatTest do
       user = insert(:user)
       other_user = insert(:user)
 
-      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
-      {:ok, chat_two} = Chat.get_or_create(user.id, other_user.ap_id)
+      {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
+      {:ok, chat_two} = Chat.bump_or_create(user.id, other_user.ap_id)
 
       assert chat.id == chat_two.id
     end
 
-    test "a returning chat will have an updated `update_at` field" do
+    test "a returning chat will have an updated `update_at` field and an incremented unread count" do
       user = insert(:user)
       other_user = insert(:user)
 
-      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
+      {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
+      assert chat.unread == 1
       :timer.sleep(1500)
-      {:ok, chat_two} = Chat.get_or_create(user.id, other_user.ap_id)
+      {: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
index b67bd14b36e08f07c57629aefa378a7991acdcb7..5fd8372b53ecd10064355c8c4a69b2e09fbda3a1 100644 (file)
@@ -5,6 +5,7 @@
 defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
   use Pleroma.DataCase
 
+  alias Pleroma.Chat
   alias Pleroma.Object
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Builder
@@ -31,4 +32,29 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
       assert user.ap_id in object.data["likes"]
     end
   end
+
+  describe "creation of ChatMessages" do
+    test "it creates a Chat for the local users and bumps the unread count" do
+      author = insert(:user, local: false)
+      recipient = insert(:user, local: true)
+
+      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey")
+      {:ok, chat_message_object} = Object.create(chat_message_data)
+
+      {:ok, create_activity_data, _meta} =
+        Builder.create(author, chat_message_object.data["id"], [recipient.ap_id])
+
+      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false)
+
+      {:ok, _create_activity, _meta} = SideEffects.handle(create_activity)
+
+      # The remote user won't get a chat
+      chat = Chat.get(author.id, recipient.ap_id)
+      refute chat
+
+      # The local user will get a chat
+      chat = Chat.get(recipient.id, author.ap_id)
+      assert chat
+    end
+  end
 end