Merge branch 'develop' into tests/mastodon_api_controller.ex
[akkoma] / test / web / activity_pub / activity_pub_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
6 use Pleroma.Web.ConnCase
7 use Oban.Testing, repo: Pleroma.Repo
8
9 import Pleroma.Factory
10 alias Pleroma.Activity
11 alias Pleroma.Delivery
12 alias Pleroma.Instances
13 alias Pleroma.Object
14 alias Pleroma.Tests.ObanHelpers
15 alias Pleroma.User
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
22
23 setup_all do
24 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
25 :ok
26 end
27
28 clear_config_all([:instance, :federating],
29 do: Pleroma.Config.put([:instance, :federating], true)
30 )
31
32 describe "/relay" do
33 clear_config([:instance, :allow_relay])
34
35 test "with the relay active, it returns the relay user", %{conn: conn} do
36 res =
37 conn
38 |> get(activity_pub_path(conn, :relay))
39 |> json_response(200)
40
41 assert res["id"] =~ "/relay"
42 end
43
44 test "with the relay disabled, it returns 404", %{conn: conn} do
45 Pleroma.Config.put([:instance, :allow_relay], false)
46
47 conn
48 |> get(activity_pub_path(conn, :relay))
49 |> json_response(404)
50 |> assert
51 end
52 end
53
54 describe "/internal/fetch" do
55 test "it returns the internal fetch user", %{conn: conn} do
56 res =
57 conn
58 |> get(activity_pub_path(conn, :internal_fetch))
59 |> json_response(200)
60
61 assert res["id"] =~ "/fetch"
62 end
63 end
64
65 describe "/users/:nickname" do
66 test "it returns a json representation of the user with accept application/json", %{
67 conn: conn
68 } do
69 user = insert(:user)
70
71 conn =
72 conn
73 |> put_req_header("accept", "application/json")
74 |> get("/users/#{user.nickname}")
75
76 user = User.get_cached_by_id(user.id)
77
78 assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
79 end
80
81 test "it returns a json representation of the user with accept application/activity+json", %{
82 conn: conn
83 } do
84 user = insert(:user)
85
86 conn =
87 conn
88 |> put_req_header("accept", "application/activity+json")
89 |> get("/users/#{user.nickname}")
90
91 user = User.get_cached_by_id(user.id)
92
93 assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
94 end
95
96 test "it returns a json representation of the user with accept application/ld+json", %{
97 conn: conn
98 } do
99 user = insert(:user)
100
101 conn =
102 conn
103 |> put_req_header(
104 "accept",
105 "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
106 )
107 |> get("/users/#{user.nickname}")
108
109 user = User.get_cached_by_id(user.id)
110
111 assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
112 end
113 end
114
115 describe "/object/:uuid" do
116 test "it returns a json representation of the object with accept application/json", %{
117 conn: conn
118 } do
119 note = insert(:note)
120 uuid = String.split(note.data["id"], "/") |> List.last()
121
122 conn =
123 conn
124 |> put_req_header("accept", "application/json")
125 |> get("/objects/#{uuid}")
126
127 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
128 end
129
130 test "it returns a json representation of the object with accept application/activity+json",
131 %{conn: conn} do
132 note = insert(:note)
133 uuid = String.split(note.data["id"], "/") |> List.last()
134
135 conn =
136 conn
137 |> put_req_header("accept", "application/activity+json")
138 |> get("/objects/#{uuid}")
139
140 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
141 end
142
143 test "it returns a json representation of the object with accept application/ld+json", %{
144 conn: conn
145 } do
146 note = insert(:note)
147 uuid = String.split(note.data["id"], "/") |> List.last()
148
149 conn =
150 conn
151 |> put_req_header(
152 "accept",
153 "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
154 )
155 |> get("/objects/#{uuid}")
156
157 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
158 end
159
160 test "it returns 404 for non-public messages", %{conn: conn} do
161 note = insert(:direct_note)
162 uuid = String.split(note.data["id"], "/") |> List.last()
163
164 conn =
165 conn
166 |> put_req_header("accept", "application/activity+json")
167 |> get("/objects/#{uuid}")
168
169 assert json_response(conn, 404)
170 end
171
172 test "it returns 404 for tombstone objects", %{conn: conn} do
173 tombstone = insert(:tombstone)
174 uuid = String.split(tombstone.data["id"], "/") |> List.last()
175
176 conn =
177 conn
178 |> put_req_header("accept", "application/activity+json")
179 |> get("/objects/#{uuid}")
180
181 assert json_response(conn, 404)
182 end
183
184 test "it caches a response", %{conn: conn} do
185 note = insert(:note)
186 uuid = String.split(note.data["id"], "/") |> List.last()
187
188 conn1 =
189 conn
190 |> put_req_header("accept", "application/activity+json")
191 |> get("/objects/#{uuid}")
192
193 assert json_response(conn1, :ok)
194 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
195
196 conn2 =
197 conn
198 |> put_req_header("accept", "application/activity+json")
199 |> get("/objects/#{uuid}")
200
201 assert json_response(conn1, :ok) == json_response(conn2, :ok)
202 assert Enum.any?(conn2.resp_headers, &(&1 == {"x-cache", "HIT from Pleroma"}))
203 end
204
205 test "cached purged after object deletion", %{conn: conn} do
206 note = insert(:note)
207 uuid = String.split(note.data["id"], "/") |> List.last()
208
209 conn1 =
210 conn
211 |> put_req_header("accept", "application/activity+json")
212 |> get("/objects/#{uuid}")
213
214 assert json_response(conn1, :ok)
215 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
216
217 Object.delete(note)
218
219 conn2 =
220 conn
221 |> put_req_header("accept", "application/activity+json")
222 |> get("/objects/#{uuid}")
223
224 assert "Not found" == json_response(conn2, :not_found)
225 end
226 end
227
228 describe "/object/:uuid/likes" do
229 setup do
230 like = insert(:like_activity)
231 like_object_ap_id = Object.normalize(like).data["id"]
232
233 uuid =
234 like_object_ap_id
235 |> String.split("/")
236 |> List.last()
237
238 [id: like.data["id"], uuid: uuid]
239 end
240
241 test "it returns the like activities in a collection", %{conn: conn, id: id, uuid: uuid} do
242 result =
243 conn
244 |> put_req_header("accept", "application/activity+json")
245 |> get("/objects/#{uuid}/likes")
246 |> json_response(200)
247
248 assert List.first(result["first"]["orderedItems"])["id"] == id
249 assert result["type"] == "OrderedCollection"
250 assert result["totalItems"] == 1
251 refute result["first"]["next"]
252 end
253
254 test "it does not crash when page number is exceeded total pages", %{conn: conn, uuid: uuid} do
255 result =
256 conn
257 |> put_req_header("accept", "application/activity+json")
258 |> get("/objects/#{uuid}/likes?page=2")
259 |> json_response(200)
260
261 assert result["type"] == "OrderedCollectionPage"
262 assert result["totalItems"] == 1
263 refute result["next"]
264 assert Enum.empty?(result["orderedItems"])
265 end
266
267 test "it contains the next key when likes count is more than 10", %{conn: conn} do
268 note = insert(:note_activity)
269 insert_list(11, :like_activity, note_activity: note)
270
271 uuid =
272 note
273 |> Object.normalize()
274 |> Map.get(:data)
275 |> Map.get("id")
276 |> String.split("/")
277 |> List.last()
278
279 result =
280 conn
281 |> put_req_header("accept", "application/activity+json")
282 |> get("/objects/#{uuid}/likes?page=1")
283 |> json_response(200)
284
285 assert result["totalItems"] == 11
286 assert length(result["orderedItems"]) == 10
287 assert result["next"]
288 end
289 end
290
291 describe "/activities/:uuid" do
292 test "it returns a json representation of the activity", %{conn: conn} do
293 activity = insert(:note_activity)
294 uuid = String.split(activity.data["id"], "/") |> List.last()
295
296 conn =
297 conn
298 |> put_req_header("accept", "application/activity+json")
299 |> get("/activities/#{uuid}")
300
301 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: activity})
302 end
303
304 test "it returns 404 for non-public activities", %{conn: conn} do
305 activity = insert(:direct_note_activity)
306 uuid = String.split(activity.data["id"], "/") |> List.last()
307
308 conn =
309 conn
310 |> put_req_header("accept", "application/activity+json")
311 |> get("/activities/#{uuid}")
312
313 assert json_response(conn, 404)
314 end
315
316 test "it caches a response", %{conn: conn} do
317 activity = insert(:note_activity)
318 uuid = String.split(activity.data["id"], "/") |> List.last()
319
320 conn1 =
321 conn
322 |> put_req_header("accept", "application/activity+json")
323 |> get("/activities/#{uuid}")
324
325 assert json_response(conn1, :ok)
326 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
327
328 conn2 =
329 conn
330 |> put_req_header("accept", "application/activity+json")
331 |> get("/activities/#{uuid}")
332
333 assert json_response(conn1, :ok) == json_response(conn2, :ok)
334 assert Enum.any?(conn2.resp_headers, &(&1 == {"x-cache", "HIT from Pleroma"}))
335 end
336
337 test "cached purged after activity deletion", %{conn: conn} do
338 user = insert(:user)
339 {:ok, activity} = CommonAPI.post(user, %{"status" => "cofe"})
340
341 uuid = String.split(activity.data["id"], "/") |> List.last()
342
343 conn1 =
344 conn
345 |> put_req_header("accept", "application/activity+json")
346 |> get("/activities/#{uuid}")
347
348 assert json_response(conn1, :ok)
349 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
350
351 Activity.delete_by_ap_id(activity.object.data["id"])
352
353 conn2 =
354 conn
355 |> put_req_header("accept", "application/activity+json")
356 |> get("/activities/#{uuid}")
357
358 assert "Not found" == json_response(conn2, :not_found)
359 end
360 end
361
362 describe "/inbox" do
363 test "it inserts an incoming activity into the database", %{conn: conn} do
364 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
365
366 conn =
367 conn
368 |> assign(:valid_signature, true)
369 |> put_req_header("content-type", "application/activity+json")
370 |> post("/inbox", data)
371
372 assert "ok" == json_response(conn, 200)
373
374 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
375 assert Activity.get_by_ap_id(data["id"])
376 end
377
378 test "it clears `unreachable` federation status of the sender", %{conn: conn} do
379 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
380
381 sender_url = data["actor"]
382 Instances.set_consistently_unreachable(sender_url)
383 refute Instances.reachable?(sender_url)
384
385 conn =
386 conn
387 |> assign(:valid_signature, true)
388 |> put_req_header("content-type", "application/activity+json")
389 |> post("/inbox", data)
390
391 assert "ok" == json_response(conn, 200)
392 assert Instances.reachable?(sender_url)
393 end
394 end
395
396 describe "/users/:nickname/inbox" do
397 setup do
398 data =
399 File.read!("test/fixtures/mastodon-post-activity.json")
400 |> Poison.decode!()
401
402 [data: data]
403 end
404
405 test "it inserts an incoming activity into the database", %{conn: conn, data: data} do
406 user = insert(:user)
407 data = Map.put(data, "bcc", [user.ap_id])
408
409 conn =
410 conn
411 |> assign(:valid_signature, true)
412 |> put_req_header("content-type", "application/activity+json")
413 |> post("/users/#{user.nickname}/inbox", data)
414
415 assert "ok" == json_response(conn, 200)
416 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
417 assert Activity.get_by_ap_id(data["id"])
418 end
419
420 test "it accepts messages from actors that are followed by the user", %{
421 conn: conn,
422 data: data
423 } do
424 recipient = insert(:user)
425 actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"})
426
427 {:ok, recipient} = User.follow(recipient, actor)
428
429 object =
430 data["object"]
431 |> Map.put("attributedTo", actor.ap_id)
432
433 data =
434 data
435 |> Map.put("actor", actor.ap_id)
436 |> Map.put("object", object)
437
438 conn =
439 conn
440 |> assign(:valid_signature, true)
441 |> put_req_header("content-type", "application/activity+json")
442 |> post("/users/#{recipient.nickname}/inbox", data)
443
444 assert "ok" == json_response(conn, 200)
445 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
446 assert Activity.get_by_ap_id(data["id"])
447 end
448
449 test "it rejects reads from other users", %{conn: conn} do
450 user = insert(:user)
451 otheruser = insert(:user)
452
453 conn =
454 conn
455 |> assign(:user, otheruser)
456 |> put_req_header("accept", "application/activity+json")
457 |> get("/users/#{user.nickname}/inbox")
458
459 assert json_response(conn, 403)
460 end
461
462 test "it doesn't crash without an authenticated user", %{conn: conn} do
463 user = insert(:user)
464
465 conn =
466 conn
467 |> put_req_header("accept", "application/activity+json")
468 |> get("/users/#{user.nickname}/inbox")
469
470 assert json_response(conn, 403)
471 end
472
473 test "it returns a note activity in a collection", %{conn: conn} do
474 note_activity = insert(:direct_note_activity)
475 note_object = Object.normalize(note_activity)
476 user = User.get_cached_by_ap_id(hd(note_activity.data["to"]))
477
478 conn =
479 conn
480 |> assign(:user, user)
481 |> put_req_header("accept", "application/activity+json")
482 |> get("/users/#{user.nickname}/inbox")
483
484 assert response(conn, 200) =~ note_object.data["content"]
485 end
486
487 test "it clears `unreachable` federation status of the sender", %{conn: conn, data: data} do
488 user = insert(:user)
489 data = Map.put(data, "bcc", [user.ap_id])
490
491 sender_host = URI.parse(data["actor"]).host
492 Instances.set_consistently_unreachable(sender_host)
493 refute Instances.reachable?(sender_host)
494
495 conn =
496 conn
497 |> assign(:valid_signature, true)
498 |> put_req_header("content-type", "application/activity+json")
499 |> post("/users/#{user.nickname}/inbox", data)
500
501 assert "ok" == json_response(conn, 200)
502 assert Instances.reachable?(sender_host)
503 end
504
505 test "it removes all follower collections but actor's", %{conn: conn} do
506 [actor, recipient] = insert_pair(:user)
507
508 data =
509 File.read!("test/fixtures/activitypub-client-post-activity.json")
510 |> Poison.decode!()
511
512 object = Map.put(data["object"], "attributedTo", actor.ap_id)
513
514 data =
515 data
516 |> Map.put("id", Utils.generate_object_id())
517 |> Map.put("actor", actor.ap_id)
518 |> Map.put("object", object)
519 |> Map.put("cc", [
520 recipient.follower_address,
521 actor.follower_address
522 ])
523 |> Map.put("to", [
524 recipient.ap_id,
525 recipient.follower_address,
526 "https://www.w3.org/ns/activitystreams#Public"
527 ])
528
529 conn
530 |> assign(:valid_signature, true)
531 |> put_req_header("content-type", "application/activity+json")
532 |> post("/users/#{recipient.nickname}/inbox", data)
533 |> json_response(200)
534
535 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
536
537 activity = Activity.get_by_ap_id(data["id"])
538
539 assert activity.id
540 assert actor.follower_address in activity.recipients
541 assert actor.follower_address in activity.data["cc"]
542
543 refute recipient.follower_address in activity.recipients
544 refute recipient.follower_address in activity.data["cc"]
545 refute recipient.follower_address in activity.data["to"]
546 end
547 end
548
549 describe "/users/:nickname/outbox" do
550 test "it will not bomb when there is no activity", %{conn: conn} do
551 user = insert(:user)
552
553 conn =
554 conn
555 |> put_req_header("accept", "application/activity+json")
556 |> get("/users/#{user.nickname}/outbox")
557
558 result = json_response(conn, 200)
559 assert user.ap_id <> "/outbox" == result["id"]
560 end
561
562 test "it returns a note activity in a collection", %{conn: conn} do
563 note_activity = insert(:note_activity)
564 note_object = Object.normalize(note_activity)
565 user = User.get_cached_by_ap_id(note_activity.data["actor"])
566
567 conn =
568 conn
569 |> put_req_header("accept", "application/activity+json")
570 |> get("/users/#{user.nickname}/outbox")
571
572 assert response(conn, 200) =~ note_object.data["content"]
573 end
574
575 test "it returns an announce activity in a collection", %{conn: conn} do
576 announce_activity = insert(:announce_activity)
577 user = User.get_cached_by_ap_id(announce_activity.data["actor"])
578
579 conn =
580 conn
581 |> put_req_header("accept", "application/activity+json")
582 |> get("/users/#{user.nickname}/outbox")
583
584 assert response(conn, 200) =~ announce_activity.data["object"]
585 end
586
587 test "it rejects posts from other users", %{conn: conn} do
588 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
589 user = insert(:user)
590 otheruser = insert(:user)
591
592 conn =
593 conn
594 |> assign(:user, otheruser)
595 |> put_req_header("content-type", "application/activity+json")
596 |> post("/users/#{user.nickname}/outbox", data)
597
598 assert json_response(conn, 403)
599 end
600
601 test "it inserts an incoming create activity into the database", %{conn: conn} do
602 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
603 user = insert(:user)
604
605 conn =
606 conn
607 |> assign(:user, user)
608 |> put_req_header("content-type", "application/activity+json")
609 |> post("/users/#{user.nickname}/outbox", data)
610
611 result = json_response(conn, 201)
612
613 assert Activity.get_by_ap_id(result["id"])
614 end
615
616 test "it rejects an incoming activity with bogus type", %{conn: conn} do
617 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
618 user = insert(:user)
619
620 data =
621 data
622 |> Map.put("type", "BadType")
623
624 conn =
625 conn
626 |> assign(:user, user)
627 |> put_req_header("content-type", "application/activity+json")
628 |> post("/users/#{user.nickname}/outbox", data)
629
630 assert json_response(conn, 400)
631 end
632
633 test "it erects a tombstone when receiving a delete activity", %{conn: conn} do
634 note_activity = insert(:note_activity)
635 note_object = Object.normalize(note_activity)
636 user = User.get_cached_by_ap_id(note_activity.data["actor"])
637
638 data = %{
639 type: "Delete",
640 object: %{
641 id: note_object.data["id"]
642 }
643 }
644
645 conn =
646 conn
647 |> assign(:user, user)
648 |> put_req_header("content-type", "application/activity+json")
649 |> post("/users/#{user.nickname}/outbox", data)
650
651 result = json_response(conn, 201)
652 assert Activity.get_by_ap_id(result["id"])
653
654 assert object = Object.get_by_ap_id(note_object.data["id"])
655 assert object.data["type"] == "Tombstone"
656 end
657
658 test "it rejects delete activity of object from other actor", %{conn: conn} do
659 note_activity = insert(:note_activity)
660 note_object = Object.normalize(note_activity)
661 user = insert(:user)
662
663 data = %{
664 type: "Delete",
665 object: %{
666 id: note_object.data["id"]
667 }
668 }
669
670 conn =
671 conn
672 |> assign(:user, user)
673 |> put_req_header("content-type", "application/activity+json")
674 |> post("/users/#{user.nickname}/outbox", data)
675
676 assert json_response(conn, 400)
677 end
678
679 test "it increases like count when receiving a like action", %{conn: conn} do
680 note_activity = insert(:note_activity)
681 note_object = Object.normalize(note_activity)
682 user = User.get_cached_by_ap_id(note_activity.data["actor"])
683
684 data = %{
685 type: "Like",
686 object: %{
687 id: note_object.data["id"]
688 }
689 }
690
691 conn =
692 conn
693 |> assign(:user, user)
694 |> put_req_header("content-type", "application/activity+json")
695 |> post("/users/#{user.nickname}/outbox", data)
696
697 result = json_response(conn, 201)
698 assert Activity.get_by_ap_id(result["id"])
699
700 assert object = Object.get_by_ap_id(note_object.data["id"])
701 assert object.data["like_count"] == 1
702 end
703 end
704
705 describe "/relay/followers" do
706 test "it returns relay followers", %{conn: conn} do
707 relay_actor = Relay.get_actor()
708 user = insert(:user)
709 User.follow(user, relay_actor)
710
711 result =
712 conn
713 |> assign(:relay, true)
714 |> get("/relay/followers")
715 |> json_response(200)
716
717 assert result["first"]["orderedItems"] == [user.ap_id]
718 end
719 end
720
721 describe "/relay/following" do
722 test "it returns relay following", %{conn: conn} do
723 result =
724 conn
725 |> assign(:relay, true)
726 |> get("/relay/following")
727 |> json_response(200)
728
729 assert result["first"]["orderedItems"] == []
730 end
731 end
732
733 describe "/users/:nickname/followers" do
734 test "it returns the followers in a collection", %{conn: conn} do
735 user = insert(:user)
736 user_two = insert(:user)
737 User.follow(user, user_two)
738
739 result =
740 conn
741 |> get("/users/#{user_two.nickname}/followers")
742 |> json_response(200)
743
744 assert result["first"]["orderedItems"] == [user.ap_id]
745 end
746
747 test "it returns returns a uri if the user has 'hide_followers' set", %{conn: conn} do
748 user = insert(:user)
749 user_two = insert(:user, %{info: %{hide_followers: true}})
750 User.follow(user, user_two)
751
752 result =
753 conn
754 |> get("/users/#{user_two.nickname}/followers")
755 |> json_response(200)
756
757 assert is_binary(result["first"])
758 end
759
760 test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is not authenticated",
761 %{conn: conn} do
762 user = insert(:user, %{info: %{hide_followers: true}})
763
764 result =
765 conn
766 |> get("/users/#{user.nickname}/followers?page=1")
767
768 assert result.status == 403
769 assert result.resp_body == ""
770 end
771
772 test "it renders the page, if the user has 'hide_followers' set and the request is authenticated with the same user",
773 %{conn: conn} do
774 user = insert(:user, %{info: %{hide_followers: true}})
775 other_user = insert(:user)
776 {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
777
778 result =
779 conn
780 |> assign(:user, user)
781 |> get("/users/#{user.nickname}/followers?page=1")
782 |> json_response(200)
783
784 assert result["totalItems"] == 1
785 assert result["orderedItems"] == [other_user.ap_id]
786 end
787
788 test "it works for more than 10 users", %{conn: conn} do
789 user = insert(:user)
790
791 Enum.each(1..15, fn _ ->
792 other_user = insert(:user)
793 User.follow(other_user, user)
794 end)
795
796 result =
797 conn
798 |> get("/users/#{user.nickname}/followers")
799 |> json_response(200)
800
801 assert length(result["first"]["orderedItems"]) == 10
802 assert result["first"]["totalItems"] == 15
803 assert result["totalItems"] == 15
804
805 result =
806 conn
807 |> get("/users/#{user.nickname}/followers?page=2")
808 |> json_response(200)
809
810 assert length(result["orderedItems"]) == 5
811 assert result["totalItems"] == 15
812 end
813 end
814
815 describe "/users/:nickname/following" do
816 test "it returns the following in a collection", %{conn: conn} do
817 user = insert(:user)
818 user_two = insert(:user)
819 User.follow(user, user_two)
820
821 result =
822 conn
823 |> get("/users/#{user.nickname}/following")
824 |> json_response(200)
825
826 assert result["first"]["orderedItems"] == [user_two.ap_id]
827 end
828
829 test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do
830 user = insert(:user, %{info: %{hide_follows: true}})
831 user_two = insert(:user)
832 User.follow(user, user_two)
833
834 result =
835 conn
836 |> get("/users/#{user.nickname}/following")
837 |> json_response(200)
838
839 assert is_binary(result["first"])
840 end
841
842 test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is not authenticated",
843 %{conn: conn} do
844 user = insert(:user, %{info: %{hide_follows: true}})
845
846 result =
847 conn
848 |> get("/users/#{user.nickname}/following?page=1")
849
850 assert result.status == 403
851 assert result.resp_body == ""
852 end
853
854 test "it renders the page, if the user has 'hide_follows' set and the request is authenticated with the same user",
855 %{conn: conn} do
856 user = insert(:user, %{info: %{hide_follows: true}})
857 other_user = insert(:user)
858 {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)
859
860 result =
861 conn
862 |> assign(:user, user)
863 |> get("/users/#{user.nickname}/following?page=1")
864 |> json_response(200)
865
866 assert result["totalItems"] == 1
867 assert result["orderedItems"] == [other_user.ap_id]
868 end
869
870 test "it works for more than 10 users", %{conn: conn} do
871 user = insert(:user)
872
873 Enum.each(1..15, fn _ ->
874 user = User.get_cached_by_id(user.id)
875 other_user = insert(:user)
876 User.follow(user, other_user)
877 end)
878
879 result =
880 conn
881 |> get("/users/#{user.nickname}/following")
882 |> json_response(200)
883
884 assert length(result["first"]["orderedItems"]) == 10
885 assert result["first"]["totalItems"] == 15
886 assert result["totalItems"] == 15
887
888 result =
889 conn
890 |> get("/users/#{user.nickname}/following?page=2")
891 |> json_response(200)
892
893 assert length(result["orderedItems"]) == 5
894 assert result["totalItems"] == 15
895 end
896 end
897
898 describe "delivery tracking" do
899 test "it tracks a signed object fetch", %{conn: conn} do
900 user = insert(:user, local: false)
901 activity = insert(:note_activity)
902 object = Object.normalize(activity)
903
904 object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
905
906 conn
907 |> put_req_header("accept", "application/activity+json")
908 |> assign(:user, user)
909 |> get(object_path)
910 |> json_response(200)
911
912 assert Delivery.get(object.id, user.id)
913 end
914
915 test "it tracks a signed activity fetch", %{conn: conn} do
916 user = insert(:user, local: false)
917 activity = insert(:note_activity)
918 object = Object.normalize(activity)
919
920 activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
921
922 conn
923 |> put_req_header("accept", "application/activity+json")
924 |> assign(:user, user)
925 |> get(activity_path)
926 |> json_response(200)
927
928 assert Delivery.get(object.id, user.id)
929 end
930
931 test "it tracks a signed object fetch when the json is cached", %{conn: conn} do
932 user = insert(:user, local: false)
933 other_user = insert(:user, local: false)
934 activity = insert(:note_activity)
935 object = Object.normalize(activity)
936
937 object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
938
939 conn
940 |> put_req_header("accept", "application/activity+json")
941 |> assign(:user, user)
942 |> get(object_path)
943 |> json_response(200)
944
945 build_conn()
946 |> put_req_header("accept", "application/activity+json")
947 |> assign(:user, other_user)
948 |> get(object_path)
949 |> json_response(200)
950
951 assert Delivery.get(object.id, user.id)
952 assert Delivery.get(object.id, other_user.id)
953 end
954
955 test "it tracks a signed activity fetch when the json is cached", %{conn: conn} do
956 user = insert(:user, local: false)
957 other_user = insert(:user, local: false)
958 activity = insert(:note_activity)
959 object = Object.normalize(activity)
960
961 activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
962
963 conn
964 |> put_req_header("accept", "application/activity+json")
965 |> assign(:user, user)
966 |> get(activity_path)
967 |> json_response(200)
968
969 build_conn()
970 |> put_req_header("accept", "application/activity+json")
971 |> assign(:user, other_user)
972 |> get(activity_path)
973 |> json_response(200)
974
975 assert Delivery.get(object.id, user.id)
976 assert Delivery.get(object.id, other_user.id)
977 end
978 end
979 end