Strip status data from Flag (when federating or closing/resolving report)
[akkoma] / test / web / activity_pub / activity_pub_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.ActivityPubTest do
6 use Pleroma.DataCase
7 alias Pleroma.Activity
8 alias Pleroma.Builders.ActivityBuilder
9 alias Pleroma.Object
10 alias Pleroma.User
11 alias Pleroma.Web.ActivityPub.ActivityPub
12 alias Pleroma.Web.ActivityPub.Utils
13 alias Pleroma.Web.AdminAPI.AccountView
14 alias Pleroma.Web.CommonAPI
15
16 import Pleroma.Factory
17 import Tesla.Mock
18 import Mock
19
20 setup do
21 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
22 :ok
23 end
24
25 clear_config([:instance, :federating])
26
27 describe "streaming out participations" do
28 test "it streams them out" do
29 user = insert(:user)
30 {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
31
32 {:ok, conversation} = Pleroma.Conversation.create_or_bump_for(activity)
33
34 participations =
35 conversation.participations
36 |> Repo.preload(:user)
37
38 with_mock Pleroma.Web.Streamer,
39 stream: fn _, _ -> nil end do
40 ActivityPub.stream_out_participations(conversation.participations)
41
42 assert called(Pleroma.Web.Streamer.stream("participation", participations))
43 end
44 end
45 end
46
47 describe "fetching restricted by visibility" do
48 test "it restricts by the appropriate visibility" do
49 user = insert(:user)
50
51 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
52
53 {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
54
55 {:ok, unlisted_activity} =
56 CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
57
58 {:ok, private_activity} =
59 CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
60
61 activities =
62 ActivityPub.fetch_activities([], %{:visibility => "direct", "actor_id" => user.ap_id})
63
64 assert activities == [direct_activity]
65
66 activities =
67 ActivityPub.fetch_activities([], %{:visibility => "unlisted", "actor_id" => user.ap_id})
68
69 assert activities == [unlisted_activity]
70
71 activities =
72 ActivityPub.fetch_activities([], %{:visibility => "private", "actor_id" => user.ap_id})
73
74 assert activities == [private_activity]
75
76 activities =
77 ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id})
78
79 assert activities == [public_activity]
80
81 activities =
82 ActivityPub.fetch_activities([], %{
83 :visibility => ~w[private public],
84 "actor_id" => user.ap_id
85 })
86
87 assert activities == [public_activity, private_activity]
88 end
89 end
90
91 describe "fetching excluded by visibility" do
92 test "it excludes by the appropriate visibility" do
93 user = insert(:user)
94
95 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
96
97 {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
98
99 {:ok, unlisted_activity} =
100 CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
101
102 {:ok, private_activity} =
103 CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
104
105 activities =
106 ActivityPub.fetch_activities([], %{
107 "exclude_visibilities" => "direct",
108 "actor_id" => user.ap_id
109 })
110
111 assert public_activity in activities
112 assert unlisted_activity in activities
113 assert private_activity in activities
114 refute direct_activity in activities
115
116 activities =
117 ActivityPub.fetch_activities([], %{
118 "exclude_visibilities" => "unlisted",
119 "actor_id" => user.ap_id
120 })
121
122 assert public_activity in activities
123 refute unlisted_activity in activities
124 assert private_activity in activities
125 assert direct_activity in activities
126
127 activities =
128 ActivityPub.fetch_activities([], %{
129 "exclude_visibilities" => "private",
130 "actor_id" => user.ap_id
131 })
132
133 assert public_activity in activities
134 assert unlisted_activity in activities
135 refute private_activity in activities
136 assert direct_activity in activities
137
138 activities =
139 ActivityPub.fetch_activities([], %{
140 "exclude_visibilities" => "public",
141 "actor_id" => user.ap_id
142 })
143
144 refute public_activity in activities
145 assert unlisted_activity in activities
146 assert private_activity in activities
147 assert direct_activity in activities
148 end
149 end
150
151 describe "building a user from his ap id" do
152 test "it returns a user" do
153 user_id = "http://mastodon.example.org/users/admin"
154 {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
155 assert user.ap_id == user_id
156 assert user.nickname == "admin@mastodon.example.org"
157 assert user.info.source_data
158 assert user.info.ap_enabled
159 assert user.follower_address == "http://mastodon.example.org/users/admin/followers"
160 end
161
162 test "it fetches the appropriate tag-restricted posts" do
163 user = insert(:user)
164
165 {:ok, status_one} = CommonAPI.post(user, %{"status" => ". #test"})
166 {:ok, status_two} = CommonAPI.post(user, %{"status" => ". #essais"})
167 {:ok, status_three} = CommonAPI.post(user, %{"status" => ". #test #reject"})
168
169 fetch_one = ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => "test"})
170
171 fetch_two =
172 ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => ["test", "essais"]})
173
174 fetch_three =
175 ActivityPub.fetch_activities([], %{
176 "type" => "Create",
177 "tag" => ["test", "essais"],
178 "tag_reject" => ["reject"]
179 })
180
181 fetch_four =
182 ActivityPub.fetch_activities([], %{
183 "type" => "Create",
184 "tag" => ["test"],
185 "tag_all" => ["test", "reject"]
186 })
187
188 assert fetch_one == [status_one, status_three]
189 assert fetch_two == [status_one, status_two, status_three]
190 assert fetch_three == [status_one, status_two]
191 assert fetch_four == [status_three]
192 end
193 end
194
195 describe "insertion" do
196 test "drops activities beyond a certain limit" do
197 limit = Pleroma.Config.get([:instance, :remote_limit])
198
199 random_text =
200 :crypto.strong_rand_bytes(limit + 1)
201 |> Base.encode64()
202 |> binary_part(0, limit + 1)
203
204 data = %{
205 "ok" => true,
206 "object" => %{
207 "content" => random_text
208 }
209 }
210
211 assert {:error, {:remote_limit_error, _}} = ActivityPub.insert(data)
212 end
213
214 test "doesn't drop activities with content being null" do
215 user = insert(:user)
216
217 data = %{
218 "actor" => user.ap_id,
219 "to" => [],
220 "object" => %{
221 "actor" => user.ap_id,
222 "to" => [],
223 "type" => "Note",
224 "content" => nil
225 }
226 }
227
228 assert {:ok, _} = ActivityPub.insert(data)
229 end
230
231 test "returns the activity if one with the same id is already in" do
232 activity = insert(:note_activity)
233 {:ok, new_activity} = ActivityPub.insert(activity.data)
234
235 assert activity.id == new_activity.id
236 end
237
238 test "inserts a given map into the activity database, giving it an id if it has none." do
239 user = insert(:user)
240
241 data = %{
242 "actor" => user.ap_id,
243 "to" => [],
244 "object" => %{
245 "actor" => user.ap_id,
246 "to" => [],
247 "type" => "Note",
248 "content" => "hey"
249 }
250 }
251
252 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
253 assert activity.data["ok"] == data["ok"]
254 assert is_binary(activity.data["id"])
255
256 given_id = "bla"
257
258 data = %{
259 "id" => given_id,
260 "actor" => user.ap_id,
261 "to" => [],
262 "context" => "blabla",
263 "object" => %{
264 "actor" => user.ap_id,
265 "to" => [],
266 "type" => "Note",
267 "content" => "hey"
268 }
269 }
270
271 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
272 assert activity.data["ok"] == data["ok"]
273 assert activity.data["id"] == given_id
274 assert activity.data["context"] == "blabla"
275 assert activity.data["context_id"]
276 end
277
278 test "adds a context when none is there" do
279 user = insert(:user)
280
281 data = %{
282 "actor" => user.ap_id,
283 "to" => [],
284 "object" => %{
285 "actor" => user.ap_id,
286 "to" => [],
287 "type" => "Note",
288 "content" => "hey"
289 }
290 }
291
292 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
293 object = Pleroma.Object.normalize(activity)
294
295 assert is_binary(activity.data["context"])
296 assert is_binary(object.data["context"])
297 assert activity.data["context_id"]
298 assert object.data["context_id"]
299 end
300
301 test "adds an id to a given object if it lacks one and is a note and inserts it to the object database" do
302 user = insert(:user)
303
304 data = %{
305 "actor" => user.ap_id,
306 "to" => [],
307 "object" => %{
308 "actor" => user.ap_id,
309 "to" => [],
310 "type" => "Note",
311 "content" => "hey"
312 }
313 }
314
315 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
316 assert object = Object.normalize(activity)
317 assert is_binary(object.data["id"])
318 end
319 end
320
321 describe "listen activities" do
322 test "does not increase user note count" do
323 user = insert(:user)
324
325 {:ok, activity} =
326 ActivityPub.listen(%{
327 to: ["https://www.w3.org/ns/activitystreams#Public"],
328 actor: user,
329 context: "",
330 object: %{
331 "actor" => user.ap_id,
332 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
333 "artist" => "lain",
334 "title" => "lain radio episode 1",
335 "length" => 180_000,
336 "type" => "Audio"
337 }
338 })
339
340 assert activity.actor == user.ap_id
341
342 user = User.get_cached_by_id(user.id)
343 assert user.info.note_count == 0
344 end
345
346 test "can be fetched into a timeline" do
347 _listen_activity_1 = insert(:listen)
348 _listen_activity_2 = insert(:listen)
349 _listen_activity_3 = insert(:listen)
350
351 timeline = ActivityPub.fetch_activities([], %{"type" => ["Listen"]})
352
353 assert length(timeline) == 3
354 end
355 end
356
357 describe "create activities" do
358 test "removes doubled 'to' recipients" do
359 user = insert(:user)
360
361 {:ok, activity} =
362 ActivityPub.create(%{
363 to: ["user1", "user1", "user2"],
364 actor: user,
365 context: "",
366 object: %{
367 "to" => ["user1", "user1", "user2"],
368 "type" => "Note",
369 "content" => "testing"
370 }
371 })
372
373 assert activity.data["to"] == ["user1", "user2"]
374 assert activity.actor == user.ap_id
375 assert activity.recipients == ["user1", "user2", user.ap_id]
376 end
377
378 test "increases user note count only for public activities" do
379 user = insert(:user)
380
381 {:ok, _} =
382 CommonAPI.post(User.get_cached_by_id(user.id), %{
383 "status" => "1",
384 "visibility" => "public"
385 })
386
387 {:ok, _} =
388 CommonAPI.post(User.get_cached_by_id(user.id), %{
389 "status" => "2",
390 "visibility" => "unlisted"
391 })
392
393 {:ok, _} =
394 CommonAPI.post(User.get_cached_by_id(user.id), %{
395 "status" => "2",
396 "visibility" => "private"
397 })
398
399 {:ok, _} =
400 CommonAPI.post(User.get_cached_by_id(user.id), %{
401 "status" => "3",
402 "visibility" => "direct"
403 })
404
405 user = User.get_cached_by_id(user.id)
406 assert user.info.note_count == 2
407 end
408
409 test "increases replies count" do
410 user = insert(:user)
411 user2 = insert(:user)
412
413 {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
414 ap_id = activity.data["id"]
415 reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
416
417 # public
418 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
419 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
420 assert object.data["repliesCount"] == 1
421
422 # unlisted
423 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
424 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
425 assert object.data["repliesCount"] == 2
426
427 # private
428 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
429 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
430 assert object.data["repliesCount"] == 2
431
432 # direct
433 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
434 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
435 assert object.data["repliesCount"] == 2
436 end
437 end
438
439 describe "fetch activities for recipients" do
440 test "retrieve the activities for certain recipients" do
441 {:ok, activity_one} = ActivityBuilder.insert(%{"to" => ["someone"]})
442 {:ok, activity_two} = ActivityBuilder.insert(%{"to" => ["someone_else"]})
443 {:ok, _activity_three} = ActivityBuilder.insert(%{"to" => ["noone"]})
444
445 activities = ActivityPub.fetch_activities(["someone", "someone_else"])
446 assert length(activities) == 2
447 assert activities == [activity_one, activity_two]
448 end
449 end
450
451 describe "fetch activities in context" do
452 test "retrieves activities that have a given context" do
453 {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
454 {:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
455 {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
456 {:ok, _activity_four} = ActivityBuilder.insert(%{"type" => "Announce", "context" => "2hu"})
457 activity_five = insert(:note_activity)
458 user = insert(:user)
459
460 {:ok, user} = User.block(user, %{ap_id: activity_five.data["actor"]})
461
462 activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user})
463 assert activities == [activity_two, activity]
464 end
465 end
466
467 test "doesn't return blocked activities" do
468 activity_one = insert(:note_activity)
469 activity_two = insert(:note_activity)
470 activity_three = insert(:note_activity)
471 user = insert(:user)
472 booster = insert(:user)
473 {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]})
474
475 activities =
476 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
477
478 assert Enum.member?(activities, activity_two)
479 assert Enum.member?(activities, activity_three)
480 refute Enum.member?(activities, activity_one)
481
482 {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
483
484 activities =
485 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
486
487 assert Enum.member?(activities, activity_two)
488 assert Enum.member?(activities, activity_three)
489 assert Enum.member?(activities, activity_one)
490
491 {:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
492 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
493 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
494 activity_three = Activity.get_by_id(activity_three.id)
495
496 activities =
497 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
498
499 assert Enum.member?(activities, activity_two)
500 refute Enum.member?(activities, activity_three)
501 refute Enum.member?(activities, boost_activity)
502 assert Enum.member?(activities, activity_one)
503
504 activities =
505 ActivityPub.fetch_activities([], %{"blocking_user" => nil, "skip_preload" => true})
506
507 assert Enum.member?(activities, activity_two)
508 assert Enum.member?(activities, activity_three)
509 assert Enum.member?(activities, boost_activity)
510 assert Enum.member?(activities, activity_one)
511 end
512
513 test "doesn't return transitive interactions concerning blocked users" do
514 blocker = insert(:user)
515 blockee = insert(:user)
516 friend = insert(:user)
517
518 {:ok, blocker} = User.block(blocker, blockee)
519
520 {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"})
521
522 {:ok, activity_two} = CommonAPI.post(friend, %{"status" => "hey! @#{blockee.nickname}"})
523
524 {:ok, activity_three} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"})
525
526 {:ok, activity_four} = CommonAPI.post(blockee, %{"status" => "hey! @#{blocker.nickname}"})
527
528 activities = ActivityPub.fetch_activities([], %{"blocking_user" => blocker})
529
530 assert Enum.member?(activities, activity_one)
531 refute Enum.member?(activities, activity_two)
532 refute Enum.member?(activities, activity_three)
533 refute Enum.member?(activities, activity_four)
534 end
535
536 test "doesn't return announce activities concerning blocked users" do
537 blocker = insert(:user)
538 blockee = insert(:user)
539 friend = insert(:user)
540
541 {:ok, blocker} = User.block(blocker, blockee)
542
543 {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"})
544
545 {:ok, activity_two} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"})
546
547 {:ok, activity_three, _} = CommonAPI.repeat(activity_two.id, friend)
548
549 activities =
550 ActivityPub.fetch_activities([], %{"blocking_user" => blocker})
551 |> Enum.map(fn act -> act.id end)
552
553 assert Enum.member?(activities, activity_one.id)
554 refute Enum.member?(activities, activity_two.id)
555 refute Enum.member?(activities, activity_three.id)
556 end
557
558 test "doesn't return activities from blocked domains" do
559 domain = "dogwhistle.zone"
560 domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
561 note = insert(:note, %{data: %{"actor" => domain_user.ap_id}})
562 activity = insert(:note_activity, %{note: note})
563 user = insert(:user)
564 {:ok, user} = User.block_domain(user, domain)
565
566 activities =
567 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
568
569 refute activity in activities
570
571 followed_user = insert(:user)
572 ActivityPub.follow(user, followed_user)
573 {:ok, repeat_activity, _} = CommonAPI.repeat(activity.id, followed_user)
574
575 activities =
576 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
577
578 refute repeat_activity in activities
579 end
580
581 test "doesn't return muted activities" do
582 activity_one = insert(:note_activity)
583 activity_two = insert(:note_activity)
584 activity_three = insert(:note_activity)
585 user = insert(:user)
586 booster = insert(:user)
587 {:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]})
588
589 activities =
590 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
591
592 assert Enum.member?(activities, activity_two)
593 assert Enum.member?(activities, activity_three)
594 refute Enum.member?(activities, activity_one)
595
596 # Calling with 'with_muted' will deliver muted activities, too.
597 activities =
598 ActivityPub.fetch_activities([], %{
599 "muting_user" => user,
600 "with_muted" => true,
601 "skip_preload" => true
602 })
603
604 assert Enum.member?(activities, activity_two)
605 assert Enum.member?(activities, activity_three)
606 assert Enum.member?(activities, activity_one)
607
608 {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]})
609
610 activities =
611 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
612
613 assert Enum.member?(activities, activity_two)
614 assert Enum.member?(activities, activity_three)
615 assert Enum.member?(activities, activity_one)
616
617 {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
618 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
619 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
620 activity_three = Activity.get_by_id(activity_three.id)
621
622 activities =
623 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
624
625 assert Enum.member?(activities, activity_two)
626 refute Enum.member?(activities, activity_three)
627 refute Enum.member?(activities, boost_activity)
628 assert Enum.member?(activities, activity_one)
629
630 activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true})
631
632 assert Enum.member?(activities, activity_two)
633 assert Enum.member?(activities, activity_three)
634 assert Enum.member?(activities, boost_activity)
635 assert Enum.member?(activities, activity_one)
636 end
637
638 test "doesn't return thread muted activities" do
639 user = insert(:user)
640 _activity_one = insert(:note_activity)
641 note_two = insert(:note, data: %{"context" => "suya.."})
642 activity_two = insert(:note_activity, note: note_two)
643
644 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
645
646 assert [_activity_one] = ActivityPub.fetch_activities([], %{"muting_user" => user})
647 end
648
649 test "returns thread muted activities when with_muted is set" do
650 user = insert(:user)
651 _activity_one = insert(:note_activity)
652 note_two = insert(:note, data: %{"context" => "suya.."})
653 activity_two = insert(:note_activity, note: note_two)
654
655 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
656
657 assert [_activity_two, _activity_one] =
658 ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true})
659 end
660
661 test "does include announces on request" do
662 activity_three = insert(:note_activity)
663 user = insert(:user)
664 booster = insert(:user)
665
666 {:ok, user} = User.follow(user, booster)
667
668 {:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster)
669
670 [announce_activity] = ActivityPub.fetch_activities([user.ap_id | user.following])
671
672 assert announce_activity.id == announce.id
673 end
674
675 test "excludes reblogs on request" do
676 user = insert(:user)
677 {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
678 {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user})
679
680 [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"})
681
682 assert activity == expected_activity
683 end
684
685 describe "public fetch activities" do
686 test "doesn't retrieve unlisted activities" do
687 user = insert(:user)
688
689 {:ok, _unlisted_activity} =
690 CommonAPI.post(user, %{"status" => "yeah", "visibility" => "unlisted"})
691
692 {:ok, listed_activity} = CommonAPI.post(user, %{"status" => "yeah"})
693
694 [activity] = ActivityPub.fetch_public_activities()
695
696 assert activity == listed_activity
697 end
698
699 test "retrieves public activities" do
700 _activities = ActivityPub.fetch_public_activities()
701
702 %{public: public} = ActivityBuilder.public_and_non_public()
703
704 activities = ActivityPub.fetch_public_activities()
705 assert length(activities) == 1
706 assert Enum.at(activities, 0) == public
707 end
708
709 test "retrieves a maximum of 20 activities" do
710 activities = ActivityBuilder.insert_list(30)
711 last_expected = List.last(activities)
712
713 activities = ActivityPub.fetch_public_activities()
714 last = List.last(activities)
715
716 assert length(activities) == 20
717 assert last == last_expected
718 end
719
720 test "retrieves ids starting from a since_id" do
721 activities = ActivityBuilder.insert_list(30)
722 later_activities = ActivityBuilder.insert_list(10)
723 since_id = List.last(activities).id
724 last_expected = List.last(later_activities)
725
726 activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id})
727 last = List.last(activities)
728
729 assert length(activities) == 10
730 assert last == last_expected
731 end
732
733 test "retrieves ids up to max_id" do
734 _first_activities = ActivityBuilder.insert_list(10)
735 activities = ActivityBuilder.insert_list(20)
736 later_activities = ActivityBuilder.insert_list(10)
737 max_id = List.first(later_activities).id
738 last_expected = List.last(activities)
739
740 activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id})
741 last = List.last(activities)
742
743 assert length(activities) == 20
744 assert last == last_expected
745 end
746
747 test "paginates via offset/limit" do
748 _first_activities = ActivityBuilder.insert_list(10)
749 activities = ActivityBuilder.insert_list(10)
750 _later_activities = ActivityBuilder.insert_list(10)
751 first_expected = List.first(activities)
752
753 activities =
754 ActivityPub.fetch_public_activities(%{"page" => "2", "page_size" => "20"}, :offset)
755
756 first = List.first(activities)
757
758 assert length(activities) == 20
759 assert first == first_expected
760 end
761
762 test "doesn't return reblogs for users for whom reblogs have been muted" do
763 activity = insert(:note_activity)
764 user = insert(:user)
765 booster = insert(:user)
766 {:ok, user} = CommonAPI.hide_reblogs(user, booster)
767
768 {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
769
770 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
771
772 refute Enum.any?(activities, fn %{id: id} -> id == activity.id end)
773 end
774
775 test "returns reblogs for users for whom reblogs have not been muted" do
776 activity = insert(:note_activity)
777 user = insert(:user)
778 booster = insert(:user)
779 {:ok, user} = CommonAPI.hide_reblogs(user, booster)
780 {:ok, user} = CommonAPI.show_reblogs(user, booster)
781
782 {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
783
784 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
785
786 assert Enum.any?(activities, fn %{id: id} -> id == activity.id end)
787 end
788 end
789
790 describe "like an object" do
791 test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do
792 Pleroma.Config.put([:instance, :federating], true)
793 note_activity = insert(:note_activity)
794 assert object_activity = Object.normalize(note_activity)
795
796 user = insert(:user)
797
798 {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
799 assert called(Pleroma.Web.Federator.publish(like_activity))
800 end
801
802 test "returns exist activity if object already liked" do
803 note_activity = insert(:note_activity)
804 assert object_activity = Object.normalize(note_activity)
805
806 user = insert(:user)
807
808 {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
809
810 {:ok, like_activity_exist, _object} = ActivityPub.like(user, object_activity)
811 assert like_activity == like_activity_exist
812 end
813
814 test "adds a like activity to the db" do
815 note_activity = insert(:note_activity)
816 assert object = Object.normalize(note_activity)
817
818 user = insert(:user)
819 user_two = insert(:user)
820
821 {:ok, like_activity, object} = ActivityPub.like(user, object)
822
823 assert like_activity.data["actor"] == user.ap_id
824 assert like_activity.data["type"] == "Like"
825 assert like_activity.data["object"] == object.data["id"]
826 assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
827 assert like_activity.data["context"] == object.data["context"]
828 assert object.data["like_count"] == 1
829 assert object.data["likes"] == [user.ap_id]
830
831 # Just return the original activity if the user already liked it.
832 {:ok, same_like_activity, object} = ActivityPub.like(user, object)
833
834 assert like_activity == same_like_activity
835 assert object.data["likes"] == [user.ap_id]
836 assert object.data["like_count"] == 1
837
838 {:ok, _like_activity, object} = ActivityPub.like(user_two, object)
839 assert object.data["like_count"] == 2
840 end
841 end
842
843 describe "unliking" do
844 test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do
845 Pleroma.Config.put([:instance, :federating], true)
846
847 note_activity = insert(:note_activity)
848 object = Object.normalize(note_activity)
849 user = insert(:user)
850
851 {:ok, object} = ActivityPub.unlike(user, object)
852 refute called(Pleroma.Web.Federator.publish())
853
854 {:ok, _like_activity, object} = ActivityPub.like(user, object)
855 assert object.data["like_count"] == 1
856
857 {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
858 assert object.data["like_count"] == 0
859
860 assert called(Pleroma.Web.Federator.publish(unlike_activity))
861 end
862
863 test "unliking a previously liked object" do
864 note_activity = insert(:note_activity)
865 object = Object.normalize(note_activity)
866 user = insert(:user)
867
868 # Unliking something that hasn't been liked does nothing
869 {:ok, object} = ActivityPub.unlike(user, object)
870 assert object.data["like_count"] == 0
871
872 {:ok, like_activity, object} = ActivityPub.like(user, object)
873 assert object.data["like_count"] == 1
874
875 {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
876 assert object.data["like_count"] == 0
877
878 assert Activity.get_by_id(like_activity.id) == nil
879 assert note_activity.actor in unlike_activity.recipients
880 end
881 end
882
883 describe "announcing an object" do
884 test "adds an announce activity to the db" do
885 note_activity = insert(:note_activity)
886 object = Object.normalize(note_activity)
887 user = insert(:user)
888
889 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
890 assert object.data["announcement_count"] == 1
891 assert object.data["announcements"] == [user.ap_id]
892
893 assert announce_activity.data["to"] == [
894 User.ap_followers(user),
895 note_activity.data["actor"]
896 ]
897
898 assert announce_activity.data["object"] == object.data["id"]
899 assert announce_activity.data["actor"] == user.ap_id
900 assert announce_activity.data["context"] == object.data["context"]
901 end
902 end
903
904 describe "announcing a private object" do
905 test "adds an announce activity to the db if the audience is not widened" do
906 user = insert(:user)
907 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
908 object = Object.normalize(note_activity)
909
910 {:ok, announce_activity, object} = ActivityPub.announce(user, object, nil, true, false)
911
912 assert announce_activity.data["to"] == [User.ap_followers(user)]
913
914 assert announce_activity.data["object"] == object.data["id"]
915 assert announce_activity.data["actor"] == user.ap_id
916 assert announce_activity.data["context"] == object.data["context"]
917 end
918
919 test "does not add an announce activity to the db if the audience is widened" do
920 user = insert(:user)
921 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
922 object = Object.normalize(note_activity)
923
924 assert {:error, _} = ActivityPub.announce(user, object, nil, true, true)
925 end
926
927 test "does not add an announce activity to the db if the announcer is not the author" do
928 user = insert(:user)
929 announcer = insert(:user)
930 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
931 object = Object.normalize(note_activity)
932
933 assert {:error, _} = ActivityPub.announce(announcer, object, nil, true, false)
934 end
935 end
936
937 describe "unannouncing an object" do
938 test "unannouncing a previously announced object" do
939 note_activity = insert(:note_activity)
940 object = Object.normalize(note_activity)
941 user = insert(:user)
942
943 # Unannouncing an object that is not announced does nothing
944 # {:ok, object} = ActivityPub.unannounce(user, object)
945 # assert object.data["announcement_count"] == 0
946
947 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
948 assert object.data["announcement_count"] == 1
949
950 {:ok, unannounce_activity, object} = ActivityPub.unannounce(user, object)
951 assert object.data["announcement_count"] == 0
952
953 assert unannounce_activity.data["to"] == [
954 User.ap_followers(user),
955 object.data["actor"]
956 ]
957
958 assert unannounce_activity.data["type"] == "Undo"
959 assert unannounce_activity.data["object"] == announce_activity.data
960 assert unannounce_activity.data["actor"] == user.ap_id
961 assert unannounce_activity.data["context"] == announce_activity.data["context"]
962
963 assert Activity.get_by_id(announce_activity.id) == nil
964 end
965 end
966
967 describe "uploading files" do
968 test "copies the file to the configured folder" do
969 file = %Plug.Upload{
970 content_type: "image/jpg",
971 path: Path.absname("test/fixtures/image.jpg"),
972 filename: "an_image.jpg"
973 }
974
975 {:ok, %Object{} = object} = ActivityPub.upload(file)
976 assert object.data["name"] == "an_image.jpg"
977 end
978
979 test "works with base64 encoded images" do
980 file = %{
981 "img" => data_uri()
982 }
983
984 {:ok, %Object{}} = ActivityPub.upload(file)
985 end
986 end
987
988 describe "fetch the latest Follow" do
989 test "fetches the latest Follow activity" do
990 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
991 follower = Repo.get_by(User, ap_id: activity.data["actor"])
992 followed = Repo.get_by(User, ap_id: activity.data["object"])
993
994 assert activity == Utils.fetch_latest_follow(follower, followed)
995 end
996 end
997
998 describe "following / unfollowing" do
999 test "creates a follow activity" do
1000 follower = insert(:user)
1001 followed = insert(:user)
1002
1003 {:ok, activity} = ActivityPub.follow(follower, followed)
1004 assert activity.data["type"] == "Follow"
1005 assert activity.data["actor"] == follower.ap_id
1006 assert activity.data["object"] == followed.ap_id
1007 end
1008
1009 test "creates an undo activity for the last follow" do
1010 follower = insert(:user)
1011 followed = insert(:user)
1012
1013 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
1014 {:ok, activity} = ActivityPub.unfollow(follower, followed)
1015
1016 assert activity.data["type"] == "Undo"
1017 assert activity.data["actor"] == follower.ap_id
1018
1019 embedded_object = activity.data["object"]
1020 assert is_map(embedded_object)
1021 assert embedded_object["type"] == "Follow"
1022 assert embedded_object["object"] == followed.ap_id
1023 assert embedded_object["id"] == follow_activity.data["id"]
1024 end
1025 end
1026
1027 describe "blocking / unblocking" do
1028 test "creates a block activity" do
1029 blocker = insert(:user)
1030 blocked = insert(:user)
1031
1032 {:ok, activity} = ActivityPub.block(blocker, blocked)
1033
1034 assert activity.data["type"] == "Block"
1035 assert activity.data["actor"] == blocker.ap_id
1036 assert activity.data["object"] == blocked.ap_id
1037 end
1038
1039 test "creates an undo activity for the last block" do
1040 blocker = insert(:user)
1041 blocked = insert(:user)
1042
1043 {:ok, block_activity} = ActivityPub.block(blocker, blocked)
1044 {:ok, activity} = ActivityPub.unblock(blocker, blocked)
1045
1046 assert activity.data["type"] == "Undo"
1047 assert activity.data["actor"] == blocker.ap_id
1048
1049 embedded_object = activity.data["object"]
1050 assert is_map(embedded_object)
1051 assert embedded_object["type"] == "Block"
1052 assert embedded_object["object"] == blocked.ap_id
1053 assert embedded_object["id"] == block_activity.data["id"]
1054 end
1055 end
1056
1057 describe "deletion" do
1058 test "it creates a delete activity and deletes the original object" do
1059 note = insert(:note_activity)
1060 object = Object.normalize(note)
1061 {:ok, delete} = ActivityPub.delete(object)
1062
1063 assert delete.data["type"] == "Delete"
1064 assert delete.data["actor"] == note.data["actor"]
1065 assert delete.data["object"] == object.data["id"]
1066
1067 assert Activity.get_by_id(delete.id) != nil
1068
1069 assert Repo.get(Object, object.id).data["type"] == "Tombstone"
1070 end
1071
1072 test "decrements user note count only for public activities" do
1073 user = insert(:user, info: %{note_count: 10})
1074
1075 {:ok, a1} =
1076 CommonAPI.post(User.get_cached_by_id(user.id), %{
1077 "status" => "yeah",
1078 "visibility" => "public"
1079 })
1080
1081 {:ok, a2} =
1082 CommonAPI.post(User.get_cached_by_id(user.id), %{
1083 "status" => "yeah",
1084 "visibility" => "unlisted"
1085 })
1086
1087 {:ok, a3} =
1088 CommonAPI.post(User.get_cached_by_id(user.id), %{
1089 "status" => "yeah",
1090 "visibility" => "private"
1091 })
1092
1093 {:ok, a4} =
1094 CommonAPI.post(User.get_cached_by_id(user.id), %{
1095 "status" => "yeah",
1096 "visibility" => "direct"
1097 })
1098
1099 {:ok, _} = Object.normalize(a1) |> ActivityPub.delete()
1100 {:ok, _} = Object.normalize(a2) |> ActivityPub.delete()
1101 {:ok, _} = Object.normalize(a3) |> ActivityPub.delete()
1102 {:ok, _} = Object.normalize(a4) |> ActivityPub.delete()
1103
1104 user = User.get_cached_by_id(user.id)
1105 assert user.info.note_count == 10
1106 end
1107
1108 test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
1109 user = insert(:user)
1110 note = insert(:note_activity)
1111 object = Object.normalize(note)
1112
1113 {:ok, object} =
1114 object
1115 |> Object.change(%{
1116 data: %{
1117 "actor" => object.data["actor"],
1118 "id" => object.data["id"],
1119 "to" => [user.ap_id],
1120 "type" => "Note"
1121 }
1122 })
1123 |> Object.update_and_set_cache()
1124
1125 {:ok, delete} = ActivityPub.delete(object)
1126
1127 assert user.ap_id in delete.data["to"]
1128 end
1129
1130 test "decreases reply count" do
1131 user = insert(:user)
1132 user2 = insert(:user)
1133
1134 {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
1135 reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
1136 ap_id = activity.data["id"]
1137
1138 {:ok, public_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
1139 {:ok, unlisted_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
1140 {:ok, private_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
1141 {:ok, direct_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
1142
1143 _ = CommonAPI.delete(direct_reply.id, user2)
1144 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1145 assert object.data["repliesCount"] == 2
1146
1147 _ = CommonAPI.delete(private_reply.id, user2)
1148 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1149 assert object.data["repliesCount"] == 2
1150
1151 _ = CommonAPI.delete(public_reply.id, user2)
1152 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1153 assert object.data["repliesCount"] == 1
1154
1155 _ = CommonAPI.delete(unlisted_reply.id, user2)
1156 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1157 assert object.data["repliesCount"] == 0
1158 end
1159 end
1160
1161 describe "timeline post-processing" do
1162 test "it filters broken threads" do
1163 user1 = insert(:user)
1164 user2 = insert(:user)
1165 user3 = insert(:user)
1166
1167 {:ok, user1} = User.follow(user1, user3)
1168 assert User.following?(user1, user3)
1169
1170 {:ok, user2} = User.follow(user2, user3)
1171 assert User.following?(user2, user3)
1172
1173 {:ok, user3} = User.follow(user3, user2)
1174 assert User.following?(user3, user2)
1175
1176 {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
1177
1178 {:ok, private_activity_1} =
1179 CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
1180
1181 {:ok, private_activity_2} =
1182 CommonAPI.post(user2, %{
1183 "status" => "hi 3",
1184 "visibility" => "private",
1185 "in_reply_to_status_id" => private_activity_1.id
1186 })
1187
1188 {:ok, private_activity_3} =
1189 CommonAPI.post(user3, %{
1190 "status" => "hi 4",
1191 "visibility" => "private",
1192 "in_reply_to_status_id" => private_activity_2.id
1193 })
1194
1195 activities =
1196 ActivityPub.fetch_activities([user1.ap_id | user1.following])
1197 |> Enum.map(fn a -> a.id end)
1198
1199 private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"])
1200
1201 assert [public_activity.id, private_activity_1.id, private_activity_3.id] == activities
1202
1203 assert length(activities) == 3
1204
1205 activities =
1206 ActivityPub.fetch_activities([user1.ap_id | user1.following], %{"user" => user1})
1207 |> Enum.map(fn a -> a.id end)
1208
1209 assert [public_activity.id, private_activity_1.id] == activities
1210 assert length(activities) == 2
1211 end
1212 end
1213
1214 describe "update" do
1215 test "it creates an update activity with the new user data" do
1216 user = insert(:user)
1217 {:ok, user} = User.ensure_keys_present(user)
1218 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
1219
1220 {:ok, update} =
1221 ActivityPub.update(%{
1222 actor: user_data["id"],
1223 to: [user.follower_address],
1224 cc: [],
1225 object: user_data
1226 })
1227
1228 assert update.data["actor"] == user.ap_id
1229 assert update.data["to"] == [user.follower_address]
1230 assert embedded_object = update.data["object"]
1231 assert embedded_object["id"] == user_data["id"]
1232 assert embedded_object["type"] == user_data["type"]
1233 end
1234 end
1235
1236 test "returned pinned statuses" do
1237 Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
1238 user = insert(:user)
1239
1240 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
1241 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
1242 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
1243
1244 CommonAPI.pin(activity_one.id, user)
1245 user = refresh_record(user)
1246
1247 CommonAPI.pin(activity_two.id, user)
1248 user = refresh_record(user)
1249
1250 CommonAPI.pin(activity_three.id, user)
1251 user = refresh_record(user)
1252
1253 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
1254
1255 assert 3 = length(activities)
1256 end
1257
1258 describe "flag/1" do
1259 setup do
1260 reporter = insert(:user)
1261 target_account = insert(:user)
1262 content = "foobar"
1263 {:ok, activity} = CommonAPI.post(target_account, %{"status" => content})
1264 context = Utils.generate_context_id()
1265
1266 reporter_ap_id = reporter.ap_id
1267 target_ap_id = target_account.ap_id
1268 activity_ap_id = activity.data["id"]
1269
1270 activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id)
1271
1272 {:ok,
1273 %{
1274 reporter: reporter,
1275 context: context,
1276 target_account: target_account,
1277 reported_activity: activity,
1278 content: content,
1279 activity_ap_id: activity_ap_id,
1280 activity_with_object: activity_with_object,
1281 reporter_ap_id: reporter_ap_id,
1282 target_ap_id: target_ap_id
1283 }}
1284 end
1285
1286 test "it can create a Flag activity",
1287 %{
1288 reporter: reporter,
1289 context: context,
1290 target_account: target_account,
1291 reported_activity: reported_activity,
1292 content: content,
1293 activity_ap_id: activity_ap_id,
1294 activity_with_object: activity_with_object,
1295 reporter_ap_id: reporter_ap_id,
1296 target_ap_id: target_ap_id
1297 } do
1298 assert {:ok, activity} =
1299 ActivityPub.flag(%{
1300 actor: reporter,
1301 context: context,
1302 account: target_account,
1303 statuses: [reported_activity],
1304 content: content
1305 })
1306
1307 note_obj = %{
1308 "type" => "Note",
1309 "id" => activity_ap_id,
1310 "content" => content,
1311 "published" => activity_with_object.object.data["published"],
1312 "actor" => AccountView.render("show.json", %{user: target_account})
1313 }
1314
1315 assert %Activity{
1316 actor: ^reporter_ap_id,
1317 data: %{
1318 "type" => "Flag",
1319 "content" => ^content,
1320 "context" => ^context,
1321 "object" => [^target_ap_id, ^note_obj]
1322 }
1323 } = activity
1324 end
1325
1326 test_with_mock "strips status data from Flag, before federating it",
1327 %{
1328 reporter: reporter,
1329 context: context,
1330 target_account: target_account,
1331 reported_activity: reported_activity,
1332 content: content
1333 },
1334 Utils,
1335 [:passthrough],
1336 [] do
1337 {:ok, activity} =
1338 ActivityPub.flag(%{
1339 actor: reporter,
1340 context: context,
1341 account: target_account,
1342 statuses: [reported_activity],
1343 content: content
1344 })
1345
1346 new_data =
1347 put_in(activity.data, ["object"], [target_account.ap_id, reported_activity.data["id"]])
1348
1349 assert_called(Utils.maybe_federate(%{activity | data: new_data}))
1350 end
1351 end
1352
1353 test "fetch_activities/2 returns activities addressed to a list " do
1354 user = insert(:user)
1355 member = insert(:user)
1356 {:ok, list} = Pleroma.List.create("foo", user)
1357 {:ok, list} = Pleroma.List.follow(list, member)
1358
1359 {:ok, activity} =
1360 CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
1361
1362 activity = Repo.preload(activity, :bookmark)
1363 activity = %Activity{activity | thread_muted?: !!activity.thread_muted?}
1364
1365 assert ActivityPub.fetch_activities([], %{"user" => user}) == [activity]
1366 end
1367
1368 def data_uri do
1369 File.read!("test/fixtures/avatar_data_uri")
1370 end
1371
1372 describe "fetch_activities_bounded" do
1373 test "fetches private posts for followed users" do
1374 user = insert(:user)
1375
1376 {:ok, activity} =
1377 CommonAPI.post(user, %{
1378 "status" => "thought I looked cute might delete later :3",
1379 "visibility" => "private"
1380 })
1381
1382 [result] = ActivityPub.fetch_activities_bounded([user.follower_address], [])
1383 assert result.id == activity.id
1384 end
1385
1386 test "fetches only public posts for other users" do
1387 user = insert(:user)
1388 {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe", "visibility" => "public"})
1389
1390 {:ok, _private_activity} =
1391 CommonAPI.post(user, %{
1392 "status" => "why is tenshi eating a corndog so cute?",
1393 "visibility" => "private"
1394 })
1395
1396 [result] = ActivityPub.fetch_activities_bounded([], [user.follower_address])
1397 assert result.id == activity.id
1398 end
1399 end
1400
1401 describe "fetch_follow_information_for_user" do
1402 test "syncronizes following/followers counters" do
1403 user =
1404 insert(:user,
1405 local: false,
1406 follower_address: "http://localhost:4001/users/fuser2/followers",
1407 following_address: "http://localhost:4001/users/fuser2/following"
1408 )
1409
1410 {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
1411 assert info.follower_count == 527
1412 assert info.following_count == 267
1413 end
1414
1415 test "detects hidden followers" do
1416 mock(fn env ->
1417 case env.url do
1418 "http://localhost:4001/users/masto_closed/followers?page=1" ->
1419 %Tesla.Env{status: 403, body: ""}
1420
1421 _ ->
1422 apply(HttpRequestMock, :request, [env])
1423 end
1424 end)
1425
1426 user =
1427 insert(:user,
1428 local: false,
1429 follower_address: "http://localhost:4001/users/masto_closed/followers",
1430 following_address: "http://localhost:4001/users/masto_closed/following"
1431 )
1432
1433 {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
1434 assert info.hide_followers == true
1435 assert info.hide_follows == false
1436 end
1437
1438 test "detects hidden follows" do
1439 mock(fn env ->
1440 case env.url do
1441 "http://localhost:4001/users/masto_closed/following?page=1" ->
1442 %Tesla.Env{status: 403, body: ""}
1443
1444 _ ->
1445 apply(HttpRequestMock, :request, [env])
1446 end
1447 end)
1448
1449 user =
1450 insert(:user,
1451 local: false,
1452 follower_address: "http://localhost:4001/users/masto_closed/followers",
1453 following_address: "http://localhost:4001/users/masto_closed/following"
1454 )
1455
1456 {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
1457 assert info.hide_followers == false
1458 assert info.hide_follows == true
1459 end
1460 end
1461 end