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