summaryrefslogtreecommitdiff
path: root/test/web/activity_pub/activity_pub_test.exs
diff options
context:
space:
mode:
Diffstat (limited to 'test/web/activity_pub/activity_pub_test.exs')
-rw-r--r--test/web/activity_pub/activity_pub_test.exs1408
1 files changed, 1029 insertions, 379 deletions
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index 8ae946969..77bd07edf 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -1,32 +1,38 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
use Pleroma.DataCase
+ use Oban.Testing, repo: Pleroma.Repo
+
alias Pleroma.Activity
alias Pleroma.Builders.ActivityBuilder
+ alias Pleroma.Config
+ alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.CommonAPI
+ import ExUnit.CaptureLog
+ import Mock
import Pleroma.Factory
import Tesla.Mock
- import Mock
setup do
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
- clear_config([:instance, :federating])
+ setup do: clear_config([:instance, :federating])
describe "streaming out participations" do
test "it streams them out" do
user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
+ {:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
{:ok, conversation} = Pleroma.Conversation.create_or_bump_for(activity)
@@ -50,8 +56,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
stream: fn _, _ -> nil end do
{:ok, activity} =
CommonAPI.post(user_one, %{
- "status" => "@#{user_two.nickname}",
- "visibility" => "direct"
+ status: "@#{user_two.nickname}",
+ visibility: "direct"
})
conversation =
@@ -68,15 +74,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "it restricts by the appropriate visibility" do
user = insert(:user)
- {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
+ {:ok, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"})
- {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
+ {:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
- {:ok, unlisted_activity} =
- CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
+ {:ok, unlisted_activity} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"})
- {:ok, private_activity} =
- CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
+ {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
activities =
ActivityPub.fetch_activities([], %{:visibility => "direct", "actor_id" => user.ap_id})
@@ -112,15 +116,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "it excludes by the appropriate visibility" do
user = insert(:user)
- {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
+ {:ok, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"})
- {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
+ {:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
- {:ok, unlisted_activity} =
- CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
+ {:ok, unlisted_activity} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"})
- {:ok, private_activity} =
- CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
+ {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
activities =
ActivityPub.fetch_activities([], %{
@@ -174,8 +176,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
assert user.ap_id == user_id
assert user.nickname == "admin@mastodon.example.org"
- assert user.info.source_data
- assert user.info.ap_enabled
+ assert user.ap_enabled
assert user.follower_address == "http://mastodon.example.org/users/admin/followers"
end
@@ -188,9 +189,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "it fetches the appropriate tag-restricted posts" do
user = insert(:user)
- {:ok, status_one} = CommonAPI.post(user, %{"status" => ". #test"})
- {:ok, status_two} = CommonAPI.post(user, %{"status" => ". #essais"})
- {:ok, status_three} = CommonAPI.post(user, %{"status" => ". #test #reject"})
+ {:ok, status_one} = CommonAPI.post(user, %{status: ". #test"})
+ {:ok, status_two} = CommonAPI.post(user, %{status: ". #essais"})
+ {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #reject"})
fetch_one = ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => "test"})
@@ -220,7 +221,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
describe "insertion" do
test "drops activities beyond a certain limit" do
- limit = Pleroma.Config.get([:instance, :remote_limit])
+ limit = Config.get([:instance, :remote_limit])
random_text =
:crypto.strong_rand_bytes(limit + 1)
@@ -366,7 +367,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert activity.actor == user.ap_id
user = User.get_cached_by_id(user.id)
- assert user.info.note_count == 0
+ assert user.note_count == 0
end
test "can be fetched into a timeline" do
@@ -381,6 +382,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
describe "create activities" do
+ test "it reverts create" do
+ user = insert(:user)
+
+ with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
+ assert {:error, :reverted} =
+ ActivityPub.create(%{
+ to: ["user1", "user2"],
+ actor: user,
+ context: "",
+ object: %{
+ "to" => ["user1", "user2"],
+ "type" => "Note",
+ "content" => "testing"
+ }
+ })
+ end
+
+ assert Repo.aggregate(Activity, :count, :id) == 0
+ assert Repo.aggregate(Object, :count, :id) == 0
+ end
+
test "removes doubled 'to' recipients" do
user = insert(:user)
@@ -406,57 +428,57 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, _} =
CommonAPI.post(User.get_cached_by_id(user.id), %{
- "status" => "1",
- "visibility" => "public"
+ status: "1",
+ visibility: "public"
})
{:ok, _} =
CommonAPI.post(User.get_cached_by_id(user.id), %{
- "status" => "2",
- "visibility" => "unlisted"
+ status: "2",
+ visibility: "unlisted"
})
{:ok, _} =
CommonAPI.post(User.get_cached_by_id(user.id), %{
- "status" => "2",
- "visibility" => "private"
+ status: "2",
+ visibility: "private"
})
{:ok, _} =
CommonAPI.post(User.get_cached_by_id(user.id), %{
- "status" => "3",
- "visibility" => "direct"
+ status: "3",
+ visibility: "direct"
})
user = User.get_cached_by_id(user.id)
- assert user.info.note_count == 2
+ assert user.note_count == 2
end
test "increases replies count" do
user = insert(:user)
user2 = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
+ {: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}
+ reply_data = %{status: "1", in_reply_to_status_id: activity.id}
# public
- {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "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 object.data["repliesCount"] == 1
# unlisted
- {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "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 object.data["repliesCount"] == 2
# private
- {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "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 object.data["repliesCount"] == 2
# direct
- {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "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 object.data["repliesCount"] == 2
end
@@ -483,7 +505,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity_five = insert(:note_activity)
user = insert(:user)
- {:ok, user} = User.block(user, %{ap_id: activity_five.data["actor"]})
+ {:ok, _user_relationship} = User.block(user, %{ap_id: activity_five.data["actor"]})
activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user})
assert activities == [activity_two, activity]
@@ -496,7 +518,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
activity_three = insert(:note_activity)
user = insert(:user)
booster = insert(:user)
- {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]})
+ {:ok, _user_relationship} = User.block(user, %{ap_id: activity_one.data["actor"]})
activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
@@ -505,7 +527,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_three)
refute Enum.member?(activities, activity_one)
- {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
+ {:ok, _user_block} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
@@ -514,7 +536,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_three)
assert Enum.member?(activities, activity_one)
- {:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
+ {:ok, _user_relationship} = 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 = Activity.get_by_id(activity_three.id)
@@ -541,15 +563,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
blockee = insert(:user)
friend = insert(:user)
- {:ok, blocker} = User.block(blocker, blockee)
+ {:ok, _user_relationship} = User.block(blocker, blockee)
- {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"})
+ {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"})
- {:ok, activity_two} = CommonAPI.post(friend, %{"status" => "hey! @#{blockee.nickname}"})
+ {:ok, activity_two} = CommonAPI.post(friend, %{status: "hey! @#{blockee.nickname}"})
- {:ok, activity_three} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"})
+ {:ok, activity_three} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
- {:ok, activity_four} = CommonAPI.post(blockee, %{"status" => "hey! @#{blocker.nickname}"})
+ {:ok, activity_four} = CommonAPI.post(blockee, %{status: "hey! @#{blocker.nickname}"})
activities = ActivityPub.fetch_activities([], %{"blocking_user" => blocker})
@@ -564,11 +586,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
blockee = insert(:user)
friend = insert(:user)
- {:ok, blocker} = User.block(blocker, blockee)
+ {:ok, _user_relationship} = User.block(blocker, blockee)
- {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"})
+ {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"})
- {:ok, activity_two} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"})
+ {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
{:ok, activity_three, _} = CommonAPI.repeat(activity_two.id, friend)
@@ -604,13 +626,48 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
refute repeat_activity in activities
end
+ test "does return activities from followed users on blocked domains" do
+ domain = "meanies.social"
+ domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
+ blocker = insert(:user)
+
+ {:ok, blocker} = User.follow(blocker, domain_user)
+ {:ok, blocker} = User.block_domain(blocker, domain)
+
+ assert User.following?(blocker, domain_user)
+ assert User.blocks_domain?(blocker, domain_user)
+ refute User.blocks?(blocker, domain_user)
+
+ note = insert(:note, %{data: %{"actor" => domain_user.ap_id}})
+ activity = insert(:note_activity, %{note: note})
+
+ activities =
+ ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true})
+
+ assert activity in activities
+
+ # And check that if the guy we DO follow boosts someone else from their domain,
+ # that should be hidden
+ another_user = insert(:user, %{ap_id: "https://#{domain}/@meanie2"})
+ bad_note = insert(:note, %{data: %{"actor" => another_user.ap_id}})
+ bad_activity = insert(:note_activity, %{note: bad_note})
+ {:ok, repeat_activity, _} = CommonAPI.repeat(bad_activity.id, domain_user)
+
+ activities =
+ ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true})
+
+ refute repeat_activity in activities
+ 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"]})
+
+ activity_one_actor = User.get_by_ap_id(activity_one.data["actor"])
+ {:ok, _user_relationships} = User.mute(user, activity_one_actor)
activities =
ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
@@ -631,7 +688,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_three)
assert Enum.member?(activities, activity_one)
- {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]})
+ {:ok, _user_mute} = User.unmute(user, activity_one_actor)
activities =
ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
@@ -640,7 +697,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_three)
assert Enum.member?(activities, activity_one)
- {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
+ activity_three_actor = User.get_by_ap_id(activity_three.data["actor"])
+ {:ok, _user_relationships} = User.mute(user, activity_three_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)
@@ -693,7 +751,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster)
- [announce_activity] = ActivityPub.fetch_activities([user.ap_id | user.following])
+ [announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)])
assert announce_activity.id == announce.id
end
@@ -712,10 +770,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "doesn't retrieve unlisted activities" do
user = insert(:user)
- {:ok, _unlisted_activity} =
- CommonAPI.post(user, %{"status" => "yeah", "visibility" => "unlisted"})
+ {:ok, _unlisted_activity} = CommonAPI.post(user, %{status: "yeah", visibility: "unlisted"})
- {:ok, listed_activity} = CommonAPI.post(user, %{"status" => "yeah"})
+ {:ok, listed_activity} = CommonAPI.post(user, %{status: "yeah"})
[activity] = ActivityPub.fetch_public_activities()
@@ -733,63 +790,61 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
test "retrieves a maximum of 20 activities" do
- activities = ActivityBuilder.insert_list(30)
- last_expected = List.last(activities)
+ ActivityBuilder.insert_list(10)
+ expected_activities = ActivityBuilder.insert_list(20)
activities = ActivityPub.fetch_public_activities()
- last = List.last(activities)
+ assert collect_ids(activities) == collect_ids(expected_activities)
assert length(activities) == 20
- assert last == last_expected
end
test "retrieves ids starting from a since_id" do
activities = ActivityBuilder.insert_list(30)
- later_activities = ActivityBuilder.insert_list(10)
+ expected_activities = ActivityBuilder.insert_list(10)
since_id = List.last(activities).id
- last_expected = List.last(later_activities)
activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id})
- last = List.last(activities)
+ assert collect_ids(activities) == collect_ids(expected_activities)
assert length(activities) == 10
- assert last == last_expected
end
test "retrieves ids up to max_id" do
- _first_activities = ActivityBuilder.insert_list(10)
- activities = ActivityBuilder.insert_list(20)
- later_activities = ActivityBuilder.insert_list(10)
- max_id = List.first(later_activities).id
- last_expected = List.last(activities)
+ ActivityBuilder.insert_list(10)
+ expected_activities = ActivityBuilder.insert_list(20)
+
+ %{id: max_id} =
+ 10
+ |> ActivityBuilder.insert_list()
+ |> List.first()
activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id})
- last = List.last(activities)
assert length(activities) == 20
- assert last == last_expected
+ assert collect_ids(activities) == collect_ids(expected_activities)
end
test "paginates via offset/limit" do
- _first_activities = ActivityBuilder.insert_list(10)
- activities = ActivityBuilder.insert_list(10)
- _later_activities = ActivityBuilder.insert_list(10)
- first_expected = List.first(activities)
+ _first_part_activities = ActivityBuilder.insert_list(10)
+ second_part_activities = ActivityBuilder.insert_list(10)
+
+ later_activities = ActivityBuilder.insert_list(10)
activities =
ActivityPub.fetch_public_activities(%{"page" => "2", "page_size" => "20"}, :offset)
- first = List.first(activities)
-
assert length(activities) == 20
- assert first == first_expected
+
+ assert collect_ids(activities) ==
+ collect_ids(second_part_activities) ++ collect_ids(later_activities)
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, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
{:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
@@ -802,8 +857,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest 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, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
+ {:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster)
{:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
@@ -813,99 +868,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end
- describe "like an object" do
- test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do
- Pleroma.Config.put([:instance, :federating], true)
- note_activity = insert(:note_activity)
- assert object_activity = Object.normalize(note_activity)
-
- user = insert(:user)
-
- {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
- assert called(Pleroma.Web.Federator.publish(like_activity))
- end
-
- test "returns exist activity if object already liked" do
- note_activity = insert(:note_activity)
- assert object_activity = Object.normalize(note_activity)
-
- user = insert(:user)
-
- {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
-
- {:ok, like_activity_exist, _object} = ActivityPub.like(user, object_activity)
- assert like_activity == like_activity_exist
- end
-
- test "adds a like activity to the db" do
- note_activity = insert(:note_activity)
- assert object = Object.normalize(note_activity)
-
- user = insert(:user)
- user_two = insert(:user)
-
- {:ok, like_activity, object} = ActivityPub.like(user, object)
-
- assert like_activity.data["actor"] == user.ap_id
- assert like_activity.data["type"] == "Like"
- assert like_activity.data["object"] == object.data["id"]
- assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
- assert like_activity.data["context"] == object.data["context"]
- assert object.data["like_count"] == 1
- assert object.data["likes"] == [user.ap_id]
-
- # Just return the original activity if the user already liked it.
- {:ok, same_like_activity, object} = ActivityPub.like(user, object)
-
- assert like_activity == same_like_activity
- assert object.data["likes"] == [user.ap_id]
- assert object.data["like_count"] == 1
-
- {:ok, _like_activity, object} = ActivityPub.like(user_two, object)
- assert object.data["like_count"] == 2
- end
- end
-
- describe "unliking" do
- test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do
- Pleroma.Config.put([:instance, :federating], true)
-
- note_activity = insert(:note_activity)
- object = Object.normalize(note_activity)
- user = insert(:user)
-
- {:ok, object} = ActivityPub.unlike(user, object)
- refute called(Pleroma.Web.Federator.publish())
-
- {:ok, _like_activity, object} = ActivityPub.like(user, object)
- assert object.data["like_count"] == 1
-
- {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
- assert object.data["like_count"] == 0
-
- assert called(Pleroma.Web.Federator.publish(unlike_activity))
- end
-
- test "unliking a previously liked object" do
- note_activity = insert(:note_activity)
- object = Object.normalize(note_activity)
- user = insert(:user)
-
- # Unliking something that hasn't been liked does nothing
- {:ok, object} = ActivityPub.unlike(user, object)
- assert object.data["like_count"] == 0
-
- {:ok, like_activity, object} = ActivityPub.like(user, object)
- assert object.data["like_count"] == 1
-
- {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
- assert object.data["like_count"] == 0
-
- assert Activity.get_by_id(like_activity.id) == nil
- assert note_activity.actor in unlike_activity.recipients
- end
- end
-
describe "announcing an object" do
test "adds an announce activity to the db" do
note_activity = insert(:note_activity)
@@ -925,12 +887,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert announce_activity.data["actor"] == user.ap_id
assert announce_activity.data["context"] == object.data["context"]
end
+
+ test "reverts annouce from object on error" do
+ note_activity = insert(:note_activity)
+ object = Object.normalize(note_activity)
+ user = insert(:user)
+
+ with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
+ assert {:error, :reverted} = ActivityPub.announce(user, object)
+ end
+
+ reloaded_object = Object.get_by_ap_id(object.data["id"])
+ assert reloaded_object == object
+ refute reloaded_object.data["announcement_count"]
+ refute reloaded_object.data["announcements"]
+ end
end
describe "announcing a private object" do
test "adds an announce activity to the db if the audience is not widened" do
user = insert(:user)
- {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
+ {:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
object = Object.normalize(note_activity)
{:ok, announce_activity, object} = ActivityPub.announce(user, object, nil, true, false)
@@ -944,7 +921,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "does not add an announce activity to the db if the audience is widened" do
user = insert(:user)
- {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
+ {:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
object = Object.normalize(note_activity)
assert {:error, _} = ActivityPub.announce(user, object, nil, true, true)
@@ -953,43 +930,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "does not add an announce activity to the db if the announcer is not the author" do
user = insert(:user)
announcer = insert(:user)
- {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
+ {:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
object = Object.normalize(note_activity)
assert {:error, _} = ActivityPub.announce(announcer, object, nil, true, false)
end
end
- describe "unannouncing an object" do
- test "unannouncing a previously announced object" do
- note_activity = insert(:note_activity)
- object = Object.normalize(note_activity)
- user = insert(:user)
-
- # Unannouncing an object that is not announced does nothing
- # {:ok, object} = ActivityPub.unannounce(user, object)
- # assert object.data["announcement_count"] == 0
-
- {:ok, announce_activity, object} = ActivityPub.announce(user, object)
- assert object.data["announcement_count"] == 1
-
- {:ok, unannounce_activity, object} = ActivityPub.unannounce(user, object)
- assert object.data["announcement_count"] == 0
-
- assert unannounce_activity.data["to"] == [
- User.ap_followers(user),
- object.data["actor"]
- ]
-
- assert unannounce_activity.data["type"] == "Undo"
- assert unannounce_activity.data["object"] == announce_activity.data
- assert unannounce_activity.data["actor"] == user.ap_id
- assert unannounce_activity.data["context"] == announce_activity.data["context"]
-
- assert Activity.get_by_id(announce_activity.id) == nil
- end
- end
-
describe "uploading files" do
test "copies the file to the configured folder" do
file = %Plug.Upload{
@@ -1004,7 +951,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "works with base64 encoded images" do
file = %{
- "img" => data_uri()
+ img: data_uri()
}
{:ok, %Object{}} = ActivityPub.upload(file)
@@ -1022,6 +969,35 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
describe "following / unfollowing" do
+ test "it reverts follow activity" do
+ follower = insert(:user)
+ followed = insert(:user)
+
+ with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
+ assert {:error, :reverted} = ActivityPub.follow(follower, followed)
+ end
+
+ assert Repo.aggregate(Activity, :count, :id) == 0
+ assert Repo.aggregate(Object, :count, :id) == 0
+ end
+
+ test "it reverts unfollow activity" do
+ follower = insert(:user)
+ followed = insert(:user)
+
+ {:ok, follow_activity} = ActivityPub.follow(follower, followed)
+
+ with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
+ assert {:error, :reverted} = ActivityPub.unfollow(follower, followed)
+ end
+
+ activity = Activity.get_by_id(follow_activity.id)
+ assert activity.data["type"] == "Follow"
+ assert activity.data["actor"] == follower.ap_id
+
+ assert activity.data["object"] == followed.ap_id
+ end
+
test "creates a follow activity" do
follower = insert(:user)
followed = insert(:user)
@@ -1048,139 +1024,70 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert embedded_object["object"] == followed.ap_id
assert embedded_object["id"] == follow_activity.data["id"]
end
- end
- describe "blocking / unblocking" do
- test "creates a block activity" do
- blocker = insert(:user)
- blocked = insert(:user)
-
- {:ok, activity} = ActivityPub.block(blocker, blocked)
-
- assert activity.data["type"] == "Block"
- assert activity.data["actor"] == blocker.ap_id
- assert activity.data["object"] == blocked.ap_id
- end
-
- test "creates an undo activity for the last block" do
- blocker = insert(:user)
- blocked = insert(:user)
+ test "creates an undo activity for a pending follow request" do
+ follower = insert(:user)
+ followed = insert(:user, %{locked: true})
- {:ok, block_activity} = ActivityPub.block(blocker, blocked)
- {:ok, activity} = ActivityPub.unblock(blocker, blocked)
+ {:ok, follow_activity} = ActivityPub.follow(follower, followed)
+ {:ok, activity} = ActivityPub.unfollow(follower, followed)
assert activity.data["type"] == "Undo"
- assert activity.data["actor"] == blocker.ap_id
+ assert activity.data["actor"] == follower.ap_id
embedded_object = activity.data["object"]
assert is_map(embedded_object)
- assert embedded_object["type"] == "Block"
- assert embedded_object["object"] == blocked.ap_id
- assert embedded_object["id"] == block_activity.data["id"]
+ assert embedded_object["type"] == "Follow"
+ assert embedded_object["object"] == followed.ap_id
+ assert embedded_object["id"] == follow_activity.data["id"]
end
end
- describe "deletion" do
- test "it creates a delete activity and deletes the original object" do
- note = insert(:note_activity)
- object = Object.normalize(note)
- {:ok, delete} = ActivityPub.delete(object)
-
- assert delete.data["type"] == "Delete"
- assert delete.data["actor"] == note.data["actor"]
- assert delete.data["object"] == object.data["id"]
+ describe "blocking" do
+ test "reverts block activity on error" do
+ [blocker, blocked] = insert_list(2, :user)
- assert Activity.get_by_id(delete.id) != nil
+ with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
+ assert {:error, :reverted} = ActivityPub.block(blocker, blocked)
+ end
- assert Repo.get(Object, object.id).data["type"] == "Tombstone"
+ assert Repo.aggregate(Activity, :count, :id) == 0
+ assert Repo.aggregate(Object, :count, :id) == 0
end
- test "decrements user note count only for public activities" do
- user = insert(:user, info: %{note_count: 10})
-
- {:ok, a1} =
- CommonAPI.post(User.get_cached_by_id(user.id), %{
- "status" => "yeah",
- "visibility" => "public"
- })
-
- {:ok, a2} =
- CommonAPI.post(User.get_cached_by_id(user.id), %{
- "status" => "yeah",
- "visibility" => "unlisted"
- })
-
- {:ok, a3} =
- CommonAPI.post(User.get_cached_by_id(user.id), %{
- "status" => "yeah",
- "visibility" => "private"
- })
-
- {:ok, a4} =
- CommonAPI.post(User.get_cached_by_id(user.id), %{
- "status" => "yeah",
- "visibility" => "direct"
- })
+ test "creates a block activity" do
+ clear_config([:instance, :federating], true)
+ blocker = insert(:user)
+ blocked = insert(:user)
- {:ok, _} = Object.normalize(a1) |> ActivityPub.delete()
- {:ok, _} = Object.normalize(a2) |> ActivityPub.delete()
- {:ok, _} = Object.normalize(a3) |> ActivityPub.delete()
- {:ok, _} = Object.normalize(a4) |> ActivityPub.delete()
+ with_mock Pleroma.Web.Federator,
+ publish: fn _ -> nil end do
+ {:ok, activity} = ActivityPub.block(blocker, blocked)
- user = User.get_cached_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)
- object = Object.normalize(note)
-
- {:ok, object} =
- object
- |> Object.change(%{
- data: %{
- "actor" => object.data["actor"],
- "id" => object.data["id"],
- "to" => [user.ap_id],
- "type" => "Note"
- }
- })
- |> Object.update_and_set_cache()
+ assert activity.data["type"] == "Block"
+ assert activity.data["actor"] == blocker.ap_id
+ assert activity.data["object"] == blocked.ap_id
- {:ok, delete} = ActivityPub.delete(object)
-
- assert user.ap_id in delete.data["to"]
+ assert called(Pleroma.Web.Federator.publish(activity))
+ end
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 object.data["repliesCount"] == 2
+ test "works with outgoing blocks disabled, but doesn't federate" do
+ clear_config([:instance, :federating], true)
+ clear_config([:activitypub, :outgoing_blocks], false)
+ blocker = insert(:user)
+ blocked = insert(:user)
- _ = CommonAPI.delete(private_reply.id, user2)
- assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
- assert object.data["repliesCount"] == 2
+ with_mock Pleroma.Web.Federator,
+ publish: fn _ -> nil end do
+ {:ok, activity} = ActivityPub.block(blocker, blocked)
- _ = CommonAPI.delete(public_reply.id, user2)
- assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
- assert object.data["repliesCount"] == 1
+ assert activity.data["type"] == "Block"
+ assert activity.data["actor"] == blocker.ap_id
+ assert activity.data["object"] == blocked.ap_id
- _ = CommonAPI.delete(unlisted_reply.id, user2)
- assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
- assert object.data["repliesCount"] == 0
+ refute called(Pleroma.Web.Federator.publish(:_))
+ end
end
end
@@ -1199,27 +1106,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, user3} = User.follow(user3, user2)
assert User.following?(user3, user2)
- {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
+ {:ok, public_activity} = CommonAPI.post(user3, %{status: "hi 1"})
- {:ok, private_activity_1} =
- CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
+ {:ok, private_activity_1} = CommonAPI.post(user3, %{status: "hi 2", visibility: "private"})
{:ok, private_activity_2} =
CommonAPI.post(user2, %{
- "status" => "hi 3",
- "visibility" => "private",
- "in_reply_to_status_id" => private_activity_1.id
+ status: "hi 3",
+ visibility: "private",
+ in_reply_to_status_id: private_activity_1.id
})
{:ok, private_activity_3} =
CommonAPI.post(user3, %{
- "status" => "hi 4",
- "visibility" => "private",
- "in_reply_to_status_id" => private_activity_2.id
+ status: "hi 4",
+ visibility: "private",
+ in_reply_to_status_id: private_activity_2.id
})
activities =
- ActivityPub.fetch_activities([user1.ap_id | user1.following])
+ ActivityPub.fetch_activities([user1.ap_id | User.following(user1)])
|> Enum.map(fn a -> a.id end)
private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"])
@@ -1229,7 +1135,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert length(activities) == 3
activities =
- ActivityPub.fetch_activities([user1.ap_id | user1.following], %{"user" => user1})
+ ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{"user" => user1})
|> Enum.map(fn a -> a.id end)
assert [public_activity.id, private_activity_1.id] == activities
@@ -1238,6 +1144,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
describe "update" do
+ setup do: clear_config([:instance, :max_pinned_statuses])
+
test "it creates an update activity with the new user data" do
user = insert(:user)
{:ok, user} = User.ensure_keys_present(user)
@@ -1260,12 +1168,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
test "returned pinned statuses" do
- Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
+ Config.put([:instance, :max_pinned_statuses], 3)
user = insert(:user)
- {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
- {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
- {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
+ {:ok, activity_one} = CommonAPI.post(user, %{status: "HI!!!"})
+ {:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"})
+ {:ok, activity_three} = CommonAPI.post(user, %{status: "HI!!!"})
CommonAPI.pin(activity_one.id, user)
user = refresh_record(user)
@@ -1281,35 +1189,99 @@ 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
+ describe "flag/1" do
+ setup do
+ reporter = insert(:user)
+ target_account = insert(:user)
+ content = "foobar"
+ {:ok, activity} = CommonAPI.post(target_account, %{status: content})
+ context = Utils.generate_context_id()
+
+ reporter_ap_id = reporter.ap_id
+ target_ap_id = target_account.ap_id
+ activity_ap_id = activity.data["id"]
+
+ activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id)
+
+ {:ok,
+ %{
+ reporter: reporter,
+ context: context,
+ target_account: target_account,
+ reported_activity: activity,
+ content: content,
+ activity_ap_id: activity_ap_id,
+ activity_with_object: activity_with_object,
+ reporter_ap_id: reporter_ap_id,
+ target_ap_id: target_ap_id
+ }}
+ end
+
+ test "it can create a Flag activity",
+ %{
+ reporter: reporter,
+ context: context,
+ target_account: target_account,
+ reported_activity: reported_activity,
+ content: content,
+ activity_ap_id: activity_ap_id,
+ activity_with_object: activity_with_object,
+ reporter_ap_id: reporter_ap_id,
+ target_ap_id: target_ap_id
+ } do
+ assert {:ok, activity} =
+ ActivityPub.flag(%{
+ actor: reporter,
+ context: context,
+ account: target_account,
+ statuses: [reported_activity],
+ content: content
+ })
+
+ note_obj = %{
+ "type" => "Note",
+ "id" => activity_ap_id,
+ "content" => content,
+ "published" => activity_with_object.object.data["published"],
+ "actor" => AccountView.render("show.json", %{user: target_account})
+ }
+
+ assert %Activity{
+ actor: ^reporter_ap_id,
+ data: %{
+ "type" => "Flag",
+ "content" => ^content,
+ "context" => ^context,
+ "object" => [^target_ap_id, ^note_obj]
+ }
+ } = activity
+ end
+
+ test_with_mock "strips status data from Flag, before federating it",
+ %{
+ reporter: reporter,
+ context: context,
+ target_account: target_account,
+ reported_activity: reported_activity,
+ content: content
+ },
+ Utils,
+ [:passthrough],
+ [] do
+ {:ok, activity} =
+ ActivityPub.flag(%{
+ actor: reporter,
+ context: context,
+ account: target_account,
+ statuses: [reported_activity],
+ content: content
+ })
+
+ new_data =
+ put_in(activity.data, ["object"], [target_account.ap_id, reported_activity.data["id"]])
+
+ assert_called(Utils.maybe_federate(%{activity | data: new_data}))
+ end
end
test "fetch_activities/2 returns activities addressed to a list " do
@@ -1318,8 +1290,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, list} = Pleroma.List.create("foo", user)
{:ok, list} = Pleroma.List.follow(list, member)
- {:ok, activity} =
- CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
+ {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
activity = Repo.preload(activity, :bookmark)
activity = %Activity{activity | thread_muted?: !!activity.thread_muted?}
@@ -1337,8 +1308,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, activity} =
CommonAPI.post(user, %{
- "status" => "thought I looked cute might delete later :3",
- "visibility" => "private"
+ status: "thought I looked cute might delete later :3",
+ visibility: "private"
})
[result] = ActivityPub.fetch_activities_bounded([user.follower_address], [])
@@ -1347,12 +1318,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "fetches only public posts for other users" do
user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe", "visibility" => "public"})
+ {:ok, activity} = CommonAPI.post(user, %{status: "#cofe", visibility: "public"})
{:ok, _private_activity} =
CommonAPI.post(user, %{
- "status" => "why is tenshi eating a corndog so cute?",
- "visibility" => "private"
+ status: "why is tenshi eating a corndog so cute?",
+ visibility: "private"
})
[result] = ActivityPub.fetch_activities_bounded([], [user.follower_address])
@@ -1392,9 +1363,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
following_address: "http://localhost:4001/users/masto_closed/following"
)
- {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
- assert info.hide_followers == true
- assert info.hide_follows == false
+ {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
+ assert follow_info.hide_followers == true
+ assert follow_info.hide_follows == false
end
test "detects hidden follows" do
@@ -1415,9 +1386,688 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
following_address: "http://localhost:4001/users/masto_closed/following"
)
- {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
- assert info.hide_followers == false
- assert info.hide_follows == true
+ {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
+ assert follow_info.hide_followers == false
+ assert follow_info.hide_follows == true
+ end
+
+ test "detects hidden follows/followers for friendica" do
+ user =
+ insert(:user,
+ local: false,
+ follower_address: "http://localhost:8080/followers/fuser3",
+ following_address: "http://localhost:8080/following/fuser3"
+ )
+
+ {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
+ assert follow_info.hide_followers == true
+ assert follow_info.follower_count == 296
+ assert follow_info.following_count == 32
+ assert follow_info.hide_follows == true
+ end
+
+ test "doesn't crash when follower and following counters are hidden" do
+ mock(fn env ->
+ case env.url do
+ "http://localhost:4001/users/masto_hidden_counters/following" ->
+ json(%{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "http://localhost:4001/users/masto_hidden_counters/followers"
+ })
+
+ "http://localhost:4001/users/masto_hidden_counters/following?page=1" ->
+ %Tesla.Env{status: 403, body: ""}
+
+ "http://localhost:4001/users/masto_hidden_counters/followers" ->
+ json(%{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "http://localhost:4001/users/masto_hidden_counters/following"
+ })
+
+ "http://localhost:4001/users/masto_hidden_counters/followers?page=1" ->
+ %Tesla.Env{status: 403, body: ""}
+ end
+ end)
+
+ user =
+ insert(:user,
+ local: false,
+ follower_address: "http://localhost:4001/users/masto_hidden_counters/followers",
+ following_address: "http://localhost:4001/users/masto_hidden_counters/following"
+ )
+
+ {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
+
+ assert follow_info.hide_followers == true
+ assert follow_info.follower_count == 0
+ assert follow_info.hide_follows == true
+ assert follow_info.following_count == 0
+ end
+ end
+
+ describe "fetch_favourites/3" do
+ test "returns a favourite activities sorted by adds to favorite" do
+ user = insert(:user)
+ other_user = insert(:user)
+ user1 = insert(:user)
+ user2 = insert(:user)
+ {:ok, a1} = CommonAPI.post(user1, %{status: "bla"})
+ {:ok, _a2} = CommonAPI.post(user2, %{status: "traps are happy"})
+ {:ok, a3} = CommonAPI.post(user2, %{status: "Trees Are "})
+ {:ok, a4} = CommonAPI.post(user2, %{status: "Agent Smith "})
+ {:ok, a5} = CommonAPI.post(user1, %{status: "Red or Blue "})
+
+ {:ok, _} = CommonAPI.favorite(user, a4.id)
+ {:ok, _} = CommonAPI.favorite(other_user, a3.id)
+ {:ok, _} = CommonAPI.favorite(user, a3.id)
+ {:ok, _} = CommonAPI.favorite(other_user, a5.id)
+ {:ok, _} = CommonAPI.favorite(user, a5.id)
+ {:ok, _} = CommonAPI.favorite(other_user, a4.id)
+ {:ok, _} = CommonAPI.favorite(user, a1.id)
+ {:ok, _} = CommonAPI.favorite(other_user, a1.id)
+ result = ActivityPub.fetch_favourites(user)
+
+ assert Enum.map(result, & &1.id) == [a1.id, a5.id, a3.id, a4.id]
+
+ result = ActivityPub.fetch_favourites(user, %{"limit" => 2})
+ assert Enum.map(result, & &1.id) == [a1.id, a5.id]
+ end
+ end
+
+ describe "Move activity" do
+ test "create" do
+ %{ap_id: old_ap_id} = old_user = insert(:user)
+ %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
+ follower = insert(:user)
+ follower_move_opted_out = insert(:user, allow_following_move: false)
+
+ User.follow(follower, old_user)
+ User.follow(follower_move_opted_out, old_user)
+
+ assert User.following?(follower, old_user)
+ assert User.following?(follower_move_opted_out, old_user)
+
+ assert {:ok, activity} = ActivityPub.move(old_user, new_user)
+
+ assert %Activity{
+ actor: ^old_ap_id,
+ data: %{
+ "actor" => ^old_ap_id,
+ "object" => ^old_ap_id,
+ "target" => ^new_ap_id,
+ "type" => "Move"
+ },
+ local: true
+ } = activity
+
+ params = %{
+ "op" => "move_following",
+ "origin_id" => old_user.id,
+ "target_id" => new_user.id
+ }
+
+ assert_enqueued(worker: Pleroma.Workers.BackgroundWorker, args: params)
+
+ Pleroma.Workers.BackgroundWorker.perform(params, nil)
+
+ refute User.following?(follower, old_user)
+ assert User.following?(follower, new_user)
+
+ assert User.following?(follower_move_opted_out, old_user)
+ refute User.following?(follower_move_opted_out, new_user)
+
+ activity = %Activity{activity | object: nil}
+
+ assert [%Notification{activity: ^activity}] = Notification.for_user(follower)
+
+ assert [%Notification{activity: ^activity}] = Notification.for_user(follower_move_opted_out)
+ end
+
+ test "old user must be in the new user's `also_known_as` list" do
+ old_user = insert(:user)
+ new_user = insert(:user)
+
+ assert {:error, "Target account must have the origin in `alsoKnownAs`"} =
+ ActivityPub.move(old_user, new_user)
+ end
+ end
+
+ test "doesn't retrieve replies activities with exclude_replies" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
+
+ {:ok, _reply} = CommonAPI.post(user, %{status: "yeah", in_reply_to_status_id: activity.id})
+
+ [result] = ActivityPub.fetch_public_activities(%{"exclude_replies" => "true"})
+
+ assert result.id == activity.id
+
+ assert length(ActivityPub.fetch_public_activities()) == 2
+ end
+
+ describe "replies filtering with public messages" do
+ setup :public_messages
+
+ test "public timeline", %{users: %{u1: user}} do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_filtering_user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 16
+ end
+
+ test "public timeline with reply_visibility `following`", %{
+ users: %{u1: user},
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4,
+ activities: activities
+ } do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_visibility", "following")
+ |> Map.put("reply_filtering_user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 14
+
+ visible_ids =
+ Map.values(u1) ++ Map.values(u2) ++ Map.values(u4) ++ Map.values(activities) ++ [u3[:r1]]
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+
+ test "public timeline with reply_visibility `self`", %{
+ users: %{u1: user},
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4,
+ activities: activities
+ } do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_visibility", "self")
+ |> Map.put("reply_filtering_user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 10
+ visible_ids = Map.values(u1) ++ [u2[:r1], u3[:r1], u4[:r1]] ++ Map.values(activities)
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+
+ test "home timeline", %{
+ users: %{u1: user},
+ activities: activities,
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4
+ } do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 13
+
+ visible_ids =
+ Map.values(u1) ++
+ Map.values(u3) ++
+ [
+ activities[:a1],
+ activities[:a2],
+ activities[:a4],
+ u2[:r1],
+ u2[:r3],
+ u4[:r1],
+ u4[:r2]
+ ]
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+
+ test "home timeline with reply_visibility `following`", %{
+ users: %{u1: user},
+ activities: activities,
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4
+ } do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_visibility", "following")
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 11
+
+ visible_ids =
+ Map.values(u1) ++
+ [
+ activities[:a1],
+ activities[:a2],
+ activities[:a4],
+ u2[:r1],
+ u2[:r3],
+ u3[:r1],
+ u4[:r1],
+ u4[:r2]
+ ]
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+
+ test "home timeline with reply_visibility `self`", %{
+ users: %{u1: user},
+ activities: activities,
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4
+ } do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_visibility", "self")
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 9
+
+ visible_ids =
+ Map.values(u1) ++
+ [
+ activities[:a1],
+ activities[:a2],
+ activities[:a4],
+ u2[:r1],
+ u3[:r1],
+ u4[:r1]
+ ]
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+ end
+
+ describe "replies filtering with private messages" do
+ setup :private_messages
+
+ test "public timeline", %{users: %{u1: user}} do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert activities_ids == []
+ end
+
+ test "public timeline with default reply_visibility `following`", %{users: %{u1: user}} do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_visibility", "following")
+ |> Map.put("reply_filtering_user", user)
+ |> Map.put("user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert activities_ids == []
+ end
+
+ test "public timeline with default reply_visibility `self`", %{users: %{u1: user}} do
+ activities_ids =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", false)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("reply_visibility", "self")
+ |> Map.put("reply_filtering_user", user)
+ |> Map.put("user", user)
+ |> ActivityPub.fetch_public_activities()
+ |> Enum.map(& &1.id)
+
+ assert activities_ids == []
+ end
+
+ test "home timeline", %{users: %{u1: user}} do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 12
+ end
+
+ test "home timeline with default reply_visibility `following`", %{users: %{u1: user}} do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_visibility", "following")
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 12
+ end
+
+ test "home timeline with default reply_visibility `self`", %{
+ users: %{u1: user},
+ activities: activities,
+ u1: u1,
+ u2: u2,
+ u3: u3,
+ u4: u4
+ } do
+ params =
+ %{}
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> Map.put("user", user)
+ |> Map.put("reply_visibility", "self")
+ |> Map.put("reply_filtering_user", user)
+
+ activities_ids =
+ ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
+ |> Enum.map(& &1.id)
+
+ assert length(activities_ids) == 10
+
+ visible_ids =
+ Map.values(u1) ++ Map.values(u4) ++ [u2[:r1], u3[:r1]] ++ Map.values(activities)
+
+ assert Enum.all?(visible_ids, &(&1 in activities_ids))
+ end
+ end
+
+ defp public_messages(_) do
+ [u1, u2, u3, u4] = insert_list(4, :user)
+ {:ok, u1} = User.follow(u1, u2)
+ {:ok, u2} = User.follow(u2, u1)
+ {:ok, u1} = User.follow(u1, u4)
+ {:ok, u4} = User.follow(u4, u1)
+
+ {:ok, u2} = User.follow(u2, u3)
+ {:ok, u3} = User.follow(u3, u2)
+
+ {:ok, a1} = CommonAPI.post(u1, %{status: "Status"})
+
+ {:ok, r1_1} =
+ CommonAPI.post(u2, %{
+ status: "@#{u1.nickname} reply from u2 to u1",
+ in_reply_to_status_id: a1.id
+ })
+
+ {:ok, r1_2} =
+ CommonAPI.post(u3, %{
+ status: "@#{u1.nickname} reply from u3 to u1",
+ in_reply_to_status_id: a1.id
+ })
+
+ {:ok, r1_3} =
+ CommonAPI.post(u4, %{
+ status: "@#{u1.nickname} reply from u4 to u1",
+ in_reply_to_status_id: a1.id
+ })
+
+ {:ok, a2} = CommonAPI.post(u2, %{status: "Status"})
+
+ {:ok, r2_1} =
+ CommonAPI.post(u1, %{
+ status: "@#{u2.nickname} reply from u1 to u2",
+ in_reply_to_status_id: a2.id
+ })
+
+ {:ok, r2_2} =
+ CommonAPI.post(u3, %{
+ status: "@#{u2.nickname} reply from u3 to u2",
+ in_reply_to_status_id: a2.id
+ })
+
+ {:ok, r2_3} =
+ CommonAPI.post(u4, %{
+ status: "@#{u2.nickname} reply from u4 to u2",
+ in_reply_to_status_id: a2.id
+ })
+
+ {:ok, a3} = CommonAPI.post(u3, %{status: "Status"})
+
+ {:ok, r3_1} =
+ CommonAPI.post(u1, %{
+ status: "@#{u3.nickname} reply from u1 to u3",
+ in_reply_to_status_id: a3.id
+ })
+
+ {:ok, r3_2} =
+ CommonAPI.post(u2, %{
+ status: "@#{u3.nickname} reply from u2 to u3",
+ in_reply_to_status_id: a3.id
+ })
+
+ {:ok, r3_3} =
+ CommonAPI.post(u4, %{
+ status: "@#{u3.nickname} reply from u4 to u3",
+ in_reply_to_status_id: a3.id
+ })
+
+ {:ok, a4} = CommonAPI.post(u4, %{status: "Status"})
+
+ {:ok, r4_1} =
+ CommonAPI.post(u1, %{
+ status: "@#{u4.nickname} reply from u1 to u4",
+ in_reply_to_status_id: a4.id
+ })
+
+ {:ok, r4_2} =
+ CommonAPI.post(u2, %{
+ status: "@#{u4.nickname} reply from u2 to u4",
+ in_reply_to_status_id: a4.id
+ })
+
+ {:ok, r4_3} =
+ CommonAPI.post(u3, %{
+ status: "@#{u4.nickname} reply from u3 to u4",
+ in_reply_to_status_id: a4.id
+ })
+
+ {:ok,
+ users: %{u1: u1, u2: u2, u3: u3, u4: u4},
+ activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id},
+ u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id},
+ u2: %{r1: r2_1.id, r2: r2_2.id, r3: r2_3.id},
+ u3: %{r1: r3_1.id, r2: r3_2.id, r3: r3_3.id},
+ u4: %{r1: r4_1.id, r2: r4_2.id, r3: r4_3.id}}
+ end
+
+ defp private_messages(_) do
+ [u1, u2, u3, u4] = insert_list(4, :user)
+ {:ok, u1} = User.follow(u1, u2)
+ {:ok, u2} = User.follow(u2, u1)
+ {:ok, u1} = User.follow(u1, u3)
+ {:ok, u3} = User.follow(u3, u1)
+ {:ok, u1} = User.follow(u1, u4)
+ {:ok, u4} = User.follow(u4, u1)
+
+ {:ok, u2} = User.follow(u2, u3)
+ {:ok, u3} = User.follow(u3, u2)
+
+ {:ok, a1} = CommonAPI.post(u1, %{status: "Status", visibility: "private"})
+
+ {:ok, r1_1} =
+ CommonAPI.post(u2, %{
+ status: "@#{u1.nickname} reply from u2 to u1",
+ in_reply_to_status_id: a1.id,
+ visibility: "private"
+ })
+
+ {:ok, r1_2} =
+ CommonAPI.post(u3, %{
+ status: "@#{u1.nickname} reply from u3 to u1",
+ in_reply_to_status_id: a1.id,
+ visibility: "private"
+ })
+
+ {:ok, r1_3} =
+ CommonAPI.post(u4, %{
+ status: "@#{u1.nickname} reply from u4 to u1",
+ in_reply_to_status_id: a1.id,
+ visibility: "private"
+ })
+
+ {:ok, a2} = CommonAPI.post(u2, %{status: "Status", visibility: "private"})
+
+ {:ok, r2_1} =
+ CommonAPI.post(u1, %{
+ status: "@#{u2.nickname} reply from u1 to u2",
+ in_reply_to_status_id: a2.id,
+ visibility: "private"
+ })
+
+ {:ok, r2_2} =
+ CommonAPI.post(u3, %{
+ status: "@#{u2.nickname} reply from u3 to u2",
+ in_reply_to_status_id: a2.id,
+ visibility: "private"
+ })
+
+ {:ok, a3} = CommonAPI.post(u3, %{status: "Status", visibility: "private"})
+
+ {:ok, r3_1} =
+ CommonAPI.post(u1, %{
+ status: "@#{u3.nickname} reply from u1 to u3",
+ in_reply_to_status_id: a3.id,
+ visibility: "private"
+ })
+
+ {:ok, r3_2} =
+ CommonAPI.post(u2, %{
+ status: "@#{u3.nickname} reply from u2 to u3",
+ in_reply_to_status_id: a3.id,
+ visibility: "private"
+ })
+
+ {:ok, a4} = CommonAPI.post(u4, %{status: "Status", visibility: "private"})
+
+ {:ok, r4_1} =
+ CommonAPI.post(u1, %{
+ status: "@#{u4.nickname} reply from u1 to u4",
+ in_reply_to_status_id: a4.id,
+ visibility: "private"
+ })
+
+ {:ok,
+ users: %{u1: u1, u2: u2, u3: u3, u4: u4},
+ activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id},
+ u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id},
+ u2: %{r1: r2_1.id, r2: r2_2.id},
+ u3: %{r1: r3_1.id, r2: r3_2.id},
+ u4: %{r1: r4_1.id}}
+ end
+
+ describe "maybe_update_follow_information/1" do
+ setup do
+ clear_config([:instance, :external_user_synchronization], true)
+
+ user = %{
+ local: false,
+ ap_id: "https://gensokyo.2hu/users/raymoo",
+ following_address: "https://gensokyo.2hu/users/following",
+ follower_address: "https://gensokyo.2hu/users/followers",
+ type: "Person"
+ }
+
+ %{user: user}
+ end
+
+ test "logs an error when it can't fetch the info", %{user: user} do
+ assert capture_log(fn ->
+ ActivityPub.maybe_update_follow_information(user)
+ end) =~ "Follower/Following counter update for #{user.ap_id} failed"
+ end
+
+ test "just returns the input if the user type is Application", %{
+ user: user
+ } do
+ user =
+ user
+ |> Map.put(:type, "Application")
+
+ refute capture_log(fn ->
+ assert ^user = ActivityPub.maybe_update_follow_information(user)
+ end) =~ "Follower/Following counter update for #{user.ap_id} failed"
+ end
+
+ test "it just returns the input if the user has no following/follower addresses", %{
+ user: user
+ } do
+ user =
+ user
+ |> Map.put(:following_address, nil)
+ |> Map.put(:follower_address, nil)
+
+ refute capture_log(fn ->
+ assert ^user = ActivityPub.maybe_update_follow_information(user)
+ end) =~ "Follower/Following counter update for #{user.ap_id} failed"
end
end
end