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