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