Merge remote-tracking branch 'remotes/upstream/develop' into 1335-user-api-id-fields...
[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_relationship} = 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_relationship} = 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_block} = 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_relationship} = 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, _user_relationship} = 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, _user_relationship} = 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
615 activity_one_actor = User.get_by_ap_id(activity_one.data["actor"])
616 {:ok, _user_relationships} = User.mute(user, activity_one_actor)
617
618 activities =
619 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
620
621 assert Enum.member?(activities, activity_two)
622 assert Enum.member?(activities, activity_three)
623 refute Enum.member?(activities, activity_one)
624
625 # Calling with 'with_muted' will deliver muted activities, too.
626 activities =
627 ActivityPub.fetch_activities([], %{
628 "muting_user" => user,
629 "with_muted" => true,
630 "skip_preload" => true
631 })
632
633 assert Enum.member?(activities, activity_two)
634 assert Enum.member?(activities, activity_three)
635 assert Enum.member?(activities, activity_one)
636
637 {:ok, _user_mute} = User.unmute(user, activity_one_actor)
638
639 activities =
640 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
641
642 assert Enum.member?(activities, activity_two)
643 assert Enum.member?(activities, activity_three)
644 assert Enum.member?(activities, activity_one)
645
646 activity_three_actor = User.get_by_ap_id(activity_three.data["actor"])
647 {:ok, _user_relationships} = User.mute(user, activity_three_actor)
648 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
649 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
650 activity_three = Activity.get_by_id(activity_three.id)
651
652 activities =
653 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
654
655 assert Enum.member?(activities, activity_two)
656 refute Enum.member?(activities, activity_three)
657 refute Enum.member?(activities, boost_activity)
658 assert Enum.member?(activities, activity_one)
659
660 activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true})
661
662 assert Enum.member?(activities, activity_two)
663 assert Enum.member?(activities, activity_three)
664 assert Enum.member?(activities, boost_activity)
665 assert Enum.member?(activities, activity_one)
666 end
667
668 test "doesn't return thread muted activities" do
669 user = insert(:user)
670 _activity_one = insert(:note_activity)
671 note_two = insert(:note, data: %{"context" => "suya.."})
672 activity_two = insert(:note_activity, note: note_two)
673
674 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
675
676 assert [_activity_one] = ActivityPub.fetch_activities([], %{"muting_user" => user})
677 end
678
679 test "returns thread muted activities when with_muted is set" do
680 user = insert(:user)
681 _activity_one = insert(:note_activity)
682 note_two = insert(:note, data: %{"context" => "suya.."})
683 activity_two = insert(:note_activity, note: note_two)
684
685 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
686
687 assert [_activity_two, _activity_one] =
688 ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true})
689 end
690
691 test "does include announces on request" do
692 activity_three = insert(:note_activity)
693 user = insert(:user)
694 booster = insert(:user)
695
696 {:ok, user} = User.follow(user, booster)
697
698 {:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster)
699
700 [announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)])
701
702 assert announce_activity.id == announce.id
703 end
704
705 test "excludes reblogs on request" do
706 user = insert(:user)
707 {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
708 {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user})
709
710 [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"})
711
712 assert activity == expected_activity
713 end
714
715 describe "public fetch activities" do
716 test "doesn't retrieve unlisted activities" do
717 user = insert(:user)
718
719 {:ok, _unlisted_activity} =
720 CommonAPI.post(user, %{"status" => "yeah", "visibility" => "unlisted"})
721
722 {:ok, listed_activity} = CommonAPI.post(user, %{"status" => "yeah"})
723
724 [activity] = ActivityPub.fetch_public_activities()
725
726 assert activity == listed_activity
727 end
728
729 test "retrieves public activities" do
730 _activities = ActivityPub.fetch_public_activities()
731
732 %{public: public} = ActivityBuilder.public_and_non_public()
733
734 activities = ActivityPub.fetch_public_activities()
735 assert length(activities) == 1
736 assert Enum.at(activities, 0) == public
737 end
738
739 test "retrieves a maximum of 20 activities" do
740 ActivityBuilder.insert_list(10)
741 expected_activities = ActivityBuilder.insert_list(20)
742
743 activities = ActivityPub.fetch_public_activities()
744
745 assert collect_ids(activities) == collect_ids(expected_activities)
746 assert length(activities) == 20
747 end
748
749 test "retrieves ids starting from a since_id" do
750 activities = ActivityBuilder.insert_list(30)
751 expected_activities = ActivityBuilder.insert_list(10)
752 since_id = List.last(activities).id
753
754 activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id})
755
756 assert collect_ids(activities) == collect_ids(expected_activities)
757 assert length(activities) == 10
758 end
759
760 test "retrieves ids up to max_id" do
761 ActivityBuilder.insert_list(10)
762 expected_activities = ActivityBuilder.insert_list(20)
763
764 %{id: max_id} =
765 10
766 |> ActivityBuilder.insert_list()
767 |> List.first()
768
769 activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id})
770
771 assert length(activities) == 20
772 assert collect_ids(activities) == collect_ids(expected_activities)
773 end
774
775 test "paginates via offset/limit" do
776 _first_part_activities = ActivityBuilder.insert_list(10)
777 second_part_activities = ActivityBuilder.insert_list(10)
778
779 later_activities = ActivityBuilder.insert_list(10)
780
781 activities =
782 ActivityPub.fetch_public_activities(%{"page" => "2", "page_size" => "20"}, :offset)
783
784 assert length(activities) == 20
785
786 assert collect_ids(activities) ==
787 collect_ids(second_part_activities) ++ collect_ids(later_activities)
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, _reblog_mute} = 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, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
808 {:ok, _reblog_mute} = 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 "react to 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 user = insert(:user)
822 reactor = insert(:user)
823 {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
824 assert object = Object.normalize(activity)
825
826 {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥")
827
828 assert called(Pleroma.Web.Federator.publish(reaction_activity))
829 end
830
831 test "adds an emoji reaction activity to the db" do
832 user = insert(:user)
833 reactor = insert(:user)
834 {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
835 assert object = Object.normalize(activity)
836
837 {:ok, reaction_activity, object} = ActivityPub.react_with_emoji(reactor, object, "🔥")
838
839 assert reaction_activity
840
841 assert reaction_activity.data["actor"] == reactor.ap_id
842 assert reaction_activity.data["type"] == "EmojiReaction"
843 assert reaction_activity.data["content"] == "🔥"
844 assert reaction_activity.data["object"] == object.data["id"]
845 assert reaction_activity.data["to"] == [User.ap_followers(reactor), activity.data["actor"]]
846 assert reaction_activity.data["context"] == object.data["context"]
847 assert object.data["reaction_count"] == 1
848 assert object.data["reactions"]["🔥"] == [reactor.ap_id]
849 end
850 end
851
852 describe "unreacting to an object" do
853 test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do
854 Pleroma.Config.put([:instance, :federating], true)
855 user = insert(:user)
856 reactor = insert(:user)
857 {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
858 assert object = Object.normalize(activity)
859
860 {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥")
861
862 assert called(Pleroma.Web.Federator.publish(reaction_activity))
863
864 {:ok, unreaction_activity, _object} =
865 ActivityPub.unreact_with_emoji(reactor, reaction_activity.data["id"])
866
867 assert called(Pleroma.Web.Federator.publish(unreaction_activity))
868 end
869
870 test "adds an undo activity to the db" do
871 user = insert(:user)
872 reactor = insert(:user)
873 {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"})
874 assert object = Object.normalize(activity)
875
876 {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥")
877
878 {:ok, unreaction_activity, _object} =
879 ActivityPub.unreact_with_emoji(reactor, reaction_activity.data["id"])
880
881 assert unreaction_activity.actor == reactor.ap_id
882 assert unreaction_activity.data["object"] == reaction_activity.data["id"]
883
884 object = Object.get_by_ap_id(object.data["id"])
885 assert object.data["reaction_count"] == 0
886 assert object.data["reactions"] == %{}
887 end
888 end
889
890 describe "like an object" do
891 test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do
892 Pleroma.Config.put([:instance, :federating], true)
893 note_activity = insert(:note_activity)
894 assert object_activity = Object.normalize(note_activity)
895
896 user = insert(:user)
897
898 {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
899 assert called(Pleroma.Web.Federator.publish(like_activity))
900 end
901
902 test "returns exist activity if object already liked" do
903 note_activity = insert(:note_activity)
904 assert object_activity = Object.normalize(note_activity)
905
906 user = insert(:user)
907
908 {:ok, like_activity, _object} = ActivityPub.like(user, object_activity)
909
910 {:ok, like_activity_exist, _object} = ActivityPub.like(user, object_activity)
911 assert like_activity == like_activity_exist
912 end
913
914 test "adds a like activity to the db" do
915 note_activity = insert(:note_activity)
916 assert object = Object.normalize(note_activity)
917
918 user = insert(:user)
919 user_two = insert(:user)
920
921 {:ok, like_activity, object} = ActivityPub.like(user, object)
922
923 assert like_activity.data["actor"] == user.ap_id
924 assert like_activity.data["type"] == "Like"
925 assert like_activity.data["object"] == object.data["id"]
926 assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
927 assert like_activity.data["context"] == object.data["context"]
928 assert object.data["like_count"] == 1
929 assert object.data["likes"] == [user.ap_id]
930
931 # Just return the original activity if the user already liked it.
932 {:ok, same_like_activity, object} = ActivityPub.like(user, object)
933
934 assert like_activity == same_like_activity
935 assert object.data["likes"] == [user.ap_id]
936 assert object.data["like_count"] == 1
937
938 {:ok, _like_activity, object} = ActivityPub.like(user_two, object)
939 assert object.data["like_count"] == 2
940 end
941 end
942
943 describe "unliking" do
944 test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do
945 Pleroma.Config.put([:instance, :federating], true)
946
947 note_activity = insert(:note_activity)
948 object = Object.normalize(note_activity)
949 user = insert(:user)
950
951 {:ok, object} = ActivityPub.unlike(user, object)
952 refute called(Pleroma.Web.Federator.publish())
953
954 {:ok, _like_activity, object} = ActivityPub.like(user, object)
955 assert object.data["like_count"] == 1
956
957 {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
958 assert object.data["like_count"] == 0
959
960 assert called(Pleroma.Web.Federator.publish(unlike_activity))
961 end
962
963 test "unliking a previously liked object" do
964 note_activity = insert(:note_activity)
965 object = Object.normalize(note_activity)
966 user = insert(:user)
967
968 # Unliking something that hasn't been liked does nothing
969 {:ok, object} = ActivityPub.unlike(user, object)
970 assert object.data["like_count"] == 0
971
972 {:ok, like_activity, object} = ActivityPub.like(user, object)
973 assert object.data["like_count"] == 1
974
975 {:ok, unlike_activity, _, object} = ActivityPub.unlike(user, object)
976 assert object.data["like_count"] == 0
977
978 assert Activity.get_by_id(like_activity.id) == nil
979 assert note_activity.actor in unlike_activity.recipients
980 end
981 end
982
983 describe "announcing an object" do
984 test "adds an announce activity to the db" do
985 note_activity = insert(:note_activity)
986 object = Object.normalize(note_activity)
987 user = insert(:user)
988
989 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
990 assert object.data["announcement_count"] == 1
991 assert object.data["announcements"] == [user.ap_id]
992
993 assert announce_activity.data["to"] == [
994 User.ap_followers(user),
995 note_activity.data["actor"]
996 ]
997
998 assert announce_activity.data["object"] == object.data["id"]
999 assert announce_activity.data["actor"] == user.ap_id
1000 assert announce_activity.data["context"] == object.data["context"]
1001 end
1002 end
1003
1004 describe "announcing a private object" do
1005 test "adds an announce activity to the db if the audience is not widened" do
1006 user = insert(:user)
1007 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
1008 object = Object.normalize(note_activity)
1009
1010 {:ok, announce_activity, object} = ActivityPub.announce(user, object, nil, true, false)
1011
1012 assert announce_activity.data["to"] == [User.ap_followers(user)]
1013
1014 assert announce_activity.data["object"] == object.data["id"]
1015 assert announce_activity.data["actor"] == user.ap_id
1016 assert announce_activity.data["context"] == object.data["context"]
1017 end
1018
1019 test "does not add an announce activity to the db if the audience is widened" do
1020 user = insert(:user)
1021 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
1022 object = Object.normalize(note_activity)
1023
1024 assert {:error, _} = ActivityPub.announce(user, object, nil, true, true)
1025 end
1026
1027 test "does not add an announce activity to the db if the announcer is not the author" do
1028 user = insert(:user)
1029 announcer = insert(:user)
1030 {:ok, note_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
1031 object = Object.normalize(note_activity)
1032
1033 assert {:error, _} = ActivityPub.announce(announcer, object, nil, true, false)
1034 end
1035 end
1036
1037 describe "unannouncing an object" do
1038 test "unannouncing a previously announced object" do
1039 note_activity = insert(:note_activity)
1040 object = Object.normalize(note_activity)
1041 user = insert(:user)
1042
1043 # Unannouncing an object that is not announced does nothing
1044 # {:ok, object} = ActivityPub.unannounce(user, object)
1045 # assert object.data["announcement_count"] == 0
1046
1047 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
1048 assert object.data["announcement_count"] == 1
1049
1050 {:ok, unannounce_activity, object} = ActivityPub.unannounce(user, object)
1051 assert object.data["announcement_count"] == 0
1052
1053 assert unannounce_activity.data["to"] == [
1054 User.ap_followers(user),
1055 object.data["actor"]
1056 ]
1057
1058 assert unannounce_activity.data["type"] == "Undo"
1059 assert unannounce_activity.data["object"] == announce_activity.data
1060 assert unannounce_activity.data["actor"] == user.ap_id
1061 assert unannounce_activity.data["context"] == announce_activity.data["context"]
1062
1063 assert Activity.get_by_id(announce_activity.id) == nil
1064 end
1065 end
1066
1067 describe "uploading files" do
1068 test "copies the file to the configured folder" do
1069 file = %Plug.Upload{
1070 content_type: "image/jpg",
1071 path: Path.absname("test/fixtures/image.jpg"),
1072 filename: "an_image.jpg"
1073 }
1074
1075 {:ok, %Object{} = object} = ActivityPub.upload(file)
1076 assert object.data["name"] == "an_image.jpg"
1077 end
1078
1079 test "works with base64 encoded images" do
1080 file = %{
1081 "img" => data_uri()
1082 }
1083
1084 {:ok, %Object{}} = ActivityPub.upload(file)
1085 end
1086 end
1087
1088 describe "fetch the latest Follow" do
1089 test "fetches the latest Follow activity" do
1090 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
1091 follower = Repo.get_by(User, ap_id: activity.data["actor"])
1092 followed = Repo.get_by(User, ap_id: activity.data["object"])
1093
1094 assert activity == Utils.fetch_latest_follow(follower, followed)
1095 end
1096 end
1097
1098 describe "following / unfollowing" do
1099 test "creates a follow activity" do
1100 follower = insert(:user)
1101 followed = insert(:user)
1102
1103 {:ok, activity} = ActivityPub.follow(follower, followed)
1104 assert activity.data["type"] == "Follow"
1105 assert activity.data["actor"] == follower.ap_id
1106 assert activity.data["object"] == followed.ap_id
1107 end
1108
1109 test "creates an undo activity for the last follow" do
1110 follower = insert(:user)
1111 followed = insert(:user)
1112
1113 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
1114 {:ok, activity} = ActivityPub.unfollow(follower, followed)
1115
1116 assert activity.data["type"] == "Undo"
1117 assert activity.data["actor"] == follower.ap_id
1118
1119 embedded_object = activity.data["object"]
1120 assert is_map(embedded_object)
1121 assert embedded_object["type"] == "Follow"
1122 assert embedded_object["object"] == followed.ap_id
1123 assert embedded_object["id"] == follow_activity.data["id"]
1124 end
1125 end
1126
1127 describe "blocking / unblocking" do
1128 test "creates a block activity" do
1129 blocker = insert(:user)
1130 blocked = insert(:user)
1131
1132 {:ok, activity} = ActivityPub.block(blocker, blocked)
1133
1134 assert activity.data["type"] == "Block"
1135 assert activity.data["actor"] == blocker.ap_id
1136 assert activity.data["object"] == blocked.ap_id
1137 end
1138
1139 test "creates an undo activity for the last block" do
1140 blocker = insert(:user)
1141 blocked = insert(:user)
1142
1143 {:ok, block_activity} = ActivityPub.block(blocker, blocked)
1144 {:ok, activity} = ActivityPub.unblock(blocker, blocked)
1145
1146 assert activity.data["type"] == "Undo"
1147 assert activity.data["actor"] == blocker.ap_id
1148
1149 embedded_object = activity.data["object"]
1150 assert is_map(embedded_object)
1151 assert embedded_object["type"] == "Block"
1152 assert embedded_object["object"] == blocked.ap_id
1153 assert embedded_object["id"] == block_activity.data["id"]
1154 end
1155 end
1156
1157 describe "deletion" do
1158 test "it creates a delete activity and deletes the original object" do
1159 note = insert(:note_activity)
1160 object = Object.normalize(note)
1161 {:ok, delete} = ActivityPub.delete(object)
1162
1163 assert delete.data["type"] == "Delete"
1164 assert delete.data["actor"] == note.data["actor"]
1165 assert delete.data["object"] == object.data["id"]
1166
1167 assert Activity.get_by_id(delete.id) != nil
1168
1169 assert Repo.get(Object, object.id).data["type"] == "Tombstone"
1170 end
1171
1172 test "decrements user note count only for public activities" do
1173 user = insert(:user, note_count: 10)
1174
1175 {:ok, a1} =
1176 CommonAPI.post(User.get_cached_by_id(user.id), %{
1177 "status" => "yeah",
1178 "visibility" => "public"
1179 })
1180
1181 {:ok, a2} =
1182 CommonAPI.post(User.get_cached_by_id(user.id), %{
1183 "status" => "yeah",
1184 "visibility" => "unlisted"
1185 })
1186
1187 {:ok, a3} =
1188 CommonAPI.post(User.get_cached_by_id(user.id), %{
1189 "status" => "yeah",
1190 "visibility" => "private"
1191 })
1192
1193 {:ok, a4} =
1194 CommonAPI.post(User.get_cached_by_id(user.id), %{
1195 "status" => "yeah",
1196 "visibility" => "direct"
1197 })
1198
1199 {:ok, _} = Object.normalize(a1) |> ActivityPub.delete()
1200 {:ok, _} = Object.normalize(a2) |> ActivityPub.delete()
1201 {:ok, _} = Object.normalize(a3) |> ActivityPub.delete()
1202 {:ok, _} = Object.normalize(a4) |> ActivityPub.delete()
1203
1204 user = User.get_cached_by_id(user.id)
1205 assert user.note_count == 10
1206 end
1207
1208 test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
1209 user = insert(:user)
1210 note = insert(:note_activity)
1211 object = Object.normalize(note)
1212
1213 {:ok, object} =
1214 object
1215 |> Object.change(%{
1216 data: %{
1217 "actor" => object.data["actor"],
1218 "id" => object.data["id"],
1219 "to" => [user.ap_id],
1220 "type" => "Note"
1221 }
1222 })
1223 |> Object.update_and_set_cache()
1224
1225 {:ok, delete} = ActivityPub.delete(object)
1226
1227 assert user.ap_id in delete.data["to"]
1228 end
1229
1230 test "decreases reply count" do
1231 user = insert(:user)
1232 user2 = insert(:user)
1233
1234 {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
1235 reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
1236 ap_id = activity.data["id"]
1237
1238 {:ok, public_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
1239 {:ok, unlisted_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
1240 {:ok, private_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
1241 {:ok, direct_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
1242
1243 _ = CommonAPI.delete(direct_reply.id, user2)
1244 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1245 assert object.data["repliesCount"] == 2
1246
1247 _ = CommonAPI.delete(private_reply.id, user2)
1248 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1249 assert object.data["repliesCount"] == 2
1250
1251 _ = CommonAPI.delete(public_reply.id, user2)
1252 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1253 assert object.data["repliesCount"] == 1
1254
1255 _ = CommonAPI.delete(unlisted_reply.id, user2)
1256 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
1257 assert object.data["repliesCount"] == 0
1258 end
1259 end
1260
1261 describe "timeline post-processing" do
1262 test "it filters broken threads" do
1263 user1 = insert(:user)
1264 user2 = insert(:user)
1265 user3 = insert(:user)
1266
1267 {:ok, user1} = User.follow(user1, user3)
1268 assert User.following?(user1, user3)
1269
1270 {:ok, user2} = User.follow(user2, user3)
1271 assert User.following?(user2, user3)
1272
1273 {:ok, user3} = User.follow(user3, user2)
1274 assert User.following?(user3, user2)
1275
1276 {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
1277
1278 {:ok, private_activity_1} =
1279 CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
1280
1281 {:ok, private_activity_2} =
1282 CommonAPI.post(user2, %{
1283 "status" => "hi 3",
1284 "visibility" => "private",
1285 "in_reply_to_status_id" => private_activity_1.id
1286 })
1287
1288 {:ok, private_activity_3} =
1289 CommonAPI.post(user3, %{
1290 "status" => "hi 4",
1291 "visibility" => "private",
1292 "in_reply_to_status_id" => private_activity_2.id
1293 })
1294
1295 activities =
1296 ActivityPub.fetch_activities([user1.ap_id | User.following(user1)])
1297 |> Enum.map(fn a -> a.id end)
1298
1299 private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"])
1300
1301 assert [public_activity.id, private_activity_1.id, private_activity_3.id] == activities
1302
1303 assert length(activities) == 3
1304
1305 activities =
1306 ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{"user" => user1})
1307 |> Enum.map(fn a -> a.id end)
1308
1309 assert [public_activity.id, private_activity_1.id] == activities
1310 assert length(activities) == 2
1311 end
1312 end
1313
1314 describe "update" do
1315 test "it creates an update activity with the new user data" do
1316 user = insert(:user)
1317 {:ok, user} = User.ensure_keys_present(user)
1318 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
1319
1320 {:ok, update} =
1321 ActivityPub.update(%{
1322 actor: user_data["id"],
1323 to: [user.follower_address],
1324 cc: [],
1325 object: user_data
1326 })
1327
1328 assert update.data["actor"] == user.ap_id
1329 assert update.data["to"] == [user.follower_address]
1330 assert embedded_object = update.data["object"]
1331 assert embedded_object["id"] == user_data["id"]
1332 assert embedded_object["type"] == user_data["type"]
1333 end
1334 end
1335
1336 test "returned pinned statuses" do
1337 Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
1338 user = insert(:user)
1339
1340 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
1341 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
1342 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
1343
1344 CommonAPI.pin(activity_one.id, user)
1345 user = refresh_record(user)
1346
1347 CommonAPI.pin(activity_two.id, user)
1348 user = refresh_record(user)
1349
1350 CommonAPI.pin(activity_three.id, user)
1351 user = refresh_record(user)
1352
1353 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
1354
1355 assert 3 = length(activities)
1356 end
1357
1358 describe "flag/1" do
1359 setup do
1360 reporter = insert(:user)
1361 target_account = insert(:user)
1362 content = "foobar"
1363 {:ok, activity} = CommonAPI.post(target_account, %{"status" => content})
1364 context = Utils.generate_context_id()
1365
1366 reporter_ap_id = reporter.ap_id
1367 target_ap_id = target_account.ap_id
1368 activity_ap_id = activity.data["id"]
1369
1370 activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id)
1371
1372 {:ok,
1373 %{
1374 reporter: reporter,
1375 context: context,
1376 target_account: target_account,
1377 reported_activity: activity,
1378 content: content,
1379 activity_ap_id: activity_ap_id,
1380 activity_with_object: activity_with_object,
1381 reporter_ap_id: reporter_ap_id,
1382 target_ap_id: target_ap_id
1383 }}
1384 end
1385
1386 test "it can create a Flag activity",
1387 %{
1388 reporter: reporter,
1389 context: context,
1390 target_account: target_account,
1391 reported_activity: reported_activity,
1392 content: content,
1393 activity_ap_id: activity_ap_id,
1394 activity_with_object: activity_with_object,
1395 reporter_ap_id: reporter_ap_id,
1396 target_ap_id: target_ap_id
1397 } do
1398 assert {:ok, activity} =
1399 ActivityPub.flag(%{
1400 actor: reporter,
1401 context: context,
1402 account: target_account,
1403 statuses: [reported_activity],
1404 content: content
1405 })
1406
1407 note_obj = %{
1408 "type" => "Note",
1409 "id" => activity_ap_id,
1410 "content" => content,
1411 "published" => activity_with_object.object.data["published"],
1412 "actor" => AccountView.render("show.json", %{user: target_account})
1413 }
1414
1415 assert %Activity{
1416 actor: ^reporter_ap_id,
1417 data: %{
1418 "type" => "Flag",
1419 "content" => ^content,
1420 "context" => ^context,
1421 "object" => [^target_ap_id, ^note_obj]
1422 }
1423 } = activity
1424 end
1425
1426 test_with_mock "strips status data from Flag, before federating it",
1427 %{
1428 reporter: reporter,
1429 context: context,
1430 target_account: target_account,
1431 reported_activity: reported_activity,
1432 content: content
1433 },
1434 Utils,
1435 [:passthrough],
1436 [] do
1437 {:ok, activity} =
1438 ActivityPub.flag(%{
1439 actor: reporter,
1440 context: context,
1441 account: target_account,
1442 statuses: [reported_activity],
1443 content: content
1444 })
1445
1446 new_data =
1447 put_in(activity.data, ["object"], [target_account.ap_id, reported_activity.data["id"]])
1448
1449 assert_called(Utils.maybe_federate(%{activity | data: new_data}))
1450 end
1451 end
1452
1453 test "fetch_activities/2 returns activities addressed to a list " do
1454 user = insert(:user)
1455 member = insert(:user)
1456 {:ok, list} = Pleroma.List.create("foo", user)
1457 {:ok, list} = Pleroma.List.follow(list, member)
1458
1459 {:ok, activity} =
1460 CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
1461
1462 activity = Repo.preload(activity, :bookmark)
1463 activity = %Activity{activity | thread_muted?: !!activity.thread_muted?}
1464
1465 assert ActivityPub.fetch_activities([], %{"user" => user}) == [activity]
1466 end
1467
1468 def data_uri do
1469 File.read!("test/fixtures/avatar_data_uri")
1470 end
1471
1472 describe "fetch_activities_bounded" do
1473 test "fetches private posts for followed users" do
1474 user = insert(:user)
1475
1476 {:ok, activity} =
1477 CommonAPI.post(user, %{
1478 "status" => "thought I looked cute might delete later :3",
1479 "visibility" => "private"
1480 })
1481
1482 [result] = ActivityPub.fetch_activities_bounded([user.follower_address], [])
1483 assert result.id == activity.id
1484 end
1485
1486 test "fetches only public posts for other users" do
1487 user = insert(:user)
1488 {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe", "visibility" => "public"})
1489
1490 {:ok, _private_activity} =
1491 CommonAPI.post(user, %{
1492 "status" => "why is tenshi eating a corndog so cute?",
1493 "visibility" => "private"
1494 })
1495
1496 [result] = ActivityPub.fetch_activities_bounded([], [user.follower_address])
1497 assert result.id == activity.id
1498 end
1499 end
1500
1501 describe "fetch_follow_information_for_user" do
1502 test "syncronizes following/followers counters" do
1503 user =
1504 insert(:user,
1505 local: false,
1506 follower_address: "http://localhost:4001/users/fuser2/followers",
1507 following_address: "http://localhost:4001/users/fuser2/following"
1508 )
1509
1510 {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
1511 assert info.follower_count == 527
1512 assert info.following_count == 267
1513 end
1514
1515 test "detects hidden followers" do
1516 mock(fn env ->
1517 case env.url do
1518 "http://localhost:4001/users/masto_closed/followers?page=1" ->
1519 %Tesla.Env{status: 403, body: ""}
1520
1521 _ ->
1522 apply(HttpRequestMock, :request, [env])
1523 end
1524 end)
1525
1526 user =
1527 insert(:user,
1528 local: false,
1529 follower_address: "http://localhost:4001/users/masto_closed/followers",
1530 following_address: "http://localhost:4001/users/masto_closed/following"
1531 )
1532
1533 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1534 assert follow_info.hide_followers == true
1535 assert follow_info.hide_follows == false
1536 end
1537
1538 test "detects hidden follows" do
1539 mock(fn env ->
1540 case env.url do
1541 "http://localhost:4001/users/masto_closed/following?page=1" ->
1542 %Tesla.Env{status: 403, body: ""}
1543
1544 _ ->
1545 apply(HttpRequestMock, :request, [env])
1546 end
1547 end)
1548
1549 user =
1550 insert(:user,
1551 local: false,
1552 follower_address: "http://localhost:4001/users/masto_closed/followers",
1553 following_address: "http://localhost:4001/users/masto_closed/following"
1554 )
1555
1556 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1557 assert follow_info.hide_followers == false
1558 assert follow_info.hide_follows == true
1559 end
1560 end
1561 end