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