b93ee708e728c9c92449fb05f5fc386b8d3af568
[akkoma] / activity_pub_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
6 use Pleroma.DataCase
7 use Oban.Testing, repo: Pleroma.Repo
8
9 alias Pleroma.Activity
10 alias Pleroma.Builders.ActivityBuilder
11 alias Pleroma.Config
12 alias Pleroma.Notification
13 alias Pleroma.Object
14 alias Pleroma.User
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.ActivityPub.Utils
17 alias Pleroma.Web.AdminAPI.AccountView
18 alias Pleroma.Web.CommonAPI
19 alias Pleroma.Web.Federator
20
21 import Pleroma.Factory
22 import Tesla.Mock
23 import Mock
24
25 setup do
26 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
27 :ok
28 end
29
30 setup do: clear_config([:instance, :federating])
31
32 describe "streaming out participations" do
33 test "it streams them out" do
34 user = insert(:user)
35 {:ok, activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
36
37 {:ok, conversation} = Pleroma.Conversation.create_or_bump_for(activity)
38
39 participations =
40 conversation.participations
41 |> Repo.preload(:user)
42
43 with_mock Pleroma.Web.Streamer,
44 stream: fn _, _ -> nil end do
45 ActivityPub.stream_out_participations(conversation.participations)
46
47 assert called(Pleroma.Web.Streamer.stream("participation", participations))
48 end
49 end
50
51 test "streams them out on activity creation" do
52 user_one = insert(:user)
53 user_two = insert(:user)
54
55 with_mock Pleroma.Web.Streamer,
56 stream: fn _, _ -> nil end do
57 {:ok, activity} =
58 CommonAPI.post(user_one, %{
59 "status" => "@#{user_two.nickname}",
60 "visibility" => "direct"
61 })
62
63 conversation =
64 activity.data["context"]
65 |> Pleroma.Conversation.get_for_ap_id()
66 |> Repo.preload(participations: :user)
67
68 assert called(Pleroma.Web.Streamer.stream("participation", conversation.participations))
69 end
70 end
71 end
72
73 describe "fetching restricted by visibility" do
74 test "it restricts by the appropriate visibility" do
75 user = insert(:user)
76
77 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
78
79 {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
80
81 {:ok, unlisted_activity} =
82 CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
83
84 {:ok, private_activity} =
85 CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
86
87 activities =
88 ActivityPub.fetch_activities([], %{:visibility => "direct", "actor_id" => user.ap_id})
89
90 assert activities == [direct_activity]
91
92 activities =
93 ActivityPub.fetch_activities([], %{:visibility => "unlisted", "actor_id" => user.ap_id})
94
95 assert activities == [unlisted_activity]
96
97 activities =
98 ActivityPub.fetch_activities([], %{:visibility => "private", "actor_id" => user.ap_id})
99
100 assert activities == [private_activity]
101
102 activities =
103 ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id})
104
105 assert activities == [public_activity]
106
107 activities =
108 ActivityPub.fetch_activities([], %{
109 :visibility => ~w[private public],
110 "actor_id" => user.ap_id
111 })
112
113 assert activities == [public_activity, private_activity]
114 end
115 end
116
117 describe "fetching excluded by visibility" do
118 test "it excludes by the appropriate visibility" do
119 user = insert(:user)
120
121 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
122
123 {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
124
125 {:ok, unlisted_activity} =
126 CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
127
128 {:ok, private_activity} =
129 CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
130
131 activities =
132 ActivityPub.fetch_activities([], %{
133 "exclude_visibilities" => "direct",
134 "actor_id" => user.ap_id
135 })
136
137 assert public_activity in activities
138 assert unlisted_activity in activities
139 assert private_activity in activities
140 refute direct_activity in activities
141
142 activities =
143 ActivityPub.fetch_activities([], %{
144 "exclude_visibilities" => "unlisted",
145 "actor_id" => user.ap_id
146 })
147
148 assert public_activity in activities
149 refute unlisted_activity in activities
150 assert private_activity in activities
151 assert direct_activity in activities
152
153 activities =
154 ActivityPub.fetch_activities([], %{
155 "exclude_visibilities" => "private",
156 "actor_id" => user.ap_id
157 })
158
159 assert public_activity in activities
160 assert unlisted_activity in activities
161 refute private_activity in activities
162 assert direct_activity in activities
163
164 activities =
165 ActivityPub.fetch_activities([], %{
166 "exclude_visibilities" => "public",
167 "actor_id" => user.ap_id
168 })
169
170 refute public_activity in activities
171 assert unlisted_activity in activities
172 assert private_activity in activities
173 assert direct_activity in activities
174 end
175 end
176
177 describe "building a user from his ap id" do
178 test "it returns a user" do
179 user_id = "http://mastodon.example.org/users/admin"
180 {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
181 assert user.ap_id == user_id
182 assert user.nickname == "admin@mastodon.example.org"
183 assert user.ap_enabled
184 assert user.follower_address == "http://mastodon.example.org/users/admin/followers"
185 end
186
187 test "it returns a user that is invisible" do
188 user_id = "http://mastodon.example.org/users/relay"
189 {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
190 assert User.invisible?(user)
191 end
192
193 test "it fetches the appropriate tag-restricted posts" do
194 user = insert(:user)
195
196 {:ok, status_one} = CommonAPI.post(user, %{"status" => ". #test"})
197 {:ok, status_two} = CommonAPI.post(user, %{"status" => ". #essais"})
198 {:ok, status_three} = CommonAPI.post(user, %{"status" => ". #test #reject"})
199
200 fetch_one = ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => "test"})
201
202 fetch_two =
203 ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => ["test", "essais"]})
204
205 fetch_three =
206 ActivityPub.fetch_activities([], %{
207 "type" => "Create",
208 "tag" => ["test", "essais"],
209 "tag_reject" => ["reject"]
210 })
211
212 fetch_four =
213 ActivityPub.fetch_activities([], %{
214 "type" => "Create",
215 "tag" => ["test"],
216 "tag_all" => ["test", "reject"]
217 })
218
219 assert fetch_one == [status_one, status_three]
220 assert fetch_two == [status_one, status_two, status_three]
221 assert fetch_three == [status_one, status_two]
222 assert fetch_four == [status_three]
223 end
224 end
225
226 describe "insertion" do
227 test "drops activities beyond a certain limit" do
228 limit = Config.get([:instance, :remote_limit])
229
230 random_text =
231 :crypto.strong_rand_bytes(limit + 1)
232 |> Base.encode64()
233 |> binary_part(0, limit + 1)
234
235 data = %{
236 "ok" => true,
237 "object" => %{
238 "content" => random_text
239 }
240 }
241
242 assert {:error, {:remote_limit_error, _}} = ActivityPub.insert(data)
243 end
244
245 test "doesn't drop activities with content being null" do
246 user = insert(:user)
247
248 data = %{
249 "actor" => user.ap_id,
250 "to" => [],
251 "object" => %{
252 "actor" => user.ap_id,
253 "to" => [],
254 "type" => "Note",
255 "content" => nil
256 }
257 }
258
259 assert {:ok, _} = ActivityPub.insert(data)
260 end
261
262 test "returns the activity if one with the same id is already in" do
263 activity = insert(:note_activity)
264 {:ok, new_activity} = ActivityPub.insert(activity.data)
265
266 assert activity.id == new_activity.id
267 end
268
269 test "inserts a given map into the activity database, giving it an id if it has none." do
270 user = insert(:user)
271
272 data = %{
273 "actor" => user.ap_id,
274 "to" => [],
275 "object" => %{
276 "actor" => user.ap_id,
277 "to" => [],
278 "type" => "Note",
279 "content" => "hey"
280 }
281 }
282
283 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
284 assert activity.data["ok"] == data["ok"]
285 assert is_binary(activity.data["id"])
286
287 given_id = "bla"
288
289 data = %{
290 "id" => given_id,
291 "actor" => user.ap_id,
292 "to" => [],
293 "context" => "blabla",
294 "object" => %{
295 "actor" => user.ap_id,
296 "to" => [],
297 "type" => "Note",
298 "content" => "hey"
299 }
300 }
301
302 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
303 assert activity.data["ok"] == data["ok"]
304 assert activity.data["id"] == given_id
305 assert activity.data["context"] == "blabla"
306 assert activity.data["context_id"]
307 end
308
309 test "adds a context when none is there" do
310 user = insert(:user)
311
312 data = %{
313 "actor" => user.ap_id,
314 "to" => [],
315 "object" => %{
316 "actor" => user.ap_id,
317 "to" => [],
318 "type" => "Note",
319 "content" => "hey"
320 }
321 }
322
323 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
324 object = Pleroma.Object.normalize(activity)
325
326 assert is_binary(activity.data["context"])
327 assert is_binary(object.data["context"])
328 assert activity.data["context_id"]
329 assert object.data["context_id"]
330 end
331
332 test "adds an id to a given object if it lacks one and is a note and inserts it to the object database" do
333 user = insert(:user)
334
335 data = %{
336 "actor" => user.ap_id,
337 "to" => [],
338 "object" => %{
339 "actor" => user.ap_id,
340 "to" => [],
341 "type" => "Note",
342 "content" => "hey"
343 }
344 }
345
346 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
347 assert object = Object.normalize(activity)
348 assert is_binary(object.data["id"])
349 end
350 end
351
352 describe "listen activities" do
353 test "does not increase user note count" do
354 user = insert(:user)
355
356 {:ok, activity} =
357 ActivityPub.listen(%{
358 to: ["https://www.w3.org/ns/activitystreams#Public"],
359 actor: user,
360 context: "",
361 object: %{
362 "actor" => user.ap_id,
363 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
364 "artist" => "lain",
365 "title" => "lain radio episode 1",
366 "length" => 180_000,
367 "type" => "Audio"
368 }
369 })
370
371 assert activity.actor == user.ap_id
372
373 user = User.get_cached_by_id(user.id)
374 assert user.note_count == 0
375 end
376
377 test "can be fetched into a timeline" do
378 _listen_activity_1 = insert(:listen)
379 _listen_activity_2 = insert(:listen)
380 _listen_activity_3 = insert(:listen)
381
382 timeline = ActivityPub.fetch_activities([], %{"type" => ["Listen"]})
383
384 assert length(timeline) == 3
385 end
386 end
387
388 describe "create activities" do
389 test "it reverts create" do
390 user = insert(:user)
391
392 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
393 assert {:error, :reverted} =
394 ActivityPub.create(%{
395 to: ["user1", "user2"],
396 actor: user,
397 context: "",
398 object: %{
399 "to" => ["user1", "user2"],
400 "type" => "Note",
401 "content" => "testing"
402 }
403 })
404 end
405
406 assert Repo.aggregate(Activity, :count, :id) == 0
407 assert Repo.aggregate(Object, :count, :id) == 0
408 end
409
410 test "removes doubled 'to' recipients" do
411 user = insert(:user)
412
413 {:ok, activity} =
414 ActivityPub.create(%{
415 to: ["user1", "user1", "user2"],
416 actor: user,
417 context: "",
418 object: %{
419 "to" => ["user1", "user1", "user2"],
420 "type" => "Note",
421 "content" => "testing"
422 }
423 })
424
425 assert activity.data["to"] == ["user1", "user2"]
426 assert activity.actor == user.ap_id
427 assert activity.recipients == ["user1", "user2", user.ap_id]
428 end
429
430 test "increases user note count only for public activities" do
431 user = insert(:user)
432
433 {:ok, _} =
434 CommonAPI.post(User.get_cached_by_id(user.id), %{
435 "status" => "1",
436 "visibility" => "public"
437 })
438
439 {:ok, _} =
440 CommonAPI.post(User.get_cached_by_id(user.id), %{
441 "status" => "2",
442 "visibility" => "unlisted"
443 })
444
445 {:ok, _} =
446 CommonAPI.post(User.get_cached_by_id(user.id), %{
447 "status" => "2",
448 "visibility" => "private"
449 })
450
451 {:ok, _} =
452 CommonAPI.post(User.get_cached_by_id(user.id), %{
453 "status" => "3",
454 "visibility" => "direct"
455 })
456
457 user = User.get_cached_by_id(user.id)
458 assert user.note_count == 2
459 end
460
461 test "increases replies count" do
462 user = insert(:user)
463 user2 = insert(:user)
464
465 {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
466 ap_id = activity.data["id"]
467 reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
468
469 # public
470 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
471 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
472 assert object.data["repliesCount"] == 1
473
474 # unlisted
475 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
476 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
477 assert object.data["repliesCount"] == 2
478
479 # private
480 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
481 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
482 assert object.data["repliesCount"] == 2
483
484 # direct
485 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
486 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
487 assert object.data["repliesCount"] == 2
488 end
489 end
490
491 describe "fetch activities for recipients" do
492 test "retrieve the activities for certain recipients" do
493 {:ok, activity_one} = ActivityBuilder.insert(%{"to" => ["someone"]})
494 {:ok, activity_two} = ActivityBuilder.insert(%{"to" => ["someone_else"]})
495 {:ok, _activity_three} = ActivityBuilder.insert(%{"to" => ["noone"]})
496
497 activities = ActivityPub.fetch_activities(["someone", "someone_else"])
498 assert length(activities) == 2
499 assert activities == [activity_one, activity_two]
500 end
501 end
502
503 describe "fetch activities in context" do
504 test "retrieves activities that have a given context" do
505 {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
506 {:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
507 {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
508 {:ok, _activity_four} = ActivityBuilder.insert(%{"type" => "Announce", "context" => "2hu"})
509 activity_five = insert(:note_activity)
510 user = insert(:user)
511
512 {:ok, _user_relationship} = User.block(user, %{ap_id: activity_five.data["actor"]})
513
514 activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user})
515 assert activities == [activity_two, activity]
516 end
517 end
518
519 test "doesn't return blocked activities" do
520 activity_one = insert(:note_activity)
521 activity_two = insert(:note_activity)
522 activity_three = insert(:note_activity)
523 user = insert(:user)
524 booster = insert(:user)
525 {:ok, _user_relationship} = User.block(user, %{ap_id: activity_one.data["actor"]})
526
527 activities =
528 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
529
530 assert Enum.member?(activities, activity_two)
531 assert Enum.member?(activities, activity_three)
532 refute Enum.member?(activities, activity_one)
533
534 {:ok, _user_block} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
535
536 activities =
537 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
538
539 assert Enum.member?(activities, activity_two)
540 assert Enum.member?(activities, activity_three)
541 assert Enum.member?(activities, activity_one)
542
543 {:ok, _user_relationship} = User.block(user, %{ap_id: activity_three.data["actor"]})
544 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
545 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
546 activity_three = Activity.get_by_id(activity_three.id)
547
548 activities =
549 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
550
551 assert Enum.member?(activities, activity_two)
552 refute Enum.member?(activities, activity_three)
553 refute Enum.member?(activities, boost_activity)
554 assert Enum.member?(activities, activity_one)
555
556 activities =
557 ActivityPub.fetch_activities([], %{"blocking_user" => nil, "skip_preload" => true})
558
559 assert Enum.member?(activities, activity_two)
560 assert Enum.member?(activities, activity_three)
561 assert Enum.member?(activities, boost_activity)
562 assert Enum.member?(activities, activity_one)
563 end
564
565 test "doesn't return transitive interactions concerning blocked users" do
566 blocker = insert(:user)
567 blockee = insert(:user)
568 friend = insert(:user)
569
570 {:ok, _user_relationship} = User.block(blocker, blockee)
571
572 {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"})
573
574 {:ok, activity_two} = CommonAPI.post(friend, %{"status" => "hey! @#{blockee.nickname}"})
575
576 {:ok, activity_three} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"})
577
578 {:ok, activity_four} = CommonAPI.post(blockee, %{"status" => "hey! @#{blocker.nickname}"})
579
580 activities = ActivityPub.fetch_activities([], %{"blocking_user" => blocker})
581
582 assert Enum.member?(activities, activity_one)
583 refute Enum.member?(activities, activity_two)
584 refute Enum.member?(activities, activity_three)
585 refute Enum.member?(activities, activity_four)
586 end
587
588 test "doesn't return announce activities concerning blocked users" do
589 blocker = insert(:user)
590 blockee = insert(:user)
591 friend = insert(:user)
592
593 {:ok, _user_relationship} = User.block(blocker, blockee)
594
595 {:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey!"})
596
597 {:ok, activity_two} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"})
598
599 {:ok, activity_three, _} = CommonAPI.repeat(activity_two.id, friend)
600
601 activities =
602 ActivityPub.fetch_activities([], %{"blocking_user" => blocker})
603 |> Enum.map(fn act -> act.id end)
604
605 assert Enum.member?(activities, activity_one.id)
606 refute Enum.member?(activities, activity_two.id)
607 refute Enum.member?(activities, activity_three.id)
608 end
609
610 test "doesn't return activities from blocked domains" do
611 domain = "dogwhistle.zone"
612 domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
613 note = insert(:note, %{data: %{"actor" => domain_user.ap_id}})
614 activity = insert(:note_activity, %{note: note})
615 user = insert(:user)
616 {:ok, user} = User.block_domain(user, domain)
617
618 activities =
619 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
620
621 refute activity in activities
622
623 followed_user = insert(:user)
624 ActivityPub.follow(user, followed_user)
625 {:ok, repeat_activity, _} = CommonAPI.repeat(activity.id, followed_user)
626
627 activities =
628 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
629
630 refute repeat_activity in activities
631 end
632
633 test "does return activities from followed users on blocked domains" do
634 domain = "meanies.social"
635 domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
636 blocker = insert(:user)
637
638 {:ok, blocker} = User.follow(blocker, domain_user)
639 {:ok, blocker} = User.block_domain(blocker, domain)
640
641 assert User.following?(blocker, domain_user)
642 assert User.blocks_domain?(blocker, domain_user)
643 refute User.blocks?(blocker, domain_user)
644
645 note = insert(:note, %{data: %{"actor" => domain_user.ap_id}})
646 activity = insert(:note_activity, %{note: note})
647
648 activities =
649 ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true})
650
651 assert activity in activities
652
653 # And check that if the guy we DO follow boosts someone else from their domain,
654 # that should be hidden
655 another_user = insert(:user, %{ap_id: "https://#{domain}/@meanie2"})
656 bad_note = insert(:note, %{data: %{"actor" => another_user.ap_id}})
657 bad_activity = insert(:note_activity, %{note: bad_note})
658 {:ok, repeat_activity, _} = CommonAPI.repeat(bad_activity.id, domain_user)
659
660 activities =
661 ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true})
662
663 refute repeat_activity in activities
664 end
665
666 test "doesn't return muted activities" do
667 activity_one = insert(:note_activity)
668 activity_two = insert(:note_activity)
669 activity_three = insert(:note_activity)
670 user = insert(:user)
671 booster = insert(:user)
672
673 activity_one_actor = User.get_by_ap_id(activity_one.data["actor"])
674 {:ok, _user_relationships} = User.mute(user, activity_one_actor)
675
676 activities =
677 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
678
679 assert Enum.member?(activities, activity_two)
680 assert Enum.member?(activities, activity_three)
681 refute Enum.member?(activities, activity_one)
682
683 # Calling with 'with_muted' will deliver muted activities, too.
684 activities =
685 ActivityPub.fetch_activities([], %{
686 "muting_user" => user,
687 "with_muted" => true,
688 "skip_preload" => true
689 })
690
691 assert Enum.member?(activities, activity_two)
692 assert Enum.member?(activities, activity_three)
693 assert Enum.member?(activities, activity_one)
694
695 {:ok, _user_mute} = User.unmute(user, activity_one_actor)
696
697 activities =
698 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
699
700 assert Enum.member?(activities, activity_two)
701 assert Enum.member?(activities, activity_three)
702 assert Enum.member?(activities, activity_one)
703
704 activity_three_actor = User.get_by_ap_id(activity_three.data["actor"])
705 {:ok, _user_relationships} = User.mute(user, activity_three_actor)
706 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
707 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
708 activity_three = Activity.get_by_id(activity_three.id)
709
710 activities =
711 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
712
713 assert Enum.member?(activities, activity_two)
714 refute Enum.member?(activities, activity_three)
715 refute Enum.member?(activities, boost_activity)
716 assert Enum.member?(activities, activity_one)
717
718 activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true})
719
720 assert Enum.member?(activities, activity_two)
721 assert Enum.member?(activities, activity_three)
722 assert Enum.member?(activities, boost_activity)
723 assert Enum.member?(activities, activity_one)
724 end
725
726 test "doesn't return thread muted activities" do
727 user = insert(:user)
728 _activity_one = insert(:note_activity)
729 note_two = insert(:note, data: %{"context" => "suya.."})
730 activity_two = insert(:note_activity, note: note_two)
731
732 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
733
734 assert [_activity_one] = ActivityPub.fetch_activities([], %{"muting_user" => user})
735 end
736
737 test "returns thread muted activities when with_muted is set" do
738 user = insert(:user)
739 _activity_one = insert(:note_activity)
740 note_two = insert(:note, data: %{"context" => "suya.."})
741 activity_two = insert(:note_activity, note: note_two)
742
743 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
744
745 assert [_activity_two, _activity_one] =
746 ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true})
747 end
748
749 test "does include announces on request" do
750 activity_three = insert(:note_activity)
751 user = insert(:user)
752 booster = insert(:user)
753
754 {:ok, user} = User.follow(user, booster)
755
756 {:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster)
757
758 [announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)])
759
760 assert announce_activity.id == announce.id
761 end
762
763 test "excludes reblogs on request" do
764 user = insert(:user)
765 {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
766 {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user})
767
768 [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"})
769
770 assert activity == expected_activity
771 end
772
773 describe "public fetch activities" do
774 test "doesn't retrieve unlisted activities" do
775 user = insert(:user)
776
777 {:ok, _unlisted_activity} =
778 CommonAPI.post(user, %{"status" => "yeah", "visibility" => "unlisted"})
779
780 {:ok, listed_activity} = CommonAPI.post(user, %{"status" => "yeah"})
781
782 [activity] = ActivityPub.fetch_public_activities()
783
784 assert activity == listed_activity
785 end
786
787 test "retrieves public activities" do
788 _activities = ActivityPub.fetch_public_activities()
789
790 %{public: public} = ActivityBuilder.public_and_non_public()
791
792 activities = ActivityPub.fetch_public_activities()
793 assert length(activities) == 1
794 assert Enum.at(activities, 0) == public
795 end
796
797 test "retrieves a maximum of 20 activities" do
798 ActivityBuilder.insert_list(10)
799 expected_activities = ActivityBuilder.insert_list(20)
800
801 activities = ActivityPub.fetch_public_activities()
802
803 assert collect_ids(activities) == collect_ids(expected_activities)
804 assert length(activities) == 20
805 end
806
807 test "retrieves ids starting from a since_id" do
808 activities = ActivityBuilder.insert_list(30)
809 expected_activities = ActivityBuilder.insert_list(10)
810 since_id = List.last(activities).id
811
812 activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id})
813
814 assert collect_ids(activities) == collect_ids(expected_activities)
815 assert length(activities) == 10
816 end
817
818 test "retrieves ids up to max_id" do
819 ActivityBuilder.insert_list(10)
820 expected_activities = ActivityBuilder.insert_list(20)
821
822 %{id: max_id} =
823 10
824 |> ActivityBuilder.insert_list()
825 |> List.first()
826
827 activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id})
828
829 assert length(activities) == 20
830 assert collect_ids(activities) == collect_ids(expected_activities)
831 end
832
833 test "paginates via offset/limit" do
834 _first_part_activities = ActivityBuilder.insert_list(10)
835 second_part_activities = ActivityBuilder.insert_list(10)
836
837 later_activities = ActivityBuilder.insert_list(10)
838
839 activities =
840 ActivityPub.fetch_public_activities(%{"page" => "2", "page_size" => "20"}, :offset)
841
842 assert length(activities) == 20
843
844 assert collect_ids(activities) ==
845 collect_ids(second_part_activities) ++ collect_ids(later_activities)
846 end
847
848 test "doesn't return reblogs for users for whom reblogs have been muted" do
849 activity = insert(:note_activity)
850 user = insert(:user)
851 booster = insert(:user)
852 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
853
854 {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
855
856 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
857
858 refute Enum.any?(activities, fn %{id: id} -> id == activity.id end)
859 end
860
861 test "returns reblogs for users for whom reblogs have not been muted" do
862 activity = insert(:note_activity)
863 user = insert(:user)
864 booster = insert(:user)
865 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
866 {:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster)
867
868 {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
869
870 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
871
872 assert Enum.any?(activities, fn %{id: id} -> id == activity.id end)
873 end
874 end
875
876 describe "react to an object" do
877 test_with_mock "sends an activity to federation", Federator, [:passthrough], [] do
878 Config.put([:instance, :federating], true)
879 user = insert(:user)
880 reactor = insert(:user)
881 {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
882 assert object = Object.normalize(activity)
883
884 {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥")
885
886 assert called(Federator.publish(reaction_activity))
887 end
888
889 test "adds an emoji reaction activity to the db" do
890 user = insert(:user)
891 reactor = insert(:user)
892 third_user = insert(:user)
893 fourth_user = insert(:user)
894 {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
895 assert object = Object.normalize(activity)
896
897 {:ok, reaction_activity, object} = ActivityPub.react_with_emoji(reactor, object, "🔥")
898
899 assert reaction_activity
900
901 assert reaction_activity.data["actor"] == reactor.ap_id
902 assert reaction_activity.data["type"] == "EmojiReact"
903 assert reaction_activity.data["content"] == "🔥"
904 assert reaction_activity.data["object"] == object.data["id"]
905 assert reaction_activity.data["to"] == [User.ap_followers(reactor), activity.data["actor"]]
906 assert reaction_activity.data["context"] == object.data["context"]
907 assert object.data["reaction_count"] == 1
908 assert object.data["reactions"] == [["🔥", [reactor.ap_id]]]
909
910 {:ok, _reaction_activity, object} = ActivityPub.react_with_emoji(third_user, object, "☕")
911
912 assert object.data["reaction_count"] == 2
913 assert object.data["reactions"] == [["🔥", [reactor.ap_id]], ["☕", [third_user.ap_id]]]
914
915 {:ok, _reaction_activity, object} = ActivityPub.react_with_emoji(fourth_user, object, "🔥")
916
917 assert object.data["reaction_count"] == 3
918
919 assert object.data["reactions"] == [
920 ["🔥", [fourth_user.ap_id, reactor.ap_id]],
921 ["☕", [third_user.ap_id]]
922 ]
923 end
924
925 test "reverts emoji reaction on error" do
926 [user, reactor] = insert_list(2, :user)
927
928 {:ok, activity} = CommonAPI.post(user, %{"status" => "Status"})
929 object = Object.normalize(activity)
930
931 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
932 assert {:error, :reverted} = ActivityPub.react_with_emoji(reactor, object, "😀")
933 end
934
935 object = Object.get_by_ap_id(object.data["id"])
936 refute object.data["reaction_count"]
937 refute object.data["reactions"]
938 end
939 end
940
941 describe "unreacting to an object" do
942 test_with_mock "sends an activity to federation", Federator, [:passthrough], [] do
943 Config.put([:instance, :federating], true)
944 user = insert(:user)
945 reactor = insert(:user)
946 {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
947 assert object = Object.normalize(activity)
948
949 {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥")
950
951 assert called(Federator.publish(reaction_activity))
952
953 {:ok, unreaction_activity, _object} =
954 ActivityPub.unreact_with_emoji(reactor, reaction_activity.data["id"])
955
956 assert called(Federator.publish(unreaction_activity))
957 end
958
959 test "adds an undo activity to the db" do
960 user = insert(:user)
961 reactor = insert(:user)
962 {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
963 assert object = Object.normalize(activity)
964
965 {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥")
966
967 {:ok, unreaction_activity, _object} =
968 ActivityPub.unreact_with_emoji(reactor, reaction_activity.data["id"])
969
970 assert unreaction_activity.actor == reactor.ap_id
971 assert unreaction_activity.data["object"] == reaction_activity.data["id"]
972
973 object = Object.get_by_ap_id(object.data["id"])
974 assert object.data["reaction_count"] == 0
975 assert object.data["reactions"] == []
976 end
977
978 test "reverts emoji unreact on error" do
979 [user, reactor] = insert_list(2, :user)
980 {:ok, activity} = CommonAPI.post(user, %{"status" => "Status"})
981 object = Object.normalize(activity)
982
983 {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "😀")
984
985 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
986 assert {:error, :reverted} =
987 ActivityPub.unreact_with_emoji(reactor, reaction_activity.data["id"])
988 end
989
990 object = Object.get_by_ap_id(object.data["id"])
991
992 assert object.data["reaction_count"] == 1
993 assert object.data["reactions"] == [["😀", [reactor.ap_id]]]
994 end
995 end
996
997 describe "unliking" do
998 test_with_mock "sends an activity to federation", Federator, [:passthrough], [] do
999 Config.put([:instance, :federating], true)
1000
1001 note_activity = insert(:note_activity)
1002 object = Object.normalize(note_activity)
1003 user = insert(:user)
1004
1005 {:ok, object} = ActivityPub.unlike(user, object)
1006 refute called(Federator.publish())
1007
1008 {:ok, _like_activity} = CommonAPI.favorite(user, note_activity.id)
1009 object = Object.get_by_id(object.id)
1010 assert object.data["like_count"] == 1
1011
1012 {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
1013 assert object.data["like_count"] == 0
1014
1015 assert called(Federator.publish(unlike_activity))
1016 end
1017
1018 test "reverts unliking on error" do
1019 note_activity = insert(:note_activity)
1020 user = insert(:user)
1021
1022 {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
1023 object = Object.normalize(note_activity)
1024 assert object.data["like_count"] == 1
1025
1026 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
1027 assert {:error, :reverted} = ActivityPub.unlike(user, object)
1028 end
1029
1030 assert Object.get_by_ap_id(object.data["id"]) == object
1031 assert object.data["like_count"] == 1
1032 assert Activity.get_by_id(like_activity.id)
1033 end
1034
1035 test "unliking a previously liked object" do
1036 note_activity = insert(:note_activity)
1037 object = Object.normalize(note_activity)
1038 user = insert(:user)
1039
1040 # Unliking something that hasn't been liked does nothing
1041 {:ok, object} = ActivityPub.unlike(user, object)
1042 assert object.data["like_count"] == 0
1043
1044 {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
1045
1046 object = Object.get_by_id(object.id)
1047 assert object.data["like_count"] == 1
1048
1049 {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
1050 assert object.data["like_count"] == 0
1051
1052 assert Activity.get_by_id(like_activity.id) == nil
1053 assert note_activity.actor in unlike_activity.recipients
1054 end
1055 end
1056
1057 describe "announcing an object" do
1058 test "adds an announce activity to the db" do
1059 note_activity = insert(:note_activity)
1060 object = Object.normalize(note_activity)
1061 user = insert(:user)
1062
1063 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
1064 assert object.data["announcement_count"] == 1
1065 assert object.data["announcements"] == [user.ap_id]
1066
1067 assert announce_activity.data["to"] == [
1068 User.ap_followers(user),
1069 note_activity.data["actor"]
1070 ]
1071
1072 assert announce_activity.data["object"] == object.data["id"]
1073 assert announce_activity.data["actor"] == user.ap_id
1074 assert announce_activity.data["context"] == object.data["context"]
1075 end
1076
1077 test "reverts annouce from object on error" do
1078 note_activity = insert(:note_activity)
1079 object = Object.normalize(note_activity)
1080 user = insert(:user)
1081
1082 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
1083 assert {:error, :reverted} = ActivityPub.announce(user, object)
1084 end
1085
1086 reloaded_object = Object.get_by_ap_id(object.data["id"])
1087 assert reloaded_object == object
1088 refute reloaded_object.data["announcement_count"]
1089 refute reloaded_object.data["announcements"]
1090 end
1091 end
1092
1093 describe "announcing a private object" do
1094 test "adds an announce activity to the db if the audience is not widened" do
1095 user = insert(:user)
1096 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
1097 object = Object.normalize(note_activity)
1098
1099 {:ok, announce_activity, object} = ActivityPub.announce(user, object, nil, true, false)
1100
1101 assert announce_activity.data["to"] == [User.ap_followers(user)]
1102
1103 assert announce_activity.data["object"] == object.data["id"]
1104 assert announce_activity.data["actor"] == user.ap_id
1105 assert announce_activity.data["context"] == object.data["context"]
1106 end
1107
1108 test "does not add an announce activity to the db if the audience is widened" do
1109 user = insert(:user)
1110 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
1111 object = Object.normalize(note_activity)
1112
1113 assert {:error, _} = ActivityPub.announce(user, object, nil, true, true)
1114 end
1115
1116 test "does not add an announce activity to the db if the announcer is not the author" do
1117 user = insert(:user)
1118 announcer = insert(:user)
1119 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
1120 object = Object.normalize(note_activity)
1121
1122 assert {:error, _} = ActivityPub.announce(announcer, object, nil, true, false)
1123 end
1124 end
1125
1126 describe "unannouncing an object" do
1127 test "unannouncing a previously announced object" do
1128 note_activity = insert(:note_activity)
1129 object = Object.normalize(note_activity)
1130 user = insert(:user)
1131
1132 # Unannouncing an object that is not announced does nothing
1133 {:ok, object} = ActivityPub.unannounce(user, object)
1134 refute object.data["announcement_count"]
1135
1136 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
1137 assert object.data["announcement_count"] == 1
1138
1139 {:ok, unannounce_activity, object} = ActivityPub.unannounce(user, object)
1140 assert object.data["announcement_count"] == 0
1141
1142 assert unannounce_activity.data["to"] == [
1143 User.ap_followers(user),
1144 object.data["actor"]
1145 ]
1146
1147 assert unannounce_activity.data["type"] == "Undo"
1148 assert unannounce_activity.data["object"] == announce_activity.data
1149 assert unannounce_activity.data["actor"] == user.ap_id
1150 assert unannounce_activity.data["context"] == announce_activity.data["context"]
1151
1152 assert Activity.get_by_id(announce_activity.id) == nil
1153 end
1154
1155 test "reverts unannouncing on error" do
1156 note_activity = insert(:note_activity)
1157 object = Object.normalize(note_activity)
1158 user = insert(:user)
1159
1160 {:ok, _announce_activity, object} = ActivityPub.announce(user, object)
1161 assert object.data["announcement_count"] == 1
1162
1163 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
1164 assert {:error, :reverted} = ActivityPub.unannounce(user, object)
1165 end
1166
1167 object = Object.get_by_ap_id(object.data["id"])
1168 assert object.data["announcement_count"] == 1
1169 end
1170 end
1171
1172 describe "uploading files" do
1173 test "copies the file to the configured folder" do
1174 file = %Plug.Upload{
1175 content_type: "image/jpg",
1176 path: Path.absname("test/fixtures/image.jpg"),
1177 filename: "an_image.jpg"
1178 }
1179
1180 {:ok, %Object{} = object} = ActivityPub.upload(file)
1181 assert object.data["name"] == "an_image.jpg"
1182 end
1183
1184 test "works with base64 encoded images" do
1185 file = %{
1186 "img" => data_uri()
1187 }
1188
1189 {:ok, %Object{}} = ActivityPub.upload(file)
1190 end
1191 end
1192
1193 describe "fetch the latest Follow" do
1194 test "fetches the latest Follow activity" do
1195 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
1196 follower = Repo.get_by(User, ap_id: activity.data["actor"])
1197 followed = Repo.get_by(User, ap_id: activity.data["object"])
1198
1199 assert activity == Utils.fetch_latest_follow(follower, followed)
1200 end
1201 end
1202
1203 describe "following / unfollowing" do
1204 test "it reverts follow activity" do
1205 follower = insert(:user)
1206 followed = insert(:user)
1207
1208 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
1209 assert {:error, :reverted} = ActivityPub.follow(follower, followed)
1210 end
1211
1212 assert Repo.aggregate(Activity, :count, :id) == 0
1213 assert Repo.aggregate(Object, :count, :id) == 0
1214 end
1215
1216 test "it reverts unfollow activity" do
1217 follower = insert(:user)
1218 followed = insert(:user)
1219
1220 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
1221
1222 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
1223 assert {:error, :reverted} = ActivityPub.unfollow(follower, followed)
1224 end
1225
1226 activity = Activity.get_by_id(follow_activity.id)
1227 assert activity.data["type"] == "Follow"
1228 assert activity.data["actor"] == follower.ap_id
1229
1230 assert activity.data["object"] == followed.ap_id
1231 end
1232
1233 test "creates a follow activity" do
1234 follower = insert(:user)
1235 followed = insert(:user)
1236
1237 {:ok, activity} = ActivityPub.follow(follower, followed)
1238 assert activity.data["type"] == "Follow"
1239 assert activity.data["actor"] == follower.ap_id
1240 assert activity.data["object"] == followed.ap_id
1241 end
1242
1243 test "creates an undo activity for the last follow" do
1244 follower = insert(:user)
1245 followed = insert(:user)
1246
1247 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
1248 {:ok, activity} = ActivityPub.unfollow(follower, followed)
1249
1250 assert activity.data["type"] == "Undo"
1251 assert activity.data["actor"] == follower.ap_id
1252
1253 embedded_object = activity.data["object"]
1254 assert is_map(embedded_object)
1255 assert embedded_object["type"] == "Follow"
1256 assert embedded_object["object"] == followed.ap_id
1257 assert embedded_object["id"] == follow_activity.data["id"]
1258 end
1259
1260 test "creates an undo activity for a pending follow request" do
1261 follower = insert(:user)
1262 followed = insert(:user, %{locked: true})
1263
1264 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
1265 {:ok, activity} = ActivityPub.unfollow(follower, followed)
1266
1267 assert activity.data["type"] == "Undo"
1268 assert activity.data["actor"] == follower.ap_id
1269
1270 embedded_object = activity.data["object"]
1271 assert is_map(embedded_object)
1272 assert embedded_object["type"] == "Follow"
1273 assert embedded_object["object"] == followed.ap_id
1274 assert embedded_object["id"] == follow_activity.data["id"]
1275 end
1276 end
1277
1278 describe "blocking / unblocking" do
1279 test "reverts block activity on error" do
1280 [blocker, blocked] = insert_list(2, :user)
1281
1282 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
1283 assert {:error, :reverted} = ActivityPub.block(blocker, blocked)
1284 end
1285
1286 assert Repo.aggregate(Activity, :count, :id) == 0
1287 assert Repo.aggregate(Object, :count, :id) == 0
1288 end
1289
1290 test "creates a block activity" do
1291 blocker = insert(:user)
1292 blocked = insert(:user)
1293
1294 {:ok, activity} = ActivityPub.block(blocker, blocked)
1295
1296 assert activity.data["type"] == "Block"
1297 assert activity.data["actor"] == blocker.ap_id
1298 assert activity.data["object"] == blocked.ap_id
1299 end
1300
1301 test "reverts unblock activity on error" do
1302 [blocker, blocked] = insert_list(2, :user)
1303 {:ok, block_activity} = ActivityPub.block(blocker, blocked)
1304
1305 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
1306 assert {:error, :reverted} = ActivityPub.unblock(blocker, blocked)
1307 end
1308
1309 assert block_activity.data["type"] == "Block"
1310 assert block_activity.data["actor"] == blocker.ap_id
1311
1312 assert Repo.aggregate(Activity, :count, :id) == 1
1313 assert Repo.aggregate(Object, :count, :id) == 1
1314 end
1315
1316 test "creates an undo activity for the last block" do
1317 blocker = insert(:user)
1318 blocked = insert(:user)
1319
1320 {:ok, block_activity} = ActivityPub.block(blocker, blocked)
1321 {:ok, activity} = ActivityPub.unblock(blocker, blocked)
1322
1323 assert activity.data["type"] == "Undo"
1324 assert activity.data["actor"] == blocker.ap_id
1325
1326 embedded_object = activity.data["object"]
1327 assert is_map(embedded_object)
1328 assert embedded_object["type"] == "Block"
1329 assert embedded_object["object"] == blocked.ap_id
1330 assert embedded_object["id"] == block_activity.data["id"]
1331 end
1332 end
1333
1334 describe "timeline post-processing" do
1335 test "it filters broken threads" do
1336 user1 = insert(:user)
1337 user2 = insert(:user)
1338 user3 = insert(:user)
1339
1340 {:ok, user1} = User.follow(user1, user3)
1341 assert User.following?(user1, user3)
1342
1343 {:ok, user2} = User.follow(user2, user3)
1344 assert User.following?(user2, user3)
1345
1346 {:ok, user3} = User.follow(user3, user2)
1347 assert User.following?(user3, user2)
1348
1349 {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
1350
1351 {:ok, private_activity_1} =
1352 CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
1353
1354 {:ok, private_activity_2} =
1355 CommonAPI.post(user2, %{
1356 "status" => "hi 3",
1357 "visibility" => "private",
1358 "in_reply_to_status_id" => private_activity_1.id
1359 })
1360
1361 {:ok, private_activity_3} =
1362 CommonAPI.post(user3, %{
1363 "status" => "hi 4",
1364 "visibility" => "private",
1365 "in_reply_to_status_id" => private_activity_2.id
1366 })
1367
1368 activities =
1369 ActivityPub.fetch_activities([user1.ap_id | User.following(user1)])
1370 |> Enum.map(fn a -> a.id end)
1371
1372 private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"])
1373
1374 assert [public_activity.id, private_activity_1.id, private_activity_3.id] == activities
1375
1376 assert length(activities) == 3
1377
1378 activities =
1379 ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{"user" => user1})
1380 |> Enum.map(fn a -> a.id end)
1381
1382 assert [public_activity.id, private_activity_1.id] == activities
1383 assert length(activities) == 2
1384 end
1385 end
1386
1387 describe "update" do
1388 setup do: clear_config([:instance, :max_pinned_statuses])
1389
1390 test "it creates an update activity with the new user data" do
1391 user = insert(:user)
1392 {:ok, user} = User.ensure_keys_present(user)
1393 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
1394
1395 {:ok, update} =
1396 ActivityPub.update(%{
1397 actor: user_data["id"],
1398 to: [user.follower_address],
1399 cc: [],
1400 object: user_data
1401 })
1402
1403 assert update.data["actor"] == user.ap_id
1404 assert update.data["to"] == [user.follower_address]
1405 assert embedded_object = update.data["object"]
1406 assert embedded_object["id"] == user_data["id"]
1407 assert embedded_object["type"] == user_data["type"]
1408 end
1409 end
1410
1411 test "returned pinned statuses" do
1412 Config.put([:instance, :max_pinned_statuses], 3)
1413 user = insert(:user)
1414
1415 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
1416 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
1417 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
1418
1419 CommonAPI.pin(activity_one.id, user)
1420 user = refresh_record(user)
1421
1422 CommonAPI.pin(activity_two.id, user)
1423 user = refresh_record(user)
1424
1425 CommonAPI.pin(activity_three.id, user)
1426 user = refresh_record(user)
1427
1428 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
1429
1430 assert 3 = length(activities)
1431 end
1432
1433 describe "flag/1" do
1434 setup do
1435 reporter = insert(:user)
1436 target_account = insert(:user)
1437 content = "foobar"
1438 {:ok, activity} = CommonAPI.post(target_account, %{"status" => content})
1439 context = Utils.generate_context_id()
1440
1441 reporter_ap_id = reporter.ap_id
1442 target_ap_id = target_account.ap_id
1443 activity_ap_id = activity.data["id"]
1444
1445 activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id)
1446
1447 {:ok,
1448 %{
1449 reporter: reporter,
1450 context: context,
1451 target_account: target_account,
1452 reported_activity: activity,
1453 content: content,
1454 activity_ap_id: activity_ap_id,
1455 activity_with_object: activity_with_object,
1456 reporter_ap_id: reporter_ap_id,
1457 target_ap_id: target_ap_id
1458 }}
1459 end
1460
1461 test "it can create a Flag activity",
1462 %{
1463 reporter: reporter,
1464 context: context,
1465 target_account: target_account,
1466 reported_activity: reported_activity,
1467 content: content,
1468 activity_ap_id: activity_ap_id,
1469 activity_with_object: activity_with_object,
1470 reporter_ap_id: reporter_ap_id,
1471 target_ap_id: target_ap_id
1472 } do
1473 assert {:ok, activity} =
1474 ActivityPub.flag(%{
1475 actor: reporter,
1476 context: context,
1477 account: target_account,
1478 statuses: [reported_activity],
1479 content: content
1480 })
1481
1482 note_obj = %{
1483 "type" => "Note",
1484 "id" => activity_ap_id,
1485 "content" => content,
1486 "published" => activity_with_object.object.data["published"],
1487 "actor" => AccountView.render("show.json", %{user: target_account})
1488 }
1489
1490 assert %Activity{
1491 actor: ^reporter_ap_id,
1492 data: %{
1493 "type" => "Flag",
1494 "content" => ^content,
1495 "context" => ^context,
1496 "object" => [^target_ap_id, ^note_obj]
1497 }
1498 } = activity
1499 end
1500
1501 test_with_mock "strips status data from Flag, before federating it",
1502 %{
1503 reporter: reporter,
1504 context: context,
1505 target_account: target_account,
1506 reported_activity: reported_activity,
1507 content: content
1508 },
1509 Utils,
1510 [:passthrough],
1511 [] do
1512 {:ok, activity} =
1513 ActivityPub.flag(%{
1514 actor: reporter,
1515 context: context,
1516 account: target_account,
1517 statuses: [reported_activity],
1518 content: content
1519 })
1520
1521 new_data =
1522 put_in(activity.data, ["object"], [target_account.ap_id, reported_activity.data["id"]])
1523
1524 assert_called(Utils.maybe_federate(%{activity | data: new_data}))
1525 end
1526 end
1527
1528 test "fetch_activities/2 returns activities addressed to a list " do
1529 user = insert(:user)
1530 member = insert(:user)
1531 {:ok, list} = Pleroma.List.create("foo", user)
1532 {:ok, list} = Pleroma.List.follow(list, member)
1533
1534 {:ok, activity} =
1535 CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
1536
1537 activity = Repo.preload(activity, :bookmark)
1538 activity = %Activity{activity | thread_muted?: !!activity.thread_muted?}
1539
1540 assert ActivityPub.fetch_activities([], %{"user" => user}) == [activity]
1541 end
1542
1543 def data_uri do
1544 File.read!("test/fixtures/avatar_data_uri")
1545 end
1546
1547 describe "fetch_activities_bounded" do
1548 test "fetches private posts for followed users" do
1549 user = insert(:user)
1550
1551 {:ok, activity} =
1552 CommonAPI.post(user, %{
1553 "status" => "thought I looked cute might delete later :3",
1554 "visibility" => "private"
1555 })
1556
1557 [result] = ActivityPub.fetch_activities_bounded([user.follower_address], [])
1558 assert result.id == activity.id
1559 end
1560
1561 test "fetches only public posts for other users" do
1562 user = insert(:user)
1563 {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe", "visibility" => "public"})
1564
1565 {:ok, _private_activity} =
1566 CommonAPI.post(user, %{
1567 "status" => "why is tenshi eating a corndog so cute?",
1568 "visibility" => "private"
1569 })
1570
1571 [result] = ActivityPub.fetch_activities_bounded([], [user.follower_address])
1572 assert result.id == activity.id
1573 end
1574 end
1575
1576 describe "fetch_follow_information_for_user" do
1577 test "syncronizes following/followers counters" do
1578 user =
1579 insert(:user,
1580 local: false,
1581 follower_address: "http://localhost:4001/users/fuser2/followers",
1582 following_address: "http://localhost:4001/users/fuser2/following"
1583 )
1584
1585 {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
1586 assert info.follower_count == 527
1587 assert info.following_count == 267
1588 end
1589
1590 test "detects hidden followers" do
1591 mock(fn env ->
1592 case env.url do
1593 "http://localhost:4001/users/masto_closed/followers?page=1" ->
1594 %Tesla.Env{status: 403, body: ""}
1595
1596 _ ->
1597 apply(HttpRequestMock, :request, [env])
1598 end
1599 end)
1600
1601 user =
1602 insert(:user,
1603 local: false,
1604 follower_address: "http://localhost:4001/users/masto_closed/followers",
1605 following_address: "http://localhost:4001/users/masto_closed/following"
1606 )
1607
1608 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1609 assert follow_info.hide_followers == true
1610 assert follow_info.hide_follows == false
1611 end
1612
1613 test "detects hidden follows" do
1614 mock(fn env ->
1615 case env.url do
1616 "http://localhost:4001/users/masto_closed/following?page=1" ->
1617 %Tesla.Env{status: 403, body: ""}
1618
1619 _ ->
1620 apply(HttpRequestMock, :request, [env])
1621 end
1622 end)
1623
1624 user =
1625 insert(:user,
1626 local: false,
1627 follower_address: "http://localhost:4001/users/masto_closed/followers",
1628 following_address: "http://localhost:4001/users/masto_closed/following"
1629 )
1630
1631 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1632 assert follow_info.hide_followers == false
1633 assert follow_info.hide_follows == true
1634 end
1635
1636 test "detects hidden follows/followers for friendica" do
1637 user =
1638 insert(:user,
1639 local: false,
1640 follower_address: "http://localhost:8080/followers/fuser3",
1641 following_address: "http://localhost:8080/following/fuser3"
1642 )
1643
1644 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1645 assert follow_info.hide_followers == true
1646 assert follow_info.follower_count == 296
1647 assert follow_info.following_count == 32
1648 assert follow_info.hide_follows == true
1649 end
1650
1651 test "doesn't crash when follower and following counters are hidden" do
1652 mock(fn env ->
1653 case env.url do
1654 "http://localhost:4001/users/masto_hidden_counters/following" ->
1655 json(%{
1656 "@context" => "https://www.w3.org/ns/activitystreams",
1657 "id" => "http://localhost:4001/users/masto_hidden_counters/followers"
1658 })
1659
1660 "http://localhost:4001/users/masto_hidden_counters/following?page=1" ->
1661 %Tesla.Env{status: 403, body: ""}
1662
1663 "http://localhost:4001/users/masto_hidden_counters/followers" ->
1664 json(%{
1665 "@context" => "https://www.w3.org/ns/activitystreams",
1666 "id" => "http://localhost:4001/users/masto_hidden_counters/following"
1667 })
1668
1669 "http://localhost:4001/users/masto_hidden_counters/followers?page=1" ->
1670 %Tesla.Env{status: 403, body: ""}
1671 end
1672 end)
1673
1674 user =
1675 insert(:user,
1676 local: false,
1677 follower_address: "http://localhost:4001/users/masto_hidden_counters/followers",
1678 following_address: "http://localhost:4001/users/masto_hidden_counters/following"
1679 )
1680
1681 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1682
1683 assert follow_info.hide_followers == true
1684 assert follow_info.follower_count == 0
1685 assert follow_info.hide_follows == true
1686 assert follow_info.following_count == 0
1687 end
1688 end
1689
1690 describe "fetch_favourites/3" do
1691 test "returns a favourite activities sorted by adds to favorite" do
1692 user = insert(:user)
1693 other_user = insert(:user)
1694 user1 = insert(:user)
1695 user2 = insert(:user)
1696 {:ok, a1} = CommonAPI.post(user1, %{"status" => "bla"})
1697 {:ok, _a2} = CommonAPI.post(user2, %{"status" => "traps are happy"})
1698 {:ok, a3} = CommonAPI.post(user2, %{"status" => "Trees Are "})
1699 {:ok, a4} = CommonAPI.post(user2, %{"status" => "Agent Smith "})
1700 {:ok, a5} = CommonAPI.post(user1, %{"status" => "Red or Blue "})
1701
1702 {:ok, _} = CommonAPI.favorite(user, a4.id)
1703 {:ok, _} = CommonAPI.favorite(other_user, a3.id)
1704 {:ok, _} = CommonAPI.favorite(user, a3.id)
1705 {:ok, _} = CommonAPI.favorite(other_user, a5.id)
1706 {:ok, _} = CommonAPI.favorite(user, a5.id)
1707 {:ok, _} = CommonAPI.favorite(other_user, a4.id)
1708 {:ok, _} = CommonAPI.favorite(user, a1.id)
1709 {:ok, _} = CommonAPI.favorite(other_user, a1.id)
1710 result = ActivityPub.fetch_favourites(user)
1711
1712 assert Enum.map(result, & &1.id) == [a1.id, a5.id, a3.id, a4.id]
1713
1714 result = ActivityPub.fetch_favourites(user, %{"limit" => 2})
1715 assert Enum.map(result, & &1.id) == [a1.id, a5.id]
1716 end
1717 end
1718
1719 describe "Move activity" do
1720 test "create" do
1721 %{ap_id: old_ap_id} = old_user = insert(:user)
1722 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
1723 follower = insert(:user)
1724 follower_move_opted_out = insert(:user, allow_following_move: false)
1725
1726 User.follow(follower, old_user)
1727 User.follow(follower_move_opted_out, old_user)
1728
1729 assert User.following?(follower, old_user)
1730 assert User.following?(follower_move_opted_out, old_user)
1731
1732 assert {:ok, activity} = ActivityPub.move(old_user, new_user)
1733
1734 assert %Activity{
1735 actor: ^old_ap_id,
1736 data: %{
1737 "actor" => ^old_ap_id,
1738 "object" => ^old_ap_id,
1739 "target" => ^new_ap_id,
1740 "type" => "Move"
1741 },
1742 local: true
1743 } = activity
1744
1745 params = %{
1746 "op" => "move_following",
1747 "origin_id" => old_user.id,
1748 "target_id" => new_user.id
1749 }
1750
1751 assert_enqueued(worker: Pleroma.Workers.BackgroundWorker, args: params)
1752
1753 Pleroma.Workers.BackgroundWorker.perform(params, nil)
1754
1755 refute User.following?(follower, old_user)
1756 assert User.following?(follower, new_user)
1757
1758 assert User.following?(follower_move_opted_out, old_user)
1759 refute User.following?(follower_move_opted_out, new_user)
1760
1761 activity = %Activity{activity | object: nil}
1762
1763 assert [%Notification{activity: ^activity}] = Notification.for_user(follower)
1764
1765 assert [%Notification{activity: ^activity}] = Notification.for_user(follower_move_opted_out)
1766 end
1767
1768 test "old user must be in the new user's `also_known_as` list" do
1769 old_user = insert(:user)
1770 new_user = insert(:user)
1771
1772 assert {:error, "Target account must have the origin in `alsoKnownAs`"} =
1773 ActivityPub.move(old_user, new_user)
1774 end
1775 end
1776
1777 test "doesn't retrieve replies activities with exclude_replies" do
1778 user = insert(:user)
1779
1780 {:ok, activity} = CommonAPI.post(user, %{"status" => "yeah"})
1781
1782 {:ok, _reply} =
1783 CommonAPI.post(user, %{"status" => "yeah", "in_reply_to_status_id" => activity.id})
1784
1785 [result] = ActivityPub.fetch_public_activities(%{"exclude_replies" => "true"})
1786
1787 assert result.id == activity.id
1788
1789 assert length(ActivityPub.fetch_public_activities()) == 2
1790 end
1791
1792 describe "replies filtering with public messages" do
1793 setup :public_messages
1794
1795 test "public timeline", %{users: %{u1: user}} do
1796 activities_ids =
1797 %{}
1798 |> Map.put("type", ["Create", "Announce"])
1799 |> Map.put("local_only", false)
1800 |> Map.put("blocking_user", user)
1801 |> Map.put("muting_user", user)
1802 |> Map.put("reply_filtering_user", user)
1803 |> ActivityPub.fetch_public_activities()
1804 |> Enum.map(& &1.id)
1805
1806 assert length(activities_ids) == 16
1807 end
1808
1809 test "public timeline with reply_visibility `following`", %{
1810 users: %{u1: user},
1811 u1: u1,
1812 u2: u2,
1813 u3: u3,
1814 u4: u4,
1815 activities: activities
1816 } do
1817 activities_ids =
1818 %{}
1819 |> Map.put("type", ["Create", "Announce"])
1820 |> Map.put("local_only", false)
1821 |> Map.put("blocking_user", user)
1822 |> Map.put("muting_user", user)
1823 |> Map.put("reply_visibility", "following")
1824 |> Map.put("reply_filtering_user", user)
1825 |> ActivityPub.fetch_public_activities()
1826 |> Enum.map(& &1.id)
1827
1828 assert length(activities_ids) == 14
1829
1830 visible_ids =
1831 Map.values(u1) ++ Map.values(u2) ++ Map.values(u4) ++ Map.values(activities) ++ [u3[:r1]]
1832
1833 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1834 end
1835
1836 test "public timeline with reply_visibility `self`", %{
1837 users: %{u1: user},
1838 u1: u1,
1839 u2: u2,
1840 u3: u3,
1841 u4: u4,
1842 activities: activities
1843 } do
1844 activities_ids =
1845 %{}
1846 |> Map.put("type", ["Create", "Announce"])
1847 |> Map.put("local_only", false)
1848 |> Map.put("blocking_user", user)
1849 |> Map.put("muting_user", user)
1850 |> Map.put("reply_visibility", "self")
1851 |> Map.put("reply_filtering_user", user)
1852 |> ActivityPub.fetch_public_activities()
1853 |> Enum.map(& &1.id)
1854
1855 assert length(activities_ids) == 10
1856 visible_ids = Map.values(u1) ++ [u2[:r1], u3[:r1], u4[:r1]] ++ Map.values(activities)
1857 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1858 end
1859
1860 test "home timeline", %{
1861 users: %{u1: user},
1862 activities: activities,
1863 u1: u1,
1864 u2: u2,
1865 u3: u3,
1866 u4: u4
1867 } do
1868 params =
1869 %{}
1870 |> Map.put("type", ["Create", "Announce"])
1871 |> Map.put("blocking_user", user)
1872 |> Map.put("muting_user", user)
1873 |> Map.put("user", user)
1874 |> Map.put("reply_filtering_user", user)
1875
1876 activities_ids =
1877 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
1878 |> Enum.map(& &1.id)
1879
1880 assert length(activities_ids) == 13
1881
1882 visible_ids =
1883 Map.values(u1) ++
1884 Map.values(u3) ++
1885 [
1886 activities[:a1],
1887 activities[:a2],
1888 activities[:a4],
1889 u2[:r1],
1890 u2[:r3],
1891 u4[:r1],
1892 u4[:r2]
1893 ]
1894
1895 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1896 end
1897
1898 test "home timeline with reply_visibility `following`", %{
1899 users: %{u1: user},
1900 activities: activities,
1901 u1: u1,
1902 u2: u2,
1903 u3: u3,
1904 u4: u4
1905 } do
1906 params =
1907 %{}
1908 |> Map.put("type", ["Create", "Announce"])
1909 |> Map.put("blocking_user", user)
1910 |> Map.put("muting_user", user)
1911 |> Map.put("user", user)
1912 |> Map.put("reply_visibility", "following")
1913 |> Map.put("reply_filtering_user", user)
1914
1915 activities_ids =
1916 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
1917 |> Enum.map(& &1.id)
1918
1919 assert length(activities_ids) == 11
1920
1921 visible_ids =
1922 Map.values(u1) ++
1923 [
1924 activities[:a1],
1925 activities[:a2],
1926 activities[:a4],
1927 u2[:r1],
1928 u2[:r3],
1929 u3[:r1],
1930 u4[:r1],
1931 u4[:r2]
1932 ]
1933
1934 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1935 end
1936
1937 test "home timeline with reply_visibility `self`", %{
1938 users: %{u1: user},
1939 activities: activities,
1940 u1: u1,
1941 u2: u2,
1942 u3: u3,
1943 u4: u4
1944 } do
1945 params =
1946 %{}
1947 |> Map.put("type", ["Create", "Announce"])
1948 |> Map.put("blocking_user", user)
1949 |> Map.put("muting_user", user)
1950 |> Map.put("user", user)
1951 |> Map.put("reply_visibility", "self")
1952 |> Map.put("reply_filtering_user", user)
1953
1954 activities_ids =
1955 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
1956 |> Enum.map(& &1.id)
1957
1958 assert length(activities_ids) == 9
1959
1960 visible_ids =
1961 Map.values(u1) ++
1962 [
1963 activities[:a1],
1964 activities[:a2],
1965 activities[:a4],
1966 u2[:r1],
1967 u3[:r1],
1968 u4[:r1]
1969 ]
1970
1971 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1972 end
1973 end
1974
1975 describe "replies filtering with private messages" do
1976 setup :private_messages
1977
1978 test "public timeline", %{users: %{u1: user}} do
1979 activities_ids =
1980 %{}
1981 |> Map.put("type", ["Create", "Announce"])
1982 |> Map.put("local_only", false)
1983 |> Map.put("blocking_user", user)
1984 |> Map.put("muting_user", user)
1985 |> Map.put("user", user)
1986 |> ActivityPub.fetch_public_activities()
1987 |> Enum.map(& &1.id)
1988
1989 assert activities_ids == []
1990 end
1991
1992 test "public timeline with default reply_visibility `following`", %{users: %{u1: user}} do
1993 activities_ids =
1994 %{}
1995 |> Map.put("type", ["Create", "Announce"])
1996 |> Map.put("local_only", false)
1997 |> Map.put("blocking_user", user)
1998 |> Map.put("muting_user", user)
1999 |> Map.put("reply_visibility", "following")
2000 |> Map.put("reply_filtering_user", user)
2001 |> Map.put("user", user)
2002 |> ActivityPub.fetch_public_activities()
2003 |> Enum.map(& &1.id)
2004
2005 assert activities_ids == []
2006 end
2007
2008 test "public timeline with default reply_visibility `self`", %{users: %{u1: user}} do
2009 activities_ids =
2010 %{}
2011 |> Map.put("type", ["Create", "Announce"])
2012 |> Map.put("local_only", false)
2013 |> Map.put("blocking_user", user)
2014 |> Map.put("muting_user", user)
2015 |> Map.put("reply_visibility", "self")
2016 |> Map.put("reply_filtering_user", user)
2017 |> Map.put("user", user)
2018 |> ActivityPub.fetch_public_activities()
2019 |> Enum.map(& &1.id)
2020
2021 assert activities_ids == []
2022 end
2023
2024 test "home timeline", %{users: %{u1: user}} do
2025 params =
2026 %{}
2027 |> Map.put("type", ["Create", "Announce"])
2028 |> Map.put("blocking_user", user)
2029 |> Map.put("muting_user", user)
2030 |> Map.put("user", user)
2031
2032 activities_ids =
2033 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
2034 |> Enum.map(& &1.id)
2035
2036 assert length(activities_ids) == 12
2037 end
2038
2039 test "home timeline with default reply_visibility `following`", %{users: %{u1: user}} do
2040 params =
2041 %{}
2042 |> Map.put("type", ["Create", "Announce"])
2043 |> Map.put("blocking_user", user)
2044 |> Map.put("muting_user", user)
2045 |> Map.put("user", user)
2046 |> Map.put("reply_visibility", "following")
2047 |> Map.put("reply_filtering_user", user)
2048
2049 activities_ids =
2050 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
2051 |> Enum.map(& &1.id)
2052
2053 assert length(activities_ids) == 12
2054 end
2055
2056 test "home timeline with default reply_visibility `self`", %{
2057 users: %{u1: user},
2058 activities: activities,
2059 u1: u1,
2060 u2: u2,
2061 u3: u3,
2062 u4: u4
2063 } do
2064 params =
2065 %{}
2066 |> Map.put("type", ["Create", "Announce"])
2067 |> Map.put("blocking_user", user)
2068 |> Map.put("muting_user", user)
2069 |> Map.put("user", user)
2070 |> Map.put("reply_visibility", "self")
2071 |> Map.put("reply_filtering_user", user)
2072
2073 activities_ids =
2074 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
2075 |> Enum.map(& &1.id)
2076
2077 assert length(activities_ids) == 10
2078
2079 visible_ids =
2080 Map.values(u1) ++ Map.values(u4) ++ [u2[:r1], u3[:r1]] ++ Map.values(activities)
2081
2082 assert Enum.all?(visible_ids, &(&1 in activities_ids))
2083 end
2084 end
2085
2086 defp public_messages(_) do
2087 [u1, u2, u3, u4] = insert_list(4, :user)
2088 {:ok, u1} = User.follow(u1, u2)
2089 {:ok, u2} = User.follow(u2, u1)
2090 {:ok, u1} = User.follow(u1, u4)
2091 {:ok, u4} = User.follow(u4, u1)
2092
2093 {:ok, u2} = User.follow(u2, u3)
2094 {:ok, u3} = User.follow(u3, u2)
2095
2096 {:ok, a1} = CommonAPI.post(u1, %{"status" => "Status"})
2097
2098 {:ok, r1_1} =
2099 CommonAPI.post(u2, %{
2100 "status" => "@#{u1.nickname} reply from u2 to u1",
2101 "in_reply_to_status_id" => a1.id
2102 })
2103
2104 {:ok, r1_2} =
2105 CommonAPI.post(u3, %{
2106 "status" => "@#{u1.nickname} reply from u3 to u1",
2107 "in_reply_to_status_id" => a1.id
2108 })
2109
2110 {:ok, r1_3} =
2111 CommonAPI.post(u4, %{
2112 "status" => "@#{u1.nickname} reply from u4 to u1",
2113 "in_reply_to_status_id" => a1.id
2114 })
2115
2116 {:ok, a2} = CommonAPI.post(u2, %{"status" => "Status"})
2117
2118 {:ok, r2_1} =
2119 CommonAPI.post(u1, %{
2120 "status" => "@#{u2.nickname} reply from u1 to u2",
2121 "in_reply_to_status_id" => a2.id
2122 })
2123
2124 {:ok, r2_2} =
2125 CommonAPI.post(u3, %{
2126 "status" => "@#{u2.nickname} reply from u3 to u2",
2127 "in_reply_to_status_id" => a2.id
2128 })
2129
2130 {:ok, r2_3} =
2131 CommonAPI.post(u4, %{
2132 "status" => "@#{u2.nickname} reply from u4 to u2",
2133 "in_reply_to_status_id" => a2.id
2134 })
2135
2136 {:ok, a3} = CommonAPI.post(u3, %{"status" => "Status"})
2137
2138 {:ok, r3_1} =
2139 CommonAPI.post(u1, %{
2140 "status" => "@#{u3.nickname} reply from u1 to u3",
2141 "in_reply_to_status_id" => a3.id
2142 })
2143
2144 {:ok, r3_2} =
2145 CommonAPI.post(u2, %{
2146 "status" => "@#{u3.nickname} reply from u2 to u3",
2147 "in_reply_to_status_id" => a3.id
2148 })
2149
2150 {:ok, r3_3} =
2151 CommonAPI.post(u4, %{
2152 "status" => "@#{u3.nickname} reply from u4 to u3",
2153 "in_reply_to_status_id" => a3.id
2154 })
2155
2156 {:ok, a4} = CommonAPI.post(u4, %{"status" => "Status"})
2157
2158 {:ok, r4_1} =
2159 CommonAPI.post(u1, %{
2160 "status" => "@#{u4.nickname} reply from u1 to u4",
2161 "in_reply_to_status_id" => a4.id
2162 })
2163
2164 {:ok, r4_2} =
2165 CommonAPI.post(u2, %{
2166 "status" => "@#{u4.nickname} reply from u2 to u4",
2167 "in_reply_to_status_id" => a4.id
2168 })
2169
2170 {:ok, r4_3} =
2171 CommonAPI.post(u3, %{
2172 "status" => "@#{u4.nickname} reply from u3 to u4",
2173 "in_reply_to_status_id" => a4.id
2174 })
2175
2176 {:ok,
2177 users: %{u1: u1, u2: u2, u3: u3, u4: u4},
2178 activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id},
2179 u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id},
2180 u2: %{r1: r2_1.id, r2: r2_2.id, r3: r2_3.id},
2181 u3: %{r1: r3_1.id, r2: r3_2.id, r3: r3_3.id},
2182 u4: %{r1: r4_1.id, r2: r4_2.id, r3: r4_3.id}}
2183 end
2184
2185 defp private_messages(_) do
2186 [u1, u2, u3, u4] = insert_list(4, :user)
2187 {:ok, u1} = User.follow(u1, u2)
2188 {:ok, u2} = User.follow(u2, u1)
2189 {:ok, u1} = User.follow(u1, u3)
2190 {:ok, u3} = User.follow(u3, u1)
2191 {:ok, u1} = User.follow(u1, u4)
2192 {:ok, u4} = User.follow(u4, u1)
2193
2194 {:ok, u2} = User.follow(u2, u3)
2195 {:ok, u3} = User.follow(u3, u2)
2196
2197 {:ok, a1} = CommonAPI.post(u1, %{"status" => "Status", "visibility" => "private"})
2198
2199 {:ok, r1_1} =
2200 CommonAPI.post(u2, %{
2201 "status" => "@#{u1.nickname} reply from u2 to u1",
2202 "in_reply_to_status_id" => a1.id,
2203 "visibility" => "private"
2204 })
2205
2206 {:ok, r1_2} =
2207 CommonAPI.post(u3, %{
2208 "status" => "@#{u1.nickname} reply from u3 to u1",
2209 "in_reply_to_status_id" => a1.id,
2210 "visibility" => "private"
2211 })
2212
2213 {:ok, r1_3} =
2214 CommonAPI.post(u4, %{
2215 "status" => "@#{u1.nickname} reply from u4 to u1",
2216 "in_reply_to_status_id" => a1.id,
2217 "visibility" => "private"
2218 })
2219
2220 {:ok, a2} = CommonAPI.post(u2, %{"status" => "Status", "visibility" => "private"})
2221
2222 {:ok, r2_1} =
2223 CommonAPI.post(u1, %{
2224 "status" => "@#{u2.nickname} reply from u1 to u2",
2225 "in_reply_to_status_id" => a2.id,
2226 "visibility" => "private"
2227 })
2228
2229 {:ok, r2_2} =
2230 CommonAPI.post(u3, %{
2231 "status" => "@#{u2.nickname} reply from u3 to u2",
2232 "in_reply_to_status_id" => a2.id,
2233 "visibility" => "private"
2234 })
2235
2236 {:ok, a3} = CommonAPI.post(u3, %{"status" => "Status", "visibility" => "private"})
2237
2238 {:ok, r3_1} =
2239 CommonAPI.post(u1, %{
2240 "status" => "@#{u3.nickname} reply from u1 to u3",
2241 "in_reply_to_status_id" => a3.id,
2242 "visibility" => "private"
2243 })
2244
2245 {:ok, r3_2} =
2246 CommonAPI.post(u2, %{
2247 "status" => "@#{u3.nickname} reply from u2 to u3",
2248 "in_reply_to_status_id" => a3.id,
2249 "visibility" => "private"
2250 })
2251
2252 {:ok, a4} = CommonAPI.post(u4, %{"status" => "Status", "visibility" => "private"})
2253
2254 {:ok, r4_1} =
2255 CommonAPI.post(u1, %{
2256 "status" => "@#{u4.nickname} reply from u1 to u4",
2257 "in_reply_to_status_id" => a4.id,
2258 "visibility" => "private"
2259 })
2260
2261 {:ok,
2262 users: %{u1: u1, u2: u2, u3: u3, u4: u4},
2263 activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id},
2264 u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id},
2265 u2: %{r1: r2_1.id, r2: r2_2.id},
2266 u3: %{r1: r3_1.id, r2: r3_2.id},
2267 u4: %{r1: r4_1.id}}
2268 end
2269 end