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