New mix tasks for controlling user confirmation status and sending confirmation mails
[akkoma] / test / web / activity_pub / activity_pub_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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 use Oban.Testing, repo: Pleroma.Repo
8
9 alias Pleroma.Activity
10 alias Pleroma.Builders.ActivityBuilder
11 alias Pleroma.Config
12 alias Pleroma.Notification
13 alias Pleroma.Object
14 alias Pleroma.User
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.ActivityPub.Utils
17 alias Pleroma.Web.AdminAPI.AccountView
18 alias Pleroma.Web.CommonAPI
19
20 import ExUnit.CaptureLog
21 import Mock
22 import Pleroma.Factory
23 import Tesla.Mock
24
25 setup do
26 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
27 :ok
28 end
29
30 setup do: clear_config([:instance, :federating])
31
32 describe "streaming out participations" do
33 test "it streams them out" do
34 user = insert(:user)
35 {:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
36
37 {:ok, conversation} = Pleroma.Conversation.create_or_bump_for(activity)
38
39 participations =
40 conversation.participations
41 |> Repo.preload(:user)
42
43 with_mock Pleroma.Web.Streamer,
44 stream: fn _, _ -> nil end do
45 ActivityPub.stream_out_participations(conversation.participations)
46
47 assert called(Pleroma.Web.Streamer.stream("participation", participations))
48 end
49 end
50
51 test "streams them out on activity creation" do
52 user_one = insert(:user)
53 user_two = insert(:user)
54
55 with_mock Pleroma.Web.Streamer,
56 stream: fn _, _ -> nil end do
57 {:ok, activity} =
58 CommonAPI.post(user_one, %{
59 status: "@#{user_two.nickname}",
60 visibility: "direct"
61 })
62
63 conversation =
64 activity.data["context"]
65 |> Pleroma.Conversation.get_for_ap_id()
66 |> Repo.preload(participations: :user)
67
68 assert called(Pleroma.Web.Streamer.stream("participation", conversation.participations))
69 end
70 end
71 end
72
73 describe "fetching restricted by visibility" do
74 test "it restricts by the appropriate visibility" do
75 user = insert(:user)
76
77 {:ok, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"})
78
79 {:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
80
81 {:ok, unlisted_activity} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"})
82
83 {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
84
85 activities = ActivityPub.fetch_activities([], %{visibility: "direct", actor_id: user.ap_id})
86
87 assert activities == [direct_activity]
88
89 activities =
90 ActivityPub.fetch_activities([], %{visibility: "unlisted", actor_id: user.ap_id})
91
92 assert activities == [unlisted_activity]
93
94 activities =
95 ActivityPub.fetch_activities([], %{visibility: "private", actor_id: user.ap_id})
96
97 assert activities == [private_activity]
98
99 activities = ActivityPub.fetch_activities([], %{visibility: "public", actor_id: user.ap_id})
100
101 assert activities == [public_activity]
102
103 activities =
104 ActivityPub.fetch_activities([], %{
105 visibility: ~w[private public],
106 actor_id: user.ap_id
107 })
108
109 assert activities == [public_activity, private_activity]
110 end
111 end
112
113 describe "fetching excluded by visibility" do
114 test "it excludes by the appropriate visibility" do
115 user = insert(:user)
116
117 {:ok, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"})
118
119 {:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
120
121 {:ok, unlisted_activity} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"})
122
123 {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
124
125 activities =
126 ActivityPub.fetch_activities([], %{
127 exclude_visibilities: "direct",
128 actor_id: user.ap_id
129 })
130
131 assert public_activity in activities
132 assert unlisted_activity in activities
133 assert private_activity in activities
134 refute direct_activity in activities
135
136 activities =
137 ActivityPub.fetch_activities([], %{
138 exclude_visibilities: "unlisted",
139 actor_id: user.ap_id
140 })
141
142 assert public_activity in activities
143 refute unlisted_activity in activities
144 assert private_activity in activities
145 assert direct_activity in activities
146
147 activities =
148 ActivityPub.fetch_activities([], %{
149 exclude_visibilities: "private",
150 actor_id: user.ap_id
151 })
152
153 assert public_activity in activities
154 assert unlisted_activity in activities
155 refute private_activity in activities
156 assert direct_activity in activities
157
158 activities =
159 ActivityPub.fetch_activities([], %{
160 exclude_visibilities: "public",
161 actor_id: user.ap_id
162 })
163
164 refute public_activity in activities
165 assert unlisted_activity in activities
166 assert private_activity in activities
167 assert direct_activity in activities
168 end
169 end
170
171 describe "building a user from his ap id" do
172 test "it returns a user" do
173 user_id = "http://mastodon.example.org/users/admin"
174 {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
175 assert user.ap_id == user_id
176 assert user.nickname == "admin@mastodon.example.org"
177 assert user.ap_enabled
178 assert user.follower_address == "http://mastodon.example.org/users/admin/followers"
179 end
180
181 test "it returns a user that is invisible" do
182 user_id = "http://mastodon.example.org/users/relay"
183 {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
184 assert User.invisible?(user)
185 end
186
187 test "it returns a user that accepts chat messages" do
188 user_id = "http://mastodon.example.org/users/admin"
189 {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
190
191 assert user.accepts_chat_messages
192 end
193 end
194
195 test "it fetches the appropriate tag-restricted posts" do
196 user = insert(:user)
197
198 {:ok, status_one} = CommonAPI.post(user, %{status: ". #test"})
199 {:ok, status_two} = CommonAPI.post(user, %{status: ". #essais"})
200 {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #reject"})
201
202 fetch_one = ActivityPub.fetch_activities([], %{type: "Create", tag: "test"})
203
204 fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["test", "essais"]})
205
206 fetch_three =
207 ActivityPub.fetch_activities([], %{
208 type: "Create",
209 tag: ["test", "essais"],
210 tag_reject: ["reject"]
211 })
212
213 fetch_four =
214 ActivityPub.fetch_activities([], %{
215 type: "Create",
216 tag: ["test"],
217 tag_all: ["test", "reject"]
218 })
219
220 assert fetch_one == [status_one, status_three]
221 assert fetch_two == [status_one, status_two, status_three]
222 assert fetch_three == [status_one, status_two]
223 assert fetch_four == [status_three]
224 end
225
226 describe "insertion" do
227 test "drops activities beyond a certain limit" do
228 limit = Config.get([:instance, :remote_limit])
229
230 random_text =
231 :crypto.strong_rand_bytes(limit + 1)
232 |> Base.encode64()
233 |> binary_part(0, limit + 1)
234
235 data = %{
236 "ok" => true,
237 "object" => %{
238 "content" => random_text
239 }
240 }
241
242 assert {:error, {:remote_limit_error, _}} = ActivityPub.insert(data)
243 end
244
245 test "doesn't drop activities with content being null" do
246 user = insert(:user)
247
248 data = %{
249 "actor" => user.ap_id,
250 "to" => [],
251 "object" => %{
252 "actor" => user.ap_id,
253 "to" => [],
254 "type" => "Note",
255 "content" => nil
256 }
257 }
258
259 assert {:ok, _} = ActivityPub.insert(data)
260 end
261
262 test "returns the activity if one with the same id is already in" do
263 activity = insert(:note_activity)
264 {:ok, new_activity} = ActivityPub.insert(activity.data)
265
266 assert activity.id == new_activity.id
267 end
268
269 test "inserts a given map into the activity database, giving it an id if it has none." do
270 user = insert(:user)
271
272 data = %{
273 "actor" => user.ap_id,
274 "to" => [],
275 "object" => %{
276 "actor" => user.ap_id,
277 "to" => [],
278 "type" => "Note",
279 "content" => "hey"
280 }
281 }
282
283 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
284 assert activity.data["ok"] == data["ok"]
285 assert is_binary(activity.data["id"])
286
287 given_id = "bla"
288
289 data = %{
290 "id" => given_id,
291 "actor" => user.ap_id,
292 "to" => [],
293 "context" => "blabla",
294 "object" => %{
295 "actor" => user.ap_id,
296 "to" => [],
297 "type" => "Note",
298 "content" => "hey"
299 }
300 }
301
302 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
303 assert activity.data["ok"] == data["ok"]
304 assert activity.data["id"] == given_id
305 assert activity.data["context"] == "blabla"
306 assert activity.data["context_id"]
307 end
308
309 test "adds a context when none is there" do
310 user = insert(:user)
311
312 data = %{
313 "actor" => user.ap_id,
314 "to" => [],
315 "object" => %{
316 "actor" => user.ap_id,
317 "to" => [],
318 "type" => "Note",
319 "content" => "hey"
320 }
321 }
322
323 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
324 object = Pleroma.Object.normalize(activity)
325
326 assert is_binary(activity.data["context"])
327 assert is_binary(object.data["context"])
328 assert activity.data["context_id"]
329 assert object.data["context_id"]
330 end
331
332 test "adds an id to a given object if it lacks one and is a note and inserts it to the object database" do
333 user = insert(:user)
334
335 data = %{
336 "actor" => user.ap_id,
337 "to" => [],
338 "object" => %{
339 "actor" => user.ap_id,
340 "to" => [],
341 "type" => "Note",
342 "content" => "hey"
343 }
344 }
345
346 {:ok, %Activity{} = activity} = ActivityPub.insert(data)
347 assert object = Object.normalize(activity)
348 assert is_binary(object.data["id"])
349 end
350 end
351
352 describe "listen activities" do
353 test "does not increase user note count" do
354 user = insert(:user)
355
356 {:ok, activity} =
357 ActivityPub.listen(%{
358 to: ["https://www.w3.org/ns/activitystreams#Public"],
359 actor: user,
360 context: "",
361 object: %{
362 "actor" => user.ap_id,
363 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
364 "artist" => "lain",
365 "title" => "lain radio episode 1",
366 "length" => 180_000,
367 "type" => "Audio"
368 }
369 })
370
371 assert activity.actor == user.ap_id
372
373 user = User.get_cached_by_id(user.id)
374 assert user.note_count == 0
375 end
376
377 test "can be fetched into a timeline" do
378 _listen_activity_1 = insert(:listen)
379 _listen_activity_2 = insert(:listen)
380 _listen_activity_3 = insert(:listen)
381
382 timeline = ActivityPub.fetch_activities([], %{type: ["Listen"]})
383
384 assert length(timeline) == 3
385 end
386 end
387
388 describe "create activities" do
389 test "it reverts create" do
390 user = insert(:user)
391
392 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
393 assert {:error, :reverted} =
394 ActivityPub.create(%{
395 to: ["user1", "user2"],
396 actor: user,
397 context: "",
398 object: %{
399 "to" => ["user1", "user2"],
400 "type" => "Note",
401 "content" => "testing"
402 }
403 })
404 end
405
406 assert Repo.aggregate(Activity, :count, :id) == 0
407 assert Repo.aggregate(Object, :count, :id) == 0
408 end
409
410 test "removes doubled 'to' recipients" do
411 user = insert(:user)
412
413 {:ok, activity} =
414 ActivityPub.create(%{
415 to: ["user1", "user1", "user2"],
416 actor: user,
417 context: "",
418 object: %{
419 "to" => ["user1", "user1", "user2"],
420 "type" => "Note",
421 "content" => "testing"
422 }
423 })
424
425 assert activity.data["to"] == ["user1", "user2"]
426 assert activity.actor == user.ap_id
427 assert activity.recipients == ["user1", "user2", user.ap_id]
428 end
429
430 test "increases user note count only for public activities" do
431 user = insert(:user)
432
433 {:ok, _} =
434 CommonAPI.post(User.get_cached_by_id(user.id), %{
435 status: "1",
436 visibility: "public"
437 })
438
439 {:ok, _} =
440 CommonAPI.post(User.get_cached_by_id(user.id), %{
441 status: "2",
442 visibility: "unlisted"
443 })
444
445 {:ok, _} =
446 CommonAPI.post(User.get_cached_by_id(user.id), %{
447 status: "2",
448 visibility: "private"
449 })
450
451 {:ok, _} =
452 CommonAPI.post(User.get_cached_by_id(user.id), %{
453 status: "3",
454 visibility: "direct"
455 })
456
457 user = User.get_cached_by_id(user.id)
458 assert user.note_count == 2
459 end
460
461 test "increases replies count" do
462 user = insert(:user)
463 user2 = insert(:user)
464
465 {:ok, activity} = CommonAPI.post(user, %{status: "1", visibility: "public"})
466 ap_id = activity.data["id"]
467 reply_data = %{status: "1", in_reply_to_status_id: activity.id}
468
469 # public
470 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "public"))
471 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
472 assert object.data["repliesCount"] == 1
473
474 # unlisted
475 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "unlisted"))
476 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
477 assert object.data["repliesCount"] == 2
478
479 # private
480 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "private"))
481 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
482 assert object.data["repliesCount"] == 2
483
484 # direct
485 {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "direct"))
486 assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
487 assert object.data["repliesCount"] == 2
488 end
489 end
490
491 describe "fetch activities for recipients" do
492 test "retrieve the activities for certain recipients" do
493 {:ok, activity_one} = ActivityBuilder.insert(%{"to" => ["someone"]})
494 {:ok, activity_two} = ActivityBuilder.insert(%{"to" => ["someone_else"]})
495 {:ok, _activity_three} = ActivityBuilder.insert(%{"to" => ["noone"]})
496
497 activities = ActivityPub.fetch_activities(["someone", "someone_else"])
498 assert length(activities) == 2
499 assert activities == [activity_one, activity_two]
500 end
501 end
502
503 describe "fetch activities in context" do
504 test "retrieves activities that have a given context" do
505 {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
506 {:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
507 {:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
508 {:ok, _activity_four} = ActivityBuilder.insert(%{"type" => "Announce", "context" => "2hu"})
509 activity_five = insert(:note_activity)
510 user = insert(:user)
511
512 {:ok, _user_relationship} = User.block(user, %{ap_id: activity_five.data["actor"]})
513
514 activities = ActivityPub.fetch_activities_for_context("2hu", %{blocking_user: user})
515 assert activities == [activity_two, activity]
516 end
517
518 test "doesn't return activities with filtered words" do
519 user = insert(:user)
520 user_two = insert(:user)
521 insert(:filter, user: user, phrase: "test", hide: true)
522
523 {:ok, %{id: id1, data: %{"context" => context}}} = CommonAPI.post(user, %{status: "1"})
524
525 {:ok, %{id: id2}} = CommonAPI.post(user_two, %{status: "2", in_reply_to_status_id: id1})
526
527 {:ok, %{id: id3} = user_activity} =
528 CommonAPI.post(user, %{status: "3 test?", in_reply_to_status_id: id2})
529
530 {:ok, %{id: id4} = filtered_activity} =
531 CommonAPI.post(user_two, %{status: "4 test!", in_reply_to_status_id: id3})
532
533 {:ok, _} = CommonAPI.post(user, %{status: "5", in_reply_to_status_id: id4})
534
535 activities =
536 context
537 |> ActivityPub.fetch_activities_for_context(%{user: user})
538 |> Enum.map(& &1.id)
539
540 assert length(activities) == 4
541 assert user_activity.id in activities
542 refute filtered_activity.id in activities
543 end
544 end
545
546 test "doesn't return blocked activities" do
547 activity_one = insert(:note_activity)
548 activity_two = insert(:note_activity)
549 activity_three = insert(:note_activity)
550 user = insert(:user)
551 booster = insert(:user)
552 {:ok, _user_relationship} = User.block(user, %{ap_id: activity_one.data["actor"]})
553
554 activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})
555
556 assert Enum.member?(activities, activity_two)
557 assert Enum.member?(activities, activity_three)
558 refute Enum.member?(activities, activity_one)
559
560 {:ok, _user_block} = User.unblock(user, %{ap_id: activity_one.data["actor"]})
561
562 activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})
563
564 assert Enum.member?(activities, activity_two)
565 assert Enum.member?(activities, activity_three)
566 assert Enum.member?(activities, activity_one)
567
568 {:ok, _user_relationship} = User.block(user, %{ap_id: activity_three.data["actor"]})
569 {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster)
570 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
571 activity_three = Activity.get_by_id(activity_three.id)
572
573 activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})
574
575 assert Enum.member?(activities, activity_two)
576 refute Enum.member?(activities, activity_three)
577 refute Enum.member?(activities, boost_activity)
578 assert Enum.member?(activities, activity_one)
579
580 activities = ActivityPub.fetch_activities([], %{blocking_user: nil, skip_preload: true})
581
582 assert Enum.member?(activities, activity_two)
583 assert Enum.member?(activities, activity_three)
584 assert Enum.member?(activities, boost_activity)
585 assert Enum.member?(activities, activity_one)
586 end
587
588 test "doesn't return transitive interactions concerning blocked users" do
589 blocker = insert(:user)
590 blockee = insert(:user)
591 friend = insert(:user)
592
593 {:ok, _user_relationship} = User.block(blocker, blockee)
594
595 {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"})
596
597 {:ok, activity_two} = CommonAPI.post(friend, %{status: "hey! @#{blockee.nickname}"})
598
599 {:ok, activity_three} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
600
601 {:ok, activity_four} = CommonAPI.post(blockee, %{status: "hey! @#{blocker.nickname}"})
602
603 activities = ActivityPub.fetch_activities([], %{blocking_user: blocker})
604
605 assert Enum.member?(activities, activity_one)
606 refute Enum.member?(activities, activity_two)
607 refute Enum.member?(activities, activity_three)
608 refute Enum.member?(activities, activity_four)
609 end
610
611 test "doesn't return announce activities with blocked users in 'to'" do
612 blocker = insert(:user)
613 blockee = insert(:user)
614 friend = insert(:user)
615
616 {:ok, _user_relationship} = User.block(blocker, blockee)
617
618 {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"})
619
620 {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
621
622 {:ok, activity_three} = CommonAPI.repeat(activity_two.id, friend)
623
624 activities =
625 ActivityPub.fetch_activities([], %{blocking_user: blocker})
626 |> Enum.map(fn act -> act.id end)
627
628 assert Enum.member?(activities, activity_one.id)
629 refute Enum.member?(activities, activity_two.id)
630 refute Enum.member?(activities, activity_three.id)
631 end
632
633 test "doesn't return announce activities with blocked users in 'cc'" do
634 blocker = insert(:user)
635 blockee = insert(:user)
636 friend = insert(:user)
637
638 {:ok, _user_relationship} = User.block(blocker, blockee)
639
640 {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"})
641
642 {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
643
644 assert object = Pleroma.Object.normalize(activity_two)
645
646 data = %{
647 "actor" => friend.ap_id,
648 "object" => object.data["id"],
649 "context" => object.data["context"],
650 "type" => "Announce",
651 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
652 "cc" => [blockee.ap_id]
653 }
654
655 assert {:ok, activity_three} = ActivityPub.insert(data)
656
657 activities =
658 ActivityPub.fetch_activities([], %{blocking_user: blocker})
659 |> Enum.map(fn act -> act.id end)
660
661 assert Enum.member?(activities, activity_one.id)
662 refute Enum.member?(activities, activity_two.id)
663 refute Enum.member?(activities, activity_three.id)
664 end
665
666 test "doesn't return activities from blocked domains" do
667 domain = "dogwhistle.zone"
668 domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
669 note = insert(:note, %{data: %{"actor" => domain_user.ap_id}})
670 activity = insert(:note_activity, %{note: note})
671 user = insert(:user)
672 {:ok, user} = User.block_domain(user, domain)
673
674 activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})
675
676 refute activity in activities
677
678 followed_user = insert(:user)
679 CommonAPI.follow(user, followed_user)
680 {:ok, repeat_activity} = CommonAPI.repeat(activity.id, followed_user)
681
682 activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})
683
684 refute repeat_activity in activities
685 end
686
687 test "does return activities from followed users on blocked domains" do
688 domain = "meanies.social"
689 domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
690 blocker = insert(:user)
691
692 {:ok, blocker} = User.follow(blocker, domain_user)
693 {:ok, blocker} = User.block_domain(blocker, domain)
694
695 assert User.following?(blocker, domain_user)
696 assert User.blocks_domain?(blocker, domain_user)
697 refute User.blocks?(blocker, domain_user)
698
699 note = insert(:note, %{data: %{"actor" => domain_user.ap_id}})
700 activity = insert(:note_activity, %{note: note})
701
702 activities = ActivityPub.fetch_activities([], %{blocking_user: blocker, skip_preload: true})
703
704 assert activity in activities
705
706 # And check that if the guy we DO follow boosts someone else from their domain,
707 # that should be hidden
708 another_user = insert(:user, %{ap_id: "https://#{domain}/@meanie2"})
709 bad_note = insert(:note, %{data: %{"actor" => another_user.ap_id}})
710 bad_activity = insert(:note_activity, %{note: bad_note})
711 {:ok, repeat_activity} = CommonAPI.repeat(bad_activity.id, domain_user)
712
713 activities = ActivityPub.fetch_activities([], %{blocking_user: blocker, skip_preload: true})
714
715 refute repeat_activity in activities
716 end
717
718 test "doesn't return muted activities" do
719 activity_one = insert(:note_activity)
720 activity_two = insert(:note_activity)
721 activity_three = insert(:note_activity)
722 user = insert(:user)
723 booster = insert(:user)
724
725 activity_one_actor = User.get_by_ap_id(activity_one.data["actor"])
726 {:ok, _user_relationships} = User.mute(user, activity_one_actor)
727
728 activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})
729
730 assert Enum.member?(activities, activity_two)
731 assert Enum.member?(activities, activity_three)
732 refute Enum.member?(activities, activity_one)
733
734 # Calling with 'with_muted' will deliver muted activities, too.
735 activities =
736 ActivityPub.fetch_activities([], %{
737 muting_user: user,
738 with_muted: true,
739 skip_preload: true
740 })
741
742 assert Enum.member?(activities, activity_two)
743 assert Enum.member?(activities, activity_three)
744 assert Enum.member?(activities, activity_one)
745
746 {:ok, _user_mute} = User.unmute(user, activity_one_actor)
747
748 activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})
749
750 assert Enum.member?(activities, activity_two)
751 assert Enum.member?(activities, activity_three)
752 assert Enum.member?(activities, activity_one)
753
754 activity_three_actor = User.get_by_ap_id(activity_three.data["actor"])
755 {:ok, _user_relationships} = User.mute(user, activity_three_actor)
756 {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster)
757 %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
758 activity_three = Activity.get_by_id(activity_three.id)
759
760 activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})
761
762 assert Enum.member?(activities, activity_two)
763 refute Enum.member?(activities, activity_three)
764 refute Enum.member?(activities, boost_activity)
765 assert Enum.member?(activities, activity_one)
766
767 activities = ActivityPub.fetch_activities([], %{muting_user: nil, skip_preload: true})
768
769 assert Enum.member?(activities, activity_two)
770 assert Enum.member?(activities, activity_three)
771 assert Enum.member?(activities, boost_activity)
772 assert Enum.member?(activities, activity_one)
773 end
774
775 test "doesn't return thread muted activities" do
776 user = insert(:user)
777 _activity_one = insert(:note_activity)
778 note_two = insert(:note, data: %{"context" => "suya.."})
779 activity_two = insert(:note_activity, note: note_two)
780
781 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
782
783 assert [_activity_one] = ActivityPub.fetch_activities([], %{muting_user: user})
784 end
785
786 test "returns thread muted activities when with_muted is set" do
787 user = insert(:user)
788 _activity_one = insert(:note_activity)
789 note_two = insert(:note, data: %{"context" => "suya.."})
790 activity_two = insert(:note_activity, note: note_two)
791
792 {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)
793
794 assert [_activity_two, _activity_one] =
795 ActivityPub.fetch_activities([], %{muting_user: user, with_muted: true})
796 end
797
798 test "does include announces on request" do
799 activity_three = insert(:note_activity)
800 user = insert(:user)
801 booster = insert(:user)
802
803 {:ok, user} = User.follow(user, booster)
804
805 {:ok, announce} = CommonAPI.repeat(activity_three.id, booster)
806
807 [announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)])
808
809 assert announce_activity.id == announce.id
810 end
811
812 test "excludes reblogs on request" do
813 user = insert(:user)
814 {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})
815 {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user})
816
817 [activity] = ActivityPub.fetch_user_activities(user, nil, %{exclude_reblogs: true})
818
819 assert activity == expected_activity
820 end
821
822 describe "irreversible filters" do
823 setup do
824 user = insert(:user)
825 user_two = insert(:user)
826
827 insert(:filter, user: user_two, phrase: "cofe", hide: true)
828 insert(:filter, user: user_two, phrase: "ok boomer", hide: true)
829 insert(:filter, user: user_two, phrase: "test", hide: false)
830
831 params = %{
832 type: ["Create", "Announce"],
833 user: user_two
834 }
835
836 {:ok, %{user: user, user_two: user_two, params: params}}
837 end
838
839 test "it returns statuses if they don't contain exact filter words", %{
840 user: user,
841 params: params
842 } do
843 {:ok, _} = CommonAPI.post(user, %{status: "hey"})
844 {:ok, _} = CommonAPI.post(user, %{status: "got cofefe?"})
845 {:ok, _} = CommonAPI.post(user, %{status: "I am not a boomer"})
846 {:ok, _} = CommonAPI.post(user, %{status: "ok boomers"})
847 {:ok, _} = CommonAPI.post(user, %{status: "ccofee is not a word"})
848 {:ok, _} = CommonAPI.post(user, %{status: "this is a test"})
849
850 activities = ActivityPub.fetch_activities([], params)
851
852 assert Enum.count(activities) == 6
853 end
854
855 test "it does not filter user's own statuses", %{user_two: user_two, params: params} do
856 {:ok, _} = CommonAPI.post(user_two, %{status: "Give me some cofe!"})
857 {:ok, _} = CommonAPI.post(user_two, %{status: "ok boomer"})
858
859 activities = ActivityPub.fetch_activities([], params)
860
861 assert Enum.count(activities) == 2
862 end
863
864 test "it excludes statuses with filter words", %{user: user, params: params} do
865 {:ok, _} = CommonAPI.post(user, %{status: "Give me some cofe!"})
866 {:ok, _} = CommonAPI.post(user, %{status: "ok boomer"})
867 {:ok, _} = CommonAPI.post(user, %{status: "is it a cOfE?"})
868 {:ok, _} = CommonAPI.post(user, %{status: "cofe is all I need"})
869 {:ok, _} = CommonAPI.post(user, %{status: "— ok BOOMER\n"})
870
871 activities = ActivityPub.fetch_activities([], params)
872
873 assert Enum.empty?(activities)
874 end
875
876 test "it returns all statuses if user does not have any filters" do
877 another_user = insert(:user)
878 {:ok, _} = CommonAPI.post(another_user, %{status: "got cofe?"})
879 {:ok, _} = CommonAPI.post(another_user, %{status: "test!"})
880
881 activities =
882 ActivityPub.fetch_activities([], %{
883 type: ["Create", "Announce"],
884 user: another_user
885 })
886
887 assert Enum.count(activities) == 2
888 end
889 end
890
891 describe "public fetch activities" do
892 test "doesn't retrieve unlisted activities" do
893 user = insert(:user)
894
895 {:ok, _unlisted_activity} = CommonAPI.post(user, %{status: "yeah", visibility: "unlisted"})
896
897 {:ok, listed_activity} = CommonAPI.post(user, %{status: "yeah"})
898
899 [activity] = ActivityPub.fetch_public_activities()
900
901 assert activity == listed_activity
902 end
903
904 test "retrieves public activities" do
905 _activities = ActivityPub.fetch_public_activities()
906
907 %{public: public} = ActivityBuilder.public_and_non_public()
908
909 activities = ActivityPub.fetch_public_activities()
910 assert length(activities) == 1
911 assert Enum.at(activities, 0) == public
912 end
913
914 test "retrieves a maximum of 20 activities" do
915 ActivityBuilder.insert_list(10)
916 expected_activities = ActivityBuilder.insert_list(20)
917
918 activities = ActivityPub.fetch_public_activities()
919
920 assert collect_ids(activities) == collect_ids(expected_activities)
921 assert length(activities) == 20
922 end
923
924 test "retrieves ids starting from a since_id" do
925 activities = ActivityBuilder.insert_list(30)
926 expected_activities = ActivityBuilder.insert_list(10)
927 since_id = List.last(activities).id
928
929 activities = ActivityPub.fetch_public_activities(%{since_id: since_id})
930
931 assert collect_ids(activities) == collect_ids(expected_activities)
932 assert length(activities) == 10
933 end
934
935 test "retrieves ids up to max_id" do
936 ActivityBuilder.insert_list(10)
937 expected_activities = ActivityBuilder.insert_list(20)
938
939 %{id: max_id} =
940 10
941 |> ActivityBuilder.insert_list()
942 |> List.first()
943
944 activities = ActivityPub.fetch_public_activities(%{max_id: max_id})
945
946 assert length(activities) == 20
947 assert collect_ids(activities) == collect_ids(expected_activities)
948 end
949
950 test "paginates via offset/limit" do
951 _first_part_activities = ActivityBuilder.insert_list(10)
952 second_part_activities = ActivityBuilder.insert_list(10)
953
954 later_activities = ActivityBuilder.insert_list(10)
955
956 activities = ActivityPub.fetch_public_activities(%{page: "2", page_size: "20"}, :offset)
957
958 assert length(activities) == 20
959
960 assert collect_ids(activities) ==
961 collect_ids(second_part_activities) ++ collect_ids(later_activities)
962 end
963
964 test "doesn't return reblogs for users for whom reblogs have been muted" do
965 activity = insert(:note_activity)
966 user = insert(:user)
967 booster = insert(:user)
968 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
969
970 {:ok, activity} = CommonAPI.repeat(activity.id, booster)
971
972 activities = ActivityPub.fetch_activities([], %{muting_user: user})
973
974 refute Enum.any?(activities, fn %{id: id} -> id == activity.id end)
975 end
976
977 test "returns reblogs for users for whom reblogs have not been muted" do
978 activity = insert(:note_activity)
979 user = insert(:user)
980 booster = insert(:user)
981 {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)
982 {:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster)
983
984 {:ok, activity} = CommonAPI.repeat(activity.id, booster)
985
986 activities = ActivityPub.fetch_activities([], %{muting_user: user})
987
988 assert Enum.any?(activities, fn %{id: id} -> id == activity.id end)
989 end
990 end
991
992 describe "uploading files" do
993 setup do
994 test_file = %Plug.Upload{
995 content_type: "image/jpg",
996 path: Path.absname("test/fixtures/image.jpg"),
997 filename: "an_image.jpg"
998 }
999
1000 %{test_file: test_file}
1001 end
1002
1003 test "sets a description if given", %{test_file: file} do
1004 {:ok, %Object{} = object} = ActivityPub.upload(file, description: "a cool file")
1005 assert object.data["name"] == "a cool file"
1006 end
1007
1008 test "it sets the default description depending on the configuration", %{test_file: file} do
1009 clear_config([Pleroma.Upload, :default_description])
1010
1011 Pleroma.Config.put([Pleroma.Upload, :default_description], nil)
1012 {:ok, %Object{} = object} = ActivityPub.upload(file)
1013 assert object.data["name"] == ""
1014
1015 Pleroma.Config.put([Pleroma.Upload, :default_description], :filename)
1016 {:ok, %Object{} = object} = ActivityPub.upload(file)
1017 assert object.data["name"] == "an_image.jpg"
1018
1019 Pleroma.Config.put([Pleroma.Upload, :default_description], "unnamed attachment")
1020 {:ok, %Object{} = object} = ActivityPub.upload(file)
1021 assert object.data["name"] == "unnamed attachment"
1022 end
1023
1024 test "copies the file to the configured folder", %{test_file: file} do
1025 clear_config([Pleroma.Upload, :default_description], :filename)
1026 {:ok, %Object{} = object} = ActivityPub.upload(file)
1027 assert object.data["name"] == "an_image.jpg"
1028 end
1029
1030 test "works with base64 encoded images" do
1031 file = %{
1032 img: data_uri()
1033 }
1034
1035 {:ok, %Object{}} = ActivityPub.upload(file)
1036 end
1037 end
1038
1039 describe "fetch the latest Follow" do
1040 test "fetches the latest Follow activity" do
1041 %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
1042 follower = Repo.get_by(User, ap_id: activity.data["actor"])
1043 followed = Repo.get_by(User, ap_id: activity.data["object"])
1044
1045 assert activity == Utils.fetch_latest_follow(follower, followed)
1046 end
1047 end
1048
1049 describe "unfollowing" do
1050 test "it reverts unfollow activity" do
1051 follower = insert(:user)
1052 followed = insert(:user)
1053
1054 {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
1055
1056 with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
1057 assert {:error, :reverted} = ActivityPub.unfollow(follower, followed)
1058 end
1059
1060 activity = Activity.get_by_id(follow_activity.id)
1061 assert activity.data["type"] == "Follow"
1062 assert activity.data["actor"] == follower.ap_id
1063
1064 assert activity.data["object"] == followed.ap_id
1065 end
1066
1067 test "creates an undo activity for the last follow" do
1068 follower = insert(:user)
1069 followed = insert(:user)
1070
1071 {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
1072 {:ok, activity} = ActivityPub.unfollow(follower, followed)
1073
1074 assert activity.data["type"] == "Undo"
1075 assert activity.data["actor"] == follower.ap_id
1076
1077 embedded_object = activity.data["object"]
1078 assert is_map(embedded_object)
1079 assert embedded_object["type"] == "Follow"
1080 assert embedded_object["object"] == followed.ap_id
1081 assert embedded_object["id"] == follow_activity.data["id"]
1082 end
1083
1084 test "creates an undo activity for a pending follow request" do
1085 follower = insert(:user)
1086 followed = insert(:user, %{locked: true})
1087
1088 {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
1089 {:ok, activity} = ActivityPub.unfollow(follower, followed)
1090
1091 assert activity.data["type"] == "Undo"
1092 assert activity.data["actor"] == follower.ap_id
1093
1094 embedded_object = activity.data["object"]
1095 assert is_map(embedded_object)
1096 assert embedded_object["type"] == "Follow"
1097 assert embedded_object["object"] == followed.ap_id
1098 assert embedded_object["id"] == follow_activity.data["id"]
1099 end
1100 end
1101
1102 describe "timeline post-processing" do
1103 test "it filters broken threads" do
1104 user1 = insert(:user)
1105 user2 = insert(:user)
1106 user3 = insert(:user)
1107
1108 {:ok, user1} = User.follow(user1, user3)
1109 assert User.following?(user1, user3)
1110
1111 {:ok, user2} = User.follow(user2, user3)
1112 assert User.following?(user2, user3)
1113
1114 {:ok, user3} = User.follow(user3, user2)
1115 assert User.following?(user3, user2)
1116
1117 {:ok, public_activity} = CommonAPI.post(user3, %{status: "hi 1"})
1118
1119 {:ok, private_activity_1} = CommonAPI.post(user3, %{status: "hi 2", visibility: "private"})
1120
1121 {:ok, private_activity_2} =
1122 CommonAPI.post(user2, %{
1123 status: "hi 3",
1124 visibility: "private",
1125 in_reply_to_status_id: private_activity_1.id
1126 })
1127
1128 {:ok, private_activity_3} =
1129 CommonAPI.post(user3, %{
1130 status: "hi 4",
1131 visibility: "private",
1132 in_reply_to_status_id: private_activity_2.id
1133 })
1134
1135 activities =
1136 ActivityPub.fetch_activities([user1.ap_id | User.following(user1)])
1137 |> Enum.map(fn a -> a.id end)
1138
1139 private_activity_1 = Activity.get_by_ap_id_with_object(private_activity_1.data["id"])
1140
1141 assert [public_activity.id, private_activity_1.id, private_activity_3.id] == activities
1142
1143 assert length(activities) == 3
1144
1145 activities =
1146 ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{user: user1})
1147 |> Enum.map(fn a -> a.id end)
1148
1149 assert [public_activity.id, private_activity_1.id] == activities
1150 assert length(activities) == 2
1151 end
1152 end
1153
1154 describe "flag/1" do
1155 setup do
1156 reporter = insert(:user)
1157 target_account = insert(:user)
1158 content = "foobar"
1159 {:ok, activity} = CommonAPI.post(target_account, %{status: content})
1160 context = Utils.generate_context_id()
1161
1162 reporter_ap_id = reporter.ap_id
1163 target_ap_id = target_account.ap_id
1164 activity_ap_id = activity.data["id"]
1165
1166 activity_with_object = Activity.get_by_ap_id_with_object(activity_ap_id)
1167
1168 {:ok,
1169 %{
1170 reporter: reporter,
1171 context: context,
1172 target_account: target_account,
1173 reported_activity: activity,
1174 content: content,
1175 activity_ap_id: activity_ap_id,
1176 activity_with_object: activity_with_object,
1177 reporter_ap_id: reporter_ap_id,
1178 target_ap_id: target_ap_id
1179 }}
1180 end
1181
1182 test "it can create a Flag activity",
1183 %{
1184 reporter: reporter,
1185 context: context,
1186 target_account: target_account,
1187 reported_activity: reported_activity,
1188 content: content,
1189 activity_ap_id: activity_ap_id,
1190 activity_with_object: activity_with_object,
1191 reporter_ap_id: reporter_ap_id,
1192 target_ap_id: target_ap_id
1193 } do
1194 assert {:ok, activity} =
1195 ActivityPub.flag(%{
1196 actor: reporter,
1197 context: context,
1198 account: target_account,
1199 statuses: [reported_activity],
1200 content: content
1201 })
1202
1203 note_obj = %{
1204 "type" => "Note",
1205 "id" => activity_ap_id,
1206 "content" => content,
1207 "published" => activity_with_object.object.data["published"],
1208 "actor" =>
1209 AccountView.render("show.json", %{user: target_account, skip_visibility_check: true})
1210 }
1211
1212 assert %Activity{
1213 actor: ^reporter_ap_id,
1214 data: %{
1215 "type" => "Flag",
1216 "content" => ^content,
1217 "context" => ^context,
1218 "object" => [^target_ap_id, ^note_obj]
1219 }
1220 } = activity
1221 end
1222
1223 test_with_mock "strips status data from Flag, before federating it",
1224 %{
1225 reporter: reporter,
1226 context: context,
1227 target_account: target_account,
1228 reported_activity: reported_activity,
1229 content: content
1230 },
1231 Utils,
1232 [:passthrough],
1233 [] do
1234 {:ok, activity} =
1235 ActivityPub.flag(%{
1236 actor: reporter,
1237 context: context,
1238 account: target_account,
1239 statuses: [reported_activity],
1240 content: content
1241 })
1242
1243 new_data =
1244 put_in(activity.data, ["object"], [target_account.ap_id, reported_activity.data["id"]])
1245
1246 assert_called(Utils.maybe_federate(%{activity | data: new_data}))
1247 end
1248 end
1249
1250 test "fetch_activities/2 returns activities addressed to a list " do
1251 user = insert(:user)
1252 member = insert(:user)
1253 {:ok, list} = Pleroma.List.create("foo", user)
1254 {:ok, list} = Pleroma.List.follow(list, member)
1255
1256 {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
1257
1258 activity = Repo.preload(activity, :bookmark)
1259 activity = %Activity{activity | thread_muted?: !!activity.thread_muted?}
1260
1261 assert ActivityPub.fetch_activities([], %{user: user}) == [activity]
1262 end
1263
1264 def data_uri do
1265 File.read!("test/fixtures/avatar_data_uri")
1266 end
1267
1268 describe "fetch_activities_bounded" do
1269 test "fetches private posts for followed users" do
1270 user = insert(:user)
1271
1272 {:ok, activity} =
1273 CommonAPI.post(user, %{
1274 status: "thought I looked cute might delete later :3",
1275 visibility: "private"
1276 })
1277
1278 [result] = ActivityPub.fetch_activities_bounded([user.follower_address], [])
1279 assert result.id == activity.id
1280 end
1281
1282 test "fetches only public posts for other users" do
1283 user = insert(:user)
1284 {:ok, activity} = CommonAPI.post(user, %{status: "#cofe", visibility: "public"})
1285
1286 {:ok, _private_activity} =
1287 CommonAPI.post(user, %{
1288 status: "why is tenshi eating a corndog so cute?",
1289 visibility: "private"
1290 })
1291
1292 [result] = ActivityPub.fetch_activities_bounded([], [user.follower_address])
1293 assert result.id == activity.id
1294 end
1295 end
1296
1297 describe "fetch_follow_information_for_user" do
1298 test "syncronizes following/followers counters" do
1299 user =
1300 insert(:user,
1301 local: false,
1302 follower_address: "http://localhost:4001/users/fuser2/followers",
1303 following_address: "http://localhost:4001/users/fuser2/following"
1304 )
1305
1306 {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
1307 assert info.follower_count == 527
1308 assert info.following_count == 267
1309 end
1310
1311 test "detects hidden followers" do
1312 mock(fn env ->
1313 case env.url do
1314 "http://localhost:4001/users/masto_closed/followers?page=1" ->
1315 %Tesla.Env{status: 403, body: ""}
1316
1317 _ ->
1318 apply(HttpRequestMock, :request, [env])
1319 end
1320 end)
1321
1322 user =
1323 insert(:user,
1324 local: false,
1325 follower_address: "http://localhost:4001/users/masto_closed/followers",
1326 following_address: "http://localhost:4001/users/masto_closed/following"
1327 )
1328
1329 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1330 assert follow_info.hide_followers == true
1331 assert follow_info.hide_follows == false
1332 end
1333
1334 test "detects hidden follows" do
1335 mock(fn env ->
1336 case env.url do
1337 "http://localhost:4001/users/masto_closed/following?page=1" ->
1338 %Tesla.Env{status: 403, body: ""}
1339
1340 _ ->
1341 apply(HttpRequestMock, :request, [env])
1342 end
1343 end)
1344
1345 user =
1346 insert(:user,
1347 local: false,
1348 follower_address: "http://localhost:4001/users/masto_closed/followers",
1349 following_address: "http://localhost:4001/users/masto_closed/following"
1350 )
1351
1352 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1353 assert follow_info.hide_followers == false
1354 assert follow_info.hide_follows == true
1355 end
1356
1357 test "detects hidden follows/followers for friendica" do
1358 user =
1359 insert(:user,
1360 local: false,
1361 follower_address: "http://localhost:8080/followers/fuser3",
1362 following_address: "http://localhost:8080/following/fuser3"
1363 )
1364
1365 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1366 assert follow_info.hide_followers == true
1367 assert follow_info.follower_count == 296
1368 assert follow_info.following_count == 32
1369 assert follow_info.hide_follows == true
1370 end
1371
1372 test "doesn't crash when follower and following counters are hidden" do
1373 mock(fn env ->
1374 case env.url do
1375 "http://localhost:4001/users/masto_hidden_counters/following" ->
1376 json(%{
1377 "@context" => "https://www.w3.org/ns/activitystreams",
1378 "id" => "http://localhost:4001/users/masto_hidden_counters/followers"
1379 })
1380
1381 "http://localhost:4001/users/masto_hidden_counters/following?page=1" ->
1382 %Tesla.Env{status: 403, body: ""}
1383
1384 "http://localhost:4001/users/masto_hidden_counters/followers" ->
1385 json(%{
1386 "@context" => "https://www.w3.org/ns/activitystreams",
1387 "id" => "http://localhost:4001/users/masto_hidden_counters/following"
1388 })
1389
1390 "http://localhost:4001/users/masto_hidden_counters/followers?page=1" ->
1391 %Tesla.Env{status: 403, body: ""}
1392 end
1393 end)
1394
1395 user =
1396 insert(:user,
1397 local: false,
1398 follower_address: "http://localhost:4001/users/masto_hidden_counters/followers",
1399 following_address: "http://localhost:4001/users/masto_hidden_counters/following"
1400 )
1401
1402 {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
1403
1404 assert follow_info.hide_followers == true
1405 assert follow_info.follower_count == 0
1406 assert follow_info.hide_follows == true
1407 assert follow_info.following_count == 0
1408 end
1409 end
1410
1411 describe "fetch_favourites/3" do
1412 test "returns a favourite activities sorted by adds to favorite" do
1413 user = insert(:user)
1414 other_user = insert(:user)
1415 user1 = insert(:user)
1416 user2 = insert(:user)
1417 {:ok, a1} = CommonAPI.post(user1, %{status: "bla"})
1418 {:ok, _a2} = CommonAPI.post(user2, %{status: "traps are happy"})
1419 {:ok, a3} = CommonAPI.post(user2, %{status: "Trees Are "})
1420 {:ok, a4} = CommonAPI.post(user2, %{status: "Agent Smith "})
1421 {:ok, a5} = CommonAPI.post(user1, %{status: "Red or Blue "})
1422
1423 {:ok, _} = CommonAPI.favorite(user, a4.id)
1424 {:ok, _} = CommonAPI.favorite(other_user, a3.id)
1425 {:ok, _} = CommonAPI.favorite(user, a3.id)
1426 {:ok, _} = CommonAPI.favorite(other_user, a5.id)
1427 {:ok, _} = CommonAPI.favorite(user, a5.id)
1428 {:ok, _} = CommonAPI.favorite(other_user, a4.id)
1429 {:ok, _} = CommonAPI.favorite(user, a1.id)
1430 {:ok, _} = CommonAPI.favorite(other_user, a1.id)
1431 result = ActivityPub.fetch_favourites(user)
1432
1433 assert Enum.map(result, & &1.id) == [a1.id, a5.id, a3.id, a4.id]
1434
1435 result = ActivityPub.fetch_favourites(user, %{limit: 2})
1436 assert Enum.map(result, & &1.id) == [a1.id, a5.id]
1437 end
1438 end
1439
1440 describe "Move activity" do
1441 test "create" do
1442 %{ap_id: old_ap_id} = old_user = insert(:user)
1443 %{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
1444 follower = insert(:user)
1445 follower_move_opted_out = insert(:user, allow_following_move: false)
1446
1447 User.follow(follower, old_user)
1448 User.follow(follower_move_opted_out, old_user)
1449
1450 assert User.following?(follower, old_user)
1451 assert User.following?(follower_move_opted_out, old_user)
1452
1453 assert {:ok, activity} = ActivityPub.move(old_user, new_user)
1454
1455 assert %Activity{
1456 actor: ^old_ap_id,
1457 data: %{
1458 "actor" => ^old_ap_id,
1459 "object" => ^old_ap_id,
1460 "target" => ^new_ap_id,
1461 "type" => "Move"
1462 },
1463 local: true
1464 } = activity
1465
1466 params = %{
1467 "op" => "move_following",
1468 "origin_id" => old_user.id,
1469 "target_id" => new_user.id
1470 }
1471
1472 assert_enqueued(worker: Pleroma.Workers.BackgroundWorker, args: params)
1473
1474 Pleroma.Workers.BackgroundWorker.perform(%Oban.Job{args: params})
1475
1476 refute User.following?(follower, old_user)
1477 assert User.following?(follower, new_user)
1478
1479 assert User.following?(follower_move_opted_out, old_user)
1480 refute User.following?(follower_move_opted_out, new_user)
1481
1482 activity = %Activity{activity | object: nil}
1483
1484 assert [%Notification{activity: ^activity}] = Notification.for_user(follower)
1485
1486 assert [%Notification{activity: ^activity}] = Notification.for_user(follower_move_opted_out)
1487 end
1488
1489 test "old user must be in the new user's `also_known_as` list" do
1490 old_user = insert(:user)
1491 new_user = insert(:user)
1492
1493 assert {:error, "Target account must have the origin in `alsoKnownAs`"} =
1494 ActivityPub.move(old_user, new_user)
1495 end
1496 end
1497
1498 test "doesn't retrieve replies activities with exclude_replies" do
1499 user = insert(:user)
1500
1501 {:ok, activity} = CommonAPI.post(user, %{status: "yeah"})
1502
1503 {:ok, _reply} = CommonAPI.post(user, %{status: "yeah", in_reply_to_status_id: activity.id})
1504
1505 [result] = ActivityPub.fetch_public_activities(%{exclude_replies: true})
1506
1507 assert result.id == activity.id
1508
1509 assert length(ActivityPub.fetch_public_activities()) == 2
1510 end
1511
1512 describe "replies filtering with public messages" do
1513 setup :public_messages
1514
1515 test "public timeline", %{users: %{u1: user}} do
1516 activities_ids =
1517 %{}
1518 |> Map.put(:type, ["Create", "Announce"])
1519 |> Map.put(:local_only, false)
1520 |> Map.put(:blocking_user, user)
1521 |> Map.put(:muting_user, user)
1522 |> Map.put(:reply_filtering_user, user)
1523 |> ActivityPub.fetch_public_activities()
1524 |> Enum.map(& &1.id)
1525
1526 assert length(activities_ids) == 16
1527 end
1528
1529 test "public timeline with reply_visibility `following`", %{
1530 users: %{u1: user},
1531 u1: u1,
1532 u2: u2,
1533 u3: u3,
1534 u4: u4,
1535 activities: activities
1536 } do
1537 activities_ids =
1538 %{}
1539 |> Map.put(:type, ["Create", "Announce"])
1540 |> Map.put(:local_only, false)
1541 |> Map.put(:blocking_user, user)
1542 |> Map.put(:muting_user, user)
1543 |> Map.put(:reply_visibility, "following")
1544 |> Map.put(:reply_filtering_user, user)
1545 |> ActivityPub.fetch_public_activities()
1546 |> Enum.map(& &1.id)
1547
1548 assert length(activities_ids) == 14
1549
1550 visible_ids =
1551 Map.values(u1) ++ Map.values(u2) ++ Map.values(u4) ++ Map.values(activities) ++ [u3[:r1]]
1552
1553 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1554 end
1555
1556 test "public timeline with reply_visibility `self`", %{
1557 users: %{u1: user},
1558 u1: u1,
1559 u2: u2,
1560 u3: u3,
1561 u4: u4,
1562 activities: activities
1563 } do
1564 activities_ids =
1565 %{}
1566 |> Map.put(:type, ["Create", "Announce"])
1567 |> Map.put(:local_only, false)
1568 |> Map.put(:blocking_user, user)
1569 |> Map.put(:muting_user, user)
1570 |> Map.put(:reply_visibility, "self")
1571 |> Map.put(:reply_filtering_user, user)
1572 |> ActivityPub.fetch_public_activities()
1573 |> Enum.map(& &1.id)
1574
1575 assert length(activities_ids) == 10
1576 visible_ids = Map.values(u1) ++ [u2[:r1], u3[:r1], u4[:r1]] ++ Map.values(activities)
1577 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1578 end
1579
1580 test "home timeline", %{
1581 users: %{u1: user},
1582 activities: activities,
1583 u1: u1,
1584 u2: u2,
1585 u3: u3,
1586 u4: u4
1587 } do
1588 params =
1589 %{}
1590 |> Map.put(:type, ["Create", "Announce"])
1591 |> Map.put(:blocking_user, user)
1592 |> Map.put(:muting_user, user)
1593 |> Map.put(:user, user)
1594 |> Map.put(:reply_filtering_user, user)
1595
1596 activities_ids =
1597 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
1598 |> Enum.map(& &1.id)
1599
1600 assert length(activities_ids) == 13
1601
1602 visible_ids =
1603 Map.values(u1) ++
1604 Map.values(u3) ++
1605 [
1606 activities[:a1],
1607 activities[:a2],
1608 activities[:a4],
1609 u2[:r1],
1610 u2[:r3],
1611 u4[:r1],
1612 u4[:r2]
1613 ]
1614
1615 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1616 end
1617
1618 test "home timeline with reply_visibility `following`", %{
1619 users: %{u1: user},
1620 activities: activities,
1621 u1: u1,
1622 u2: u2,
1623 u3: u3,
1624 u4: u4
1625 } do
1626 params =
1627 %{}
1628 |> Map.put(:type, ["Create", "Announce"])
1629 |> Map.put(:blocking_user, user)
1630 |> Map.put(:muting_user, user)
1631 |> Map.put(:user, user)
1632 |> Map.put(:reply_visibility, "following")
1633 |> Map.put(:reply_filtering_user, user)
1634
1635 activities_ids =
1636 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
1637 |> Enum.map(& &1.id)
1638
1639 assert length(activities_ids) == 11
1640
1641 visible_ids =
1642 Map.values(u1) ++
1643 [
1644 activities[:a1],
1645 activities[:a2],
1646 activities[:a4],
1647 u2[:r1],
1648 u2[:r3],
1649 u3[:r1],
1650 u4[:r1],
1651 u4[:r2]
1652 ]
1653
1654 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1655 end
1656
1657 test "home timeline with reply_visibility `self`", %{
1658 users: %{u1: user},
1659 activities: activities,
1660 u1: u1,
1661 u2: u2,
1662 u3: u3,
1663 u4: u4
1664 } do
1665 params =
1666 %{}
1667 |> Map.put(:type, ["Create", "Announce"])
1668 |> Map.put(:blocking_user, user)
1669 |> Map.put(:muting_user, user)
1670 |> Map.put(:user, user)
1671 |> Map.put(:reply_visibility, "self")
1672 |> Map.put(:reply_filtering_user, user)
1673
1674 activities_ids =
1675 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
1676 |> Enum.map(& &1.id)
1677
1678 assert length(activities_ids) == 9
1679
1680 visible_ids =
1681 Map.values(u1) ++
1682 [
1683 activities[:a1],
1684 activities[:a2],
1685 activities[:a4],
1686 u2[:r1],
1687 u3[:r1],
1688 u4[:r1]
1689 ]
1690
1691 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1692 end
1693
1694 test "filtering out announces where the user is the actor of the announced message" do
1695 user = insert(:user)
1696 other_user = insert(:user)
1697 third_user = insert(:user)
1698 User.follow(user, other_user)
1699
1700 {:ok, post} = CommonAPI.post(user, %{status: "yo"})
1701 {:ok, other_post} = CommonAPI.post(third_user, %{status: "yo"})
1702 {:ok, _announce} = CommonAPI.repeat(post.id, other_user)
1703 {:ok, _announce} = CommonAPI.repeat(post.id, third_user)
1704 {:ok, announce} = CommonAPI.repeat(other_post.id, other_user)
1705
1706 params = %{
1707 type: ["Announce"]
1708 }
1709
1710 results =
1711 [user.ap_id | User.following(user)]
1712 |> ActivityPub.fetch_activities(params)
1713
1714 assert length(results) == 3
1715
1716 params = %{
1717 type: ["Announce"],
1718 announce_filtering_user: user
1719 }
1720
1721 [result] =
1722 [user.ap_id | User.following(user)]
1723 |> ActivityPub.fetch_activities(params)
1724
1725 assert result.id == announce.id
1726 end
1727 end
1728
1729 describe "replies filtering with private messages" do
1730 setup :private_messages
1731
1732 test "public timeline", %{users: %{u1: user}} do
1733 activities_ids =
1734 %{}
1735 |> Map.put(:type, ["Create", "Announce"])
1736 |> Map.put(:local_only, false)
1737 |> Map.put(:blocking_user, user)
1738 |> Map.put(:muting_user, user)
1739 |> Map.put(:user, user)
1740 |> ActivityPub.fetch_public_activities()
1741 |> Enum.map(& &1.id)
1742
1743 assert activities_ids == []
1744 end
1745
1746 test "public timeline with default reply_visibility `following`", %{users: %{u1: user}} do
1747 activities_ids =
1748 %{}
1749 |> Map.put(:type, ["Create", "Announce"])
1750 |> Map.put(:local_only, false)
1751 |> Map.put(:blocking_user, user)
1752 |> Map.put(:muting_user, user)
1753 |> Map.put(:reply_visibility, "following")
1754 |> Map.put(:reply_filtering_user, user)
1755 |> Map.put(:user, user)
1756 |> ActivityPub.fetch_public_activities()
1757 |> Enum.map(& &1.id)
1758
1759 assert activities_ids == []
1760 end
1761
1762 test "public timeline with default reply_visibility `self`", %{users: %{u1: user}} do
1763 activities_ids =
1764 %{}
1765 |> Map.put(:type, ["Create", "Announce"])
1766 |> Map.put(:local_only, false)
1767 |> Map.put(:blocking_user, user)
1768 |> Map.put(:muting_user, user)
1769 |> Map.put(:reply_visibility, "self")
1770 |> Map.put(:reply_filtering_user, user)
1771 |> Map.put(:user, user)
1772 |> ActivityPub.fetch_public_activities()
1773 |> Enum.map(& &1.id)
1774
1775 assert activities_ids == []
1776 end
1777
1778 test "home timeline", %{users: %{u1: user}} do
1779 params =
1780 %{}
1781 |> Map.put(:type, ["Create", "Announce"])
1782 |> Map.put(:blocking_user, user)
1783 |> Map.put(:muting_user, user)
1784 |> Map.put(:user, user)
1785
1786 activities_ids =
1787 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
1788 |> Enum.map(& &1.id)
1789
1790 assert length(activities_ids) == 12
1791 end
1792
1793 test "home timeline with default reply_visibility `following`", %{users: %{u1: user}} do
1794 params =
1795 %{}
1796 |> Map.put(:type, ["Create", "Announce"])
1797 |> Map.put(:blocking_user, user)
1798 |> Map.put(:muting_user, user)
1799 |> Map.put(:user, user)
1800 |> Map.put(:reply_visibility, "following")
1801 |> Map.put(:reply_filtering_user, user)
1802
1803 activities_ids =
1804 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
1805 |> Enum.map(& &1.id)
1806
1807 assert length(activities_ids) == 12
1808 end
1809
1810 test "home timeline with default reply_visibility `self`", %{
1811 users: %{u1: user},
1812 activities: activities,
1813 u1: u1,
1814 u2: u2,
1815 u3: u3,
1816 u4: u4
1817 } do
1818 params =
1819 %{}
1820 |> Map.put(:type, ["Create", "Announce"])
1821 |> Map.put(:blocking_user, user)
1822 |> Map.put(:muting_user, user)
1823 |> Map.put(:user, user)
1824 |> Map.put(:reply_visibility, "self")
1825 |> Map.put(:reply_filtering_user, user)
1826
1827 activities_ids =
1828 ActivityPub.fetch_activities([user.ap_id | User.following(user)], params)
1829 |> Enum.map(& &1.id)
1830
1831 assert length(activities_ids) == 10
1832
1833 visible_ids =
1834 Map.values(u1) ++ Map.values(u4) ++ [u2[:r1], u3[:r1]] ++ Map.values(activities)
1835
1836 assert Enum.all?(visible_ids, &(&1 in activities_ids))
1837 end
1838 end
1839
1840 defp public_messages(_) do
1841 [u1, u2, u3, u4] = insert_list(4, :user)
1842 {:ok, u1} = User.follow(u1, u2)
1843 {:ok, u2} = User.follow(u2, u1)
1844 {:ok, u1} = User.follow(u1, u4)
1845 {:ok, u4} = User.follow(u4, u1)
1846
1847 {:ok, u2} = User.follow(u2, u3)
1848 {:ok, u3} = User.follow(u3, u2)
1849
1850 {:ok, a1} = CommonAPI.post(u1, %{status: "Status"})
1851
1852 {:ok, r1_1} =
1853 CommonAPI.post(u2, %{
1854 status: "@#{u1.nickname} reply from u2 to u1",
1855 in_reply_to_status_id: a1.id
1856 })
1857
1858 {:ok, r1_2} =
1859 CommonAPI.post(u3, %{
1860 status: "@#{u1.nickname} reply from u3 to u1",
1861 in_reply_to_status_id: a1.id
1862 })
1863
1864 {:ok, r1_3} =
1865 CommonAPI.post(u4, %{
1866 status: "@#{u1.nickname} reply from u4 to u1",
1867 in_reply_to_status_id: a1.id
1868 })
1869
1870 {:ok, a2} = CommonAPI.post(u2, %{status: "Status"})
1871
1872 {:ok, r2_1} =
1873 CommonAPI.post(u1, %{
1874 status: "@#{u2.nickname} reply from u1 to u2",
1875 in_reply_to_status_id: a2.id
1876 })
1877
1878 {:ok, r2_2} =
1879 CommonAPI.post(u3, %{
1880 status: "@#{u2.nickname} reply from u3 to u2",
1881 in_reply_to_status_id: a2.id
1882 })
1883
1884 {:ok, r2_3} =
1885 CommonAPI.post(u4, %{
1886 status: "@#{u2.nickname} reply from u4 to u2",
1887 in_reply_to_status_id: a2.id
1888 })
1889
1890 {:ok, a3} = CommonAPI.post(u3, %{status: "Status"})
1891
1892 {:ok, r3_1} =
1893 CommonAPI.post(u1, %{
1894 status: "@#{u3.nickname} reply from u1 to u3",
1895 in_reply_to_status_id: a3.id
1896 })
1897
1898 {:ok, r3_2} =
1899 CommonAPI.post(u2, %{
1900 status: "@#{u3.nickname} reply from u2 to u3",
1901 in_reply_to_status_id: a3.id
1902 })
1903
1904 {:ok, r3_3} =
1905 CommonAPI.post(u4, %{
1906 status: "@#{u3.nickname} reply from u4 to u3",
1907 in_reply_to_status_id: a3.id
1908 })
1909
1910 {:ok, a4} = CommonAPI.post(u4, %{status: "Status"})
1911
1912 {:ok, r4_1} =
1913 CommonAPI.post(u1, %{
1914 status: "@#{u4.nickname} reply from u1 to u4",
1915 in_reply_to_status_id: a4.id
1916 })
1917
1918 {:ok, r4_2} =
1919 CommonAPI.post(u2, %{
1920 status: "@#{u4.nickname} reply from u2 to u4",
1921 in_reply_to_status_id: a4.id
1922 })
1923
1924 {:ok, r4_3} =
1925 CommonAPI.post(u3, %{
1926 status: "@#{u4.nickname} reply from u3 to u4",
1927 in_reply_to_status_id: a4.id
1928 })
1929
1930 {:ok,
1931 users: %{u1: u1, u2: u2, u3: u3, u4: u4},
1932 activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id},
1933 u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id},
1934 u2: %{r1: r2_1.id, r2: r2_2.id, r3: r2_3.id},
1935 u3: %{r1: r3_1.id, r2: r3_2.id, r3: r3_3.id},
1936 u4: %{r1: r4_1.id, r2: r4_2.id, r3: r4_3.id}}
1937 end
1938
1939 defp private_messages(_) do
1940 [u1, u2, u3, u4] = insert_list(4, :user)
1941 {:ok, u1} = User.follow(u1, u2)
1942 {:ok, u2} = User.follow(u2, u1)
1943 {:ok, u1} = User.follow(u1, u3)
1944 {:ok, u3} = User.follow(u3, u1)
1945 {:ok, u1} = User.follow(u1, u4)
1946 {:ok, u4} = User.follow(u4, u1)
1947
1948 {:ok, u2} = User.follow(u2, u3)
1949 {:ok, u3} = User.follow(u3, u2)
1950
1951 {:ok, a1} = CommonAPI.post(u1, %{status: "Status", visibility: "private"})
1952
1953 {:ok, r1_1} =
1954 CommonAPI.post(u2, %{
1955 status: "@#{u1.nickname} reply from u2 to u1",
1956 in_reply_to_status_id: a1.id,
1957 visibility: "private"
1958 })
1959
1960 {:ok, r1_2} =
1961 CommonAPI.post(u3, %{
1962 status: "@#{u1.nickname} reply from u3 to u1",
1963 in_reply_to_status_id: a1.id,
1964 visibility: "private"
1965 })
1966
1967 {:ok, r1_3} =
1968 CommonAPI.post(u4, %{
1969 status: "@#{u1.nickname} reply from u4 to u1",
1970 in_reply_to_status_id: a1.id,
1971 visibility: "private"
1972 })
1973
1974 {:ok, a2} = CommonAPI.post(u2, %{status: "Status", visibility: "private"})
1975
1976 {:ok, r2_1} =
1977 CommonAPI.post(u1, %{
1978 status: "@#{u2.nickname} reply from u1 to u2",
1979 in_reply_to_status_id: a2.id,
1980 visibility: "private"
1981 })
1982
1983 {:ok, r2_2} =
1984 CommonAPI.post(u3, %{
1985 status: "@#{u2.nickname} reply from u3 to u2",
1986 in_reply_to_status_id: a2.id,
1987 visibility: "private"
1988 })
1989
1990 {:ok, a3} = CommonAPI.post(u3, %{status: "Status", visibility: "private"})
1991
1992 {:ok, r3_1} =
1993 CommonAPI.post(u1, %{
1994 status: "@#{u3.nickname} reply from u1 to u3",
1995 in_reply_to_status_id: a3.id,
1996 visibility: "private"
1997 })
1998
1999 {:ok, r3_2} =
2000 CommonAPI.post(u2, %{
2001 status: "@#{u3.nickname} reply from u2 to u3",
2002 in_reply_to_status_id: a3.id,
2003 visibility: "private"
2004 })
2005
2006 {:ok, a4} = CommonAPI.post(u4, %{status: "Status", visibility: "private"})
2007
2008 {:ok, r4_1} =
2009 CommonAPI.post(u1, %{
2010 status: "@#{u4.nickname} reply from u1 to u4",
2011 in_reply_to_status_id: a4.id,
2012 visibility: "private"
2013 })
2014
2015 {:ok,
2016 users: %{u1: u1, u2: u2, u3: u3, u4: u4},
2017 activities: %{a1: a1.id, a2: a2.id, a3: a3.id, a4: a4.id},
2018 u1: %{r1: r1_1.id, r2: r1_2.id, r3: r1_3.id},
2019 u2: %{r1: r2_1.id, r2: r2_2.id},
2020 u3: %{r1: r3_1.id, r2: r3_2.id},
2021 u4: %{r1: r4_1.id}}
2022 end
2023
2024 describe "maybe_update_follow_information/1" do
2025 setup do
2026 clear_config([:instance, :external_user_synchronization], true)
2027
2028 user = %{
2029 local: false,
2030 ap_id: "https://gensokyo.2hu/users/raymoo",
2031 following_address: "https://gensokyo.2hu/users/following",
2032 follower_address: "https://gensokyo.2hu/users/followers",
2033 type: "Person"
2034 }
2035
2036 %{user: user}
2037 end
2038
2039 test "logs an error when it can't fetch the info", %{user: user} do
2040 assert capture_log(fn ->
2041 ActivityPub.maybe_update_follow_information(user)
2042 end) =~ "Follower/Following counter update for #{user.ap_id} failed"
2043 end
2044
2045 test "just returns the input if the user type is Application", %{
2046 user: user
2047 } do
2048 user =
2049 user
2050 |> Map.put(:type, "Application")
2051
2052 refute capture_log(fn ->
2053 assert ^user = ActivityPub.maybe_update_follow_information(user)
2054 end) =~ "Follower/Following counter update for #{user.ap_id} failed"
2055 end
2056
2057 test "it just returns the input if the user has no following/follower addresses", %{
2058 user: user
2059 } do
2060 user =
2061 user
2062 |> Map.put(:following_address, nil)
2063 |> Map.put(:follower_address, nil)
2064
2065 refute capture_log(fn ->
2066 assert ^user = ActivityPub.maybe_update_follow_information(user)
2067 end) =~ "Follower/Following counter update for #{user.ap_id} failed"
2068 end
2069 end
2070
2071 describe "global activity expiration" do
2072 setup do: clear_config([:mrf, :policies])
2073
2074 test "creates an activity expiration for local Create activities" do
2075 Pleroma.Config.put(
2076 [:mrf, :policies],
2077 Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy
2078 )
2079
2080 {:ok, %{id: id_create}} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
2081 {:ok, _follow} = ActivityBuilder.insert(%{"type" => "Follow", "context" => "3hu"})
2082
2083 assert [%{activity_id: ^id_create}] = Pleroma.ActivityExpiration |> Repo.all()
2084 end
2085 end
2086
2087 describe "handling of clashing nicknames" do
2088 test "renames an existing user with a clashing nickname and a different ap id" do
2089 orig_user =
2090 insert(
2091 :user,
2092 local: false,
2093 nickname: "admin@mastodon.example.org",
2094 ap_id: "http://mastodon.example.org/users/harinezumigari"
2095 )
2096
2097 %{
2098 nickname: orig_user.nickname,
2099 ap_id: orig_user.ap_id <> "part_2"
2100 }
2101 |> ActivityPub.maybe_handle_clashing_nickname()
2102
2103 user = User.get_by_id(orig_user.id)
2104
2105 assert user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
2106 end
2107
2108 test "does nothing with a clashing nickname and the same ap id" do
2109 orig_user =
2110 insert(
2111 :user,
2112 local: false,
2113 nickname: "admin@mastodon.example.org",
2114 ap_id: "http://mastodon.example.org/users/harinezumigari"
2115 )
2116
2117 %{
2118 nickname: orig_user.nickname,
2119 ap_id: orig_user.ap_id
2120 }
2121 |> ActivityPub.maybe_handle_clashing_nickname()
2122
2123 user = User.get_by_id(orig_user.id)
2124
2125 assert user.nickname == orig_user.nickname
2126 end
2127 end
2128 end