950ce17ddc7be71cf4bf5bcdee0bdfe20018ffe7
[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
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 == new_activity
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 assert is_binary(activity.data["object"]["id"])
196 assert %Object{} = Object.get_by_ap_id(activity.data["object"]["id"])
197 end
198 end
199
200 describe "create activities" do
201 test "removes doubled 'to' recipients" do
202 user = insert(:user)
203
204 {:ok, activity} =
205 ActivityPub.create(%{
206 to: ["user1", "user1", "user2"],
207 actor: user,
208 context: "",
209 object: %{}
210 })
211
212 assert activity.data["to"] == ["user1", "user2"]
213 assert activity.actor == user.ap_id
214 assert activity.recipients == ["user1", "user2", user.ap_id]
215 end
216 end
217
218 describe "fetch activities for recipients" do
219 test "retrieve the activities for certain recipients" do
220 {:ok, activity_one} = ActivityBuilder.insert(%{"to" => ["someone"]})
221 {:ok, activity_two} = ActivityBuilder.insert(%{"to" => ["someone_else"]})
222 {:ok, _activity_three} = ActivityBuilder.insert(%{"to" => ["noone"]})
223
224 activities = ActivityPub.fetch_activities(["someone", "someone_else"])
225 assert length(activities) == 2
226 assert activities == [activity_one, activity_two]
227 end
228 end
229
230 describe "fetch activities in context" do
231 test "retrieves activities that have a given context" do
232 {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
233 {:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
234 {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
235 {:ok, _activity_four} = ActivityBuilder.insert(%{"type" => "Announce", "context" => "2hu"})
236 activity_five = insert(:note_activity)
237 user = insert(:user)
238
239 {:ok, user} = User.block(user, %{ap_id: activity_five.data["actor"]})
240
241 activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user})
242 assert activities == [activity_two, activity]
243 end
244 end
245
246 test "doesn't return blocked activities" do
247 activity_one = insert(:note_activity)
248 activity_two = insert(:note_activity)
249 activity_three = insert(:note_activity)
250 user = insert(:user)
251 booster = insert(:user)
252 {:ok, user} = User.block(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 refute Enum.member?(activities, activity_one)
259
260 {:ok, user} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
261
262 activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
263
264 assert Enum.member?(activities, activity_two)
265 assert Enum.member?(activities, activity_three)
266 assert Enum.member?(activities, activity_one)
267
268 {:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
269 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
270 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
271 activity_three = Repo.get(Activity, activity_three.id)
272
273 activities = ActivityPub.fetch_activities([], %{"blocking_user" => user})
274
275 assert Enum.member?(activities, activity_two)
276 refute Enum.member?(activities, activity_three)
277 refute Enum.member?(activities, boost_activity)
278 assert Enum.member?(activities, activity_one)
279
280 activities = ActivityPub.fetch_activities([], %{"blocking_user" => nil})
281
282 assert Enum.member?(activities, activity_two)
283 assert Enum.member?(activities, activity_three)
284 assert Enum.member?(activities, boost_activity)
285 assert Enum.member?(activities, activity_one)
286 end
287
288 test "doesn't return muted activities" do
289 activity_one = insert(:note_activity)
290 activity_two = insert(:note_activity)
291 activity_three = insert(:note_activity)
292 user = insert(:user)
293 booster = insert(:user)
294 {:ok, user} = User.mute(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 refute Enum.member?(activities, activity_one)
301
302 # Calling with 'with_muted' will deliver muted activities, too.
303 activities = ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true})
304
305 assert Enum.member?(activities, activity_two)
306 assert Enum.member?(activities, activity_three)
307 assert Enum.member?(activities, activity_one)
308
309 {:ok, user} = User.unmute(user, %User{ap_id: activity_one.data["actor"]})
310
311 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
312
313 assert Enum.member?(activities, activity_two)
314 assert Enum.member?(activities, activity_three)
315 assert Enum.member?(activities, activity_one)
316
317 {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
318 {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
319 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
320 activity_three = Repo.get(Activity, activity_three.id)
321
322 activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
323
324 assert Enum.member?(activities, activity_two)
325 refute Enum.member?(activities, activity_three)
326 refute Enum.member?(activities, boost_activity)
327 assert Enum.member?(activities, activity_one)
328
329 activities = ActivityPub.fetch_activities([], %{"muting_user" => nil})
330
331 assert Enum.member?(activities, activity_two)
332 assert Enum.member?(activities, activity_three)
333 assert Enum.member?(activities, boost_activity)
334 assert Enum.member?(activities, activity_one)
335 end
336
337 test "excludes reblogs on request" do
338 user = insert(:user)
339 {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
340 {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user})
341
342 [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"})
343
344 assert activity == expected_activity
345 end
346
347 describe "public fetch activities" do
348 test "doesn't retrieve unlisted activities" do
349 user = insert(:user)
350
351 {:ok, _unlisted_activity} =
352 CommonAPI.post(user, %{"status" => "yeah", "visibility" => "unlisted"})
353
354 {:ok, listed_activity} = CommonAPI.post(user, %{"status" => "yeah"})
355
356 [activity] = ActivityPub.fetch_public_activities()
357
358 assert activity == listed_activity
359 end
360
361 test "retrieves public activities" do
362 _activities = ActivityPub.fetch_public_activities()
363
364 %{public: public} = ActivityBuilder.public_and_non_public()
365
366 activities = ActivityPub.fetch_public_activities()
367 assert length(activities) == 1
368 assert Enum.at(activities, 0) == public
369 end
370
371 test "retrieves a maximum of 20 activities" do
372 activities = ActivityBuilder.insert_list(30)
373 last_expected = List.last(activities)
374
375 activities = ActivityPub.fetch_public_activities()
376 last = List.last(activities)
377
378 assert length(activities) == 20
379 assert last == last_expected
380 end
381
382 test "retrieves ids starting from a since_id" do
383 activities = ActivityBuilder.insert_list(30)
384 later_activities = ActivityBuilder.insert_list(10)
385 since_id = List.last(activities).id
386 last_expected = List.last(later_activities)
387
388 activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id})
389 last = List.last(activities)
390
391 assert length(activities) == 10
392 assert last == last_expected
393 end
394
395 test "retrieves ids up to max_id" do
396 _first_activities = ActivityBuilder.insert_list(10)
397 activities = ActivityBuilder.insert_list(20)
398 later_activities = ActivityBuilder.insert_list(10)
399 max_id = List.first(later_activities).id
400 last_expected = List.last(activities)
401
402 activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id})
403 last = List.last(activities)
404
405 assert length(activities) == 20
406 assert last == last_expected
407 end
408 end
409
410 describe "like an object" do
411 test "adds a like activity to the db" do
412 note_activity = insert(:note_activity)
413 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
414 user = insert(:user)
415 user_two = insert(:user)
416
417 {:ok, like_activity, object} = ActivityPub.like(user, object)
418
419 assert like_activity.data["actor"] == user.ap_id
420 assert like_activity.data["type"] == "Like"
421 assert like_activity.data["object"] == object.data["id"]
422 assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
423 assert like_activity.data["context"] == object.data["context"]
424 assert object.data["like_count"] == 1
425 assert object.data["likes"] == [user.ap_id]
426
427 # Just return the original activity if the user already liked it.
428 {:ok, same_like_activity, object} = ActivityPub.like(user, object)
429
430 assert like_activity == same_like_activity
431 assert object.data["likes"] == [user.ap_id]
432
433 [note_activity] = Activity.get_all_create_by_object_ap_id(object.data["id"])
434 assert note_activity.data["object"]["like_count"] == 1
435
436 {:ok, _like_activity, object} = ActivityPub.like(user_two, object)
437 assert object.data["like_count"] == 2
438 end
439 end
440
441 describe "unliking" do
442 test "unliking a previously liked object" do
443 note_activity = insert(:note_activity)
444 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
445 user = insert(:user)
446
447 # Unliking something that hasn't been liked does nothing
448 {:ok, object} = ActivityPub.unlike(user, object)
449 assert object.data["like_count"] == 0
450
451 {:ok, like_activity, object} = ActivityPub.like(user, object)
452 assert object.data["like_count"] == 1
453
454 {:ok, _, _, object} = ActivityPub.unlike(user, object)
455 assert object.data["like_count"] == 0
456
457 assert Repo.get(Activity, like_activity.id) == nil
458 end
459 end
460
461 describe "announcing an object" do
462 test "adds an announce activity to the db" do
463 note_activity = insert(:note_activity)
464 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
465 user = insert(:user)
466
467 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
468 assert object.data["announcement_count"] == 1
469 assert object.data["announcements"] == [user.ap_id]
470
471 assert announce_activity.data["to"] == [
472 User.ap_followers(user),
473 note_activity.data["actor"]
474 ]
475
476 assert announce_activity.data["object"] == object.data["id"]
477 assert announce_activity.data["actor"] == user.ap_id
478 assert announce_activity.data["context"] == object.data["context"]
479 end
480 end
481
482 describe "unannouncing an object" do
483 test "unannouncing a previously announced object" do
484 note_activity = insert(:note_activity)
485 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
486 user = insert(:user)
487
488 # Unannouncing an object that is not announced does nothing
489 # {:ok, object} = ActivityPub.unannounce(user, object)
490 # assert object.data["announcement_count"] == 0
491
492 {:ok, announce_activity, object} = ActivityPub.announce(user, object)
493 assert object.data["announcement_count"] == 1
494
495 {:ok, unannounce_activity, object} = ActivityPub.unannounce(user, object)
496 assert object.data["announcement_count"] == 0
497
498 assert unannounce_activity.data["to"] == [
499 User.ap_followers(user),
500 announce_activity.data["actor"]
501 ]
502
503 assert unannounce_activity.data["type"] == "Undo"
504 assert unannounce_activity.data["object"] == announce_activity.data
505 assert unannounce_activity.data["actor"] == user.ap_id
506 assert unannounce_activity.data["context"] == announce_activity.data["context"]
507
508 assert Repo.get(Activity, announce_activity.id) == nil
509 end
510 end
511
512 describe "uploading files" do
513 test "copies the file to the configured folder" do
514 file = %Plug.Upload{
515 content_type: "image/jpg",
516 path: Path.absname("test/fixtures/image.jpg"),
517 filename: "an_image.jpg"
518 }
519
520 {:ok, %Object{} = object} = ActivityPub.upload(file)
521 assert object.data["name"] == "an_image.jpg"
522 end
523
524 test "works with base64 encoded images" do
525 file = %{
526 "img" => data_uri()
527 }
528
529 {:ok, %Object{}} = ActivityPub.upload(file)
530 end
531 end
532
533 describe "fetch the latest Follow" do
534 test "fetches the latest Follow activity" do
535 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
536 follower = Repo.get_by(User, ap_id: activity.data["actor"])
537 followed = Repo.get_by(User, ap_id: activity.data["object"])
538
539 assert activity == Utils.fetch_latest_follow(follower, followed)
540 end
541 end
542
543 describe "fetching an object" do
544 test "it fetches an object" do
545 {:ok, object} =
546 ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
547
548 assert activity = Activity.get_create_by_object_ap_id(object.data["id"])
549 assert activity.data["id"]
550
551 {:ok, object_again} =
552 ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
553
554 assert [attachment] = object.data["attachment"]
555 assert is_list(attachment["url"])
556
557 assert object == object_again
558 end
559
560 test "it works with objects only available via Ostatus" do
561 {:ok, object} = ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873")
562 assert activity = Activity.get_create_by_object_ap_id(object.data["id"])
563 assert activity.data["id"]
564
565 {:ok, object_again} =
566 ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873")
567
568 assert object == object_again
569 end
570
571 test "it correctly stitches up conversations between ostatus and ap" do
572 last = "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
573 {:ok, object} = ActivityPub.fetch_object_from_id(last)
574
575 object = Object.get_by_ap_id(object.data["inReplyTo"])
576 assert object
577 end
578 end
579
580 describe "following / unfollowing" do
581 test "creates a follow activity" do
582 follower = insert(:user)
583 followed = insert(:user)
584
585 {:ok, activity} = ActivityPub.follow(follower, followed)
586 assert activity.data["type"] == "Follow"
587 assert activity.data["actor"] == follower.ap_id
588 assert activity.data["object"] == followed.ap_id
589 end
590
591 test "creates an undo activity for the last follow" do
592 follower = insert(:user)
593 followed = insert(:user)
594
595 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
596 {:ok, activity} = ActivityPub.unfollow(follower, followed)
597
598 assert activity.data["type"] == "Undo"
599 assert activity.data["actor"] == follower.ap_id
600
601 assert is_map(activity.data["object"])
602 assert activity.data["object"]["type"] == "Follow"
603 assert activity.data["object"]["object"] == followed.ap_id
604 assert activity.data["object"]["id"] == follow_activity.data["id"]
605 end
606 end
607
608 describe "blocking / unblocking" do
609 test "creates a block activity" do
610 blocker = insert(:user)
611 blocked = insert(:user)
612
613 {:ok, activity} = ActivityPub.block(blocker, blocked)
614
615 assert activity.data["type"] == "Block"
616 assert activity.data["actor"] == blocker.ap_id
617 assert activity.data["object"] == blocked.ap_id
618 end
619
620 test "creates an undo activity for the last block" do
621 blocker = insert(:user)
622 blocked = insert(:user)
623
624 {:ok, block_activity} = ActivityPub.block(blocker, blocked)
625 {:ok, activity} = ActivityPub.unblock(blocker, blocked)
626
627 assert activity.data["type"] == "Undo"
628 assert activity.data["actor"] == blocker.ap_id
629
630 assert is_map(activity.data["object"])
631 assert activity.data["object"]["type"] == "Block"
632 assert activity.data["object"]["object"] == blocked.ap_id
633 assert activity.data["object"]["id"] == block_activity.data["id"]
634 end
635 end
636
637 describe "deletion" do
638 test "it creates a delete activity and deletes the original object" do
639 note = insert(:note_activity)
640 object = Object.get_by_ap_id(note.data["object"]["id"])
641 {:ok, delete} = ActivityPub.delete(object)
642
643 assert delete.data["type"] == "Delete"
644 assert delete.data["actor"] == note.data["actor"]
645 assert delete.data["object"] == note.data["object"]["id"]
646
647 assert Repo.get(Activity, delete.id) != nil
648
649 assert Repo.get(Object, object.id).data["type"] == "Tombstone"
650 end
651 end
652
653 describe "timeline post-processing" do
654 test "it filters broken threads" do
655 user1 = insert(:user)
656 user2 = insert(:user)
657 user3 = insert(:user)
658
659 {:ok, user1} = User.follow(user1, user3)
660 assert User.following?(user1, user3)
661
662 {:ok, user2} = User.follow(user2, user3)
663 assert User.following?(user2, user3)
664
665 {:ok, user3} = User.follow(user3, user2)
666 assert User.following?(user3, user2)
667
668 {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
669
670 {:ok, private_activity_1} =
671 CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
672
673 {:ok, private_activity_2} =
674 CommonAPI.post(user2, %{
675 "status" => "hi 3",
676 "visibility" => "private",
677 "in_reply_to_status_id" => private_activity_1.id
678 })
679
680 {:ok, private_activity_3} =
681 CommonAPI.post(user3, %{
682 "status" => "hi 4",
683 "visibility" => "private",
684 "in_reply_to_status_id" => private_activity_2.id
685 })
686
687 activities = ActivityPub.fetch_activities([user1.ap_id | user1.following])
688
689 assert [public_activity, private_activity_1, private_activity_3] == activities
690 assert length(activities) == 3
691
692 activities = ActivityPub.contain_timeline(activities, user1)
693
694 assert [public_activity, private_activity_1] == activities
695 assert length(activities) == 2
696 end
697 end
698
699 test "it can fetch plume articles" do
700 {:ok, object} =
701 ActivityPub.fetch_object_from_id(
702 "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"
703 )
704
705 assert object
706 end
707
708 describe "update" do
709 test "it creates an update activity with the new user data" do
710 user = insert(:user)
711 {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
712 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
713
714 {:ok, update} =
715 ActivityPub.update(%{
716 actor: user_data["id"],
717 to: [user.follower_address],
718 cc: [],
719 object: user_data
720 })
721
722 assert update.data["actor"] == user.ap_id
723 assert update.data["to"] == [user.follower_address]
724 assert update.data["object"]["id"] == user_data["id"]
725 assert update.data["object"]["type"] == user_data["type"]
726 end
727 end
728
729 test "it can fetch peertube videos" do
730 {:ok, object} =
731 ActivityPub.fetch_object_from_id(
732 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
733 )
734
735 assert object
736 end
737
738 test "returned pinned statuses" do
739 Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
740 user = insert(:user)
741
742 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
743 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
744 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
745
746 CommonAPI.pin(activity_one.id, user)
747 user = refresh_record(user)
748
749 CommonAPI.pin(activity_two.id, user)
750 user = refresh_record(user)
751
752 CommonAPI.pin(activity_three.id, user)
753 user = refresh_record(user)
754
755 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
756
757 assert 3 = length(activities)
758 end
759
760 test "it can create a Flag activity" do
761 reporter = insert(:user)
762 target_account = insert(:user)
763 {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"})
764 context = Utils.generate_context_id()
765 content = "foobar"
766
767 reporter_ap_id = reporter.ap_id
768 target_ap_id = target_account.ap_id
769 activity_ap_id = activity.data["id"]
770
771 assert {:ok, activity} =
772 ActivityPub.flag(%{
773 actor: reporter,
774 context: context,
775 account: target_account,
776 statuses: [activity],
777 content: content
778 })
779
780 assert %Activity{
781 actor: ^reporter_ap_id,
782 data: %{
783 "type" => "Flag",
784 "content" => ^content,
785 "context" => ^context,
786 "object" => [^target_ap_id, ^activity_ap_id]
787 }
788 } = activity
789 end
790
791 describe "publish_one/1" do
792 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
793 Instances,
794 [:passthrough],
795 [] do
796 actor = insert(:user)
797 inbox = "http://200.site/users/nick1/inbox"
798
799 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
800
801 assert called(Instances.set_reachable(inbox))
802 end
803
804 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
805 Instances,
806 [:passthrough],
807 [] do
808 actor = insert(:user)
809 inbox = "http://200.site/users/nick1/inbox"
810
811 assert {:ok, _} =
812 ActivityPub.publish_one(%{
813 inbox: inbox,
814 json: "{}",
815 actor: actor,
816 id: 1,
817 unreachable_since: NaiveDateTime.utc_now()
818 })
819
820 assert called(Instances.set_reachable(inbox))
821 end
822
823 test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
824 Instances,
825 [:passthrough],
826 [] do
827 actor = insert(:user)
828 inbox = "http://200.site/users/nick1/inbox"
829
830 assert {:ok, _} =
831 ActivityPub.publish_one(%{
832 inbox: inbox,
833 json: "{}",
834 actor: actor,
835 id: 1,
836 unreachable_since: nil
837 })
838
839 refute called(Instances.set_reachable(inbox))
840 end
841
842 test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
843 Instances,
844 [:passthrough],
845 [] do
846 actor = insert(:user)
847 inbox = "http://404.site/users/nick1/inbox"
848
849 assert {:error, _} =
850 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
851
852 assert called(Instances.set_unreachable(inbox))
853 end
854
855 test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
856 Instances,
857 [:passthrough],
858 [] do
859 actor = insert(:user)
860 inbox = "http://connrefused.site/users/nick1/inbox"
861
862 assert {:error, _} =
863 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
864
865 assert called(Instances.set_unreachable(inbox))
866 end
867
868 test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
869 Instances,
870 [:passthrough],
871 [] do
872 actor = insert(:user)
873 inbox = "http://200.site/users/nick1/inbox"
874
875 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
876
877 refute called(Instances.set_unreachable(inbox))
878 end
879
880 test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
881 Instances,
882 [:passthrough],
883 [] do
884 actor = insert(:user)
885 inbox = "http://connrefused.site/users/nick1/inbox"
886
887 assert {:error, _} =
888 ActivityPub.publish_one(%{
889 inbox: inbox,
890 json: "{}",
891 actor: actor,
892 id: 1,
893 unreachable_since: NaiveDateTime.utc_now()
894 })
895
896 refute called(Instances.set_unreachable(inbox))
897 end
898 end
899
900 def data_uri do
901 File.read!("test/fixtures/avatar_data_uri")
902 end
903 end