Merge branch 'develop' into feature/database-compaction
[akkoma] / test / web / activity_pub / activity_pub_test.exs
index a6f8b822ac1124b64cb47558941a917b9518c758..68bfb3858f7a89f2199da7f47bbf638353cf17b7 100644 (file)
@@ -1,17 +1,17 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
   use Pleroma.DataCase
-  alias Pleroma.Web.ActivityPub.ActivityPub
-  alias Pleroma.Web.ActivityPub.Utils
-  alias Pleroma.Web.CommonAPI
   alias Pleroma.Activity
+  alias Pleroma.Builders.ActivityBuilder
+  alias Pleroma.Instances
   alias Pleroma.Object
   alias Pleroma.User
-  alias Pleroma.Instances
-  alias Pleroma.Builders.ActivityBuilder
+  alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.ActivityPub.Utils
+  alias Pleroma.Web.CommonAPI
 
   import Pleroma.Factory
   import Tesla.Mock
@@ -55,6 +55,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
         ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id})
 
       assert activities == [public_activity]
+
+      activities =
+        ActivityPub.fetch_activities([], %{
+          :visibility => ~w[private public],
+          "actor_id" => user.ap_id
+        })
+
+      assert activities == [public_activity, private_activity]
     end
   end
 
@@ -132,7 +140,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       activity = insert(:note_activity)
       {:ok, new_activity} = ActivityPub.insert(activity.data)
 
-      assert activity == new_activity
+      assert activity.id == new_activity.id
     end
 
     test "inserts a given map into the activity database, giving it an id if it has none." do
@@ -184,8 +192,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       }
 
       {:ok, %Activity{} = activity} = ActivityPub.insert(data)
-      assert is_binary(activity.data["object"]["id"])
-      assert %Object{} = Object.get_by_ap_id(activity.data["object"]["id"])
+      object = Object.normalize(activity.data["object"])
+
+      assert is_binary(object.data["id"])
+      assert %Object{} = Object.get_by_ap_id(activity.data["object"])
     end
   end
 
@@ -198,13 +208,69 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
           to: ["user1", "user1", "user2"],
           actor: user,
           context: "",
-          object: %{}
+          object: %{
+            "to" => ["user1", "user1", "user2"],
+            "type" => "Note",
+            "content" => "testing"
+          }
         })
 
       assert activity.data["to"] == ["user1", "user2"]
       assert activity.actor == user.ap_id
       assert activity.recipients == ["user1", "user2", user.ap_id]
     end
