[#1335] Reorganized `users.mutes` as relation to UserMute entity.
[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_block} = 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_block} = 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_block} = 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_block} = 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, _user_block} = 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, _user_block} = 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
615 activity_one_actor = User.get_by_ap_id(activity_one.data["actor"])
616 {:ok, _user_mute} = User.mute(user, activity_one_actor)
617
618 activities =
619 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
620
621 assert Enum.member?(activities, activity_two)
622 assert Enum.member?(activities, activity_three)
623 refute Enum.member?(activities, activity_one)
624
625 # Calling with 'with_muted' will deliver muted activities, too.
626 activities =
627 ActivityPub.fetch_activities([], %{
628 "muting_user" => user,
629 "with_muted" => true,
630 "skip_preload" => true
631 })
632
633 assert Enum.member?(activities, activity_two)
634 assert Enum.member?(activities, activity_three)
635 assert Enum.member?(activities, activity_one)
636
637 {:ok, _user_mute} = User.unmute(user, activity_one_actor)
638
639 activities =
640 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
641
642 assert Enum.member?(activities, activity_two)
643 assert Enum.member?(activities, activity_three)
644 assert Enum.member?(activities, activity_one)
645
646 activity_three_actor = User.get_by_ap_id(activity_three.data["actor"])
647 {:ok, _user_mute} = User.mute(user, activity_three_actor)
648 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
649 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
650 activity_three = Activity.get_by_id(activity_three.id)
651
652 activities =
653 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
654
655 assert Enum.member?(activities, activity_two)
656 refute Enum.member?(activities, activity_three)
657 refute Enum.member?(activities, boost_activity)
658 assert Enum.member?(activities, activity_one)
659
660 activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true})
661
662 assert Enum.member?(activities, activity_two)
663 assert Enum.member?(activities, activity_three)
664 assert Enum.member?(activities, boost_activity)
665 assert Enum.member?(activities, activity_one)
666 end
667
668 test "doesn't return thread muted activities" do
669 user = insert(:user)
670 _activity_one = insert(:note_activity)
671 note_two = insert(:note, data: %{"context" => "suya.."})
672 activity_two = insert(:note_activity, note: note_two)
673
674 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
675
676 assert [_activity_one] = ActivityPub.fetch_activities([], %{"muting_user" => user})
677 end
678
679 test "returns thread muted activities when with_muted is set" do
680 user = insert(:user)
681 _activity_one = insert(:note_activity)
682 note_two = insert(:note, data: %{"context" => "suya.."})
683 activity_two = insert(:note_activity, note: note_two)
684
685 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
686
687 assert [_activity_two, _activity_one] =
688 ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true})
689 end
690
691 test "does include announces on request" do
692 activity_three = insert(:note_activity)
693 user = insert(:user)
694 booster = insert(:user)
695
696 {:ok, user} = User.follow(user, booster)
697
698 {:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster)
699
700 [announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)])
701
702 assert announce_activity.id == announce.id
703 end
704
705 test "excludes reblogs on request" do
706 user = insert(:user)
707 {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
708 {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user})
709
710 [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"})
711
712 assert activity == expected_activity
713 end
714
715 describe "public fetch activities" do
716 test "doesn't retrieve unlisted activities" do
717 user = insert(:user)
718
719 {:ok, _unlisted_activity} =
720 CommonAPI.post(user, %{"status" => "yeah", "visibility" => "unlisted"})
721
722 {:ok, listed_activity} = CommonAPI.post(user, %{"status" => "yeah"})
723
724 [activity] = ActivityPub.fetch_public_activities()
725
726 assert activity == listed_activity
727 end
728
729 test "retrieves public activities" do
730 _activities = ActivityPub.fetch_public_activities()
731
732 %{public: public} = ActivityBuilder.public_and_non_public()
733
734 activities = ActivityPub.fetch_public_activities()
735 assert length(activities) == 1
736 assert Enum.at(activities, 0) == public
737 end
738
739 test "retrieves a maximum of 20 activities" do
740 ActivityBuilder.insert_list(10)
741 expected_activities = ActivityBuilder.insert_list(20)
742
743 activities = ActivityPub.fetch_public_activities()
744
745 assert collect_ids(activities) == collect_ids(expected_activities)
746 assert length(activities) == 20
747 end
748
749 test "retrieves ids starting from a since_id" do
750 activities = ActivityBuilder.insert_list(30)
751 expected_activities = ActivityBuilder.insert_list(10)
752 since_id = List.last(activities).id
753
754 activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id})
755
756 assert collect_ids(activities) == collect_ids(expected_activities)
757 assert length(activities) == 10
758 end
759
760 test "retrieves ids up to max_id" do
761 ActivityBuilder.insert_list(10)
762 expected_activities = ActivityBuilder.insert_list(20)
763
764 %{id: max_id} =
765 10
766 |> ActivityBuilder.insert_list()
767 |> List.first()
768
769 activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id})
770
771 assert length(activities) == 20
772 assert collect_ids(activities) == collect_ids(expected_activities)
773 end
774
775 test "paginates via offset/limit" do
776 _first_part_activities = ActivityBuilder.insert_list(10)
777 second_part_activities = ActivityBuilder.insert_list(10)
778
779 later_activities = ActivityBuilder.insert_list(10)
780
781 activities =
782 ActivityPub.fetch_public_activities(%{"page" => "2", "page_size" => "20"}, :offset)
783
784 assert length(activities) == 20
785
786 assert collect_ids(activities) ==
787 collect_ids(second_part_activities) ++ collect_ids(later_activities)
788 end
789
790 test "doesn't return reblogs for users for whom reblogs have been muted" do
791 activity = insert(:note_activity)
792 user = insert(:user)
793 booster = insert(:user)
794 {:ok, user} = CommonAPI.hide_reblogs(user, booster)
795
796 {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
797
798 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
799
800 refute Enum.any?(activities, fn %{id: id} -> id == activity.id end)
801 end
802
803 test "returns reblogs for users for whom reblogs have not been muted" do
804 activity = insert(:note_activity)
805 user = insert(:user)
806 booster = insert(:user)
807 {:ok, user} = CommonAPI.hide_reblogs(user, booster)
808 {:ok, user} = CommonAPI.show_reblogs(user, booster)
809
810 {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
811
812 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
813
814 assert Enum.any?(activities, fn %{id: id} -> id == activity.id end)
815 end
816 end
817
818 describe "like an object" do
819 test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do
820 Pleroma.Config.put([:instance, :federating], true)
821 note_activity = insert(:note_activity)
822 assert object_activity = Object.normalize(note_activity)
823
824 user = insert(:user)
825
826 {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
827 assert called(Pleroma.Web.Federator.publish(like_activity))
828 end
829
830 test "returns exist activity if object already liked" do
831 note_activity = insert(:note_activity)
832 assert object_activity = Object.normalize(note_activity)
833
834 user = insert(:user)
835
836 {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
837
838 {:ok, like_activity_exist, _object} = ActivityPub.like(user, object_activity)
839 assert like_activity == like_activity_exist
840 end
841
842 test "adds a like activity to the db" do
843 note_activity = insert(:note_activity)
844 assert object = Object.normalize(note_activity)
845
846 user = insert(:user)
847 user_two = insert(:user)
848
849 {:ok, like_activity, object} = ActivityPub.like(user, object)
850
851 assert like_activity.data["actor"] == user.ap_id
852 assert like_activity.data["type"] == "Like"
853 assert like_activity.data["object"] == object.data["id"]
854 assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
855 assert like_activity.data["context"] == object.data["context"]
856 assert object.data["like_count"] == 1
857 assert object.data["likes"] == [user.ap_id]
858
859 # Just return the original activity if the user already liked it.
860 {:ok, same_like_activity, object} = ActivityPub.like(user, object)
861
862 assert like_activity == same_like_activity
863 assert object.data["likes"] == [user.ap_id]
864 assert object.data["like_count"] == 1
865
866 {:ok, _like_activity, object} = ActivityPub.like(user_two, object)
867 assert object.data["like_count"] == 2
868 end
869 end
870
871 describe "unliking" do
872 test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do
873 Pleroma.Config.put([:instance, :federating], true)
874
875 note_activity = insert(:note_activity)
876 object = Object.normalize(note_activity)
877 user = insert(:user)
878
879 {:ok, object} = ActivityPub.unlike(user, object)
880 refute called(Pleroma.Web.Federator.publish())
881
882 {:ok, _like_activity, object} = ActivityPub.like(user, object)
883 assert object.data["like_count"] == 1
884
885 {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
886 assert object.data["like_count"] == 0
887
888 assert called(Pleroma.Web.Federator.publish(unlike_activity))
889 end
890
891 test "unliking a previously liked object" do
892 note_activity = insert(:note_activity)
893 object = Object.normalize(note_activity)
894 user = insert(:user)
895
896 # Unliking something that hasn't been liked does nothing
897 {:ok, object} = ActivityPub.unlike(user, object)
898 assert object.data["like_count"] == 0
899
900 {:ok, like_activity, object} = ActivityPub.like(user, object)
901 assert object.data["like_count"] == 1
902
903 {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
904 assert object.data["like_count"] == 0
905
906 assert Activity.get_by_id(like_activity.id) == nil
907 assert note_activity.actor in unlike_activity.recipients
908 end
909 end
910
911 describe "announcing an object" do
912 test "adds an announce activity to the db" do
913 note_activity = insert(:note_activity)
914 object = Object.normalize(note_activity)
915 user = insert(:user)
916
917 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
918 assert object.data["announcement_count"] == 1
919 assert object.data["announcements"] == [user.ap_id]
920
921 assert announce_activity.data["to"] == [
922 User.ap_followers(user),
923 note_activity.data["actor"]
924 ]
925
926 assert announce_activity.data["object"] == object.data["id"]
927 assert announce_activity.data["actor"] == user.ap_id
928 assert announce_activity.data["context"] == object.data["context"]
929 end
930 end
931
932 describe "announcing a private object" do
933 test "adds an announce activity to the db if the audience is not widened" do
934 user = insert(:user)
935 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
936 object = Object.normalize(note_activity)
937
938 {:ok, announce_activity, object} = ActivityPub.announce(user, object, nil, true, false)
939
940 assert announce_activity.data["to"] == [User.ap_followers(user)]
941
942 assert announce_activity.data["object"] == object.data["id"]
943 assert announce_activity.data["actor"] == user.ap_id
944 assert announce_activity.data["context"] == object.data["context"]
945 end
946
947 test "does not add an announce activity to the db if the audience is widened" do
948 user = insert(:user)
949 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
950 object = Object.normalize(note_activity)
951
952 assert {:error, _} = ActivityPub.announce(user, object, nil, true, true)
953 end
954
955 test "does not add an announce activity to the db if the announcer is not the author" do
956 user = insert(:user)
957 announcer = insert(:user)
958 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
959 object = Object.normalize(note_activity)
960
961 assert {:error, _} = ActivityPub.announce(announcer, object, nil, true, false)
962 end
963 end
964
965 describe "unannouncing an object" do
966 test "unannouncing a previously announced object" do
967 note_activity = insert(:note_activity)
968 object = Object.normalize(note_activity)
969 user = insert(:user)
970
971 # Unannouncing an object that is not announced does nothing
972 # {:ok, object} = ActivityPub.unannounce(user, object)
973 # assert object.data["announcement_count"] == 0
974
975 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
976 assert object.data["announcement_count"] == 1
977
978 {:ok, unannounce_activity, object} = ActivityPub.unannounce(user, object)
979 assert object.data["announcement_count"] == 0
980
981 assert unannounce_activity.data["to"] == [
982 User.ap_followers(user),
983 object.data["actor"]
984 ]
985
986 assert unannounce_activity.data["type"] == "Undo"
987 assert unannounce_activity.data["object"] == announce_activity.data
988 assert unannounce_activity.data["actor"] == user.ap_id
989 assert unannounce_activity.data["context"] == announce_activity.data["context"]
990
991 assert Activity.get_by_id(announce_activity.id) == nil
992 end
993 end
994
995 describe "uploading files" do
996 test "copies the file to the configured folder" do
997 file = %Plug.Upload{
998 content_type: "image/jpg",
999 path: Path.absname("test/fixtures/image.jpg"),
1000 filename: "an_image.jpg"
1001 }
1002
1003 {:ok, %Object{} = object} = ActivityPub.upload(file)
1004 assert object.data["name"] == "an_image.jpg"
1005 end
1006
1007 test "works with base64 encoded images" do
1008 file = %{
1009 "img" => data_uri()
1010 }
1011
1012 {:ok, %Object{}} = ActivityPub.upload(file)
1013 end
1014 end
1015
1016 describe "fetch the latest Follow" do
1017 test "fetches the latest Follow activity" do
1018 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
1019 follower = Repo.get_by(User, ap_id: activity.data["actor"])
1020 followed = Repo.get_by(User, ap_id: activity.data["object"])
1021
1022 assert activity == Utils.fetch_latest_follow(follower, followed)
1023 end
1024 end
1025
1026 describe "following / unfollowing" do
1027 test "creates a follow activity" do
1028 follower = insert(:user)
1029 followed = insert(:user)
1030
1031 {:ok, activity} = ActivityPub.follow(follower, followed)
1032 assert activity.data["type"] == "Follow"
1033 assert activity.data["actor"] == follower.ap_id
1034 assert activity.data["object"] == followed.ap_id
1035 end
1036
1037 test "creates an undo activity for the last follow" do
1038 follower = insert(:user)
1039 followed = insert(:user)
1040
1041 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
1042 {:ok, activity} = ActivityPub.unfollow(follower, followed)
1043
1044 assert activity.data["type"] == "Undo"
1045 assert activity.data["actor"] == follower.ap_id
1046
1047 embedded_object = activity.data["object"]
1048 assert is_map(embedded_object)
1049 assert embedded_object["type"] == "Follow"
1050 assert embedded_object["object"] == followed.ap_id
1051 assert embedded_object["id"] == follow_activity.data["id"]
1052 end
1053 end
1054
1055 describe "blocking / unblocking" do
1056 test "creates a block activity" do
1057 blocker = insert(:user)
1058 blocked = insert(:user)
1059
1060 {:ok, activity} = ActivityPub.block(blocker, blocked)
1061
1062 assert activity.data["type"] == "Block"
1063 assert activity.data["actor"] == blocker.ap_id
1064 assert activity.data["object"] == blocked.ap_id
1065 end
1066
1067 test "creates an undo activity for the last block" do
1068 blocker = insert(:user)
1069 blocked = insert(:user)
1070
1071 {:ok, block_activity} = ActivityPub.block(blocker, blocked)
1072 {:ok, activity} = ActivityPub.unblock(blocker, blocked)
1073
1074 assert activity.data["type"] == "Undo"
1075 assert activity.data["actor"] == blocker.ap_id
1076
1077 embedded_object = activity.data["object"]
1078 assert is_map(embedded_object)
1079 assert embedded_object["type"] == "Block"
1080 assert embedded_object["object"] == blocked.ap_id
1081 assert embedded_object["id"] == block_activity.data["id"]
1082 end
1083 end
1084
1085 describe "deletion" do
1086 test "it creates a delete activity and deletes the original object" do
1087 note = insert(:note_activity)
1088 object = Object.normalize(note)
1089 {:ok, delete} = ActivityPub.delete(object)
1090
1091 assert delete.data["type"] == "Delete"
1092 assert delete.data["actor"] == note.data["actor"]
1093 assert delete.data["object"] == object.data["id"]
1094
1095 assert Activity.get_by_id(delete.id) != nil
1096
1097 assert Repo.get(Object, object.id).data["type"] == "Tombstone"
1098 end
1099
1100 test "decrements user note count only for public activities" do
1101 user = insert(:user, note_count: 10)
1102
1103 {:ok, a1} =
1104 CommonAPI.post(User.get_cached_by_id(user.id), %{
1105 "status" => "yeah",
1106 "visibility" => "public"
1107 })
1108
1109 {:ok, a2} =
1110 CommonAPI.post(User.get_cached_by_id(user.id), %{
1111 "status" => "yeah",
1112 "visibility" => "unlisted"
1113 })
1114
1115 {:ok, a3} =
1116 CommonAPI.post(User.get_cached_by_id(user.id), %{
1117 "status" => "yeah",
1118 "visibility" => "private"
1119 })
1120
1121 {:ok, a4} =
1122 CommonAPI.post(User.get_cached_by_id(user.id), %{
1123 "status" => "yeah",
1124 "visibility" => "direct"
1125 })
1126
1127 {:ok, _} = Object.normalize(a1) |> ActivityPub.delete()
1128 {:ok, _} = Object.normalize(a2) |> ActivityPub.delete()
1129 {:ok, _} = Object.normalize(a3) |> ActivityPub.delete()
1130 {:ok, _} = Object.normalize(a4) |> ActivityPub.delete()
1131
1132 user = User.get_cached_by_id(user.id)
1133 assert user.note_count == 10
1134 end
1135
1136 test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
1137 user = insert(:user)
1138 note = insert(:note_activity)
1139 object = Object.normalize(note)
1140
1141 {:ok, object} =
1142 object
1143 |> Object.change(%{
1144 data: %{
1145 "actor" => object.data["actor"],
1146 "id" => object.data["id"],
1147 "to" => [user.ap_id],
1148 "type" => "Note"
1149 }
1150 })
1151 |> Object.update_and_set_cache()
1152
1153 {:ok, delete} = ActivityPub.delete(object)
1154
1155 assert user.ap_id in delete.data["to"]
1156 end
1157
1158 test "decreases reply count" do
1159 user = insert(:user)
1160 user2 = insert(:user)
1161
1162 {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
1163 reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
1164 ap_id = activity.data["id"]
1165
1166 {:ok, public_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
1167 {:ok, unlisted_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
1168 {:ok, private_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
1169 {:ok, direct_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
1170
1171 _ = CommonAPI.delete(direct_reply.id, user2)
1172 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1173 assert object.data["repliesCount"] == 2
1174
1175 _ = CommonAPI.delete(private_reply.id, user2)
1176 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1177 assert object.data["repliesCount"] == 2
1178
1179 _ = CommonAPI.delete(public_reply.id, user2)
1180 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1181 assert object.data["repliesCount"] == 1
1182
1183 _ = CommonAPI.delete(unlisted_reply.id, user2)
1184 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1185 assert object.data["repliesCount"] == 0
1186 end
1187 end
1188
1189 describe "timeline post-processing" do
1190 test "it filters broken threads" do
1191 user1 = insert(:user)
1192 user2 = insert(:user)
1193 user3 = insert(:user)
1194
1195 {:ok, user1} = User.follow(user1, user3)
1196 assert User.following?(user1, user3)
1197
1198 {:ok, user2} = User.follow(user2, user3)
1199 assert User.following?(user2, user3)
1200
1201 {:ok, user3} = User.follow(user3, user2)
1202 assert User.following?(user3, user2)
1203
1204 {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
1205
1206 {:ok, private_activity_1} =
1207 CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
1208
1209 {:ok, private_activity_2} =
1210 CommonAPI.post(user2, %{
1211 "status" => "hi 3",
1212 "visibility" => "private",
1213 "in_reply_to_status_id" => private_activity_1.id
1214 })
1215
1216 {:ok, private_activity_3} =
1217 CommonAPI.post(user3, %{
1218 "status" => "hi 4",
1219 "visibility" => "private",
1220 "in_reply_to_status_id" => private_activity_2.id
1221 })
1222
1223 activities =
1224 ActivityPub.fetch_activities([user1.ap_id | User.following(user1)])
1225 |> Enum.map(fn a -> a.id end)
1226
1227 private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"])
1228
1229 assert [public_activity.id, private_activity_1.id, private_activity_3.id] == activities
1230
1231 assert length(activities) == 3
1232
1233 activities =
1234 ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{"user" => user1})
1235 |> Enum.map(fn a -> a.id end)
1236
1237 assert [public_activity.id, private_activity_1.id] == activities
1238 assert length(activities) == 2
1239 end
1240 end
1241
1242 describe "update" do
1243 test "it creates an update activity with the new user data" do
1244 user = insert(:user)
1245 {:ok, user} = User.ensure_keys_present(user)
1246 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
1247
1248 {:ok, update} =
1249 ActivityPub.update(%{
1250 actor: user_data["id"],
1251 to: [user.follower_address],
1252 cc: [],
1253 object: user_data
1254 })
1255
1256 assert update.data["actor"] == user.ap_id
1257 assert update.data["to"] == [user.follower_address]
1258 assert embedded_object = update.data["object"]
1259 assert embedded_object["id"] == user_data["id"]
1260 assert embedded_object["type"] == user_data["type"]
1261 end
1262 end
1263
1264 test "returned pinned statuses" do
1265 Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
1266 user = insert(:user)
1267
1268 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
1269 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
1270 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
1271
1272 CommonAPI.pin(activity_one.id, user)
1273 user = refresh_record(user)
1274
1275 CommonAPI.pin(activity_two.id, user)
1276 user = refresh_record(user)
1277
1278 CommonAPI.pin(activity_three.id, user)
1279 user = refresh_record(user)
1280
1281 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
1282
1283 assert 3 = length(activities)
1284 end
1285
1286 describe "flag/1" do
1287 setup do
1288 reporter = insert(:user)
1289 target_account = insert(:user)
1290 content = "foobar"
1291 {:ok, activity} = CommonAPI.post(target_account, %{"status" => content})
1292 context = Utils.generate_context_id()
1293
1294 reporter_ap_id = reporter.ap_id
1295 target_ap_id = target_account.ap_id
1296 activity_ap_id = activity.data["id"]
1297
1298 activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id)
1299
1300 {:ok,
1301 %{
1302 reporter: reporter,
1303 context: context,
1304 target_account: target_account,
1305 reported_activity: activity,
1306 content: content,
1307 activity_ap_id: activity_ap_id,
1308 activity_with_object: activity_with_object,
1309 reporter_ap_id: reporter_ap_id,
1310 target_ap_id: target_ap_id
1311 }}
1312 end
1313
1314 test "it can create a Flag activity",
1315 %{
1316 reporter: reporter,
1317 context: context,
1318 target_account: target_account,
1319 reported_activity: reported_activity,
1320 content: content,
1321 activity_ap_id: activity_ap_id,
1322 activity_with_object: activity_with_object,
1323 reporter_ap_id: reporter_ap_id,
1324 target_ap_id: target_ap_id
1325 } do
1326 assert {:ok, activity} =
1327 ActivityPub.flag(%{
1328 actor: reporter,
1329 context: context,
1330 account: target_account,
1331 statuses: [reported_activity],
1332 content: content
1333 })
1334
1335 note_obj = %{
1336 "type" => "Note",
1337 "id" => activity_ap_id,
1338 "content" => content,
1339 "published" => activity_with_object.object.data["published"],
1340 "actor" => AccountView.render("show.json", %{user: target_account})
1341 }
1342
1343 assert %Activity{
1344 actor: ^reporter_ap_id,
1345 data: %{
1346 "type" => "Flag",
1347 "content" => ^content,
1348 "context" => ^context,
1349 "object" => [^target_ap_id, ^note_obj]
1350 }
1351 } = activity
1352 end
1353
1354 test_with_mock "strips status data from Flag, before federating it",
1355 %{
1356 reporter: reporter,
1357 context: context,
1358 target_account: target_account,
1359 reported_activity: reported_activity,
1360 content: content
1361 },
1362 Utils,
1363 [:passthrough],
1364 [] do
1365 {:ok, activity} =
1366 ActivityPub.flag(%{
1367 actor: reporter,
1368 context: context,
1369 account: target_account,
1370 statuses: [reported_activity],
1371 content: content
1372 })
1373
1374 new_data =
1375 put_in(activity.data, ["object"], [target_account.ap_id, reported_activity.data["id"]])
1376
1377 assert_called(Utils.maybe_federate(%{activity | data: new_data}))
1378 end
1379 end
1380
1381 test "fetch_activities/2 returns activities addressed to a list " do
1382 user = insert(:user)
1383 member = insert(:user)
1384 {:ok, list} = Pleroma.List.create("foo", user)
1385 {:ok, list} = Pleroma.List.follow(list, member)
1386
1387 {:ok, activity} =
1388 CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
1389
1390 activity = Repo.preload(activity, :bookmark)
1391 activity = %Activity{activity | thread_muted?: !!activity.thread_muted?}
1392
1393 assert ActivityPub.fetch_activities([], %{"user" => user}) == [activity]
1394 end
1395
1396 def data_uri do
1397 File.read!("test/fixtures/avatar_data_uri")
1398 end
1399
1400 describe "fetch_activities_bounded" do
1401 test "fetches private posts for followed users" do
1402 user = insert(:user)
1403
1404 {:ok, activity} =
1405 CommonAPI.post(user, %{
1406 "status" => "thought I looked cute might delete later :3",
1407 "visibility" => "private"
1408 })
1409
1410 [result] = ActivityPub.fetch_activities_bounded([user.follower_address], [])
1411 assert result.id == activity.id
1412 end
1413
1414 test "fetches only public posts for other users" do
1415 user = insert(:user)
1416 {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe", "visibility" => "public"})
1417
1418 {:ok, _private_activity} =
1419 CommonAPI.post(user, %{
1420 "status" => "why is tenshi eating a corndog so cute?",
1421 "visibility" => "private"
1422 })
1423
1424 [result] = ActivityPub.fetch_activities_bounded([], [user.follower_address])
1425 assert result.id == activity.id
1426 end
1427 end
1428
1429 describe "fetch_follow_information_for_user" do
1430 test "syncronizes following/followers counters" do
1431 user =
1432 insert(:user,
1433 local: false,
1434 follower_address: "http://localhost:4001/users/fuser2/followers",
1435 following_address: "http://localhost:4001/users/fuser2/following"
1436 )
1437
1438 {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
1439 assert info.follower_count == 527
1440 assert info.following_count == 267
1441 end
1442
1443 test "detects hidden followers" do
1444 mock(fn env ->
1445 case env.url do
1446 "http://localhost:4001/users/masto_closed/followers?page=1" ->
1447 %Tesla.Env{status: 403, body: ""}
1448
1449 _ ->
1450 apply(HttpRequestMock, :request, [env])
1451 end
1452 end)
1453
1454 user =
1455 insert(:user,
1456 local: false,
1457 follower_address: "http://localhost:4001/users/masto_closed/followers",
1458 following_address: "http://localhost:4001/users/masto_closed/following"
1459 )
1460
1461 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1462 assert follow_info.hide_followers == true
1463 assert follow_info.hide_follows == false
1464 end
1465
1466 test "detects hidden follows" do
1467 mock(fn env ->
1468 case env.url do
1469 "http://localhost:4001/users/masto_closed/following?page=1" ->
1470 %Tesla.Env{status: 403, body: ""}
1471
1472 _ ->
1473 apply(HttpRequestMock, :request, [env])
1474 end
1475 end)
1476
1477 user =
1478 insert(:user,
1479 local: false,
1480 follower_address: "http://localhost:4001/users/masto_closed/followers",
1481 following_address: "http://localhost:4001/users/masto_closed/following"
1482 )
1483
1484 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1485 assert follow_info.hide_followers == false
1486 assert follow_info.hide_follows == true
1487 end
1488 end
1489 end