1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
6 use Pleroma.Web.ConnCase
7 use Oban.Testing, repo: Pleroma.Repo
10 alias Pleroma.Activity
11 alias Pleroma.Delivery
12 alias Pleroma.Instances
14 alias Pleroma.Tests.ObanHelpers
16 alias Pleroma.Web.ActivityPub.ObjectView
17 alias Pleroma.Web.ActivityPub.Relay
18 alias Pleroma.Web.ActivityPub.UserView
19 alias Pleroma.Web.ActivityPub.Utils
20 alias Pleroma.Web.CommonAPI
21 alias Pleroma.Workers.ReceiverWorker
24 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
28 clear_config_all([:instance, :federating],
29 do: Pleroma.Config.put([:instance, :federating], true)
33 clear_config([:instance, :allow_relay])
35 test "with the relay active, it returns the relay user", %{conn: conn} do
38 |> get(activity_pub_path(conn, :relay))
41 assert res["id"] =~ "/relay"
44 test "with the relay disabled, it returns 404", %{conn: conn} do
45 Pleroma.Config.put([:instance, :allow_relay], false)
48 |> get(activity_pub_path(conn, :relay))
54 describe "/internal/fetch" do
55 test "it returns the internal fetch user", %{conn: conn} do
58 |> get(activity_pub_path(conn, :internal_fetch))
61 assert res["id"] =~ "/fetch"
65 describe "/users/:nickname" do
66 test "it returns a json representation of the user with accept application/json", %{
73 |> put_req_header("accept", "application/json")
74 |> get("/users/#{user.nickname}")
76 user = User.get_cached_by_id(user.id)
78 assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
81 test "it returns a json representation of the user with accept application/activity+json", %{
88 |> put_req_header("accept", "application/activity+json")
89 |> get("/users/#{user.nickname}")
91 user = User.get_cached_by_id(user.id)
93 assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
96 test "it returns a json representation of the user with accept application/ld+json", %{
105 "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
107 |> get("/users/#{user.nickname}")
109 user = User.get_cached_by_id(user.id)
111 assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
114 test "it returns 404 for remote users", %{
117 user = insert(:user, local: false, nickname: "remoteuser@example.com")
121 |> put_req_header("accept", "application/json")
122 |> get("/users/#{user.nickname}.json")
124 assert json_response(conn, 404)
128 describe "/object/:uuid" do
129 test "it returns a json representation of the object with accept application/json", %{
133 uuid = String.split(note.data["id"], "/") |> List.last()
137 |> put_req_header("accept", "application/json")
138 |> get("/objects/#{uuid}")
140 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
143 test "it returns a json representation of the object with accept application/activity+json",
146 uuid = String.split(note.data["id"], "/") |> List.last()
150 |> put_req_header("accept", "application/activity+json")
151 |> get("/objects/#{uuid}")
153 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
156 test "it returns a json representation of the object with accept application/ld+json", %{
160 uuid = String.split(note.data["id"], "/") |> List.last()
166 "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
168 |> get("/objects/#{uuid}")
170 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
173 test "it returns 404 for non-public messages", %{conn: conn} do
174 note = insert(:direct_note)
175 uuid = String.split(note.data["id"], "/") |> List.last()
179 |> put_req_header("accept", "application/activity+json")
180 |> get("/objects/#{uuid}")
182 assert json_response(conn, 404)
185 test "it returns 404 for tombstone objects", %{conn: conn} do
186 tombstone = insert(:tombstone)
187 uuid = String.split(tombstone.data["id"], "/") |> List.last()
191 |> put_req_header("accept", "application/activity+json")
192 |> get("/objects/#{uuid}")
194 assert json_response(conn, 404)
197 test "it caches a response", %{conn: conn} do
199 uuid = String.split(note.data["id"], "/") |> List.last()
203 |> put_req_header("accept", "application/activity+json")
204 |> get("/objects/#{uuid}")
206 assert json_response(conn1, :ok)
207 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
211 |> put_req_header("accept", "application/activity+json")
212 |> get("/objects/#{uuid}")
214 assert json_response(conn1, :ok) == json_response(conn2, :ok)
215 assert Enum.any?(conn2.resp_headers, &(&1 == {"x-cache", "HIT from Pleroma"}))
218 test "cached purged after object deletion", %{conn: conn} do
220 uuid = String.split(note.data["id"], "/") |> List.last()
224 |> put_req_header("accept", "application/activity+json")
225 |> get("/objects/#{uuid}")
227 assert json_response(conn1, :ok)
228 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
234 |> put_req_header("accept", "application/activity+json")
235 |> get("/objects/#{uuid}")
237 assert "Not found" == json_response(conn2, :not_found)
241 describe "/activities/:uuid" do
242 test "it returns a json representation of the activity", %{conn: conn} do
243 activity = insert(:note_activity)
244 uuid = String.split(activity.data["id"], "/") |> List.last()
248 |> put_req_header("accept", "application/activity+json")
249 |> get("/activities/#{uuid}")
251 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: activity})
254 test "it returns 404 for non-public activities", %{conn: conn} do
255 activity = insert(:direct_note_activity)
256 uuid = String.split(activity.data["id"], "/") |> List.last()
260 |> put_req_header("accept", "application/activity+json")
261 |> get("/activities/#{uuid}")
263 assert json_response(conn, 404)
266 test "it caches a response", %{conn: conn} do
267 activity = insert(:note_activity)
268 uuid = String.split(activity.data["id"], "/") |> List.last()
272 |> put_req_header("accept", "application/activity+json")
273 |> get("/activities/#{uuid}")
275 assert json_response(conn1, :ok)
276 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
280 |> put_req_header("accept", "application/activity+json")
281 |> get("/activities/#{uuid}")
283 assert json_response(conn1, :ok) == json_response(conn2, :ok)
284 assert Enum.any?(conn2.resp_headers, &(&1 == {"x-cache", "HIT from Pleroma"}))
287 test "cached purged after activity deletion", %{conn: conn} do
289 {:ok, activity} = CommonAPI.post(user, %{"status" => "cofe"})
291 uuid = String.split(activity.data["id"], "/") |> List.last()
295 |> put_req_header("accept", "application/activity+json")
296 |> get("/activities/#{uuid}")
298 assert json_response(conn1, :ok)
299 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
301 Activity.delete_all_by_object_ap_id(activity.object.data["id"])
305 |> put_req_header("accept", "application/activity+json")
306 |> get("/activities/#{uuid}")
308 assert "Not found" == json_response(conn2, :not_found)
313 test "it inserts an incoming activity into the database", %{conn: conn} do
314 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
318 |> assign(:valid_signature, true)
319 |> put_req_header("content-type", "application/activity+json")
320 |> post("/inbox", data)
322 assert "ok" == json_response(conn, 200)
324 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
325 assert Activity.get_by_ap_id(data["id"])
328 test "it clears `unreachable` federation status of the sender", %{conn: conn} do
329 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
331 sender_url = data["actor"]
332 Instances.set_consistently_unreachable(sender_url)
333 refute Instances.reachable?(sender_url)
337 |> assign(:valid_signature, true)
338 |> put_req_header("content-type", "application/activity+json")
339 |> post("/inbox", data)
341 assert "ok" == json_response(conn, 200)
342 assert Instances.reachable?(sender_url)
345 test "accept follow activity", %{conn: conn} do
346 Pleroma.Config.put([:instance, :federating], true)
347 relay = Relay.get_actor()
349 assert {:ok, %Activity{} = activity} = Relay.follow("https://relay.mastodon.host/actor")
351 followed_relay = Pleroma.User.get_by_ap_id("https://relay.mastodon.host/actor")
352 relay = refresh_record(relay)
355 File.read!("test/fixtures/relay/accept-follow.json")
356 |> String.replace("{{ap_id}}", relay.ap_id)
357 |> String.replace("{{activity_id}}", activity.data["id"])
361 |> assign(:valid_signature, true)
362 |> put_req_header("content-type", "application/activity+json")
363 |> post("/inbox", accept)
364 |> json_response(200)
366 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
368 assert Pleroma.FollowingRelationship.following?(
373 Mix.shell(Mix.Shell.Process)
376 Mix.shell(Mix.Shell.IO)
379 :ok = Mix.Tasks.Pleroma.Relay.run(["list"])
380 assert_receive {:mix_shell, :info, ["relay.mastodon.host"]}
384 describe "/users/:nickname/inbox" do
387 File.read!("test/fixtures/mastodon-post-activity.json")
393 test "it inserts an incoming activity into the database", %{conn: conn, data: data} do
395 data = Map.put(data, "bcc", [user.ap_id])
399 |> assign(:valid_signature, true)
400 |> put_req_header("content-type", "application/activity+json")
401 |> post("/users/#{user.nickname}/inbox", data)
403 assert "ok" == json_response(conn, 200)
404 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
405 assert Activity.get_by_ap_id(data["id"])
408 test "it accepts messages with to as string instead of array", %{conn: conn, data: data} do
412 Map.put(data, "to", user.ap_id)
417 |> assign(:valid_signature, true)
418 |> put_req_header("content-type", "application/activity+json")
419 |> post("/users/#{user.nickname}/inbox", data)
421 assert "ok" == json_response(conn, 200)
422 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
423 assert Activity.get_by_ap_id(data["id"])
426 test "it accepts messages with cc as string instead of array", %{conn: conn, data: data} do
430 Map.put(data, "cc", user.ap_id)
435 |> assign(:valid_signature, true)
436 |> put_req_header("content-type", "application/activity+json")
437 |> post("/users/#{user.nickname}/inbox", data)
439 assert "ok" == json_response(conn, 200)
440 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
441 %Activity{} = activity = Activity.get_by_ap_id(data["id"])
442 assert user.ap_id in activity.recipients
445 test "it accepts messages with bcc as string instead of array", %{conn: conn, data: data} do
449 Map.put(data, "bcc", user.ap_id)
455 |> assign(:valid_signature, true)
456 |> put_req_header("content-type", "application/activity+json")
457 |> post("/users/#{user.nickname}/inbox", data)
459 assert "ok" == json_response(conn, 200)
460 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
461 assert Activity.get_by_ap_id(data["id"])
464 test "it accepts announces with to as string instead of array", %{conn: conn} do
468 "@context" => "https://www.w3.org/ns/activitystreams",
469 "actor" => "http://mastodon.example.org/users/admin",
470 "id" => "http://mastodon.example.org/users/admin/statuses/19512778738411822/activity",
471 "object" => "https://mastodon.social/users/emelie/statuses/101849165031453009",
472 "to" => "https://www.w3.org/ns/activitystreams#Public",
473 "cc" => [user.ap_id],
479 |> assign(:valid_signature, true)
480 |> put_req_header("content-type", "application/activity+json")
481 |> post("/users/#{user.nickname}/inbox", data)
483 assert "ok" == json_response(conn, 200)
484 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
485 %Activity{} = activity = Activity.get_by_ap_id(data["id"])
486 assert "https://www.w3.org/ns/activitystreams#Public" in activity.recipients
489 test "it accepts messages from actors that are followed by the user", %{
493 recipient = insert(:user)
494 actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"})
496 {:ok, recipient} = User.follow(recipient, actor)
500 |> Map.put("attributedTo", actor.ap_id)
504 |> Map.put("actor", actor.ap_id)
505 |> Map.put("object", object)
509 |> assign(:valid_signature, true)
510 |> put_req_header("content-type", "application/activity+json")
511 |> post("/users/#{recipient.nickname}/inbox", data)
513 assert "ok" == json_response(conn, 200)
514 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
515 assert Activity.get_by_ap_id(data["id"])
518 test "it rejects reads from other users", %{conn: conn} do
520 otheruser = insert(:user)
524 |> assign(:user, otheruser)
525 |> put_req_header("accept", "application/activity+json")
526 |> get("/users/#{user.nickname}/inbox")
528 assert json_response(conn, 403)
531 test "it doesn't crash without an authenticated user", %{conn: conn} do
536 |> put_req_header("accept", "application/activity+json")
537 |> get("/users/#{user.nickname}/inbox")
539 assert json_response(conn, 403)
542 test "it returns a note activity in a collection", %{conn: conn} do
543 note_activity = insert(:direct_note_activity)
544 note_object = Object.normalize(note_activity)
545 user = User.get_cached_by_ap_id(hd(note_activity.data["to"]))
549 |> assign(:user, user)
550 |> put_req_header("accept", "application/activity+json")
551 |> get("/users/#{user.nickname}/inbox?page=true")
553 assert response(conn, 200) =~ note_object.data["content"]
556 test "it clears `unreachable` federation status of the sender", %{conn: conn, data: data} do
558 data = Map.put(data, "bcc", [user.ap_id])
560 sender_host = URI.parse(data["actor"]).host
561 Instances.set_consistently_unreachable(sender_host)
562 refute Instances.reachable?(sender_host)
566 |> assign(:valid_signature, true)
567 |> put_req_header("content-type", "application/activity+json")
568 |> post("/users/#{user.nickname}/inbox", data)
570 assert "ok" == json_response(conn, 200)
571 assert Instances.reachable?(sender_host)
574 test "it removes all follower collections but actor's", %{conn: conn} do
575 [actor, recipient] = insert_pair(:user)
578 File.read!("test/fixtures/activitypub-client-post-activity.json")
581 object = Map.put(data["object"], "attributedTo", actor.ap_id)
585 |> Map.put("id", Utils.generate_object_id())
586 |> Map.put("actor", actor.ap_id)
587 |> Map.put("object", object)
589 recipient.follower_address,
590 actor.follower_address
594 recipient.follower_address,
595 "https://www.w3.org/ns/activitystreams#Public"
599 |> assign(:valid_signature, true)
600 |> put_req_header("content-type", "application/activity+json")
601 |> post("/users/#{recipient.nickname}/inbox", data)
602 |> json_response(200)
604 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
606 activity = Activity.get_by_ap_id(data["id"])
609 assert actor.follower_address in activity.recipients
610 assert actor.follower_address in activity.data["cc"]
612 refute recipient.follower_address in activity.recipients
613 refute recipient.follower_address in activity.data["cc"]
614 refute recipient.follower_address in activity.data["to"]
618 describe "/users/:nickname/outbox" do
619 test "it will not bomb when there is no activity", %{conn: conn} do
624 |> put_req_header("accept", "application/activity+json")
625 |> get("/users/#{user.nickname}/outbox")
627 result = json_response(conn, 200)
628 assert user.ap_id <> "/outbox" == result["id"]
631 test "it returns a note activity in a collection", %{conn: conn} do
632 note_activity = insert(:note_activity)
633 note_object = Object.normalize(note_activity)
634 user = User.get_cached_by_ap_id(note_activity.data["actor"])
638 |> put_req_header("accept", "application/activity+json")
639 |> get("/users/#{user.nickname}/outbox?page=true")
641 assert response(conn, 200) =~ note_object.data["content"]
644 test "it returns an announce activity in a collection", %{conn: conn} do
645 announce_activity = insert(:announce_activity)
646 user = User.get_cached_by_ap_id(announce_activity.data["actor"])
650 |> put_req_header("accept", "application/activity+json")
651 |> get("/users/#{user.nickname}/outbox?page=true")
653 assert response(conn, 200) =~ announce_activity.data["object"]
657 describe "POST /users/:nickname/outbox (C2S)" do
661 "@context" => "https://www.w3.org/ns/activitystreams",
663 "object" => %{"type" => "Note", "content" => "AP C2S test"},
664 "to" => "https://www.w3.org/ns/activitystreams#Public",
670 test "it rejects posts from other users / unauthenticated users", %{
675 otheruser = insert(:user)
679 |> assign(:user, otheruser)
680 |> put_req_header("content-type", "application/activity+json")
681 |> post("/users/#{user.nickname}/outbox", activity)
683 assert json_response(conn, 403)
686 test "it inserts an incoming create activity into the database", %{
694 |> assign(:user, user)
695 |> put_req_header("content-type", "application/activity+json")
696 |> post("/users/#{user.nickname}/outbox", activity)
697 |> json_response(201)
699 assert Activity.get_by_ap_id(result["id"])
700 assert result["object"]
701 assert %Object{data: object} = Object.normalize(result["object"])
702 assert object["content"] == activity["object"]["content"]
705 test "it rejects anything beyond 'Note' creations", %{conn: conn, activity: activity} do
710 |> put_in(["object", "type"], "Benis")
714 |> assign(:user, user)
715 |> put_req_header("content-type", "application/activity+json")
716 |> post("/users/#{user.nickname}/outbox", activity)
717 |> json_response(400)
720 test "it inserts an incoming sensitive activity into the database", %{
725 object = Map.put(activity["object"], "sensitive", true)
726 activity = Map.put(activity, "object", object)
730 |> assign(:user, user)
731 |> put_req_header("content-type", "application/activity+json")
732 |> post("/users/#{user.nickname}/outbox", activity)
733 |> json_response(201)
735 assert Activity.get_by_ap_id(result["id"])
736 assert result["object"]
737 assert %Object{data: object} = Object.normalize(result["object"])
738 assert object["sensitive"] == activity["object"]["sensitive"]
739 assert object["content"] == activity["object"]["content"]
742 test "it rejects an incoming activity with bogus type", %{conn: conn, activity: activity} do
744 activity = Map.put(activity, "type", "BadType")
748 |> assign(:user, user)
749 |> put_req_header("content-type", "application/activity+json")
750 |> post("/users/#{user.nickname}/outbox", activity)
752 assert json_response(conn, 400)
755 test "it erects a tombstone when receiving a delete activity", %{conn: conn} do
756 note_activity = insert(:note_activity)
757 note_object = Object.normalize(note_activity)
758 user = User.get_cached_by_ap_id(note_activity.data["actor"])
763 id: note_object.data["id"]
769 |> assign(:user, user)
770 |> put_req_header("content-type", "application/activity+json")
771 |> post("/users/#{user.nickname}/outbox", data)
773 result = json_response(conn, 201)
774 assert Activity.get_by_ap_id(result["id"])
776 assert object = Object.get_by_ap_id(note_object.data["id"])
777 assert object.data["type"] == "Tombstone"
780 test "it rejects delete activity of object from other actor", %{conn: conn} do
781 note_activity = insert(:note_activity)
782 note_object = Object.normalize(note_activity)
788 id: note_object.data["id"]
794 |> assign(:user, user)
795 |> put_req_header("content-type", "application/activity+json")
796 |> post("/users/#{user.nickname}/outbox", data)
798 assert json_response(conn, 400)
801 test "it increases like count when receiving a like action", %{conn: conn} do
802 note_activity = insert(:note_activity)
803 note_object = Object.normalize(note_activity)
804 user = User.get_cached_by_ap_id(note_activity.data["actor"])
809 id: note_object.data["id"]
815 |> assign(:user, user)
816 |> put_req_header("content-type", "application/activity+json")
817 |> post("/users/#{user.nickname}/outbox", data)
819 result = json_response(conn, 201)
820 assert Activity.get_by_ap_id(result["id"])
822 assert object = Object.get_by_ap_id(note_object.data["id"])
823 assert object.data["like_count"] == 1
827 describe "/relay/followers" do
828 test "it returns relay followers", %{conn: conn} do
829 relay_actor = Relay.get_actor()
831 User.follow(user, relay_actor)
835 |> assign(:relay, true)
836 |> get("/relay/followers")
837 |> json_response(200)
839 assert result["first"]["orderedItems"] == [user.ap_id]
843 describe "/relay/following" do
844 test "it returns relay following", %{conn: conn} do
847 |> assign(:relay, true)
848 |> get("/relay/following")
849 |> json_response(200)
851 assert result["first"]["orderedItems"] == []
855 describe "/users/:nickname/followers" do
856 test "it returns the followers in a collection", %{conn: conn} do
858 user_two = insert(:user)
859 User.follow(user, user_two)
863 |> get("/users/#{user_two.nickname}/followers")
864 |> json_response(200)
866 assert result["first"]["orderedItems"] == [user.ap_id]
869 test "it returns returns a uri if the user has 'hide_followers' set", %{conn: conn} do
871 user_two = insert(:user, hide_followers: true)
872 User.follow(user, user_two)
876 |> get("/users/#{user_two.nickname}/followers")
877 |> json_response(200)
879 assert is_binary(result["first"])
882 test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is not authenticated",
884 user = insert(:user, hide_followers: true)
888 |> get("/users/#{user.nickname}/followers?page=1")
890 assert result.status == 403
891 assert result.resp_body == ""
894 test "it renders the page, if the user has 'hide_followers' set and the request is authenticated with the same user",
896 user = insert(:user, hide_followers: true)
897 other_user = insert(:user)
898 {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
902 |> assign(:user, user)
903 |> get("/users/#{user.nickname}/followers?page=1")
904 |> json_response(200)
906 assert result["totalItems"] == 1
907 assert result["orderedItems"] == [other_user.ap_id]
910 test "it works for more than 10 users", %{conn: conn} do
913 Enum.each(1..15, fn _ ->
914 other_user = insert(:user)
915 User.follow(other_user, user)
920 |> get("/users/#{user.nickname}/followers")
921 |> json_response(200)
923 assert length(result["first"]["orderedItems"]) == 10
924 assert result["first"]["totalItems"] == 15
925 assert result["totalItems"] == 15
929 |> get("/users/#{user.nickname}/followers?page=2")
930 |> json_response(200)
932 assert length(result["orderedItems"]) == 5
933 assert result["totalItems"] == 15
937 describe "/users/:nickname/following" do
938 test "it returns the following in a collection", %{conn: conn} do
940 user_two = insert(:user)
941 User.follow(user, user_two)
945 |> get("/users/#{user.nickname}/following")
946 |> json_response(200)
948 assert result["first"]["orderedItems"] == [user_two.ap_id]
951 test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do
952 user = insert(:user, hide_follows: true)
953 user_two = insert(:user)
954 User.follow(user, user_two)
958 |> get("/users/#{user.nickname}/following")
959 |> json_response(200)
961 assert is_binary(result["first"])
964 test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is not authenticated",
966 user = insert(:user, hide_follows: true)
970 |> get("/users/#{user.nickname}/following?page=1")
972 assert result.status == 403
973 assert result.resp_body == ""
976 test "it renders the page, if the user has 'hide_follows' set and the request is authenticated with the same user",
978 user = insert(:user, hide_follows: true)
979 other_user = insert(:user)
980 {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)
984 |> assign(:user, user)
985 |> get("/users/#{user.nickname}/following?page=1")
986 |> json_response(200)
988 assert result["totalItems"] == 1
989 assert result["orderedItems"] == [other_user.ap_id]
992 test "it works for more than 10 users", %{conn: conn} do
995 Enum.each(1..15, fn _ ->
996 user = User.get_cached_by_id(user.id)
997 other_user = insert(:user)
998 User.follow(user, other_user)
1003 |> get("/users/#{user.nickname}/following")
1004 |> json_response(200)
1006 assert length(result["first"]["orderedItems"]) == 10
1007 assert result["first"]["totalItems"] == 15
1008 assert result["totalItems"] == 15
1012 |> get("/users/#{user.nickname}/following?page=2")
1013 |> json_response(200)
1015 assert length(result["orderedItems"]) == 5
1016 assert result["totalItems"] == 15
1020 describe "delivery tracking" do
1021 test "it tracks a signed object fetch", %{conn: conn} do
1022 user = insert(:user, local: false)
1023 activity = insert(:note_activity)
1024 object = Object.normalize(activity)
1026 object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
1029 |> put_req_header("accept", "application/activity+json")
1030 |> assign(:user, user)
1032 |> json_response(200)
1034 assert Delivery.get(object.id, user.id)
1037 test "it tracks a signed activity fetch", %{conn: conn} do
1038 user = insert(:user, local: false)
1039 activity = insert(:note_activity)
1040 object = Object.normalize(activity)
1042 activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
1045 |> put_req_header("accept", "application/activity+json")
1046 |> assign(:user, user)
1047 |> get(activity_path)
1048 |> json_response(200)
1050 assert Delivery.get(object.id, user.id)
1053 test "it tracks a signed object fetch when the json is cached", %{conn: conn} do
1054 user = insert(:user, local: false)
1055 other_user = insert(:user, local: false)
1056 activity = insert(:note_activity)
1057 object = Object.normalize(activity)
1059 object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
1062 |> put_req_header("accept", "application/activity+json")
1063 |> assign(:user, user)
1065 |> json_response(200)
1068 |> put_req_header("accept", "application/activity+json")
1069 |> assign(:user, other_user)
1071 |> json_response(200)
1073 assert Delivery.get(object.id, user.id)
1074 assert Delivery.get(object.id, other_user.id)
1077 test "it tracks a signed activity fetch when the json is cached", %{conn: conn} do
1078 user = insert(:user, local: false)
1079 other_user = insert(:user, local: false)
1080 activity = insert(:note_activity)
1081 object = Object.normalize(activity)
1083 activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
1086 |> put_req_header("accept", "application/activity+json")
1087 |> assign(:user, user)
1088 |> get(activity_path)
1089 |> json_response(200)
1092 |> put_req_header("accept", "application/activity+json")
1093 |> assign(:user, other_user)
1094 |> get(activity_path)
1095 |> json_response(200)
1097 assert Delivery.get(object.id, user.id)
1098 assert Delivery.get(object.id, other_user.id)
1102 describe "Additionnal ActivityPub C2S endpoints" do
1103 test "/api/ap/whoami", %{conn: conn} do
1104 user = insert(:user)
1108 |> assign(:user, user)
1109 |> get("/api/ap/whoami")
1111 user = User.get_cached_by_id(user.id)
1113 assert UserView.render("user.json", %{user: user}) == json_response(conn, 200)
1116 clear_config([:media_proxy])
1117 clear_config([Pleroma.Upload])
1119 test "uploadMedia", %{conn: conn} do
1120 user = insert(:user)
1122 desc = "Description of the image"
1124 image = %Plug.Upload{
1125 content_type: "image/jpg",
1126 path: Path.absname("test/fixtures/image.jpg"),
1127 filename: "an_image.jpg"
1132 |> assign(:user, user)
1133 |> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
1135 assert object = json_response(conn, :created)
1136 assert object["name"] == desc
1137 assert object["type"] == "Document"
1138 assert object["actor"] == user.ap_id