Refactor tests that used ActivityPub.fetch_object_from_id
[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] == activities
836 assert length(activities) == 3
837
838 activities = ActivityPub.contain_timeline(activities, user1)
839
840 assert [public_activity, private_activity_1] == activities
841 assert length(activities) == 2
842 end
843 end
844
845 describe "update" do
846 test "it creates an update activity with the new user data" do
847 user = insert(:user)
848 {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
849 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
850
851 {:ok, update} =
852 ActivityPub.update(%{
853 actor: user_data["id"],
854 to: [user.follower_address],
855 cc: [],
856 object: user_data
857 })
858
859 assert update.data["actor"] == user.ap_id
860 assert update.data["to"] == [user.follower_address]
861 assert update.data["object"]["id"] == user_data["id"]
862 assert update.data["object"]["type"] == user_data["type"]
863 end
864 end
865
866 test "returned pinned statuses" do
867 Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
868 user = insert(:user)
869
870 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
871 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
872 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
873
874 CommonAPI.pin(activity_one.id, user)
875 user = refresh_record(user)
876
877 CommonAPI.pin(activity_two.id, user)
878 user = refresh_record(user)
879
880 CommonAPI.pin(activity_three.id, user)
881 user = refresh_record(user)
882
883 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
884
885 assert 3 = length(activities)
886 end
887
888 test "it can create a Flag activity" do
889 reporter = insert(:user)
890 target_account = insert(:user)
891 {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"})
892 context = Utils.generate_context_id()
893 content = "foobar"
894
895 reporter_ap_id = reporter.ap_id
896 target_ap_id = target_account.ap_id
897 activity_ap_id = activity.data["id"]
898
899 assert {:ok, activity} =
900 ActivityPub.flag(%{
901 actor: reporter,
902 context: context,
903 account: target_account,
904 statuses: [activity],
905 content: content
906 })
907
908 assert %Activity{
909 actor: ^reporter_ap_id,
910 data: %{
911 "type" => "Flag",
912 "content" => ^content,
913 "context" => ^context,
914 "object" => [^target_ap_id, ^activity_ap_id]
915 }
916 } = activity
917 end
918
919 describe "publish_one/1" do
920 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
921 Instances,
922 [:passthrough],
923 [] do
924 actor = insert(:user)
925 inbox = "http://200.site/users/nick1/inbox"
926
927 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
928
929 assert called(Instances.set_reachable(inbox))
930 end
931
932 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
933 Instances,
934 [:passthrough],
935 [] do
936 actor = insert(:user)
937 inbox = "http://200.site/users/nick1/inbox"
938
939 assert {:ok, _} =
940 ActivityPub.publish_one(%{
941 inbox: inbox,
942 json: "{}",
943 actor: actor,
944 id: 1,
945 unreachable_since: NaiveDateTime.utc_now()
946 })
947
948 assert called(Instances.set_reachable(inbox))
949 end
950
951 test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
952 Instances,
953 [:passthrough],
954 [] do
955 actor = insert(:user)
956 inbox = "http://200.site/users/nick1/inbox"
957
958 assert {:ok, _} =
959 ActivityPub.publish_one(%{
960 inbox: inbox,
961 json: "{}",
962 actor: actor,
963 id: 1,
964 unreachable_since: nil
965 })
966
967 refute called(Instances.set_reachable(inbox))
968 end
969
970 test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
971 Instances,
972 [:passthrough],
973 [] do
974 actor = insert(:user)
975 inbox = "http://404.site/users/nick1/inbox"
976
977 assert {:error, _} =
978 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
979
980 assert called(Instances.set_unreachable(inbox))
981 end
982
983 test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
984 Instances,
985 [:passthrough],
986 [] do
987 actor = insert(:user)
988 inbox = "http://connrefused.site/users/nick1/inbox"
989
990 assert {:error, _} =
991 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
992
993 assert called(Instances.set_unreachable(inbox))
994 end
995
996 test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
997 Instances,
998 [:passthrough],
999 [] do
1000 actor = insert(:user)
1001 inbox = "http://200.site/users/nick1/inbox"
1002
1003 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
1004
1005 refute called(Instances.set_unreachable(inbox))
1006 end
1007
1008 test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
1009 Instances,
1010 [:passthrough],
1011 [] do
1012 actor = insert(:user)
1013 inbox = "http://connrefused.site/users/nick1/inbox"
1014
1015 assert {:error, _} =
1016 ActivityPub.publish_one(%{
1017 inbox: inbox,
1018 json: "{}",
1019 actor: actor,
1020 id: 1,
1021 unreachable_since: NaiveDateTime.utc_now()
1022 })
1023
1024 refute called(Instances.set_unreachable(inbox))
1025 end
1026 end
1027
1028 def data_uri do
1029 File.read!("test/fixtures/avatar_data_uri")
1030 end
1031 end