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