Merge branch 'relay-list-change' into 'develop'
[akkoma] / test / web / activity_pub / activity_pub_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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
114 test "it returns 404 for remote users", %{
115 conn: conn
116 } do
117 user = insert(:user, local: false, nickname: "remoteuser@example.com")
118
119 conn =
120 conn
121 |> put_req_header("accept", "application/json")
122 |> get("/users/#{user.nickname}.json")
123
124 assert json_response(conn, 404)
125 end
126 end
127
128 describe "/object/:uuid" do
129 test "it returns a json representation of the object with accept application/json", %{
130 conn: conn
131 } 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/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/activity+json",
144 %{conn: conn} do
145 note = insert(:note)
146 uuid = String.split(note.data["id"], "/") |> List.last()
147
148 conn =
149 conn
150 |> put_req_header("accept", "application/activity+json")
151 |> get("/objects/#{uuid}")
152
153 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
154 end
155
156 test "it returns a json representation of the object with accept application/ld+json", %{
157 conn: conn
158 } do
159 note = insert(:note)
160 uuid = String.split(note.data["id"], "/") |> List.last()
161
162 conn =
163 conn
164 |> put_req_header(
165 "accept",
166 "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
167 )
168 |> get("/objects/#{uuid}")
169
170 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
171 end
172
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()
176
177 conn =
178 conn
179 |> put_req_header("accept", "application/activity+json")
180 |> get("/objects/#{uuid}")
181
182 assert json_response(conn, 404)
183 end
184
185 test "it returns 404 for tombstone objects", %{conn: conn} do
186 tombstone = insert(:tombstone)
187 uuid = String.split(tombstone.data["id"], "/") |> List.last()
188
189 conn =
190 conn
191 |> put_req_header("accept", "application/activity+json")
192 |> get("/objects/#{uuid}")
193
194 assert json_response(conn, 404)
195 end
196
197 test "it caches a response", %{conn: conn} do
198 note = insert(:note)
199 uuid = String.split(note.data["id"], "/") |> List.last()
200
201 conn1 =
202 conn
203 |> put_req_header("accept", "application/activity+json")
204 |> get("/objects/#{uuid}")
205
206 assert json_response(conn1, :ok)
207 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
208
209 conn2 =
210 conn
211 |> put_req_header("accept", "application/activity+json")
212 |> get("/objects/#{uuid}")
213
214 assert json_response(conn1, :ok) == json_response(conn2, :ok)
215 assert Enum.any?(conn2.resp_headers, &(&1 == {"x-cache", "HIT from Pleroma"}))
216 end
217
218 test "cached purged after object deletion", %{conn: conn} do
219 note = insert(:note)
220 uuid = String.split(note.data["id"], "/") |> List.last()
221
222 conn1 =
223 conn
224 |> put_req_header("accept", "application/activity+json")
225 |> get("/objects/#{uuid}")
226
227 assert json_response(conn1, :ok)
228 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
229
230 Object.delete(note)
231
232 conn2 =
233 conn
234 |> put_req_header("accept", "application/activity+json")
235 |> get("/objects/#{uuid}")
236
237 assert "Not found" == json_response(conn2, :not_found)
238 end
239 end
240
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()
245
246 conn =
247 conn
248 |> put_req_header("accept", "application/activity+json")
249 |> get("/activities/#{uuid}")
250
251 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: activity})
252 end
253
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()
257
258 conn =
259 conn
260 |> put_req_header("accept", "application/activity+json")
261 |> get("/activities/#{uuid}")
262
263 assert json_response(conn, 404)
264 end
265
266 test "it caches a response", %{conn: conn} do
267 activity = insert(:note_activity)
268 uuid = String.split(activity.data["id"], "/") |> List.last()
269
270 conn1 =
271 conn
272 |> put_req_header("accept", "application/activity+json")
273 |> get("/activities/#{uuid}")
274
275 assert json_response(conn1, :ok)
276 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
277
278 conn2 =
279 conn
280 |> put_req_header("accept", "application/activity+json")
281 |> get("/activities/#{uuid}")
282
283 assert json_response(conn1, :ok) == json_response(conn2, :ok)
284 assert Enum.any?(conn2.resp_headers, &(&1 == {"x-cache", "HIT from Pleroma"}))
285 end
286
287 test "cached purged after activity deletion", %{conn: conn} do
288 user = insert(:user)
289 {:ok, activity} = CommonAPI.post(user, %{"status" => "cofe"})
290
291 uuid = String.split(activity.data["id"], "/") |> List.last()
292
293 conn1 =
294 conn
295 |> put_req_header("accept", "application/activity+json")
296 |> get("/activities/#{uuid}")
297
298 assert json_response(conn1, :ok)
299 assert Enum.any?(conn1.resp_headers, &(&1 == {"x-cache", "MISS from Pleroma"}))
300
301 Activity.delete_all_by_object_ap_id(activity.object.data["id"])
302
303 conn2 =
304 conn
305 |> put_req_header("accept", "application/activity+json")
306 |> get("/activities/#{uuid}")
307
308 assert "Not found" == json_response(conn2, :not_found)
309 end
310 end
311
312 describe "/inbox" do
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!()
315
316 conn =
317 conn
318 |> assign(:valid_signature, true)
319 |> put_req_header("content-type", "application/activity+json")
320 |> post("/inbox", data)
321
322 assert "ok" == json_response(conn, 200)
323
324 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
325 assert Activity.get_by_ap_id(data["id"])
326 end
327
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!()
330
331 sender_url = data["actor"]
332 Instances.set_consistently_unreachable(sender_url)
333 refute Instances.reachable?(sender_url)
334
335 conn =
336 conn
337 |> assign(:valid_signature, true)
338 |> put_req_header("content-type", "application/activity+json")
339 |> post("/inbox", data)
340
341 assert "ok" == json_response(conn, 200)
342 assert Instances.reachable?(sender_url)
343 end
344
345 test "accept follow activity", %{conn: conn} do
346 Pleroma.Config.put([:instance, :federating], true)
347 relay = Relay.get_actor()
348
349 assert {:ok, %Activity{} = activity} = Relay.follow("https://relay.mastodon.host/actor")
350
351 followed_relay = Pleroma.User.get_by_ap_id("https://relay.mastodon.host/actor")
352 relay = refresh_record(relay)
353
354 accept =
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"])
358
359 assert "ok" ==
360 conn
361 |> assign(:valid_signature, true)
362 |> put_req_header("content-type", "application/activity+json")
363 |> post("/inbox", accept)
364 |> json_response(200)
365
366 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
367
368 assert Pleroma.FollowingRelationship.following?(
369 relay,
370 followed_relay
371 )
372
373 Mix.shell(Mix.Shell.Process)
374
375 on_exit(fn ->
376 Mix.shell(Mix.Shell.IO)
377 end)
378
379 :ok = Mix.Tasks.Pleroma.Relay.run(["list"])
380 assert_receive {:mix_shell, :info, ["relay.mastodon.host"]}
381 end
382 end
383
384 describe "/users/:nickname/inbox" do
385 setup do
386 data =
387 File.read!("test/fixtures/mastodon-post-activity.json")
388 |> Poison.decode!()
389
390 [data: data]
391 end
392
393 test "it inserts an incoming activity into the database", %{conn: conn, data: data} do
394 user = insert(:user)
395 data = Map.put(data, "bcc", [user.ap_id])
396
397 conn =
398 conn
399 |> assign(:valid_signature, true)
400 |> put_req_header("content-type", "application/activity+json")
401 |> post("/users/#{user.nickname}/inbox", data)
402
403 assert "ok" == json_response(conn, 200)
404 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
405 assert Activity.get_by_ap_id(data["id"])
406 end
407
408 test "it accepts messages with to as string instead of array", %{conn: conn, data: data} do
409 user = insert(:user)
410
411 data =
412 Map.put(data, "to", user.ap_id)
413 |> Map.delete("cc")
414
415 conn =
416 conn
417 |> assign(:valid_signature, true)
418 |> put_req_header("content-type", "application/activity+json")
419 |> post("/users/#{user.nickname}/inbox", data)
420
421 assert "ok" == json_response(conn, 200)
422 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
423 assert Activity.get_by_ap_id(data["id"])
424 end
425
426 test "it accepts messages with cc as string instead of array", %{conn: conn, data: data} do
427 user = insert(:user)
428
429 data =
430 Map.put(data, "cc", user.ap_id)
431 |> Map.delete("to")
432
433 conn =
434 conn
435 |> assign(:valid_signature, true)
436 |> put_req_header("content-type", "application/activity+json")
437 |> post("/users/#{user.nickname}/inbox", data)
438
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
443 end
444
445 test "it accepts messages with bcc as string instead of array", %{conn: conn, data: data} do
446 user = insert(:user)
447
448 data =
449 Map.put(data, "bcc", user.ap_id)
450 |> Map.delete("to")
451 |> Map.delete("cc")
452
453 conn =
454 conn
455 |> assign(:valid_signature, true)
456 |> put_req_header("content-type", "application/activity+json")
457 |> post("/users/#{user.nickname}/inbox", data)
458
459 assert "ok" == json_response(conn, 200)
460 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
461 assert Activity.get_by_ap_id(data["id"])
462 end
463
464 test "it accepts announces with to as string instead of array", %{conn: conn} do
465 user = insert(:user)
466
467 data = %{
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],
474 "type" => "Announce"
475 }
476
477 conn =
478 conn
479 |> assign(:valid_signature, true)
480 |> put_req_header("content-type", "application/activity+json")
481 |> post("/users/#{user.nickname}/inbox", data)
482
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
487 end
488
489 test "it accepts messages from actors that are followed by the user", %{
490 conn: conn,
491 data: data
492 } do
493 recipient = insert(:user)
494 actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"})
495
496 {:ok, recipient} = User.follow(recipient, actor)
497
498 object =
499 data["object"]
500 |> Map.put("attributedTo", actor.ap_id)
501
502 data =
503 data
504 |> Map.put("actor", actor.ap_id)
505 |> Map.put("object", object)
506
507 conn =
508 conn
509 |> assign(:valid_signature, true)
510 |> put_req_header("content-type", "application/activity+json")
511 |> post("/users/#{recipient.nickname}/inbox", data)
512
513 assert "ok" == json_response(conn, 200)
514 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
515 assert Activity.get_by_ap_id(data["id"])
516 end
517
518 test "it rejects reads from other users", %{conn: conn} do
519 user = insert(:user)
520 otheruser = insert(:user)
521
522 conn =
523 conn
524 |> assign(:user, otheruser)
525 |> put_req_header("accept", "application/activity+json")
526 |> get("/users/#{user.nickname}/inbox")
527
528 assert json_response(conn, 403)
529 end
530
531 test "it doesn't crash without an authenticated user", %{conn: conn} do
532 user = insert(:user)
533
534 conn =
535 conn
536 |> put_req_header("accept", "application/activity+json")
537 |> get("/users/#{user.nickname}/inbox")
538
539 assert json_response(conn, 403)
540 end
541
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"]))
546
547 conn =
548 conn
549 |> assign(:user, user)
550 |> put_req_header("accept", "application/activity+json")
551 |> get("/users/#{user.nickname}/inbox?page=true")
552
553 assert response(conn, 200) =~ note_object.data["content"]
554 end
555
556 test "it clears `unreachable` federation status of the sender", %{conn: conn, data: data} do
557 user = insert(:user)
558 data = Map.put(data, "bcc", [user.ap_id])
559
560 sender_host = URI.parse(data["actor"]).host
561 Instances.set_consistently_unreachable(sender_host)
562 refute Instances.reachable?(sender_host)
563
564 conn =
565 conn
566 |> assign(:valid_signature, true)
567 |> put_req_header("content-type", "application/activity+json")
568 |> post("/users/#{user.nickname}/inbox", data)
569
570 assert "ok" == json_response(conn, 200)
571 assert Instances.reachable?(sender_host)
572 end
573
574 test "it removes all follower collections but actor's", %{conn: conn} do
575 [actor, recipient] = insert_pair(:user)
576
577 data =
578 File.read!("test/fixtures/activitypub-client-post-activity.json")
579 |> Poison.decode!()
580
581 object = Map.put(data["object"], "attributedTo", actor.ap_id)
582
583 data =
584 data
585 |> Map.put("id", Utils.generate_object_id())
586 |> Map.put("actor", actor.ap_id)
587 |> Map.put("object", object)
588 |> Map.put("cc", [
589 recipient.follower_address,
590 actor.follower_address
591 ])
592 |> Map.put("to", [
593 recipient.ap_id,
594 recipient.follower_address,
595 "https://www.w3.org/ns/activitystreams#Public"
596 ])
597
598 conn
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)
603
604 ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
605
606 activity = Activity.get_by_ap_id(data["id"])
607
608 assert activity.id
609 assert actor.follower_address in activity.recipients
610 assert actor.follower_address in activity.data["cc"]
611
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"]
615 end
616 end
617
618 describe "/users/:nickname/outbox" do
619 test "it will not bomb when there is no activity", %{conn: conn} do
620 user = insert(:user)
621
622 conn =
623 conn
624 |> put_req_header("accept", "application/activity+json")
625 |> get("/users/#{user.nickname}/outbox")
626
627 result = json_response(conn, 200)
628 assert user.ap_id <> "/outbox" == result["id"]
629 end
630
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"])
635
636 conn =
637 conn
638 |> put_req_header("accept", "application/activity+json")
639 |> get("/users/#{user.nickname}/outbox?page=true")
640
641 assert response(conn, 200) =~ note_object.data["content"]
642 end
643
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"])
647
648 conn =
649 conn
650 |> put_req_header("accept", "application/activity+json")
651 |> get("/users/#{user.nickname}/outbox?page=true")
652
653 assert response(conn, 200) =~ announce_activity.data["object"]
654 end
655
656 test "it rejects posts from other users", %{conn: conn} do
657 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
658 user = insert(:user)
659 otheruser = insert(:user)
660
661 conn =
662 conn
663 |> assign(:user, otheruser)
664 |> put_req_header("content-type", "application/activity+json")
665 |> post("/users/#{user.nickname}/outbox", data)
666
667 assert json_response(conn, 403)
668 end
669
670 test "it inserts an incoming create activity into the database", %{conn: conn} do
671 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
672 user = insert(:user)
673
674 conn =
675 conn
676 |> assign(:user, user)
677 |> put_req_header("content-type", "application/activity+json")
678 |> post("/users/#{user.nickname}/outbox", data)
679
680 result = json_response(conn, 201)
681
682 assert Activity.get_by_ap_id(result["id"])
683 end
684
685 test "it rejects an incoming activity with bogus type", %{conn: conn} do
686 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
687 user = insert(:user)
688
689 data =
690 data
691 |> Map.put("type", "BadType")
692
693 conn =
694 conn
695 |> assign(:user, user)
696 |> put_req_header("content-type", "application/activity+json")
697 |> post("/users/#{user.nickname}/outbox", data)
698
699 assert json_response(conn, 400)
700 end
701
702 test "it erects a tombstone when receiving a delete activity", %{conn: conn} do
703 note_activity = insert(:note_activity)
704 note_object = Object.normalize(note_activity)
705 user = User.get_cached_by_ap_id(note_activity.data["actor"])
706
707 data = %{
708 type: "Delete",
709 object: %{
710 id: note_object.data["id"]
711 }
712 }
713
714 conn =
715 conn
716 |> assign(:user, user)
717 |> put_req_header("content-type", "application/activity+json")
718 |> post("/users/#{user.nickname}/outbox", data)
719
720 result = json_response(conn, 201)
721 assert Activity.get_by_ap_id(result["id"])
722
723 assert object = Object.get_by_ap_id(note_object.data["id"])
724 assert object.data["type"] == "Tombstone"
725 end
726
727 test "it rejects delete activity of object from other actor", %{conn: conn} do
728 note_activity = insert(:note_activity)
729 note_object = Object.normalize(note_activity)
730 user = insert(:user)
731
732 data = %{
733 type: "Delete",
734 object: %{
735 id: note_object.data["id"]
736 }
737 }
738
739 conn =
740 conn
741 |> assign(:user, user)
742 |> put_req_header("content-type", "application/activity+json")
743 |> post("/users/#{user.nickname}/outbox", data)
744
745 assert json_response(conn, 400)
746 end
747
748 test "it increases like count when receiving a like action", %{conn: conn} do
749 note_activity = insert(:note_activity)
750 note_object = Object.normalize(note_activity)
751 user = User.get_cached_by_ap_id(note_activity.data["actor"])
752
753 data = %{
754 type: "Like",
755 object: %{
756 id: note_object.data["id"]
757 }
758 }
759
760 conn =
761 conn
762 |> assign(:user, user)
763 |> put_req_header("content-type", "application/activity+json")
764 |> post("/users/#{user.nickname}/outbox", data)
765
766 result = json_response(conn, 201)
767 assert Activity.get_by_ap_id(result["id"])
768
769 assert object = Object.get_by_ap_id(note_object.data["id"])
770 assert object.data["like_count"] == 1
771 end
772 end
773
774 describe "/relay/followers" do
775 test "it returns relay followers", %{conn: conn} do
776 relay_actor = Relay.get_actor()
777 user = insert(:user)
778 User.follow(user, relay_actor)
779
780 result =
781 conn
782 |> assign(:relay, true)
783 |> get("/relay/followers")
784 |> json_response(200)
785
786 assert result["first"]["orderedItems"] == [user.ap_id]
787 end
788 end
789
790 describe "/relay/following" do
791 test "it returns relay following", %{conn: conn} do
792 result =
793 conn
794 |> assign(:relay, true)
795 |> get("/relay/following")
796 |> json_response(200)
797
798 assert result["first"]["orderedItems"] == []
799 end
800 end
801
802 describe "/users/:nickname/followers" do
803 test "it returns the followers in a collection", %{conn: conn} do
804 user = insert(:user)
805 user_two = insert(:user)
806 User.follow(user, user_two)
807
808 result =
809 conn
810 |> get("/users/#{user_two.nickname}/followers")
811 |> json_response(200)
812
813 assert result["first"]["orderedItems"] == [user.ap_id]
814 end
815
816 test "it returns returns a uri if the user has 'hide_followers' set", %{conn: conn} do
817 user = insert(:user)
818 user_two = insert(:user, hide_followers: true)
819 User.follow(user, user_two)
820
821 result =
822 conn
823 |> get("/users/#{user_two.nickname}/followers")
824 |> json_response(200)
825
826 assert is_binary(result["first"])
827 end
828
829 test "it returns a 403 error on pages, if the user has 'hide_followers' set and the request is not authenticated",
830 %{conn: conn} do
831 user = insert(:user, hide_followers: true)
832
833 result =
834 conn
835 |> get("/users/#{user.nickname}/followers?page=1")
836
837 assert result.status == 403
838 assert result.resp_body == ""
839 end
840
841 test "it renders the page, if the user has 'hide_followers' set and the request is authenticated with the same user",
842 %{conn: conn} do
843 user = insert(:user, hide_followers: true)
844 other_user = insert(:user)
845 {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
846
847 result =
848 conn
849 |> assign(:user, user)
850 |> get("/users/#{user.nickname}/followers?page=1")
851 |> json_response(200)
852
853 assert result["totalItems"] == 1
854 assert result["orderedItems"] == [other_user.ap_id]
855 end
856
857 test "it works for more than 10 users", %{conn: conn} do
858 user = insert(:user)
859
860 Enum.each(1..15, fn _ ->
861 other_user = insert(:user)
862 User.follow(other_user, user)
863 end)
864
865 result =
866 conn
867 |> get("/users/#{user.nickname}/followers")
868 |> json_response(200)
869
870 assert length(result["first"]["orderedItems"]) == 10
871 assert result["first"]["totalItems"] == 15
872 assert result["totalItems"] == 15
873
874 result =
875 conn
876 |> get("/users/#{user.nickname}/followers?page=2")
877 |> json_response(200)
878
879 assert length(result["orderedItems"]) == 5
880 assert result["totalItems"] == 15
881 end
882 end
883
884 describe "/users/:nickname/following" do
885 test "it returns the following in a collection", %{conn: conn} do
886 user = insert(:user)
887 user_two = insert(:user)
888 User.follow(user, user_two)
889
890 result =
891 conn
892 |> get("/users/#{user.nickname}/following")
893 |> json_response(200)
894
895 assert result["first"]["orderedItems"] == [user_two.ap_id]
896 end
897
898 test "it returns a uri if the user has 'hide_follows' set", %{conn: conn} do
899 user = insert(:user, hide_follows: true)
900 user_two = insert(:user)
901 User.follow(user, user_two)
902
903 result =
904 conn
905 |> get("/users/#{user.nickname}/following")
906 |> json_response(200)
907
908 assert is_binary(result["first"])
909 end
910
911 test "it returns a 403 error on pages, if the user has 'hide_follows' set and the request is not authenticated",
912 %{conn: conn} do
913 user = insert(:user, hide_follows: true)
914
915 result =
916 conn
917 |> get("/users/#{user.nickname}/following?page=1")
918
919 assert result.status == 403
920 assert result.resp_body == ""
921 end
922
923 test "it renders the page, if the user has 'hide_follows' set and the request is authenticated with the same user",
924 %{conn: conn} do
925 user = insert(:user, hide_follows: true)
926 other_user = insert(:user)
927 {:ok, user, _other_user, _activity} = CommonAPI.follow(user, other_user)
928
929 result =
930 conn
931 |> assign(:user, user)
932 |> get("/users/#{user.nickname}/following?page=1")
933 |> json_response(200)
934
935 assert result["totalItems"] == 1
936 assert result["orderedItems"] == [other_user.ap_id]
937 end
938
939 test "it works for more than 10 users", %{conn: conn} do
940 user = insert(:user)
941
942 Enum.each(1..15, fn _ ->
943 user = User.get_cached_by_id(user.id)
944 other_user = insert(:user)
945 User.follow(user, other_user)
946 end)
947
948 result =
949 conn
950 |> get("/users/#{user.nickname}/following")
951 |> json_response(200)
952
953 assert length(result["first"]["orderedItems"]) == 10
954 assert result["first"]["totalItems"] == 15
955 assert result["totalItems"] == 15
956
957 result =
958 conn
959 |> get("/users/#{user.nickname}/following?page=2")
960 |> json_response(200)
961
962 assert length(result["orderedItems"]) == 5
963 assert result["totalItems"] == 15
964 end
965 end
966
967 describe "delivery tracking" do
968 test "it tracks a signed object fetch", %{conn: conn} do
969 user = insert(:user, local: false)
970 activity = insert(:note_activity)
971 object = Object.normalize(activity)
972
973 object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
974
975 conn
976 |> put_req_header("accept", "application/activity+json")
977 |> assign(:user, user)
978 |> get(object_path)
979 |> json_response(200)
980
981 assert Delivery.get(object.id, user.id)
982 end
983
984 test "it tracks a signed activity fetch", %{conn: conn} do
985 user = insert(:user, local: false)
986 activity = insert(:note_activity)
987 object = Object.normalize(activity)
988
989 activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
990
991 conn
992 |> put_req_header("accept", "application/activity+json")
993 |> assign(:user, user)
994 |> get(activity_path)
995 |> json_response(200)
996
997 assert Delivery.get(object.id, user.id)
998 end
999
1000 test "it tracks a signed object fetch when the json is cached", %{conn: conn} do
1001 user = insert(:user, local: false)
1002 other_user = insert(:user, local: false)
1003 activity = insert(:note_activity)
1004 object = Object.normalize(activity)
1005
1006 object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
1007
1008 conn
1009 |> put_req_header("accept", "application/activity+json")
1010 |> assign(:user, user)
1011 |> get(object_path)
1012 |> json_response(200)
1013
1014 build_conn()
1015 |> put_req_header("accept", "application/activity+json")
1016 |> assign(:user, other_user)
1017 |> get(object_path)
1018 |> json_response(200)
1019
1020 assert Delivery.get(object.id, user.id)
1021 assert Delivery.get(object.id, other_user.id)
1022 end
1023
1024 test "it tracks a signed activity fetch when the json is cached", %{conn: conn} do
1025 user = insert(:user, local: false)
1026 other_user = insert(:user, local: false)
1027 activity = insert(:note_activity)
1028 object = Object.normalize(activity)
1029
1030 activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
1031
1032 conn
1033 |> put_req_header("accept", "application/activity+json")
1034 |> assign(:user, user)
1035 |> get(activity_path)
1036 |> json_response(200)
1037
1038 build_conn()
1039 |> put_req_header("accept", "application/activity+json")
1040 |> assign(:user, other_user)
1041 |> get(activity_path)
1042 |> json_response(200)
1043
1044 assert Delivery.get(object.id, user.id)
1045 assert Delivery.get(object.id, other_user.id)
1046 end
1047 end
1048
1049 describe "Additionnal ActivityPub C2S endpoints" do
1050 test "/api/ap/whoami", %{conn: conn} do
1051 user = insert(:user)
1052
1053 conn =
1054 conn
1055 |> assign(:user, user)
1056 |> get("/api/ap/whoami")
1057
1058 user = User.get_cached_by_id(user.id)
1059
1060 assert UserView.render("user.json", %{user: user}) == json_response(conn, 200)
1061 end
1062
1063 clear_config([:media_proxy])
1064 clear_config([Pleroma.Upload])
1065
1066 test "uploadMedia", %{conn: conn} do
1067 user = insert(:user)
1068
1069 desc = "Description of the image"
1070
1071 image = %Plug.Upload{
1072 content_type: "image/jpg",
1073 path: Path.absname("test/fixtures/image.jpg"),
1074 filename: "an_image.jpg"
1075 }
1076
1077 conn =
1078 conn
1079 |> assign(:user, user)
1080 |> post("/api/ap/upload_media", %{"file" => image, "description" => desc})
1081
1082 assert object = json_response(conn, :created)
1083 assert object["name"] == desc
1084 assert object["type"] == "Document"
1085 assert object["actor"] == user.ap_id
1086 end
1087 end
1088 end