Remove containment tests from transmogrifier and fix thread visibility solver
[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.Instances
10 alias Pleroma.Object
11 alias Pleroma.User
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.ActivityPub.Utils
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 describe "fetching restricted by visibility" do
26 test "it restricts by the appropriate visibility" do
27 user = insert(:user)
28
29 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
30
31 {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
32
33 {:ok, unlisted_activity} =
34 CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
35
36 {:ok, private_activity} =
37 CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
38
39 activities =
40 ActivityPub.fetch_activities([], %{:visibility => "direct", "actor_id" => user.ap_id})
41
42 assert activities == [direct_activity]
43
44 activities =
45 ActivityPub.fetch_activities([], %{:visibility => "unlisted", "actor_id" => user.ap_id})
46
47 assert activities == [unlisted_activity]
48
49 activities =
50 ActivityPub.fetch_activities([], %{:visibility => "private", "actor_id" => user.ap_id})
51
52 assert activities == [private_activity]
53
54 activities =
55 ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id})
56
57 assert activities == [public_activity]
58
59 activities =
60 ActivityPub.fetch_activities([], %{
61 :visibility => ~w[private public],
62 "actor_id" => user.ap_id
63 })
64
65 assert activities == [public_activity, private_activity]
66 end
67 end
68
69 describe "building a user from his ap id" do
70 test "it returns a user" do
71 user_id = "http://mastodon.example.org/users/admin"
72 {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
73 assert user.ap_id == user_id
74 assert user.nickname == "admin@mastodon.example.org"
75 assert user.info.source_data
76 assert user.info.ap_enabled
77 assert user.follower_address == "http://mastodon.example.org/users/admin/followers"
78 end
79
80 test "it fetches the appropriate tag-restricted posts" do
81 user = insert(:user)
82
83 {:ok, status_one} = CommonAPI.post(user, %{"status" => ". #test"})
84 {:ok, status_two} = CommonAPI.post(user, %{"status" => ". #essais"})
85 {:ok, status_three} = CommonAPI.post(user, %{"status" => ". #test #reject"})
86
87 fetch_one = ActivityPub.fetch_activities([], %{"tag" => "test"})
88 fetch_two = ActivityPub.fetch_activities([], %{"tag" => ["test", "essais"]})
89
90 fetch_three =
91 ActivityPub.fetch_activities([], %{
92 "tag" => ["test", "essais"],
93 "tag_reject" => ["reject"]
94 })
95
96 fetch_four =
97 ActivityPub.fetch_activities([], %{
98 "tag" => ["test"],
99 "tag_all" => ["test", "reject"]
100 })
101
102 assert fetch_one == [status_one, status_three]
103 assert fetch_two == [status_one, status_two, status_three]
104 assert fetch_three == [status_one, status_two]
105 assert fetch_four == [status_three]
106 end
107 end
108
109 describe "insertion" do
110 test "drops activities beyond a certain limit" do
111 limit = Pleroma.Config.get([:instance, :remote_limit])
112
113 random_text =
114 :crypto.strong_rand_bytes(limit + 1)
115 |> Base.encode64()
116 |> binary_part(0, limit + 1)
117
118 data = %{
119 "ok" => true,
120 "object" => %{
121 "content" => random_text
122 }
123 }
124
125 assert {:error, {:remote_limit_error, _}} = ActivityPub.insert(data)
126 end
127
128 test "doesn't drop activities with content being null" do
129 data = %{
130 "ok" => true,
131 "object" => %{
132 "content" => nil
133 }
134 }
135
136 assert {:ok, _} = ActivityPub.insert(data)
137 end
138
139 test "returns the activity if one with the same id is already in" do
140 activity = insert(:note_activity)
141 {:ok, new_activity} = ActivityPub.insert(activity.data)
142
143 assert activity.id == new_activity.id
144 end
145
146 test "inserts a given map into the activity database, giving it an id if it has none." do
147 data = %{
148 "ok" => true
149 }
150
151 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
152 assert activity.data["ok"] == data["ok"]
153 assert is_binary(activity.data["id"])
154
155 given_id = "bla"
156
157 data = %{
158 "ok" => true,
159 "id" => given_id,
160 "context" => "blabla"
161 }
162
163 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
164 assert activity.data["ok"] == data["ok"]
165 assert activity.data["id"] == given_id
166 assert activity.data["context"] == "blabla"
167 assert activity.data["context_id"]
168 end
169
170 test "adds a context when none is there" do
171 data = %{
172 "id" => "some_id",
173 "object" => %{
174 "id" => "object_id"
175 }
176 }
177
178 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
179
180 assert is_binary(activity.data["context"])
181 assert is_binary(activity.data["object"]["context"])
182 assert activity.data["context_id"]
183 assert activity.data["object"]["context_id"]
184 end
185
186 test "adds an id to a given object if it lacks one and is a note and inserts it to the object database" do
187 data = %{
188 "object" => %{
189 "type" => "Note",
190 "ok" => true
191 }
192 }
193
194 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
195 object = Object.normalize(activity.data["object"])
196
197 assert is_binary(object.data["id"])
198 assert %Object{} = Object.get_by_ap_id(activity.data["object"])
199 end
200 end
201
202 describe "create activities" do
203 test "removes doubled 'to' recipients" do
204 user = insert(:user)
205
206 {:ok, activity} =
207 ActivityPub.create(%{
208 to: ["user1", "user1", "user2"],
209 actor: user,
210 context: "",
211 object: %{
212 "to" => ["user1", "user1", "user2"],
213 "type" => "Note",
214 "content" => "testing"
215 }
216 })
217
218 assert activity.data["to"] == ["user1", "user2"]
219 assert activity.actor == user.ap_id
220 assert activity.recipients == ["user1", "user2", user.ap_id]
221 end
222
223 test "increases user note count only for public activities" do
224 user = insert(:user)
225
226 {:ok, _} =
227 CommonAPI.post(User.get_by_id(user.id), %{"status" => "1", "visibility" => "public"})
228
229 {:ok, _} =
230 CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "unlisted"})
231
232 {:ok, _} =
233 CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "private"})
234
235 {:ok, _} =
236 CommonAPI.post(User.get_by_id(user.id), %{"status" => "3", "visibility" => "direct"})
237
238 user = User.get_by_id(user.id)
239 assert user.info.note_count == 2
240 end
241
242 test "increases replies count" do
243 user = insert(:user)
244 user2 = insert(:user)
245
246 {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
247 ap_id = activity.data["id"]
248 reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
249
250 # public
251 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
252 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
253 assert object.data["repliesCount"] == 1
254
255 # unlisted
256 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
257 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
258 assert object.data["repliesCount"] == 2
259
260 # private
261 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
262 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
263 assert object.data["repliesCount"] == 2
264
265 # direct
266 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
267 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
268 assert object.data["repliesCount"] == 2
269 end
270 end
271
272 describe "fetch activities for recipients" do
273 test "retrieve the activities for certain recipients" do
274 {:ok, activity_one} = ActivityBuilder.insert(%{"to" => ["someone"]})
275 {:ok, activity_two} = ActivityBuilder.insert(%{"to" => ["someone_else"]})
276 {:ok, _activity_three} = ActivityBuilder.insert(%{"to" => ["noone"]})
277
278 activities = ActivityPub.fetch_activities(["someone", "someone_else"])
279 assert length(activities) == 2
280 assert activities == [activity_one, activity_two]
281 end
282 end
283
284 describe "fetch activities in context" do
285 test "retrieves activities that have a given context" do
286 {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
287 {:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
288 {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
289 {:ok, _activity_four} = ActivityBuilder.insert(%{"type" => "Announce", "context" => "2hu"})
290 activity_five = insert(:note_activity)
291 user = insert(:user)
292
293 {:ok, user} = User.block(user, %{ap_id: activity_five.data["actor"]})
294
295 activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user})
296 assert activities == [activity_two, activity]
297 end
298 end
299
300 test "doesn't return blocked activities" do
301 activity_one = insert(:note_activity)
302 activity_two = insert(:note_activity)
303 activity_three = insert(:note_activity)
304 user = insert(:user)
305 booster = insert(:user)
306 {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]})
307
308 activities =
309 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
310
311 assert Enum.member?(activities, activity_two)
312 assert Enum.member?(activities, activity_three)
313 refute Enum.member?(activities, activity_one)
314
315 {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
316
317 activities =
318 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
319
320 assert Enum.member?(activities, activity_two)
321 assert Enum.member?(activities, activity_three)
322 assert Enum.member?(activities, activity_one)
323
324 {:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
325 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
326 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
327 activity_three = Activity.get_by_id(activity_three.id)
328
329 activities =
330 ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
331
332 assert Enum.member?(activities, activity_two)
333 refute Enum.member?(activities, activity_three)
334 refute Enum.member?(activities, boost_activity)
335 assert Enum.member?(activities, activity_one)
336
337 activities =
338 ActivityPub.fetch_activities([], %{"blocking_user" => nil, "skip_preload" => true})
339
340 assert Enum.member?(activities, activity_two)
341 assert Enum.member?(activities, activity_three)
342 assert Enum.member?(activities, boost_activity)
343 assert Enum.member?(activities, activity_one)
344 end
345
346 test "doesn't return muted activities" do
347 activity_one = insert(:note_activity)
348 activity_two = insert(:note_activity)
349 activity_three = insert(:note_activity)
350 user = insert(:user)
351 booster = insert(:user)
352 {:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]})
353
354 activities =
355 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
356
357 assert Enum.member?(activities, activity_two)
358 assert Enum.member?(activities, activity_three)
359 refute Enum.member?(activities, activity_one)
360
361 # Calling with 'with_muted' will deliver muted activities, too.
362 activities =
363 ActivityPub.fetch_activities([], %{
364 "muting_user" => user,
365 "with_muted" => true,
366 "skip_preload" => true
367 })
368
369 assert Enum.member?(activities, activity_two)
370 assert Enum.member?(activities, activity_three)
371 assert Enum.member?(activities, activity_one)
372
373 {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]})
374
375 activities =
376 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
377
378 assert Enum.member?(activities, activity_two)
379 assert Enum.member?(activities, activity_three)
380 assert Enum.member?(activities, activity_one)
381
382 {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
383 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
384 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
385 activity_three = Activity.get_by_id(activity_three.id)
386
387 activities =
388 ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
389
390 assert Enum.member?(activities, activity_two)
391 refute Enum.member?(activities, activity_three)
392 refute Enum.member?(activities, boost_activity)
393 assert Enum.member?(activities, activity_one)
394
395 activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true})
396
397 assert Enum.member?(activities, activity_two)
398 assert Enum.member?(activities, activity_three)
399 assert Enum.member?(activities, boost_activity)
400 assert Enum.member?(activities, activity_one)
401 end
402
403 test "does include announces on request" do
404 activity_three = insert(:note_activity)
405 user = insert(:user)
406 booster = insert(:user)
407
408 {:ok, user} = User.follow(user, booster)
409
410 {:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster)
411
412 [announce_activity] = ActivityPub.fetch_activities([user.ap_id | user.following])
413
414 assert announce_activity.id == announce.id
415 end
416
417 test "excludes reblogs on request" do
418 user = insert(:user)
419 {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
420 {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user})
421
422 [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"})
423
424 assert activity == expected_activity
425 end
426
427 describe "public fetch activities" do
428 test "doesn't retrieve unlisted activities" do
429 user = insert(:user)
430
431 {:ok, _unlisted_activity} =
432 CommonAPI.post(user, %{"status" => "yeah", "visibility" => "unlisted"})
433
434 {:ok, listed_activity} = CommonAPI.post(user, %{"status" => "yeah"})
435
436 [activity] = ActivityPub.fetch_public_activities()
437
438 assert activity == listed_activity
439 end
440
441 test "retrieves public activities" do
442 _activities = ActivityPub.fetch_public_activities()
443
444 %{public: public} = ActivityBuilder.public_and_non_public()
445
446 activities = ActivityPub.fetch_public_activities()
447 assert length(activities) == 1
448 assert Enum.at(activities, 0) == public
449 end
450
451 test "retrieves a maximum of 20 activities" do
452 activities = ActivityBuilder.insert_list(30)
453 last_expected = List.last(activities)
454
455 activities = ActivityPub.fetch_public_activities()
456 last = List.last(activities)
457
458 assert length(activities) == 20
459 assert last == last_expected
460 end
461
462 test "retrieves ids starting from a since_id" do
463 activities = ActivityBuilder.insert_list(30)
464 later_activities = ActivityBuilder.insert_list(10)
465 since_id = List.last(activities).id
466 last_expected = List.last(later_activities)
467
468 activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id})
469 last = List.last(activities)
470
471 assert length(activities) == 10
472 assert last == last_expected
473 end
474
475 test "retrieves ids up to max_id" do
476 _first_activities = ActivityBuilder.insert_list(10)
477 activities = ActivityBuilder.insert_list(20)
478 later_activities = ActivityBuilder.insert_list(10)
479 max_id = List.first(later_activities).id
480 last_expected = List.last(activities)
481
482 activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id})
483 last = List.last(activities)
484
485 assert length(activities) == 20
486 assert last == last_expected
487 end
488
489 test "doesn't return reblogs for users for whom reblogs have been muted" do
490 activity = insert(:note_activity)
491 user = insert(:user)
492 booster = insert(:user)
493 {:ok, user} = CommonAPI.hide_reblogs(user, booster)
494
495 {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
496
497 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
498
499 refute Enum.any?(activities, fn %{id: id} -> id == activity.id end)
500 end
501
502 test "returns reblogs for users for whom reblogs have not been muted" do
503 activity = insert(:note_activity)
504 user = insert(:user)
505 booster = insert(:user)
506 {:ok, user} = CommonAPI.hide_reblogs(user, booster)
507 {:ok, user} = CommonAPI.show_reblogs(user, booster)
508
509 {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
510
511 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
512
513 assert Enum.any?(activities, fn %{id: id} -> id == activity.id end)
514 end
515 end
516
517 describe "like an object" do
518 test "adds a like activity to the db" do
519 note_activity = insert(:note_activity)
520 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
521 user = insert(:user)
522 user_two = insert(:user)
523
524 {:ok, like_activity, object} = ActivityPub.like(user, object)
525
526 assert like_activity.data["actor"] == user.ap_id
527 assert like_activity.data["type"] == "Like"
528 assert like_activity.data["object"] == object.data["id"]
529 assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
530 assert like_activity.data["context"] == object.data["context"]
531 assert object.data["like_count"] == 1
532 assert object.data["likes"] == [user.ap_id]
533
534 # Just return the original activity if the user already liked it.
535 {:ok, same_like_activity, object} = ActivityPub.like(user, object)
536
537 assert like_activity == same_like_activity
538 assert object.data["likes"] == [user.ap_id]
539
540 [note_activity] = Activity.get_all_create_by_object_ap_id(object.data["id"])
541 assert note_activity.data["object"]["like_count"] == 1
542
543 {:ok, _like_activity, object} = ActivityPub.like(user_two, object)
544 assert object.data["like_count"] == 2
545 end
546 end
547
548 describe "unliking" do
549 test "unliking a previously liked object" do
550 note_activity = insert(:note_activity)
551 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
552 user = insert(:user)
553
554 # Unliking something that hasn't been liked does nothing
555 {:ok, object} = ActivityPub.unlike(user, object)
556 assert object.data["like_count"] == 0
557
558 {:ok, like_activity, object} = ActivityPub.like(user, object)
559 assert object.data["like_count"] == 1
560
561 {:ok, _, _, object} = ActivityPub.unlike(user, object)
562 assert object.data["like_count"] == 0
563
564 assert Activity.get_by_id(like_activity.id) == nil
565 end
566 end
567
568 describe "announcing an object" do
569 test "adds an announce activity to the db" do
570 note_activity = insert(:note_activity)
571 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
572 user = insert(:user)
573
574 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
575 assert object.data["announcement_count"] == 1
576 assert object.data["announcements"] == [user.ap_id]
577
578 assert announce_activity.data["to"] == [
579 User.ap_followers(user),
580 note_activity.data["actor"]
581 ]
582
583 assert announce_activity.data["object"] == object.data["id"]
584 assert announce_activity.data["actor"] == user.ap_id
585 assert announce_activity.data["context"] == object.data["context"]
586 end
587 end
588
589 describe "unannouncing an object" do
590 test "unannouncing a previously announced object" do
591 note_activity = insert(:note_activity)
592 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
593 user = insert(:user)
594
595 # Unannouncing an object that is not announced does nothing
596 # {:ok, object} = ActivityPub.unannounce(user, object)
597 # assert object.data["announcement_count"] == 0
598
599 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
600 assert object.data["announcement_count"] == 1
601
602 {:ok, unannounce_activity, object} = ActivityPub.unannounce(user, object)
603 assert object.data["announcement_count"] == 0
604
605 assert unannounce_activity.data["to"] == [
606 User.ap_followers(user),
607 announce_activity.data["actor"]
608 ]
609
610 assert unannounce_activity.data["type"] == "Undo"
611 assert unannounce_activity.data["object"] == announce_activity.data
612 assert unannounce_activity.data["actor"] == user.ap_id
613 assert unannounce_activity.data["context"] == announce_activity.data["context"]
614
615 assert Activity.get_by_id(announce_activity.id) == nil
616 end
617 end
618
619 describe "uploading files" do
620 test "copies the file to the configured folder" do
621 file = %Plug.Upload{
622 content_type: "image/jpg",
623 path: Path.absname("test/fixtures/image.jpg"),
624 filename: "an_image.jpg"
625 }
626
627 {:ok, %Object{} = object} = ActivityPub.upload(file)
628 assert object.data["name"] == "an_image.jpg"
629 end
630
631 test "works with base64 encoded images" do
632 file = %{
633 "img" => data_uri()
634 }
635
636 {:ok, %Object{}} = ActivityPub.upload(file)
637 end
638 end
639
640 describe "fetch the latest Follow" do
641 test "fetches the latest Follow activity" do
642 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
643 follower = Repo.get_by(User, ap_id: activity.data["actor"])
644 followed = Repo.get_by(User, ap_id: activity.data["object"])
645
646 assert activity == Utils.fetch_latest_follow(follower, followed)
647 end
648 end
649
650 describe "following / unfollowing" do
651 test "creates a follow activity" do
652 follower = insert(:user)
653 followed = insert(:user)
654
655 {:ok, activity} = ActivityPub.follow(follower, followed)
656 assert activity.data["type"] == "Follow"
657 assert activity.data["actor"] == follower.ap_id
658 assert activity.data["object"] == followed.ap_id
659 end
660
661 test "creates an undo activity for the last follow" do
662 follower = insert(:user)
663 followed = insert(:user)
664
665 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
666 {:ok, activity} = ActivityPub.unfollow(follower, followed)
667
668 assert activity.data["type"] == "Undo"
669 assert activity.data["actor"] == follower.ap_id
670
671 assert is_map(activity.data["object"])
672 assert activity.data["object"]["type"] == "Follow"
673 assert activity.data["object"]["object"] == followed.ap_id
674 assert activity.data["object"]["id"] == follow_activity.data["id"]
675 end
676 end
677
678 describe "blocking / unblocking" do
679 test "creates a block activity" do
680 blocker = insert(:user)
681 blocked = insert(:user)
682
683 {:ok, activity} = ActivityPub.block(blocker, blocked)
684
685 assert activity.data["type"] == "Block"
686 assert activity.data["actor"] == blocker.ap_id
687 assert activity.data["object"] == blocked.ap_id
688 end
689
690 test "creates an undo activity for the last block" do
691 blocker = insert(:user)
692 blocked = insert(:user)
693
694 {:ok, block_activity} = ActivityPub.block(blocker, blocked)
695 {:ok, activity} = ActivityPub.unblock(blocker, blocked)
696
697 assert activity.data["type"] == "Undo"
698 assert activity.data["actor"] == blocker.ap_id
699
700 assert is_map(activity.data["object"])
701 assert activity.data["object"]["type"] == "Block"
702 assert activity.data["object"]["object"] == blocked.ap_id
703 assert activity.data["object"]["id"] == block_activity.data["id"]
704 end
705 end
706
707 describe "deletion" do
708 test "it creates a delete activity and deletes the original object" do
709 note = insert(:note_activity)
710 object = Object.get_by_ap_id(note.data["object"]["id"])
711 {:ok, delete} = ActivityPub.delete(object)
712
713 assert delete.data["type"] == "Delete"
714 assert delete.data["actor"] == note.data["actor"]
715 assert delete.data["object"] == note.data["object"]["id"]
716
717 assert Activity.get_by_id(delete.id) != nil
718
719 assert Repo.get(Object, object.id).data["type"] == "Tombstone"
720 end
721
722 test "decrements user note count only for public activities" do
723 user = insert(:user, info: %{note_count: 10})
724
725 {:ok, a1} =
726 CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "public"})
727
728 {:ok, a2} =
729 CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "unlisted"})
730
731 {:ok, a3} =
732 CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "private"})
733
734 {:ok, a4} =
735 CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "direct"})
736
737 {:ok, _} = Object.normalize(a1) |> ActivityPub.delete()
738 {:ok, _} = Object.normalize(a2) |> ActivityPub.delete()
739 {:ok, _} = Object.normalize(a3) |> ActivityPub.delete()
740 {:ok, _} = Object.normalize(a4) |> ActivityPub.delete()
741
742 user = User.get_by_id(user.id)
743 assert user.info.note_count == 10
744 end
745
746 test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
747 user = insert(:user)
748 note = insert(:note_activity)
749
750 {:ok, object} =
751 Object.get_by_ap_id(note.data["object"]["id"])
752 |> Object.change(%{
753 data: %{
754 "actor" => note.data["object"]["actor"],
755 "id" => note.data["object"]["id"],
756 "to" => [user.ap_id],
757 "type" => "Note"
758 }
759 })
760 |> Object.update_and_set_cache()
761
762 {:ok, delete} = ActivityPub.delete(object)
763
764 assert user.ap_id in delete.data["to"]
765 end
766
767 test "decreases reply count" do
768 user = insert(:user)
769 user2 = insert(:user)
770
771 {:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
772 reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
773 ap_id = activity.data["id"]
774
775 {:ok, public_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
776 {:ok, unlisted_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
777 {:ok, private_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
778 {:ok, direct_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
779
780 _ = CommonAPI.delete(direct_reply.id, user2)
781 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
782 assert object.data["repliesCount"] == 2
783
784 _ = CommonAPI.delete(private_reply.id, user2)
785 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
786 assert object.data["repliesCount"] == 2
787
788 _ = CommonAPI.delete(public_reply.id, user2)
789 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
790 assert object.data["repliesCount"] == 1
791
792 _ = CommonAPI.delete(unlisted_reply.id, user2)
793 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
794 assert object.data["repliesCount"] == 0
795 end
796 end
797
798 describe "timeline post-processing" do
799 test "it filters broken threads" do
800 user1 = insert(:user)
801 user2 = insert(:user)
802 user3 = insert(:user)
803
804 {:ok, user1} = User.follow(user1, user3)
805 assert User.following?(user1, user3)
806
807 {:ok, user2} = User.follow(user2, user3)
808 assert User.following?(user2, user3)
809
810 {:ok, user3} = User.follow(user3, user2)
811 assert User.following?(user3, user2)
812
813 {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
814
815 {:ok, private_activity_1} =
816 CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
817
818 {:ok, private_activity_2} =
819 CommonAPI.post(user2, %{
820 "status" => "hi 3",
821 "visibility" => "private",
822 "in_reply_to_status_id" => private_activity_1.id
823 })
824
825 {:ok, private_activity_3} =
826 CommonAPI.post(user3, %{
827 "status" => "hi 4",
828 "visibility" => "private",
829 "in_reply_to_status_id" => private_activity_2.id
830 })
831
832 activities = ActivityPub.fetch_activities([user1.ap_id | user1.following])
833
834 private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"])
835 assert [public_activity, private_activity_1, private_activity_3] ==
836 activities
837
838 assert length(activities) == 3
839
840 activities = ActivityPub.contain_timeline(activities, user1)
841
842 assert [public_activity, private_activity_1] == activities
843 assert length(activities) == 2
844 end
845 end
846
847 describe "update" do
848 test "it creates an update activity with the new user data" do
849 user = insert(:user)
850 {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
851 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
852
853 {:ok, update} =
854 ActivityPub.update(%{
855 actor: user_data["id"],
856 to: [user.follower_address],
857 cc: [],
858 object: user_data
859 })
860
861 assert update.data["actor"] == user.ap_id
862 assert update.data["to"] == [user.follower_address]
863 assert update.data["object"]["id"] == user_data["id"]
864 assert update.data["object"]["type"] == user_data["type"]
865 end
866 end
867
868 test "returned pinned statuses" do
869 Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
870 user = insert(:user)
871
872 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
873 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
874 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
875
876 CommonAPI.pin(activity_one.id, user)
877 user = refresh_record(user)
878
879 CommonAPI.pin(activity_two.id, user)
880 user = refresh_record(user)
881
882 CommonAPI.pin(activity_three.id, user)
883 user = refresh_record(user)
884
885 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
886
887 assert 3 = length(activities)
888 end
889
890 test "it can create a Flag activity" do
891 reporter = insert(:user)
892 target_account = insert(:user)
893 {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"})
894 context = Utils.generate_context_id()
895 content = "foobar"
896
897 reporter_ap_id = reporter.ap_id
898 target_ap_id = target_account.ap_id
899 activity_ap_id = activity.data["id"]
900
901 assert {:ok, activity} =
902 ActivityPub.flag(%{
903 actor: reporter,
904 context: context,
905 account: target_account,
906 statuses: [activity],
907 content: content
908 })
909
910 assert %Activity{
911 actor: ^reporter_ap_id,
912 data: %{
913 "type" => "Flag",
914 "content" => ^content,
915 "context" => ^context,
916 "object" => [^target_ap_id, ^activity_ap_id]
917 }
918 } = activity
919 end
920
921 describe "publish_one/1" do
922 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
923 Instances,
924 [:passthrough],
925 [] do
926 actor = insert(:user)
927 inbox = "http://200.site/users/nick1/inbox"
928
929 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
930
931 assert called(Instances.set_reachable(inbox))
932 end
933
934 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
935 Instances,
936 [:passthrough],
937 [] do
938 actor = insert(:user)
939 inbox = "http://200.site/users/nick1/inbox"
940
941 assert {:ok, _} =
942 ActivityPub.publish_one(%{
943 inbox: inbox,
944 json: "{}",
945 actor: actor,
946 id: 1,
947 unreachable_since: NaiveDateTime.utc_now()
948 })
949
950 assert called(Instances.set_reachable(inbox))
951 end
952
953 test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
954 Instances,
955 [:passthrough],
956 [] do
957 actor = insert(:user)
958 inbox = "http://200.site/users/nick1/inbox"
959
960 assert {:ok, _} =
961 ActivityPub.publish_one(%{
962 inbox: inbox,
963 json: "{}",
964 actor: actor,
965 id: 1,
966 unreachable_since: nil
967 })
968
969 refute called(Instances.set_reachable(inbox))
970 end
971
972 test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
973 Instances,
974 [:passthrough],
975 [] do
976 actor = insert(:user)
977 inbox = "http://404.site/users/nick1/inbox"
978
979 assert {:error, _} =
980 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
981
982 assert called(Instances.set_unreachable(inbox))
983 end
984
985 test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
986 Instances,
987 [:passthrough],
988 [] do
989 actor = insert(:user)
990 inbox = "http://connrefused.site/users/nick1/inbox"
991
992 assert {:error, _} =
993 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
994
995 assert called(Instances.set_unreachable(inbox))
996 end
997
998 test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
999 Instances,
1000 [:passthrough],
1001 [] do
1002 actor = insert(:user)
1003 inbox = "http://200.site/users/nick1/inbox"
1004
1005 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
1006
1007 refute called(Instances.set_unreachable(inbox))
1008 end
1009
1010 test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
1011 Instances,
1012 [:passthrough],
1013 [] do
1014 actor = insert(:user)
1015 inbox = "http://connrefused.site/users/nick1/inbox"
1016
1017 assert {:error, _} =
1018 ActivityPub.publish_one(%{
1019 inbox: inbox,
1020 json: "{}",
1021 actor: actor,
1022 id: 1,
1023 unreachable_since: NaiveDateTime.utc_now()
1024 })
1025
1026 refute called(Instances.set_unreachable(inbox))
1027 end
1028 end
1029
1030 def data_uri do
1031 File.read!("test/fixtures/avatar_data_uri")
1032 end
1033 end