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 inserts an incoming sensitive activity into the database", %{
710 object = Map.put(activity["object"], "sensitive", true)
711 activity = Map.put(activity, "object", object)
715 |> assign(:user, user)
716 |> put_req_header("content-type", "application/activity+json")
717 |> post("/users/#{user.nickname}/outbox", activity)
718 |> json_response(201)
720 assert Activity.get_by_ap_id(result["id"])
721 assert result["object"]
722 assert %Object{data: object} = Object.normalize(result["object"])
723 assert object["sensitive"] == activity["object"]["sensitive"]
724 assert object["content"] == activity["object"]["content"]
727 test "it rejects an incoming activity with bogus type", %{conn: conn, activity: activity} do
729 activity = Map.put(activity, "type", "BadType")
733 |> assign(:user, user)
734 |> put_req_header("content-type", "application/activity+json")
735 |> post("/users/#{user.nickname}/outbox", activity)
737 assert json_response(conn, 400)
740 test "it erects a tombstone when receiving a delete activity", %{conn: conn} do
741 note_activity = insert(:note_activity)
742 note_object = Object.normalize(note_activity)
743 user = User.get_cached_by_ap_id(note_activity.data["actor"])
748 id: note_object.data["id"]
754 |> assign(:user, user)
755 |> put_req_header("content-type", "application/activity+json")
756 |> post("/users/#{user.nickname}/outbox", data)
758 result = json_response(conn, 201)
759 assert Activity.get_by_ap_id(result["id"])
761 assert object = Object.get_by_ap_id(note_object.data["id"])
762 assert object.data["type"] == "Tombstone"
765 test "it rejects delete activity of object from other actor", %{conn: conn} do
766 note_activity = insert(:note_activity)
767 note_object = Object.normalize(note_activity)
773 id: note_object.data["id"]
779 |> assign(:user, user)
780 |> put_req_header("content-type", "application/activity+json")
781 |> post("/users/#{user.nickname}/outbox", data)
783 assert json_response(conn, 400)
786 test "it increases like count when receiving a like action", %{conn: conn} do
787 note_activity = insert(:note_activity)
788 note_object = Object.normalize(note_activity)
789 user = User.get_cached_by_ap_id(note_activity.data["actor"])
794 id: note_object.data["id"]
800 |> assign(:user, user)
801 |> put_req_header("content-type", "application/activity+json")
802 |> post("/users/#{user.nickname}/outbox", data)
804 result = json_response(conn, 201)
805 assert Activity.get_by_ap_id(result["id"])
807 assert object = Object.get_by_ap_id(note_object.data["id"])
808 assert object.data["like_count"] == 1
812 describe "/relay/followers" do
813 test "it returns relay followers", %{conn: conn} do
814 relay_actor = Relay.get_actor()
816 User.follow(user, relay_actor)
820 |> assign(:relay, true)
821 |> get("/relay/followers")
822 |> json_response(200)
824 assert result["first"]["orderedItems"] == [user.ap_id]
828 describe "/relay/following" do
829 test "it returns relay following", %{conn: conn} do
832 |> assign(:relay, true)
833 |> get("/relay/following")
834 |> json_response(200)
836 assert result["first"]["orderedItems"] == []
840 describe "/users/:nickname/followers" do
841 test "it returns the followers in a collection", %{conn: conn} do
843 user_two = insert(:user)
844 User.follow(user, user_two)
848 |> get("/users/#{user_two.nickname}/followers")
849 |> json_response(200)
851 assert result["first"]["orderedItems"] == [user.ap_id]
854 test "it returns returns a uri if the user has 'hide_followers' set", %{conn: conn} do
856 user_two = insert(:user, hide_followers: true)
857 User.follow(user, user_two)
861 |> get("/users/#{user_two.nickname}/followers")
862 |> json_response(200)
864 assert is_binary(result["first"])
867 test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is not authenticated",
869 user = insert(:user, hide_followers: true)
873 |> get("/users/#{user.nickname}/followers?page=1")
875 assert result.status == 403
876 assert result.resp_body == ""
879 test "it renders the page, if the user has 'hide_followers' set and the request is authenticated with the same user",
881 user = insert(:user, hide_followers: true)
882 other_user = insert(:user)
883 {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
887 |> assign(:user, user)
888 |> get("/users/#{user.nickname}/followers?page=1")
889 |> json_response(200)
891 assert result["totalItems"] == 1
892 assert result["orderedItems"] == [other_user.ap_id]
895 test "it works for more than 10 users", %{conn: conn} do
898 Enum.each(1..15, fn _ ->
899 other_user = insert(:user)
900 User.follow(other_user, user)
905 |> get("/users/#{user.nickname}/followers")
906 |> json_response(200)
908 assert length(result["first"]["orderedItems"]) == 10
909 assert result["first"]["totalItems"] == 15
910 assert result["totalItems"] == 15
914 |> get("/users/#{user.nickname}/followers?page=2")
915 |> json_response(200)
917 assert length(result["orderedItems"]) == 5
918 assert result["totalItems"] == 15
922 describe "/users/:nickname/following" do
923 test "it returns the following in a collection", %{conn: conn} do
925 user_two = insert(:user)
926 User.follow(user, user_two)
930 |> get("/users/#{user.nickname}/following")
931 |> json_response(200)
933 assert result["first"]["orderedItems"] == [user_two.ap_id]
936 test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do
937 user = insert(:user, hide_follows: true)
938 user_two = insert(:user)
939 User.follow(user, user_two)
943 |> get("/users/#{user.nickname}/following")
944 |> json_response(200)
946 assert is_binary(result["first"])
949 test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is not authenticated",
951 user = insert(:user, hide_follows: true)
955 |> get("/users/#{user.nickname}/following?page=1")
957 assert result.status == 403
958 assert result.resp_body == ""
961 test "it renders the page, if the user has 'hide_follows' set and the request is authenticated with the same user",
963 user = insert(:user, hide_follows: true)
964 other_user = insert(:user)
965 {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)
969 |> assign(:user, user)
970 |> get("/users/#{user.nickname}/following?page=1")
971 |> json_response(200)
973 assert result["totalItems"] == 1
974 assert result["orderedItems"] == [other_user.ap_id]
977 test "it works for more than 10 users", %{conn: conn} do
980 Enum.each(1..15, fn _ ->
981 user = User.get_cached_by_id(user.id)
982 other_user = insert(:user)
983 User.follow(user, other_user)
988 |> get("/users/#{user.nickname}/following")
989 |> json_response(200)
991 assert length(result["first"]["orderedItems"]) == 10
992 assert result["first"]["totalItems"] == 15
993 assert result["totalItems"] == 15
997 |> get("/users/#{user.nickname}/following?page=2")
998 |> json_response(200)
1000 assert length(result["orderedItems"]) == 5
1001 assert result["totalItems"] == 15
1005 describe "delivery tracking" do
1006 test "it tracks a signed object fetch", %{conn: conn} do
1007 user = insert(:user, local: false)
1008 activity = insert(:note_activity)
1009 object = Object.normalize(activity)
1011 object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
1014 |> put_req_header("accept", "application/activity+json")
1015 |> assign(:user, user)
1017 |> json_response(200)
1019 assert Delivery.get(object.id, user.id)
1022 test "it tracks a signed activity fetch", %{conn: conn} do
1023 user = insert(:user, local: false)
1024 activity = insert(:note_activity)
1025 object = Object.normalize(activity)
1027 activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
1030 |> put_req_header("accept", "application/activity+json")
1031 |> assign(:user, user)
1032 |> get(activity_path)
1033 |> json_response(200)
1035 assert Delivery.get(object.id, user.id)
1038 test "it tracks a signed object fetch when the json is cached", %{conn: conn} do
1039 user = insert(:user, local: false)
1040 other_user = insert(:user, local: false)
1041 activity = insert(:note_activity)
1042 object = Object.normalize(activity)
1044 object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
1047 |> put_req_header("accept", "application/activity+json")
1048 |> assign(:user, user)
1050 |> json_response(200)
1053 |> put_req_header("accept", "application/activity+json")
1054 |> assign(:user, other_user)
1056 |> json_response(200)
1058 assert Delivery.get(object.id, user.id)
1059 assert Delivery.get(object.id, other_user.id)
1062 test "it tracks a signed activity fetch when the json is cached", %{conn: conn} do
1063 user = insert(:user, local: false)
1064 other_user = insert(:user, local: false)
1065 activity = insert(:note_activity)
1066 object = Object.normalize(activity)
1068 activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
1071 |> put_req_header("accept", "application/activity+json")
1072 |> assign(:user, user)
1073 |> get(activity_path)
1074 |> json_response(200)
1077 |> put_req_header("accept", "application/activity+json")
1078 |> assign(:user, other_user)
1079 |> get(activity_path)
1080 |> json_response(200)
1082 assert Delivery.get(object.id, user.id)
1083 assert Delivery.get(object.id, other_user.id)
1087 describe "Additionnal ActivityPub C2S endpoints" do
1088 test "/api/ap/whoami", %{conn: conn} do
1089 user = insert(:user)
1093 |> assign(:user, user)
1094 |> get("/api/ap/whoami")
1096 user = User.get_cached_by_id(user.id)
1098 assert UserView.render("user.json", %{user: user}) == json_response(conn, 200)
1101 clear_config([:media_proxy])
1102 clear_config([Pleroma.Upload])
1104 test "uploadMedia", %{conn: conn} do
1105 user = insert(:user)
1107 desc = "Description of the image"
1109 image = %Plug.Upload{
1110 content_type: "image/jpg",
1111 path: Path.absname("test/fixtures/image.jpg"),
1112 filename: "an_image.jpg"
1117 |> assign(:user, user)
1118 |> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
1120 assert object = json_response(conn, :created)
1121 assert object["name"] == desc
1122 assert object["type"] == "Document"
1123 assert object["actor"] == user.ap_id