Merge branch 'feature/reports' into 'develop'
[akkoma] / test / web / activity_pub / activity_pub_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
6 use Pleroma.DataCase
7 alias Pleroma.Web.ActivityPub.ActivityPub
8 alias Pleroma.Web.ActivityPub.Utils
9 alias Pleroma.Web.CommonAPI
10 alias Pleroma.Activity
11 alias Pleroma.Object
12 alias Pleroma.User
13 alias Pleroma.Instances
14 alias Pleroma.Builders.ActivityBuilder
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 end
59 end
60
61 describe "building a user from his ap id" do
62 test "it returns a user" do
63 user_id = "http://mastodon.example.org/users/admin"
64 {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
65 assert user.ap_id == user_id
66 assert user.nickname == "admin@mastodon.example.org"
67 assert user.info.source_data
68 assert user.info.ap_enabled
69 assert user.follower_address == "http://mastodon.example.org/users/admin/followers"
70 end
71
72 test "it fetches the appropriate tag-restricted posts" do
73 user = insert(:user)
74
75 {:ok, status_one} = CommonAPI.post(user, %{"status" => ". #test"})
76 {:ok, status_two} = CommonAPI.post(user, %{"status" => ". #essais"})
77 {:ok, status_three} = CommonAPI.post(user, %{"status" => ". #test #reject"})
78
79 fetch_one = ActivityPub.fetch_activities([], %{"tag" => "test"})
80 fetch_two = ActivityPub.fetch_activities([], %{"tag" => ["test", "essais"]})
81
82 fetch_three =
83 ActivityPub.fetch_activities([], %{
84 "tag" => ["test", "essais"],
85 "tag_reject" => ["reject"]
86 })
87
88 fetch_four =
89 ActivityPub.fetch_activities([], %{
90 "tag" => ["test"],
91 "tag_all" => ["test", "reject"]
92 })
93
94 assert fetch_one == [status_one, status_three]
95 assert fetch_two == [status_one, status_two, status_three]
96 assert fetch_three == [status_one, status_two]
97 assert fetch_four == [status_three]
98 end
99 end
100
101 describe "insertion" do
102 test "drops activities beyond a certain limit" do
103 limit = Pleroma.Config.get([:instance, :remote_limit])
104
105 random_text =
106 :crypto.strong_rand_bytes(limit + 1)
107 |> Base.encode64()
108 |> binary_part(0, limit + 1)
109
110 data = %{
111 "ok" => true,
112 "object" => %{
113 "content" => random_text
114 }
115 }
116
117 assert {:error, {:remote_limit_error, _}} = ActivityPub.insert(data)
118 end
119
120 test "doesn't drop activities with content being null" do
121 data = %{
122 "ok" => true,
123 "object" => %{
124 "content" => nil
125 }
126 }
127
128 assert {:ok, _} = ActivityPub.insert(data)
129 end
130
131 test "returns the activity if one with the same id is already in" do
132 activity = insert(:note_activity)
133 {:ok, new_activity} = ActivityPub.insert(activity.data)
134
135 assert activity == new_activity
136 end
137
138 test "inserts a given map into the activity database, giving it an id if it has none." do
139 data = %{
140 "ok" => true
141 }
142
143 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
144 assert activity.data["ok"] == data["ok"]
145 assert is_binary(activity.data["id"])
146
147 given_id = "bla"
148
149 data = %{
150 "ok" => true,
151 "id" => given_id,
152 "context" => "blabla"
153 }
154
155 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
156 assert activity.data["ok"] == data["ok"]
157 assert activity.data["id"] == given_id
158 assert activity.data["context"] == "blabla"
159 assert activity.data["context_id"]
160 end
161
162 test "adds a context when none is there" do
163 data = %{
164 "id" => "some_id",
165 "object" => %{
166 "id" => "object_id"
167 }
168 }
169
170 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
171
172 assert is_binary(activity.data["context"])
173 assert is_binary(activity.data["object"]["context"])
174 assert activity.data["context_id"]
175 assert activity.data["object"]["context_id"]
176 end
177
178 test "adds an id to a given object if it lacks one and is a note and inserts it to the object database" do
179 data = %{
180 "object" => %{
181 "type" => "Note",
182 "ok" => true
183 }
184 }
185
186 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
187 assert is_binary(activity.data["object"]["id"])
188 assert %Object{} = Object.get_by_ap_id(activity.data["object"]["id"])
189 end
190 end
191
192 describe "create activities" do
193 test "removes doubled 'to' recipients" do
194 user = insert(:user)
195
196 {:ok, activity} =
197 ActivityPub.create(%{
198 to: ["user1", "user1", "user2"],
199 actor: user,
200 context: "",
201 object: %{}
202 })
203
204 assert activity.data["to"] == ["user1", "user2"]
205 assert activity.actor == user.ap_id
206 assert activity.recipients == ["user1", "user2", user.ap_id]
207 end
208 end
209
210 describe "fetch activities for recipients" do
211 test "retrieve the activities for certain recipients" do
212 {:ok, activity_one} = ActivityBuilder.insert(%{"to" => ["someone"]})
213 {:ok, activity_two} = ActivityBuilder.insert(%{"to" => ["someone_else"]})
214 {:ok, _activity_three} = ActivityBuilder.insert(%{"to" => ["noone"]})
215
216 activities = ActivityPub.fetch_activities(["someone", "someone_else"])
217 assert length(activities) == 2
218 assert activities == [activity_one, activity_two]
219 end
220 end
221
222 describe "fetch activities in context" do
223 test "retrieves activities that have a given context" do
224 {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
225 {:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
226 {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
227 {:ok, _activity_four} = ActivityBuilder.insert(%{"type" => "Announce", "context" => "2hu"})
228 activity_five = insert(:note_activity)
229 user = insert(:user)
230
231 {:ok, user} = User.block(user, %{ap_id: activity_five.data["actor"]})
232
233 activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user})
234 assert activities == [activity_two, activity]
235 end
236 end
237
238 test "doesn't return blocked activities" do
239 activity_one = insert(:note_activity)
240 activity_two = insert(:note_activity)
241 activity_three = insert(:note_activity)
242 user = insert(:user)
243 booster = insert(:user)
244 {:ok, user} = User.block(user, %{ap_id: activity_one.data["actor"]})
245
246 activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
247
248 assert Enum.member?(activities, activity_two)
249 assert Enum.member?(activities, activity_three)
250 refute Enum.member?(activities, activity_one)
251
252 {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
253
254 activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
255
256 assert Enum.member?(activities, activity_two)
257 assert Enum.member?(activities, activity_three)
258 assert Enum.member?(activities, activity_one)
259
260 {:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
261 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
262 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
263 activity_three = Repo.get(Activity, activity_three.id)
264
265 activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
266
267 assert Enum.member?(activities, activity_two)
268 refute Enum.member?(activities, activity_three)
269 refute Enum.member?(activities, boost_activity)
270 assert Enum.member?(activities, activity_one)
271
272 activities = ActivityPub.fetch_activities([], %{"blocking_user" => nil})
273
274 assert Enum.member?(activities, activity_two)
275 assert Enum.member?(activities, activity_three)
276 assert Enum.member?(activities, boost_activity)
277 assert Enum.member?(activities, activity_one)
278 end
279
280 test "doesn't return muted activities" do
281 activity_one = insert(:note_activity)
282 activity_two = insert(:note_activity)
283 activity_three = insert(:note_activity)
284 user = insert(:user)
285 booster = insert(:user)
286 {:ok, user} = User.mute(user, %User{ap_id: activity_one.data["actor"]})
287
288 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
289
290 assert Enum.member?(activities, activity_two)
291 assert Enum.member?(activities, activity_three)
292 refute Enum.member?(activities, activity_one)
293
294 {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]})
295
296 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
297
298 assert Enum.member?(activities, activity_two)
299 assert Enum.member?(activities, activity_three)
300 assert Enum.member?(activities, activity_one)
301
302 {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
303 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
304 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
305 activity_three = Repo.get(Activity, activity_three.id)
306
307 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
308
309 assert Enum.member?(activities, activity_two)
310 refute Enum.member?(activities, activity_three)
311 refute Enum.member?(activities, boost_activity)
312 assert Enum.member?(activities, activity_one)
313
314 activities = ActivityPub.fetch_activities([], %{"muting_user" => nil})
315
316 assert Enum.member?(activities, activity_two)
317 assert Enum.member?(activities, activity_three)
318 assert Enum.member?(activities, boost_activity)
319 assert Enum.member?(activities, activity_one)
320 end
321
322 test "excludes reblogs on request" do
323 user = insert(:user)
324 {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
325 {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user})
326
327 [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"})
328
329 assert activity == expected_activity
330 end
331
332 describe "public fetch activities" do
333 test "doesn't retrieve unlisted activities" do
334 user = insert(:user)
335
336 {:ok, _unlisted_activity} =
337 CommonAPI.post(user, %{"status" => "yeah", "visibility" => "unlisted"})
338
339 {:ok, listed_activity} = CommonAPI.post(user, %{"status" => "yeah"})
340
341 [activity] = ActivityPub.fetch_public_activities()
342
343 assert activity == listed_activity
344 end
345
346 test "retrieves public activities" do
347 _activities = ActivityPub.fetch_public_activities()
348
349 %{public: public} = ActivityBuilder.public_and_non_public()
350
351 activities = ActivityPub.fetch_public_activities()
352 assert length(activities) == 1
353 assert Enum.at(activities, 0) == public
354 end
355
356 test "retrieves a maximum of 20 activities" do
357 activities = ActivityBuilder.insert_list(30)
358 last_expected = List.last(activities)
359
360 activities = ActivityPub.fetch_public_activities()
361 last = List.last(activities)
362
363 assert length(activities) == 20
364 assert last == last_expected
365 end
366
367 test "retrieves ids starting from a since_id" do
368 activities = ActivityBuilder.insert_list(30)
369 later_activities = ActivityBuilder.insert_list(10)
370 since_id = List.last(activities).id
371 last_expected = List.last(later_activities)
372
373 activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id})
374 last = List.last(activities)
375
376 assert length(activities) == 10
377 assert last == last_expected
378 end
379
380 test "retrieves ids up to max_id" do
381 _first_activities = ActivityBuilder.insert_list(10)
382 activities = ActivityBuilder.insert_list(20)
383 later_activities = ActivityBuilder.insert_list(10)
384 max_id = List.first(later_activities).id
385 last_expected = List.last(activities)
386
387 activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id})
388 last = List.last(activities)
389
390 assert length(activities) == 20
391 assert last == last_expected
392 end
393 end
394
395 describe "like an object" do
396 test "adds a like activity to the db" do
397 note_activity = insert(:note_activity)
398 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
399 user = insert(:user)
400 user_two = insert(:user)
401
402 {:ok, like_activity, object} = ActivityPub.like(user, object)
403
404 assert like_activity.data["actor"] == user.ap_id
405 assert like_activity.data["type"] == "Like"
406 assert like_activity.data["object"] == object.data["id"]
407 assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
408 assert like_activity.data["context"] == object.data["context"]
409 assert object.data["like_count"] == 1
410 assert object.data["likes"] == [user.ap_id]
411
412 # Just return the original activity if the user already liked it.
413 {:ok, same_like_activity, object} = ActivityPub.like(user, object)
414
415 assert like_activity == same_like_activity
416 assert object.data["likes"] == [user.ap_id]
417
418 [note_activity] = Activity.get_all_create_by_object_ap_id(object.data["id"])
419 assert note_activity.data["object"]["like_count"] == 1
420
421 {:ok, _like_activity, object} = ActivityPub.like(user_two, object)
422 assert object.data["like_count"] == 2
423 end
424 end
425
426 describe "unliking" do
427 test "unliking a previously liked object" do
428 note_activity = insert(:note_activity)
429 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
430 user = insert(:user)
431
432 # Unliking something that hasn't been liked does nothing
433 {:ok, object} = ActivityPub.unlike(user, object)
434 assert object.data["like_count"] == 0
435
436 {:ok, like_activity, object} = ActivityPub.like(user, object)
437 assert object.data["like_count"] == 1
438
439 {:ok, _, _, object} = ActivityPub.unlike(user, object)
440 assert object.data["like_count"] == 0
441
442 assert Repo.get(Activity, like_activity.id) == nil
443 end
444 end
445
446 describe "announcing an object" do
447 test "adds an announce activity to the db" do
448 note_activity = insert(:note_activity)
449 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
450 user = insert(:user)
451
452 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
453 assert object.data["announcement_count"] == 1
454 assert object.data["announcements"] == [user.ap_id]
455
456 assert announce_activity.data["to"] == [
457 User.ap_followers(user),
458 note_activity.data["actor"]
459 ]
460
461 assert announce_activity.data["object"] == object.data["id"]
462 assert announce_activity.data["actor"] == user.ap_id
463 assert announce_activity.data["context"] == object.data["context"]
464 end
465 end
466
467 describe "unannouncing an object" do
468 test "unannouncing a previously announced object" do
469 note_activity = insert(:note_activity)
470 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
471 user = insert(:user)
472
473 # Unannouncing an object that is not announced does nothing
474 # {:ok, object} = ActivityPub.unannounce(user, object)
475 # assert object.data["announcement_count"] == 0
476
477 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
478 assert object.data["announcement_count"] == 1
479
480 {:ok, unannounce_activity, object} = ActivityPub.unannounce(user, object)
481 assert object.data["announcement_count"] == 0
482
483 assert unannounce_activity.data["to"] == [
484 User.ap_followers(user),
485 announce_activity.data["actor"]
486 ]
487
488 assert unannounce_activity.data["type"] == "Undo"
489 assert unannounce_activity.data["object"] == announce_activity.data
490 assert unannounce_activity.data["actor"] == user.ap_id
491 assert unannounce_activity.data["context"] == announce_activity.data["context"]
492
493 assert Repo.get(Activity, announce_activity.id) == nil
494 end
495 end
496
497 describe "uploading files" do
498 test "copies the file to the configured folder" do
499 file = %Plug.Upload{
500 content_type: "image/jpg",
501 path: Path.absname("test/fixtures/image.jpg"),
502 filename: "an_image.jpg"
503 }
504
505 {:ok, %Object{} = object} = ActivityPub.upload(file)
506 assert object.data["name"] == "an_image.jpg"
507 end
508
509 test "works with base64 encoded images" do
510 file = %{
511 "img" => data_uri()
512 }
513
514 {:ok, %Object{}} = ActivityPub.upload(file)
515 end
516 end
517
518 describe "fetch the latest Follow" do
519 test "fetches the latest Follow activity" do
520 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
521 follower = Repo.get_by(User, ap_id: activity.data["actor"])
522 followed = Repo.get_by(User, ap_id: activity.data["object"])
523
524 assert activity == Utils.fetch_latest_follow(follower, followed)
525 end
526 end
527
528 describe "fetching an object" do
529 test "it fetches an object" do
530 {:ok, object} =
531 ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
532
533 assert activity = Activity.get_create_by_object_ap_id(object.data["id"])
534 assert activity.data["id"]
535
536 {:ok, object_again} =
537 ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
538
539 assert [attachment] = object.data["attachment"]
540 assert is_list(attachment["url"])
541
542 assert object == object_again
543 end
544
545 test "it works with objects only available via Ostatus" do
546 {:ok, object} = ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873")
547 assert activity = Activity.get_create_by_object_ap_id(object.data["id"])
548 assert activity.data["id"]
549
550 {:ok, object_again} =
551 ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873")
552
553 assert object == object_again
554 end
555
556 test "it correctly stitches up conversations between ostatus and ap" do
557 last = "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
558 {:ok, object} = ActivityPub.fetch_object_from_id(last)
559
560 object = Object.get_by_ap_id(object.data["inReplyTo"])
561 assert object
562 end
563 end
564
565 describe "following / unfollowing" do
566 test "creates a follow activity" do
567 follower = insert(:user)
568 followed = insert(:user)
569
570 {:ok, activity} = ActivityPub.follow(follower, followed)
571 assert activity.data["type"] == "Follow"
572 assert activity.data["actor"] == follower.ap_id
573 assert activity.data["object"] == followed.ap_id
574 end
575
576 test "creates an undo activity for the last follow" do
577 follower = insert(:user)
578 followed = insert(:user)
579
580 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
581 {:ok, activity} = ActivityPub.unfollow(follower, followed)
582
583 assert activity.data["type"] == "Undo"
584 assert activity.data["actor"] == follower.ap_id
585
586 assert is_map(activity.data["object"])
587 assert activity.data["object"]["type"] == "Follow"
588 assert activity.data["object"]["object"] == followed.ap_id
589 assert activity.data["object"]["id"] == follow_activity.data["id"]
590 end
591 end
592
593 describe "blocking / unblocking" do
594 test "creates a block activity" do
595 blocker = insert(:user)
596 blocked = insert(:user)
597
598 {:ok, activity} = ActivityPub.block(blocker, blocked)
599
600 assert activity.data["type"] == "Block"
601 assert activity.data["actor"] == blocker.ap_id
602 assert activity.data["object"] == blocked.ap_id
603 end
604
605 test "creates an undo activity for the last block" do
606 blocker = insert(:user)
607 blocked = insert(:user)
608
609 {:ok, block_activity} = ActivityPub.block(blocker, blocked)
610 {:ok, activity} = ActivityPub.unblock(blocker, blocked)
611
612 assert activity.data["type"] == "Undo"
613 assert activity.data["actor"] == blocker.ap_id
614
615 assert is_map(activity.data["object"])
616 assert activity.data["object"]["type"] == "Block"
617 assert activity.data["object"]["object"] == blocked.ap_id
618 assert activity.data["object"]["id"] == block_activity.data["id"]
619 end
620 end
621
622 describe "deletion" do
623 test "it creates a delete activity and deletes the original object" do
624 note = insert(:note_activity)
625 object = Object.get_by_ap_id(note.data["object"]["id"])
626 {:ok, delete} = ActivityPub.delete(object)
627
628 assert delete.data["type"] == "Delete"
629 assert delete.data["actor"] == note.data["actor"]
630 assert delete.data["object"] == note.data["object"]["id"]
631
632 assert Repo.get(Activity, delete.id) != nil
633
634 assert Repo.get(Object, object.id).data["type"] == "Tombstone"
635 end
636 end
637
638 describe "timeline post-processing" do
639 test "it filters broken threads" do
640 user1 = insert(:user)
641 user2 = insert(:user)
642 user3 = insert(:user)
643
644 {:ok, user1} = User.follow(user1, user3)
645 assert User.following?(user1, user3)
646
647 {:ok, user2} = User.follow(user2, user3)
648 assert User.following?(user2, user3)
649
650 {:ok, user3} = User.follow(user3, user2)
651 assert User.following?(user3, user2)
652
653 {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
654
655 {:ok, private_activity_1} =
656 CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
657
658 {:ok, private_activity_2} =
659 CommonAPI.post(user2, %{
660 "status" => "hi 3",
661 "visibility" => "private",
662 "in_reply_to_status_id" => private_activity_1.id
663 })
664
665 {:ok, private_activity_3} =
666 CommonAPI.post(user3, %{
667 "status" => "hi 4",
668 "visibility" => "private",
669 "in_reply_to_status_id" => private_activity_2.id
670 })
671
672 activities = ActivityPub.fetch_activities([user1.ap_id | user1.following])
673
674 assert [public_activity, private_activity_1, private_activity_3] == activities
675 assert length(activities) == 3
676
677 activities = ActivityPub.contain_timeline(activities, user1)
678
679 assert [public_activity, private_activity_1] == activities
680 assert length(activities) == 2
681 end
682 end
683
684 test "it can fetch plume articles" do
685 {:ok, object} =
686 ActivityPub.fetch_object_from_id(
687 "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"
688 )
689
690 assert object
691 end
692
693 describe "update" do
694 test "it creates an update activity with the new user data" do
695 user = insert(:user)
696 {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
697 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
698
699 {:ok, update} =
700 ActivityPub.update(%{
701 actor: user_data["id"],
702 to: [user.follower_address],
703 cc: [],
704 object: user_data
705 })
706
707 assert update.data["actor"] == user.ap_id
708 assert update.data["to"] == [user.follower_address]
709 assert update.data["object"]["id"] == user_data["id"]
710 assert update.data["object"]["type"] == user_data["type"]
711 end
712 end
713
714 test "it can fetch peertube videos" do
715 {:ok, object} =
716 ActivityPub.fetch_object_from_id(
717 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
718 )
719
720 assert object
721 end
722
723 test "returned pinned statuses" do
724 Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
725 user = insert(:user)
726
727 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
728 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
729 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
730
731 CommonAPI.pin(activity_one.id, user)
732 user = refresh_record(user)
733
734 CommonAPI.pin(activity_two.id, user)
735 user = refresh_record(user)
736
737 CommonAPI.pin(activity_three.id, user)
738 user = refresh_record(user)
739
740 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
741
742 assert 3 = length(activities)
743 end
744
745 test "it can create a Flag activity" do
746 reporter = insert(:user)
747 target_account = insert(:user)
748 {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"})
749 context = Utils.generate_context_id()
750 content = "foobar"
751
752 reporter_ap_id = reporter.ap_id
753 target_ap_id = target_account.ap_id
754 activity_ap_id = activity.data["id"]
755
756 assert {:ok, activity} =
757 ActivityPub.flag(%{
758 actor: reporter,
759 context: context,
760 account: target_account,
761 statuses: [activity],
762 content: content
763 })
764
765 assert %Activity{
766 actor: ^reporter_ap_id,
767 data: %{
768 "type" => "Flag",
769 "content" => ^content,
770 "context" => ^context,
771 "object" => [^target_ap_id, ^activity_ap_id]
772 }
773 } = activity
774 end
775
776 describe "publish_one/1" do
777 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
778 Instances,
779 [:passthrough],
780 [] do
781 actor = insert(:user)
782 inbox = "http://200.site/users/nick1/inbox"
783
784 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
785
786 assert called(Instances.set_reachable(inbox))
787 end
788
789 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
790 Instances,
791 [:passthrough],
792 [] do
793 actor = insert(:user)
794 inbox = "http://200.site/users/nick1/inbox"
795
796 assert {:ok, _} =
797 ActivityPub.publish_one(%{
798 inbox: inbox,
799 json: "{}",
800 actor: actor,
801 id: 1,
802 unreachable_since: NaiveDateTime.utc_now()
803 })
804
805 assert called(Instances.set_reachable(inbox))
806 end
807
808 test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
809 Instances,
810 [:passthrough],
811 [] do
812 actor = insert(:user)
813 inbox = "http://200.site/users/nick1/inbox"
814
815 assert {:ok, _} =
816 ActivityPub.publish_one(%{
817 inbox: inbox,
818 json: "{}",
819 actor: actor,
820 id: 1,
821 unreachable_since: nil
822 })
823
824 refute called(Instances.set_reachable(inbox))
825 end
826
827 test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
828 Instances,
829 [:passthrough],
830 [] do
831 actor = insert(:user)
832 inbox = "http://404.site/users/nick1/inbox"
833
834 assert {:error, _} =
835 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
836
837 assert called(Instances.set_unreachable(inbox))
838 end
839
840 test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
841 Instances,
842 [:passthrough],
843 [] do
844 actor = insert(:user)
845 inbox = "http://connrefused.site/users/nick1/inbox"
846
847 assert {:error, _} =
848 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
849
850 assert called(Instances.set_unreachable(inbox))
851 end
852
853 test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
854 Instances,
855 [:passthrough],
856 [] do
857 actor = insert(:user)
858 inbox = "http://200.site/users/nick1/inbox"
859
860 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
861
862 refute called(Instances.set_unreachable(inbox))
863 end
864
865 test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
866 Instances,
867 [:passthrough],
868 [] do
869 actor = insert(:user)
870 inbox = "http://connrefused.site/users/nick1/inbox"
871
872 assert {:error, _} =
873 ActivityPub.publish_one(%{
874 inbox: inbox,
875 json: "{}",
876 actor: actor,
877 id: 1,
878 unreachable_since: NaiveDateTime.utc_now()
879 })
880
881 refute called(Instances.set_unreachable(inbox))
882 end
883 end
884
885 def data_uri do
886 File.read!("test/fixtures/avatar_data_uri")
887 end
888 end