+
+    test "increases user note count only for public activities" do
+      user = insert(:user)
+
+      {:ok, _} =
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "1", "visibility" => "public"})
+
+      {:ok, _} =
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "unlisted"})
+
+      {:ok, _} =
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "private"})
+
+      {:ok, _} =
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "3", "visibility" => "direct"})
+
+      user = User.get_by_id(user.id)
+      assert user.info.note_count == 2
+    end
+
+    test "increases replies count" do
+      user = insert(:user)
+      user2 = insert(:user)
+
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
+      ap_id = activity.data["id"]
+      reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
+
+      # public
+      {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
+      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+      assert data["object"]["repliesCount"] == 1
+      assert object.data["repliesCount"] == 1
+
+      # unlisted
+      {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
+      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+      assert data["object"]["repliesCount"] == 2
+      assert object.data["repliesCount"] == 2
+
+      # private
+      {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
+      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+      assert data["object"]["repliesCount"] == 2
+      assert object.data["repliesCount"] == 2
+
+      # direct
+      {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
+      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+      assert data["object"]["repliesCount"] == 2
+      assert object.data["repliesCount"] == 2
+    end
   end
 
   describe "fetch activities for recipients" do
@@ -243,7 +309,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     booster = insert(:user)
     {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]})
 
-    activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
+    activities =
+      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
 
     assert Enum.member?(activities, activity_two)
     assert Enum.member?(activities, activity_three)
@@ -251,7 +318,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
     {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
 
-    activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
+    activities =
+      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
 
     assert Enum.member?(activities, activity_two)
     assert Enum.member?(activities, activity_three)
@@ -260,16 +328,75 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     {:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
     {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
     %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
-    activity_three = Repo.get(Activity, activity_three.id)
+    activity_three = Activity.get_by_id(activity_three.id)
+
+    activities =
+      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
+
+    assert Enum.member?(activities, activity_two)
+    refute Enum.member?(activities, activity_three)
+    refute Enum.member?(activities, boost_activity)
+    assert Enum.member?(activities, activity_one)
+
+    activities =
+      ActivityPub.fetch_activities([], %{"blocking_user" => nil, "skip_preload" => true})
+
+    assert Enum.member?(activities, activity_two)
+    assert Enum.member?(activities, activity_three)
+    assert Enum.member?(activities, boost_activity)
+    assert Enum.member?(activities, activity_one)
+  end
+
+  test "doesn't return muted activities" do
+    activity_one = insert(:note_activity)
+    activity_two = insert(:note_activity)
+    activity_three = insert(:note_activity)
+    user = insert(:user)
+    booster = insert(:user)
+    {:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]})
+
+    activities =
+      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
+
+    assert Enum.member?(activities, activity_two)
+    assert Enum.member?(activities, activity_three)
+    refute Enum.member?(activities, activity_one)
+
+    # Calling with 'with_muted' will deliver muted activities, too.
+    activities =
+      ActivityPub.fetch_activities([], %{
+        "muting_user" => user,
+        "with_muted" => true,
+        "skip_preload" => true
+      })
+
+    assert Enum.member?(activities, activity_two)
+    assert Enum.member?(activities, activity_three)
+    assert Enum.member?(activities, activity_one)
+
+    {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]})
+
+    activities =
+      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
+
+    assert Enum.member?(activities, activity_two)
+    assert Enum.member?(activities, activity_three)
+    assert Enum.member?(activities, activity_one)
+
+    {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
+    {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
+    %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
+    activity_three = Activity.get_by_id(activity_three.id)
 
-    activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
+    activities =
+      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
 
     assert Enum.member?(activities, activity_two)
     refute Enum.member?(activities, activity_three)
     refute Enum.member?(activities, boost_activity)
     assert Enum.member?(activities, activity_one)
 
-    activities = ActivityPub.fetch_activities([], %{"blocking_user" => nil})
+    activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true})
 
     assert Enum.member?(activities, activity_two)
     assert Enum.member?(activities, activity_three)
@@ -277,6 +404,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     assert Enum.member?(activities, activity_one)
   end
 
+  test "does include announces on request" do
+    activity_three = insert(:note_activity)
+    user = insert(:user)
+    booster = insert(:user)
+
+    {:ok, user} = User.follow(user, booster)
+
+    {:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster)
+
+    [announce_activity] = ActivityPub.fetch_activities([user.ap_id | user.following])
+
+    assert announce_activity.id == announce.id
+  end
+
   test "excludes reblogs on request" do
     user = insert(:user)
     {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
@@ -348,6 +489,33 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert length(activities) == 20
       assert last == last_expected
     end
+
+    test "doesn't return reblogs for users for whom reblogs have been muted" do
+      activity = insert(:note_activity)
+      user = insert(:user)
+      booster = insert(:user)
+      {:ok, user} = CommonAPI.hide_reblogs(user, booster)
+
+      {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
+
+      activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
+
+      refute Enum.any?(activities, fn %{id: id} -> id == activity.id end)
+    end
+
+    test "returns reblogs for users for whom reblogs have not been muted" do
+      activity = insert(:note_activity)
+      user = insert(:user)
+      booster = insert(:user)
+      {:ok, user} = CommonAPI.hide_reblogs(user, booster)
+      {:ok, user} = CommonAPI.show_reblogs(user, booster)
+
+      {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
+
+      activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
+
+      assert Enum.any?(activities, fn %{id: id} -> id == activity.id end)
+    end
   end
 
   describe "like an object" do
@@ -397,7 +565,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       {:ok, _, _, object} = ActivityPub.unlike(user, object)
       assert object.data["like_count"] == 0
 
-      assert Repo.get(Activity, like_activity.id) == nil
+      assert Activity.get_by_id(like_activity.id) == nil
     end
   end
 
@@ -448,7 +616,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert unannounce_activity.data["actor"] == user.ap_id
       assert unannounce_activity.data["context"] == announce_activity.data["context"]
 
-      assert Repo.get(Activity, announce_activity.id) == nil
+      assert Activity.get_by_id(announce_activity.id) == nil
     end
   end
 
@@ -587,10 +755,89 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert delete.data["actor"] == note.data["actor"]
       assert delete.data["object"] == note.data["object"]["id"]
 
-      assert Repo.get(Activity, delete.id) != nil
+      assert Activity.get_by_id(delete.id) != nil
 
       assert Repo.get(Object, object.id).data["type"] == "Tombstone"
     end
+
+    test "decrements user note count only for public activities" do
+      user = insert(:user, info: %{note_count: 10})
+
+      {:ok, a1} =
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "public"})
+
+      {:ok, a2} =
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "unlisted"})
+
+      {:ok, a3} =
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "private"})
+
+      {:ok, a4} =
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "direct"})
+
+      {:ok, _} = a1.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
+      {:ok, _} = a2.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
+      {:ok, _} = a3.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
+      {:ok, _} = a4.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
+
+      user = User.get_by_id(user.id)
+      assert user.info.note_count == 10
+    end
+
+    test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
+      user = insert(:user)
+      note = insert(:note_activity)
+
+      {:ok, object} =
+        Object.get_by_ap_id(note.data["object"]["id"])
+        |> Object.change(%{
+          data: %{
+            "actor" => note.data["object"]["actor"],
+            "id" => note.data["object"]["id"],
+            "to" => [user.ap_id],
+            "type" => "Note"
+          }
+        })
+        |> Object.update_and_set_cache()
+
+      {:ok, delete} = ActivityPub.delete(object)
+
+      assert user.ap_id in delete.data["to"]
+    end
+
+    test "decreases reply count" do
+      user = insert(:user)
+      user2 = insert(:user)
+
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
+      reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
+      ap_id = activity.data["id"]
+
+      {:ok, public_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
+      {:ok, unlisted_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
+      {:ok, private_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
+      {:ok, direct_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
+
+      _ = CommonAPI.delete(direct_reply.id, user2)
+      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+      assert data["object"]["repliesCount"] == 2
+      assert object.data["repliesCount"] == 2
+
+      _ = CommonAPI.delete(private_reply.id, user2)
+      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+      assert data["object"]["repliesCount"] == 2
+      assert object.data["repliesCount"] == 2
+
+      _ = CommonAPI.delete(public_reply.id, user2)
+      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+      assert data["object"]["repliesCount"] == 1
+      assert object.data["repliesCount"] == 1
+
+      _ = CommonAPI.delete(unlisted_reply.id, user2)
+      assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+      assert data["object"]["repliesCount"] == 0
+      assert object.data["repliesCount"] == 0
+    end
   end
 
   describe "timeline post-processing" do
@@ -629,6 +876,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
       activities = ActivityPub.fetch_activities([user1.ap_id | user1.following])
 
+      private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"])
       assert [public_activity, private_activity_1, private_activity_3] == activities
       assert length(activities) == 3
 
@@ -639,15 +887,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     end
   end
 
-  test "it can fetch plume articles" do
-    {:ok, object} =
-      ActivityPub.fetch_object_from_id(
-        "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"
-      )
-
-    assert object
-  end
-
   describe "update" do
     test "it creates an update activity with the new user data" do
       user = insert(:user)
@@ -700,6 +939,37 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     assert 3 = length(activities)
   end
 
+  test "it can create a Flag activity" do
+    reporter = insert(:user)
+    target_account = insert(:user)
+    {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"})
+    context = Utils.generate_context_id()
+    content = "foobar"
+
+    reporter_ap_id = reporter.ap_id
+    target_ap_id = target_account.ap_id
+    activity_ap_id = activity.data["id"]
+
+    assert {:ok, activity} =
+             ActivityPub.flag(%{
+               actor: reporter,
+               context: context,
+               account: target_account,
+               statuses: [activity],
+               content: content
+             })
+
+    assert %Activity{
+             actor: ^reporter_ap_id,
+             data: %{
+               "type" => "Flag",
+               "content" => ^content,
+               "context" => ^context,
+               "object" => [^target_ap_id, ^activity_ap_id]
+             }
+           } = activity
+  end
+
   describe "publish_one/1" do
     test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
                    Instances,