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