Merge branch 'bugfix/delete-activity-audience' of git.pleroma.social:pleroma/pleroma...
[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
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 object = Object.get_by_ap_id(note.data["object"]["id"])
699 object = Kernel.put_in(object.data["to"], [user.ap_id])
700 {:ok, delete} = ActivityPub.delete(object)
701
702 assert user.ap_id in delete.data["to"]
703 end
704 end
705
706 describe "timeline post-processing" do
707 test "it filters broken threads" do
708 user1 = insert(:user)
709 user2 = insert(:user)
710 user3 = insert(:user)
711
712 {:ok, user1} = User.follow(user1, user3)
713 assert User.following?(user1, user3)
714
715 {:ok, user2} = User.follow(user2, user3)
716 assert User.following?(user2, user3)
717
718 {:ok, user3} = User.follow(user3, user2)
719 assert User.following?(user3, user2)
720
721 {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
722
723 {:ok, private_activity_1} =
724 CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
725
726 {:ok, private_activity_2} =
727 CommonAPI.post(user2, %{
728 "status" => "hi 3",
729 "visibility" => "private",
730 "in_reply_to_status_id" => private_activity_1.id
731 })
732
733 {:ok, private_activity_3} =
734 CommonAPI.post(user3, %{
735 "status" => "hi 4",
736 "visibility" => "private",
737 "in_reply_to_status_id" => private_activity_2.id
738 })
739
740 activities = ActivityPub.fetch_activities([user1.ap_id | user1.following])
741
742 assert [public_activity, private_activity_1, private_activity_3] == activities
743 assert length(activities) == 3
744
745 activities = ActivityPub.contain_timeline(activities, user1)
746
747 assert [public_activity, private_activity_1] == activities
748 assert length(activities) == 2
749 end
750 end
751
752 test "it can fetch plume articles" do
753 {:ok, object} =
754 ActivityPub.fetch_object_from_id(
755 "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"
756 )
757
758 assert object
759 end
760
761 describe "update" do
762 test "it creates an update activity with the new user data" do
763 user = insert(:user)
764 {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
765 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
766
767 {:ok, update} =
768 ActivityPub.update(%{
769 actor: user_data["id"],
770 to: [user.follower_address],
771 cc: [],
772 object: user_data
773 })
774
775 assert update.data["actor"] == user.ap_id
776 assert update.data["to"] == [user.follower_address]
777 assert update.data["object"]["id"] == user_data["id"]
778 assert update.data["object"]["type"] == user_data["type"]
779 end
780 end
781
782 test "it can fetch peertube videos" do
783 {:ok, object} =
784 ActivityPub.fetch_object_from_id(
785 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
786 )
787
788 assert object
789 end
790
791 test "returned pinned statuses" do
792 Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
793 user = insert(:user)
794
795 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
796 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
797 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
798
799 CommonAPI.pin(activity_one.id, user)
800 user = refresh_record(user)
801
802 CommonAPI.pin(activity_two.id, user)
803 user = refresh_record(user)
804
805 CommonAPI.pin(activity_three.id, user)
806 user = refresh_record(user)
807
808 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
809
810 assert 3 = length(activities)
811 end
812
813 test "it can create a Flag activity" do
814 reporter = insert(:user)
815 target_account = insert(:user)
816 {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"})
817 context = Utils.generate_context_id()
818 content = "foobar"
819
820 reporter_ap_id = reporter.ap_id
821 target_ap_id = target_account.ap_id
822 activity_ap_id = activity.data["id"]
823
824 assert {:ok, activity} =
825 ActivityPub.flag(%{
826 actor: reporter,
827 context: context,
828 account: target_account,
829 statuses: [activity],
830 content: content
831 })
832
833 assert %Activity{
834 actor: ^reporter_ap_id,
835 data: %{
836 "type" => "Flag",
837 "content" => ^content,
838 "context" => ^context,
839 "object" => [^target_ap_id, ^activity_ap_id]
840 }
841 } = activity
842 end
843
844 describe "publish_one/1" do
845 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
846 Instances,
847 [:passthrough],
848 [] do
849 actor = insert(:user)
850 inbox = "http://200.site/users/nick1/inbox"
851
852 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
853
854 assert called(Instances.set_reachable(inbox))
855 end
856
857 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
858 Instances,
859 [:passthrough],
860 [] do
861 actor = insert(:user)
862 inbox = "http://200.site/users/nick1/inbox"
863
864 assert {:ok, _} =
865 ActivityPub.publish_one(%{
866 inbox: inbox,
867 json: "{}",
868 actor: actor,
869 id: 1,
870 unreachable_since: NaiveDateTime.utc_now()
871 })
872
873 assert called(Instances.set_reachable(inbox))
874 end
875
876 test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
877 Instances,
878 [:passthrough],
879 [] do
880 actor = insert(:user)
881 inbox = "http://200.site/users/nick1/inbox"
882
883 assert {:ok, _} =
884 ActivityPub.publish_one(%{
885 inbox: inbox,
886 json: "{}",
887 actor: actor,
888 id: 1,
889 unreachable_since: nil
890 })
891
892 refute called(Instances.set_reachable(inbox))
893 end
894
895 test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
896 Instances,
897 [:passthrough],
898 [] do
899 actor = insert(:user)
900 inbox = "http://404.site/users/nick1/inbox"
901
902 assert {:error, _} =
903 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
904
905 assert called(Instances.set_unreachable(inbox))
906 end
907
908 test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
909 Instances,
910 [:passthrough],
911 [] do
912 actor = insert(:user)
913 inbox = "http://connrefused.site/users/nick1/inbox"
914
915 assert {:error, _} =
916 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
917
918 assert called(Instances.set_unreachable(inbox))
919 end
920
921 test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
922 Instances,
923 [:passthrough],
924 [] do
925 actor = insert(:user)
926 inbox = "http://200.site/users/nick1/inbox"
927
928 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
929
930 refute called(Instances.set_unreachable(inbox))
931 end
932
933 test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
934 Instances,
935 [:passthrough],
936 [] do
937 actor = insert(:user)
938 inbox = "http://connrefused.site/users/nick1/inbox"
939
940 assert {:error, _} =
941 ActivityPub.publish_one(%{
942 inbox: inbox,
943 json: "{}",
944 actor: actor,
945 id: 1,
946 unreachable_since: NaiveDateTime.utc_now()
947 })
948
949 refute called(Instances.set_unreachable(inbox))
950 end
951 end
952
953 def data_uri do
954 File.read!("test/fixtures/avatar_data_uri")
955 end
956 end