import Tesla.Mock
setup do
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+ clear_config([Pleroma.Uploaders.Local, :uploads], "uploads")
mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
assert User.invisible?(user)
end
- test "it returns a user that accepts chat messages" do
- user_id = "http://mastodon.example.org/users/admin"
- {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
-
- assert user.accepts_chat_messages
- end
-
test "works for guppe actors" do
user_id = "https://gup.pe/u/bernie2020"
assert user.name == "Bernie2020 group"
assert user.actor_type == "Group"
end
+
+ test "works for bridgy actors" do
+ user_id = "https://fed.brid.gy/jk.nipponalba.scot"
+
+ Tesla.Mock.mock(fn
+ %{method: :get, url: ^user_id} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/bridgy/actor.json"),
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
+
+ assert user.actor_type == "Person"
+
+ assert user.avatar == %{
+ "type" => "Image",
+ "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}]
+ }
+
+ assert user.banner == %{
+ "type" => "Image",
+ "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}]
+ }
+ end
+
+ test "fetches user featured collection" do
+ ap_id = "https://example.com/users/lain"
+
+ featured_url = "https://example.com/users/lain/collections/featured"
+
+ user_data =
+ "test/fixtures/users_mock/user.json"
+ |> File.read!()
+ |> String.replace("{{nickname}}", "lain")
+ |> Jason.decode!()
+ |> Map.put("featured", featured_url)
+ |> Jason.encode!()
+
+ object_id = Ecto.UUID.generate()
+
+ featured_data =
+ "test/fixtures/mastodon/collections/featured.json"
+ |> File.read!()
+ |> String.replace("{{domain}}", "example.com")
+ |> String.replace("{{nickname}}", "lain")
+ |> String.replace("{{object_id}}", object_id)
+
+ object_url = "https://example.com/objects/#{object_id}"
+
+ object_data =
+ "test/fixtures/statuses/note.json"
+ |> File.read!()
+ |> String.replace("{{object_id}}", object_id)
+ |> String.replace("{{nickname}}", "lain")
+
+ Tesla.Mock.mock(fn
+ %{
+ method: :get,
+ url: ^ap_id
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: user_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{
+ method: :get,
+ url: ^featured_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: featured_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ Tesla.Mock.mock_global(fn
+ %{
+ method: :get,
+ url: ^object_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: object_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ {:ok, user} = ActivityPub.make_user_from_ap_id(ap_id)
+ Process.sleep(50)
+
+ assert user.featured_address == featured_url
+ assert Map.has_key?(user.pinned_objects, object_url)
+
+ in_db = Pleroma.User.get_by_ap_id(ap_id)
+ assert in_db.featured_address == featured_url
+ assert Map.has_key?(user.pinned_objects, object_url)
+
+ assert %{data: %{"id" => ^object_url}} = Object.get_by_ap_id(object_url)
+ end
+ end
+
+ test "fetches user featured collection using the first property" do
+ featured_url = "https://friendica.example.com/raha/collections/featured"
+ first_url = "https://friendica.example.com/featured/raha?page=1"
+
+ featured_data =
+ "test/fixtures/friendica/friendica_featured_collection.json"
+ |> File.read!()
+
+ page_data =
+ "test/fixtures/friendica/friendica_featured_collection_first.json"
+ |> File.read!()
+
+ Tesla.Mock.mock(fn
+ %{
+ method: :get,
+ url: ^featured_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: featured_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{
+ method: :get,
+ url: ^first_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: page_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ {:ok, data} = ActivityPub.fetch_and_prepare_featured_from_ap_id(featured_url)
+ assert Map.has_key?(data, "http://inserted")
+ end
+
+ test "fetches user featured when it has string IDs" do
+ featured_url = "https://example.com/alisaie/collections/featured"
+ dead_url = "https://example.com/users/alisaie/statuses/108311386746229284"
+
+ featured_data =
+ "test/fixtures/mastodon/featured_collection.json"
+ |> File.read!()
+
+ Tesla.Mock.mock(fn
+ %{
+ method: :get,
+ url: ^featured_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: featured_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{
+ method: :get,
+ url: ^dead_url
+ } ->
+ %Tesla.Env{
+ status: 404,
+ body: "{}",
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ {:ok, %{}} = ActivityPub.fetch_and_prepare_featured_from_ap_id(featured_url)
end
test "it fetches the appropriate tag-restricted posts" do
user = insert(:user)
- {:ok, status_one} = CommonAPI.post(user, %{status: ". #test"})
+ {: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_three} = CommonAPI.post(user, %{status: ". #test #Reject"})
- {:ok, status_four} = CommonAPI.post(user, %{status: ". #any1 #any2"})
- {:ok, status_five} = CommonAPI.post(user, %{status: ". #any2 #any1"})
+ {:ok, status_four} = CommonAPI.post(user, %{status: ". #Any1 #any2"})
+ {:ok, status_five} = CommonAPI.post(user, %{status: ". #Any2 #any1"})
- for hashtag_timeline_strategy <- [true, false] do
- clear_config([:instance, :improved_hashtag_timeline], hashtag_timeline_strategy)
+ for hashtag_timeline_strategy <- [:enabled, :disabled] do
+ clear_config([:features, :improved_hashtag_timeline], hashtag_timeline_strategy)
fetch_one = ActivityPub.fetch_activities([], %{type: "Create", tag: "test"})
- fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["test", "essais"]})
+ fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["TEST", "essais"]})
fetch_three =
ActivityPub.fetch_activities([], %{
type: "Create",
- tag: ["test", "essais"],
+ tag: ["test", "Essais"],
tag_reject: ["reject"]
})
ActivityPub.fetch_activities([], %{
type: "Create",
tag: ["test"],
- tag_all: ["test", "reject"]
+ tag_all: ["test", "REJECT"]
})
# Testing that deduplication (if needed) is done on DB (not Ecto) level; :limit is important
fetch_five =
ActivityPub.fetch_activities([], %{
type: "Create",
- tag: ["any1", "any2"],
+ tag: ["ANY1", "any2"],
limit: 2
})
+ fetch_six =
+ ActivityPub.fetch_activities([], %{
+ type: "Create",
+ tag: ["any1", "Any2"],
+ tag_all: [],
+ tag_reject: []
+ })
+
+ # Regression test: passing empty lists as filter options shouldn't affect the results
+ assert fetch_five == fetch_six
+
[fetch_one, fetch_two, fetch_three, fetch_four, fetch_five] =
Enum.map([fetch_one, fetch_two, fetch_three, fetch_four, fetch_five], fn statuses ->
Enum.map(statuses, fn s -> Repo.preload(s, object: :hashtags) end)
end
end
- describe "listen activities" do
- test "does not increase user note count" do
- user = insert(:user)
-
- {:ok, activity} =
- ActivityPub.listen(%{
- to: ["https://www.w3.org/ns/activitystreams#Public"],
- actor: user,
- context: "",
- object: %{
- "actor" => user.ap_id,
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "artist" => "lain",
- "title" => "lain radio episode 1",
- "length" => 180_000,
- "type" => "Audio"
- }
- })
-
- assert activity.actor == user.ap_id
-
- user = User.get_cached_by_id(user.id)
- assert user.note_count == 0
- end
-
- test "can be fetched into a timeline" do
- _listen_activity_1 = insert(:listen)
- _listen_activity_2 = insert(:listen)
- _listen_activity_3 = insert(:listen)
-
- timeline = ActivityPub.fetch_activities([], %{type: ["Listen"]})
-
- assert length(timeline) == 3
- end
- end
-
describe "create activities" do
setup do
[user: insert(:user)]
assert Enum.member?(activities, activity_one)
end
+ test "doesn't return activities from deactivated users" do
+ _user = insert(:user)
+ deactivated = insert(:user)
+ active = insert(:user)
+ {:ok, activity_one} = CommonAPI.post(deactivated, %{status: "hey!"})
+ {:ok, activity_two} = CommonAPI.post(active, %{status: "yay!"})
+ {:ok, _updated_user} = User.set_activation(deactivated, false)
+
+ activities = ActivityPub.fetch_activities([], %{})
+
+ refute Enum.member?(activities, activity_one)
+ assert Enum.member?(activities, activity_two)
+ end
+
+ test "always see your own posts even when they address people you block" do
+ user = insert(:user)
+ blockee = insert(:user)
+
+ {:ok, _} = User.block(user, blockee)
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey! @#{blockee.nickname}"})
+
+ activities = ActivityPub.fetch_activities([], %{blocking_user: user})
+
+ assert Enum.member?(activities, activity)
+ end
+
test "doesn't return transitive interactions concerning blocked users" do
blocker = insert(:user)
blockee = insert(:user)
refute repeat_activity in activities
end
+ test "see your own posts even when they adress actors from blocked domains" do
+ user = insert(:user)
+
+ domain = "dogwhistle.zone"
+ domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
+
+ {:ok, user} = User.block_domain(user, domain)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey! @#{domain_user.nickname}"})
+
+ activities = ActivityPub.fetch_activities([], %{blocking_user: user})
+
+ assert Enum.member?(activities, activity)
+ end
+
test "does return activities from followed users on blocked domains" do
domain = "meanies.social"
domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
test "it sets the default description depending on the configuration", %{test_file: file} do
clear_config([Pleroma.Upload, :default_description])
- Pleroma.Config.put([Pleroma.Upload, :default_description], nil)
+ clear_config([Pleroma.Upload, :default_description], nil)
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == ""
- Pleroma.Config.put([Pleroma.Upload, :default_description], :filename)
+ clear_config([Pleroma.Upload, :default_description], :filename)
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == "an_image.jpg"
- Pleroma.Config.put([Pleroma.Upload, :default_description], "unnamed attachment")
+ clear_config([Pleroma.Upload, :default_description], "unnamed attachment")
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == "unnamed attachment"
end
"target" => ^new_ap_id,
"type" => "Move"
},
- local: true
+ local: true,
+ recipients: recipients
} = activity
+ assert old_user.follower_address in recipients
+
params = %{
"op" => "move_following",
"origin_id" => old_user.id,
assert {:error, "Target account must have the origin in `alsoKnownAs`"} =
ActivityPub.move(old_user, new_user)
end
+
+ test "do not move remote user following relationships" 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_remote = insert(:user, local: false)
+
+ User.follow(follower_remote, old_user)
+
+ assert User.following?(follower_remote, 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(%Oban.Job{args: params})
+
+ assert User.following?(follower_remote, old_user)
+ refute User.following?(follower_remote, new_user)
+ end
end
test "doesn't retrieve replies activities with exclude_replies" do