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