Merge branch 'remove-todo-txt' into 'develop'
[akkoma] / test / web / activity_pub / activity_pub_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
6 use Pleroma.DataCase
7 alias Pleroma.Web.ActivityPub.ActivityPub
8 alias Pleroma.Web.ActivityPub.Utils
9 alias Pleroma.Web.CommonAPI
10 alias Pleroma.Activity
11 alias Pleroma.Object
12 alias Pleroma.User
13 alias Pleroma.Instances
14 alias Pleroma.Builders.ActivityBuilder
15
16 import Pleroma.Factory
17 import Tesla.Mock
18 import Mock
19
20 setup do
21 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
22 :ok
23 end
24
25 describe "fetching restricted by visibility" do
26 test "it restricts by the appropriate visibility" do
27 user = insert(:user)
28
29 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
30
31 {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
32
33 {:ok, unlisted_activity} =
34 CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
35
36 {:ok, private_activity} =
37 CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
38
39 activities =
40 ActivityPub.fetch_activities([], %{:visibility => "direct", "actor_id" => user.ap_id})
41
42 assert activities == [direct_activity]
43
44 activities =
45 ActivityPub.fetch_activities([], %{:visibility => "unlisted", "actor_id" => user.ap_id})
46
47 assert activities == [unlisted_activity]
48
49 activities =
50 ActivityPub.fetch_activities([], %{:visibility => "private", "actor_id" => user.ap_id})
51
52 assert activities == [private_activity]
53
54 activities =
55 ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id})
56
57 assert activities == [public_activity]
58
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 end
695
696 describe "timeline post-processing" do
697 test "it filters broken threads" do
698 user1 = insert(:user)
699 user2 = insert(:user)
700 user3 = insert(:user)
701
702 {:ok, user1} = User.follow(user1, user3)
703 assert User.following?(user1, user3)
704
705 {:ok, user2} = User.follow(user2, user3)
706 assert User.following?(user2, user3)
707
708 {:ok, user3} = User.follow(user3, user2)
709 assert User.following?(user3, user2)
710
711 {:ok, public_activity} = CommonAPI.post(user3, %{"status" => "hi 1"})
712
713 {:ok, private_activity_1} =
714 CommonAPI.post(user3, %{"status" => "hi 2", "visibility" => "private"})
715
716 {:ok, private_activity_2} =
717 CommonAPI.post(user2, %{
718 "status" => "hi 3",
719 "visibility" => "private",
720 "in_reply_to_status_id" => private_activity_1.id
721 })
722
723 {:ok, private_activity_3} =
724 CommonAPI.post(user3, %{
725 "status" => "hi 4",
726 "visibility" => "private",
727 "in_reply_to_status_id" => private_activity_2.id
728 })
729
730 activities = ActivityPub.fetch_activities([user1.ap_id | user1.following])
731
732 assert [public_activity, private_activity_1, private_activity_3] == activities
733 assert length(activities) == 3
734
735 activities = ActivityPub.contain_timeline(activities, user1)
736
737 assert [public_activity, private_activity_1] == activities
738 assert length(activities) == 2
739 end
740 end
741
742 test "it can fetch plume articles" do
743 {:ok, object} =
744 ActivityPub.fetch_object_from_id(
745 "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"
746 )
747
748 assert object
749 end
750
751 describe "update" do
752 test "it creates an update activity with the new user data" do
753 user = insert(:user)
754 {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
755 user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
756
757 {:ok, update} =
758 ActivityPub.update(%{
759 actor: user_data["id"],
760 to: [user.follower_address],
761 cc: [],
762 object: user_data
763 })
764
765 assert update.data["actor"] == user.ap_id
766 assert update.data["to"] == [user.follower_address]
767 assert update.data["object"]["id"] == user_data["id"]
768 assert update.data["object"]["type"] == user_data["type"]
769 end
770 end
771
772 test "it can fetch peertube videos" do
773 {:ok, object} =
774 ActivityPub.fetch_object_from_id(
775 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
776 )
777
778 assert object
779 end
780
781 test "returned pinned statuses" do
782 Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
783 user = insert(:user)
784
785 {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
786 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
787 {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
788
789 CommonAPI.pin(activity_one.id, user)
790 user = refresh_record(user)
791
792 CommonAPI.pin(activity_two.id, user)
793 user = refresh_record(user)
794
795 CommonAPI.pin(activity_three.id, user)
796 user = refresh_record(user)
797
798 activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
799
800 assert 3 = length(activities)
801 end
802
803 test "it can create a Flag activity" do
804 reporter = insert(:user)
805 target_account = insert(:user)
806 {:ok, activity} = CommonAPI.post(target_account, %{"status" => "foobar"})
807 context = Utils.generate_context_id()
808 content = "foobar"
809
810 reporter_ap_id = reporter.ap_id
811 target_ap_id = target_account.ap_id
812 activity_ap_id = activity.data["id"]
813
814 assert {:ok, activity} =
815 ActivityPub.flag(%{
816 actor: reporter,
817 context: context,
818 account: target_account,
819 statuses: [activity],
820 content: content
821 })
822
823 assert %Activity{
824 actor: ^reporter_ap_id,
825 data: %{
826 "type" => "Flag",
827 "content" => ^content,
828 "context" => ^context,
829 "object" => [^target_ap_id, ^activity_ap_id]
830 }
831 } = activity
832 end
833
834 describe "publish_one/1" do
835 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
836 Instances,
837 [:passthrough],
838 [] do
839 actor = insert(:user)
840 inbox = "http://200.site/users/nick1/inbox"
841
842 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
843
844 assert called(Instances.set_reachable(inbox))
845 end
846
847 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
848 Instances,
849 [:passthrough],
850 [] do
851 actor = insert(:user)
852 inbox = "http://200.site/users/nick1/inbox"
853
854 assert {:ok, _} =
855 ActivityPub.publish_one(%{
856 inbox: inbox,
857 json: "{}",
858 actor: actor,
859 id: 1,
860 unreachable_since: NaiveDateTime.utc_now()
861 })
862
863 assert called(Instances.set_reachable(inbox))
864 end
865
866 test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
867 Instances,
868 [:passthrough],
869 [] do
870 actor = insert(:user)
871 inbox = "http://200.site/users/nick1/inbox"
872
873 assert {:ok, _} =
874 ActivityPub.publish_one(%{
875 inbox: inbox,
876 json: "{}",
877 actor: actor,
878 id: 1,
879 unreachable_since: nil
880 })
881
882 refute called(Instances.set_reachable(inbox))
883 end
884
885 test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
886 Instances,
887 [:passthrough],
888 [] do
889 actor = insert(:user)
890 inbox = "http://404.site/users/nick1/inbox"
891
892 assert {:error, _} =
893 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
894
895 assert called(Instances.set_unreachable(inbox))
896 end
897
898 test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
899 Instances,
900 [:passthrough],
901 [] do
902 actor = insert(:user)
903 inbox = "http://connrefused.site/users/nick1/inbox"
904
905 assert {:error, _} =
906 ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
907
908 assert called(Instances.set_unreachable(inbox))
909 end
910
911 test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
912 Instances,
913 [:passthrough],
914 [] do
915 actor = insert(:user)
916 inbox = "http://200.site/users/nick1/inbox"
917
918 assert {:ok, _} = ActivityPub.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
919
920 refute called(Instances.set_unreachable(inbox))
921 end
922
923 test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
924 Instances,
925 [:passthrough],
926 [] do
927 actor = insert(:user)
928 inbox = "http://connrefused.site/users/nick1/inbox"
929
930 assert {:error, _} =
931 ActivityPub.publish_one(%{
932 inbox: inbox,
933 json: "{}",
934 actor: actor,
935 id: 1,
936 unreachable_since: NaiveDateTime.utc_now()
937 })
938
939 refute called(Instances.set_unreachable(inbox))
940 end
941 end
942
943 def data_uri do
944 File.read!("test/fixtures/avatar_data_uri")
945 end
946 end