total rebase
[anni] / test / pleroma / user_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.UserTest do
6   alias Pleroma.Activity
7   alias Pleroma.Builders.UserBuilder
8   alias Pleroma.Object
9   alias Pleroma.Repo
10   alias Pleroma.Tests.ObanHelpers
11   alias Pleroma.User
12   alias Pleroma.Web.ActivityPub.ActivityPub
13   alias Pleroma.Web.CommonAPI
14
15   use Pleroma.DataCase, async: false
16   use Oban.Testing, repo: Pleroma.Repo
17
18   import Pleroma.Factory
19   import ExUnit.CaptureLog
20   import Swoosh.TestAssertions
21
22   setup do
23     Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
24     :ok
25   end
26
27   setup_all do
28     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
29     :ok
30   end
31
32   setup do: clear_config([:instance, :account_activation_required])
33
34   describe "service actors" do
35     test "returns updated invisible actor" do
36       uri = "#{Pleroma.Web.Endpoint.url()}/relay"
37       followers_uri = "#{uri}/followers"
38
39       insert(
40         :user,
41         %{
42           nickname: "relay",
43           invisible: false,
44           local: true,
45           ap_id: uri,
46           follower_address: followers_uri
47         }
48       )
49
50       actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
51       assert actor.invisible
52     end
53
54     test "returns relay user" do
55       uri = "#{Pleroma.Web.Endpoint.url()}/relay"
56       followers_uri = "#{uri}/followers"
57
58       assert %User{
59                nickname: "relay",
60                invisible: true,
61                local: true,
62                ap_id: ^uri,
63                follower_address: ^followers_uri
64              } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
65
66       assert capture_log(fn ->
67                refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
68              end) =~ "Cannot create service actor:"
69     end
70
71     test "returns invisible actor" do
72       uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
73       followers_uri = "#{uri}/followers"
74       user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
75
76       assert %User{
77                nickname: "internal.fetch-test",
78                invisible: true,
79                local: true,
80                ap_id: ^uri,
81                follower_address: ^followers_uri
82              } = user
83
84       user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
85       assert user.id == user2.id
86     end
87   end
88
89   describe "AP ID user relationships" do
90     setup do
91       {:ok, user: insert(:user)}
92     end
93
94     test "outgoing_relationships_ap_ids/1", %{user: user} do
95       rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
96
97       ap_ids_by_rel =
98         Enum.into(
99           rel_types,
100           %{},
101           fn rel_type ->
102             rel_records =
103               insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
104
105             ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
106             {rel_type, Enum.sort(ap_ids)}
107           end
108         )
109
110       assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
111       assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
112
113       assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
114       assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
115
116       assert ap_ids_by_rel[:notification_mute] ==
117                Enum.sort(User.notification_muted_users_ap_ids(user))
118
119       assert ap_ids_by_rel[:notification_mute] ==
120                Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
121
122       assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
123
124       assert ap_ids_by_rel[:reblog_mute] ==
125                Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
126
127       assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
128
129       assert ap_ids_by_rel[:inverse_subscription] ==
130                Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
131
132       outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
133
134       assert ap_ids_by_rel ==
135                Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
136     end
137   end
138
139   describe "when tags are nil" do
140     test "tagging a user" do
141       user = insert(:user, %{tags: nil})
142       user = User.tag(user, ["cool", "dude"])
143
144       assert "cool" in user.tags
145       assert "dude" in user.tags
146     end
147
148     test "untagging a user" do
149       user = insert(:user, %{tags: nil})
150       user = User.untag(user, ["cool", "dude"])
151
152       assert user.tags == []
153     end
154   end
155
156   test "ap_id returns the activity pub id for the user" do
157     user = UserBuilder.build()
158
159     expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}"
160
161     assert expected_ap_id == User.ap_id(user)
162   end
163
164   test "ap_followers returns the followers collection for the user" do
165     user = UserBuilder.build()
166
167     expected_followers_collection = "#{User.ap_id(user)}/followers"
168
169     assert expected_followers_collection == User.ap_followers(user)
170   end
171
172   test "ap_following returns the following collection for the user" do
173     user = UserBuilder.build()
174
175     expected_followers_collection = "#{User.ap_id(user)}/following"
176
177     assert expected_followers_collection == User.ap_following(user)
178   end
179
180   test "returns all pending follow requests" do
181     unlocked = insert(:user)
182     locked = insert(:user, is_locked: true)
183     follower = insert(:user)
184
185     CommonAPI.follow(follower, unlocked)
186     CommonAPI.follow(follower, locked)
187
188     assert [] = User.get_follow_requests(unlocked)
189     assert [activity] = User.get_follow_requests(locked)
190
191     assert activity
192   end
193
194   test "doesn't return already accepted or duplicate follow requests" do
195     locked = insert(:user, is_locked: true)
196     pending_follower = insert(:user)
197     accepted_follower = insert(:user)
198
199     CommonAPI.follow(pending_follower, locked)
200     CommonAPI.follow(pending_follower, locked)
201     CommonAPI.follow(accepted_follower, locked)
202
203     Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
204
205     assert [^pending_follower] = User.get_follow_requests(locked)
206   end
207
208   test "doesn't return follow requests for deactivated accounts" do
209     locked = insert(:user, is_locked: true)
210     pending_follower = insert(:user, %{is_active: false})
211
212     CommonAPI.follow(pending_follower, locked)
213
214     refute pending_follower.is_active
215     assert [] = User.get_follow_requests(locked)
216   end
217
218   test "clears follow requests when requester is blocked" do
219     followed = insert(:user, is_locked: true)
220     follower = insert(:user)
221
222     CommonAPI.follow(follower, followed)
223     assert [_activity] = User.get_follow_requests(followed)
224
225     {:ok, _user_relationship} = User.block(followed, follower)
226     assert [] = User.get_follow_requests(followed)
227   end
228
229   test "follow_all follows multiple users" do
230     user = insert(:user)
231     followed_zero = insert(:user)
232     followed_one = insert(:user)
233     followed_two = insert(:user)
234     blocked = insert(:user)
235     not_followed = insert(:user)
236     reverse_blocked = insert(:user)
237
238     {:ok, _user_relationship} = User.block(user, blocked)
239     {:ok, _user_relationship} = User.block(reverse_blocked, user)
240
241     {:ok, user, followed_zero} = User.follow(user, followed_zero)
242
243     {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
244
245     assert User.following?(user, followed_one)
246     assert User.following?(user, followed_two)
247     assert User.following?(user, followed_zero)
248     refute User.following?(user, not_followed)
249     refute User.following?(user, blocked)
250     refute User.following?(user, reverse_blocked)
251   end
252
253   test "follow_all follows multiple users without duplicating" do
254     user = insert(:user)
255     followed_zero = insert(:user)
256     followed_one = insert(:user)
257     followed_two = insert(:user)
258
259     {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
260     assert length(User.following(user)) == 3
261
262     {:ok, user} = User.follow_all(user, [followed_one, followed_two])
263     assert length(User.following(user)) == 4
264   end
265
266   test "follow takes a user and another user" do
267     user = insert(:user)
268     followed = insert(:user)
269
270     {:ok, user, followed} = User.follow(user, followed)
271
272     user = User.get_cached_by_id(user.id)
273     followed = User.get_cached_by_ap_id(followed.ap_id)
274
275     assert followed.follower_count == 1
276     assert user.following_count == 1
277
278     assert User.ap_followers(followed) in User.following(user)
279   end
280
281   test "can't follow a deactivated users" do
282     user = insert(:user)
283     followed = insert(:user, %{is_active: false})
284
285     {:error, _} = User.follow(user, followed)
286   end
287
288   test "can't follow a user who blocked us" do
289     blocker = insert(:user)
290     blockee = insert(:user)
291
292     {:ok, _user_relationship} = User.block(blocker, blockee)
293
294     {:error, _} = User.follow(blockee, blocker)
295   end
296
297   test "can't subscribe to a user who blocked us" do
298     blocker = insert(:user)
299     blocked = insert(:user)
300
301     {:ok, _user_relationship} = User.block(blocker, blocked)
302
303     {:error, _} = User.subscribe(blocked, blocker)
304   end
305
306   test "local users do not automatically follow local locked accounts" do
307     follower = insert(:user, is_locked: true)
308     followed = insert(:user, is_locked: true)
309
310     {:ok, follower, followed} = User.maybe_direct_follow(follower, followed)
311
312     refute User.following?(follower, followed)
313   end
314
315   describe "unfollow/2" do
316     setup do: clear_config([:instance, :external_user_synchronization])
317
318     test "unfollow with synchronizes external user" do
319       clear_config([:instance, :external_user_synchronization], true)
320
321       followed =
322         insert(:user,
323           nickname: "fuser1",
324           follower_address: "http://localhost:4001/users/fuser1/followers",
325           following_address: "http://localhost:4001/users/fuser1/following",
326           ap_id: "http://localhost:4001/users/fuser1"
327         )
328
329       user =
330         insert(:user, %{
331           local: false,
332           nickname: "fuser2",
333           ap_id: "http://localhost:4001/users/fuser2",
334           follower_address: "http://localhost:4001/users/fuser2/followers",
335           following_address: "http://localhost:4001/users/fuser2/following"
336         })
337
338       {:ok, user, followed} = User.follow(user, followed, :follow_accept)
339
340       {:ok, user, _activity} = User.unfollow(user, followed)
341
342       user = User.get_cached_by_id(user.id)
343
344       assert User.following(user) == []
345     end
346
347     test "unfollow takes a user and another user" do
348       followed = insert(:user)
349       user = insert(:user)
350
351       {:ok, user, followed} = User.follow(user, followed, :follow_accept)
352
353       assert User.following(user) == [user.follower_address, followed.follower_address]
354
355       {:ok, user, _activity} = User.unfollow(user, followed)
356
357       assert User.following(user) == [user.follower_address]
358     end
359
360     test "unfollow doesn't unfollow yourself" do
361       user = insert(:user)
362
363       {:error, _} = User.unfollow(user, user)
364
365       assert User.following(user) == [user.follower_address]
366     end
367   end
368
369   test "test if a user is following another user" do
370     followed = insert(:user)
371     user = insert(:user)
372     User.follow(user, followed, :follow_accept)
373
374     assert User.following?(user, followed)
375     refute User.following?(followed, user)
376   end
377
378   test "fetches correct profile for nickname beginning with number" do
379     # Use old-style integer ID to try to reproduce the problem
380     user = insert(:user, %{id: 1080})
381     user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
382     assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
383   end
384
385   describe "user registration" do
386     @full_user_data %{
387       bio: "A guy",
388       name: "my name",
389       nickname: "nick",
390       password: "test",
391       password_confirmation: "test",
392       email: "email@example.com"
393     }
394
395     setup do: clear_config([:instance, :autofollowed_nicknames])
396     setup do: clear_config([:instance, :autofollowing_nicknames])
397     setup do: clear_config([:welcome])
398     setup do: clear_config([:instance, :account_activation_required])
399
400     test "it autofollows accounts that are set for it" do
401       user = insert(:user)
402       remote_user = insert(:user, %{local: false})
403
404       clear_config([:instance, :autofollowed_nicknames], [
405         user.nickname,
406         remote_user.nickname
407       ])
408
409       cng = User.register_changeset(%User{}, @full_user_data)
410
411       {:ok, registered_user} = User.register(cng)
412
413       assert User.following?(registered_user, user)
414       refute User.following?(registered_user, remote_user)
415     end
416
417     test "it adds automatic followers for new registered accounts" do
418       user1 = insert(:user)
419       user2 = insert(:user)
420
421       clear_config([:instance, :autofollowing_nicknames], [
422         user1.nickname,
423         user2.nickname
424       ])
425
426       cng = User.register_changeset(%User{}, @full_user_data)
427
428       {:ok, registered_user} = User.register(cng)
429
430       assert User.following?(user1, registered_user)
431       assert User.following?(user2, registered_user)
432     end
433
434     test "it sends a welcome message if it is set" do
435       welcome_user = insert(:user)
436       clear_config([:welcome, :direct_message, :enabled], true)
437       clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
438       clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message")
439
440       cng = User.register_changeset(%User{}, @full_user_data)
441       {:ok, registered_user} = User.register(cng)
442       ObanHelpers.perform_all()
443
444       activity = Repo.one(Pleroma.Activity)
445       assert registered_user.ap_id in activity.recipients
446       assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message"
447       assert activity.actor == welcome_user.ap_id
448     end
449
450     test "it sends a welcome chat message if it is set" do
451       welcome_user = insert(:user)
452       clear_config([:welcome, :chat_message, :enabled], true)
453       clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
454       clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
455
456       cng = User.register_changeset(%User{}, @full_user_data)
457       {:ok, registered_user} = User.register(cng)
458       ObanHelpers.perform_all()
459
460       activity = Repo.one(Pleroma.Activity)
461       assert registered_user.ap_id in activity.recipients
462       assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
463       assert activity.actor == welcome_user.ap_id
464     end
465
466     setup do:
467             clear_config(:mrf_simple,
468               media_removal: [],
469               media_nsfw: [],
470               federated_timeline_removal: [],
471               report_removal: [],
472               reject: [],
473               followers_only: [],
474               accept: [],
475               avatar_removal: [],
476               banner_removal: [],
477               reject_deletes: []
478             )
479
480     setup do: clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
481
482     test "it sends a welcome chat message when Simple policy applied to local instance" do
483       clear_config([:mrf_simple, :media_nsfw], [{"localhost", ""}])
484
485       welcome_user = insert(:user)
486       clear_config([:welcome, :chat_message, :enabled], true)
487       clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
488       clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
489
490       cng = User.register_changeset(%User{}, @full_user_data)
491       {:ok, registered_user} = User.register(cng)
492       ObanHelpers.perform_all()
493
494       activity = Repo.one(Pleroma.Activity)
495       assert registered_user.ap_id in activity.recipients
496       assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
497       assert activity.actor == welcome_user.ap_id
498     end
499
500     test "it sends a welcome email message if it is set" do
501       welcome_user = insert(:user)
502       clear_config([:welcome, :email, :enabled], true)
503       clear_config([:welcome, :email, :sender], welcome_user.email)
504
505       clear_config(
506         [:welcome, :email, :subject],
507         "Hello, welcome to cool site: <%= instance_name %>"
508       )
509
510       instance_name = Pleroma.Config.get([:instance, :name])
511
512       cng = User.register_changeset(%User{}, @full_user_data)
513       {:ok, registered_user} = User.register(cng)
514       ObanHelpers.perform_all()
515
516       assert_email_sent(
517         from: {instance_name, welcome_user.email},
518         to: {registered_user.name, registered_user.email},
519         subject: "Hello, welcome to cool site: #{instance_name}",
520         html_body: "Welcome to #{instance_name}"
521       )
522     end
523
524     test "it sends a confirm email" do
525       clear_config([:instance, :account_activation_required], true)
526
527       cng = User.register_changeset(%User{}, @full_user_data)
528       {:ok, registered_user} = User.register(cng)
529       ObanHelpers.perform_all()
530
531       Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
532       # temporary hackney fix until hackney max_connections bug is fixed
533       # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
534       |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
535       |> assert_email_sent()
536     end
537
538     test "sends a pending approval email" do
539       clear_config([:instance, :account_approval_required], true)
540
541       {:ok, user} =
542         User.register_changeset(%User{}, @full_user_data)
543         |> User.register()
544
545       ObanHelpers.perform_all()
546
547       assert_email_sent(
548         from: Pleroma.Config.Helpers.sender(),
549         to: {user.name, user.email},
550         subject: "Your account is awaiting approval"
551       )
552     end
553
554     test "it sends a registration confirmed email if no others will be sent" do
555       clear_config([:welcome, :email, :enabled], false)
556       clear_config([:instance, :account_activation_required], false)
557       clear_config([:instance, :account_approval_required], false)
558
559       {:ok, user} =
560         User.register_changeset(%User{}, @full_user_data)
561         |> User.register()
562
563       ObanHelpers.perform_all()
564
565       instance_name = Pleroma.Config.get([:instance, :name])
566       sender = Pleroma.Config.get([:instance, :notify_email])
567
568       assert_email_sent(
569         from: {instance_name, sender},
570         to: {user.name, user.email},
571         subject: "Account registered on #{instance_name}"
572       )
573     end
574
575     test "it fails gracefully with invalid email config" do
576       cng = User.register_changeset(%User{}, @full_user_data)
577
578       # Disable the mailer but enable all the things that want to send emails
579       clear_config([Pleroma.Emails.Mailer, :enabled], false)
580       clear_config([:instance, :account_activation_required], true)
581       clear_config([:instance, :account_approval_required], true)
582       clear_config([:welcome, :email, :enabled], true)
583       clear_config([:welcome, :email, :sender], "lain@lain.com")
584
585       # The user is still created
586       assert {:ok, %User{nickname: "nick"}} = User.register(cng)
587
588       # No emails are sent
589       ObanHelpers.perform_all()
590       refute_email_sent()
591     end
592
593     test "it works when the registering user does not provide an email" do
594       clear_config([Pleroma.Emails.Mailer, :enabled], false)
595       clear_config([:instance, :account_activation_required], false)
596       clear_config([:instance, :account_approval_required], true)
597
598       cng = User.register_changeset(%User{}, @full_user_data |> Map.put(:email, ""))
599
600       # The user is still created
601       assert {:ok, %User{nickname: "nick"}} = User.register(cng)
602
603       # No emails are sent
604       ObanHelpers.perform_all()
605       refute_email_sent()
606     end
607
608     test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
609       clear_config([:instance, :account_activation_required], true)
610
611       @full_user_data
612       |> Map.keys()
613       |> Enum.each(fn key ->
614         params = Map.delete(@full_user_data, key)
615         changeset = User.register_changeset(%User{}, params)
616
617         assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
618       end)
619     end
620
621     test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
622       clear_config([:instance, :account_activation_required], false)
623
624       @full_user_data
625       |> Map.keys()
626       |> Enum.each(fn key ->
627         params = Map.delete(@full_user_data, key)
628         changeset = User.register_changeset(%User{}, params)
629
630         assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
631       end)
632     end
633
634     test "it restricts certain nicknames" do
635       clear_config([User, :restricted_nicknames], ["about"])
636       [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
637
638       assert is_binary(restricted_name)
639
640       params =
641         @full_user_data
642         |> Map.put(:nickname, restricted_name)
643
644       changeset = User.register_changeset(%User{}, params)
645
646       refute changeset.valid?
647     end
648
649     test "it is case-insensitive when restricting nicknames" do
650       clear_config([User, :restricted_nicknames], ["about"])
651       [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
652
653       assert is_binary(restricted_name)
654
655       restricted_upcase_name = String.upcase(restricted_name)
656
657       params =
658         @full_user_data
659         |> Map.put(:nickname, restricted_upcase_name)
660
661       changeset = User.register_changeset(%User{}, params)
662
663       refute changeset.valid?
664     end
665
666     test "it blocks blacklisted email domains" do
667       clear_config([User, :email_blacklist], ["trolling.world"])
668
669       # Block with match
670       params = Map.put(@full_user_data, :email, "troll@trolling.world")
671       changeset = User.register_changeset(%User{}, params)
672       refute changeset.valid?
673
674       # Block with case-insensitive match
675       params = Map.put(@full_user_data, :email, "troll@TrOlLing.wOrld")
676       changeset = User.register_changeset(%User{}, params)
677       refute changeset.valid?
678
679       # Block with subdomain match
680       params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
681       changeset = User.register_changeset(%User{}, params)
682       refute changeset.valid?
683
684       # Pass with different domains that are similar
685       params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
686       changeset = User.register_changeset(%User{}, params)
687       assert changeset.valid?
688
689       params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
690       changeset = User.register_changeset(%User{}, params)
691       assert changeset.valid?
692     end
693
694     test "it sets the password_hash, ap_id, private key and followers collection address" do
695       changeset = User.register_changeset(%User{}, @full_user_data)
696
697       assert changeset.valid?
698
699       assert is_binary(changeset.changes[:password_hash])
700       assert is_binary(changeset.changes[:keys])
701       assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
702       assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
703     end
704
705     test "it sets the 'accepts_chat_messages' set to true" do
706       changeset = User.register_changeset(%User{}, @full_user_data)
707       assert changeset.valid?
708
709       {:ok, user} = Repo.insert(changeset)
710
711       assert user.accepts_chat_messages
712     end
713
714     test "it creates a confirmed user" do
715       changeset = User.register_changeset(%User{}, @full_user_data)
716       assert changeset.valid?
717
718       {:ok, user} = Repo.insert(changeset)
719
720       assert user.is_confirmed
721     end
722   end
723
724   describe "user registration, with :account_activation_required" do
725     @full_user_data %{
726       bio: "A guy",
727       name: "my name",
728       nickname: "nick",
729       password: "test",
730       password_confirmation: "test",
731       email: "email@example.com"
732     }
733     setup do: clear_config([:instance, :account_activation_required], true)
734
735     test "it creates unconfirmed user" do
736       changeset = User.register_changeset(%User{}, @full_user_data)
737       assert changeset.valid?
738
739       {:ok, user} = Repo.insert(changeset)
740
741       refute user.is_confirmed
742       assert user.confirmation_token
743     end
744
745     test "it creates confirmed user if :confirmed option is given" do
746       changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
747       assert changeset.valid?
748
749       {:ok, user} = Repo.insert(changeset)
750
751       assert user.is_confirmed
752       refute user.confirmation_token
753     end
754   end
755
756   describe "user registration, with :account_approval_required" do
757     @full_user_data %{
758       bio: "A guy",
759       name: "my name",
760       nickname: "nick",
761       password: "test",
762       password_confirmation: "test",
763       email: "email@example.com",
764       registration_reason: "I'm a cool guy :)"
765     }
766     setup do: clear_config([:instance, :account_approval_required], true)
767
768     test "it creates unapproved user" do
769       changeset = User.register_changeset(%User{}, @full_user_data)
770       assert changeset.valid?
771
772       {:ok, user} = Repo.insert(changeset)
773
774       refute user.is_approved
775       assert user.registration_reason == "I'm a cool guy :)"
776     end
777
778     test "it restricts length of registration reason" do
779       reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
780
781       assert is_integer(reason_limit)
782
783       params =
784         @full_user_data
785         |> Map.put(
786           :registration_reason,
787           "Quia et nesciunt dolores numquam ipsam nisi sapiente soluta. Ullam repudiandae nisi quam porro officiis officiis ad. Consequatur animi velit ex quia. Odit voluptatem perferendis quia ut nisi. Dignissimos sit soluta atque aliquid dolorem ut dolorum ut. Labore voluptates iste iusto amet voluptatum earum. Ad fugit illum nam eos ut nemo. Pariatur ea fuga non aspernatur. Dignissimos debitis officia corporis est nisi ab et. Atque itaque alias eius voluptas minus. Accusamus numquam tempore occaecati in."
788         )
789
790       changeset = User.register_changeset(%User{}, params)
791
792       refute changeset.valid?
793     end
794   end
795
796   describe "user registration, with :birthday_required and :birthday_min_age" do
797     @full_user_data %{
798       bio: "A guy",
799       name: "my name",
800       nickname: "nick",
801       password: "test",
802       password_confirmation: "test",
803       email: "email@example.com"
804     }
805
806     setup do
807       clear_config([:instance, :birthday_required], true)
808       clear_config([:instance, :birthday_min_age], 18 * 365)
809     end
810
811     test "it passes when correct birth date is provided" do
812       today = Date.utc_today()
813       birthday = Date.add(today, -19 * 365)
814
815       params =
816         @full_user_data
817         |> Map.put(:birthday, birthday)
818
819       changeset = User.register_changeset(%User{}, params)
820
821       assert changeset.valid?
822     end
823
824     test "it fails when birth date is not provided" do
825       changeset = User.register_changeset(%User{}, @full_user_data)
826
827       refute changeset.valid?
828     end
829
830     test "it fails when provided invalid birth date" do
831       today = Date.utc_today()
832       birthday = Date.add(today, -17 * 365)
833
834       params =
835         @full_user_data
836         |> Map.put(:birthday, birthday)
837
838       changeset = User.register_changeset(%User{}, params)
839
840       refute changeset.valid?
841     end
842   end
843
844   describe "get_or_fetch/1" do
845     test "gets an existing user by nickname" do
846       user = insert(:user)
847       {:ok, fetched_user} = User.get_or_fetch(user.nickname)
848
849       assert user == fetched_user
850     end
851
852     test "gets an existing user by ap_id" do
853       ap_id = "http://mastodon.example.org/users/admin"
854
855       user =
856         insert(
857           :user,
858           local: false,
859           nickname: "admin@mastodon.example.org",
860           ap_id: ap_id
861         )
862
863       {:ok, fetched_user} = User.get_or_fetch(ap_id)
864       freshed_user = refresh_record(user)
865       assert freshed_user == fetched_user
866     end
867
868     test "gets an existing user by nickname starting with http" do
869       user = insert(:user, nickname: "httpssome")
870       {:ok, fetched_user} = User.get_or_fetch("httpssome")
871
872       assert user == fetched_user
873     end
874   end
875
876   describe "get_or_fetch/1 remote users with tld, while BE is running on a subdomain" do
877     setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
878
879     test "for mastodon" do
880       Tesla.Mock.mock(fn
881         %{url: "https://example.com/.well-known/host-meta"} ->
882           %Tesla.Env{
883             status: 302,
884             headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
885           }
886
887         %{url: "https://sub.example.com/.well-known/host-meta"} ->
888           %Tesla.Env{
889             status: 200,
890             body:
891               "test/fixtures/webfinger/masto-host-meta.xml"
892               |> File.read!()
893               |> String.replace("{{domain}}", "sub.example.com")
894           }
895
896         %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
897           %Tesla.Env{
898             status: 200,
899             body:
900               "test/fixtures/webfinger/masto-webfinger.json"
901               |> File.read!()
902               |> String.replace("{{nickname}}", "a")
903               |> String.replace("{{domain}}", "example.com")
904               |> String.replace("{{subdomain}}", "sub.example.com"),
905             headers: [{"content-type", "application/jrd+json"}]
906           }
907
908         %{url: "https://sub.example.com/users/a"} ->
909           %Tesla.Env{
910             status: 200,
911             body:
912               "test/fixtures/webfinger/masto-user.json"
913               |> File.read!()
914               |> String.replace("{{nickname}}", "a")
915               |> String.replace("{{domain}}", "sub.example.com"),
916             headers: [{"content-type", "application/activity+json"}]
917           }
918
919         %{url: "https://sub.example.com/users/a/collections/featured"} ->
920           %Tesla.Env{
921             status: 200,
922             body:
923               File.read!("test/fixtures/users_mock/masto_featured.json")
924               |> String.replace("{{domain}}", "sub.example.com")
925               |> String.replace("{{nickname}}", "a"),
926             headers: [{"content-type", "application/activity+json"}]
927           }
928       end)
929
930       ap_id = "a@example.com"
931       {:ok, fetched_user} = User.get_or_fetch(ap_id)
932
933       assert fetched_user.ap_id == "https://sub.example.com/users/a"
934       assert fetched_user.nickname == "a@example.com"
935     end
936
937     test "for pleroma" do
938       Tesla.Mock.mock(fn
939         %{url: "https://example.com/.well-known/host-meta"} ->
940           %Tesla.Env{
941             status: 302,
942             headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
943           }
944
945         %{url: "https://sub.example.com/.well-known/host-meta"} ->
946           %Tesla.Env{
947             status: 200,
948             body:
949               "test/fixtures/webfinger/pleroma-host-meta.xml"
950               |> File.read!()
951               |> String.replace("{{domain}}", "sub.example.com")
952           }
953
954         %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
955           %Tesla.Env{
956             status: 200,
957             body:
958               "test/fixtures/webfinger/pleroma-webfinger.json"
959               |> File.read!()
960               |> String.replace("{{nickname}}", "a")
961               |> String.replace("{{domain}}", "example.com")
962               |> String.replace("{{subdomain}}", "sub.example.com"),
963             headers: [{"content-type", "application/jrd+json"}]
964           }
965
966         %{url: "https://sub.example.com/users/a"} ->
967           %Tesla.Env{
968             status: 200,
969             body:
970               "test/fixtures/webfinger/pleroma-user.json"
971               |> File.read!()
972               |> String.replace("{{nickname}}", "a")
973               |> String.replace("{{domain}}", "sub.example.com"),
974             headers: [{"content-type", "application/activity+json"}]
975           }
976       end)
977
978       ap_id = "a@example.com"
979       {:ok, fetched_user} = User.get_or_fetch(ap_id)
980
981       assert fetched_user.ap_id == "https://sub.example.com/users/a"
982       assert fetched_user.nickname == "a@example.com"
983     end
984   end
985
986   describe "fetching a user from nickname or trying to build one" do
987     test "gets an existing user" do
988       user = insert(:user)
989       {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
990
991       assert user == fetched_user
992     end
993
994     test "gets an existing user, case insensitive" do
995       user = insert(:user, nickname: "nick")
996       {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
997
998       assert user == fetched_user
999     end
1000
1001     test "gets an existing user by fully qualified nickname" do
1002       user = insert(:user)
1003
1004       {:ok, fetched_user} =
1005         User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
1006
1007       assert user == fetched_user
1008     end
1009
1010     test "gets an existing user by fully qualified nickname, case insensitive" do
1011       user = insert(:user, nickname: "nick")
1012       casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
1013
1014       {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
1015
1016       assert user == fetched_user
1017     end
1018
1019     @tag capture_log: true
1020     test "returns nil if no user could be fetched" do
1021       {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistent@social.heldscal.la")
1022       assert fetched_user == "not found nonexistent@social.heldscal.la"
1023     end
1024
1025     test "returns nil for nonexistent local user" do
1026       {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistent")
1027       assert fetched_user == "not found nonexistent"
1028     end
1029
1030     test "updates an existing user, if stale" do
1031       a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
1032
1033       orig_user =
1034         insert(
1035           :user,
1036           local: false,
1037           nickname: "admin@mastodon.example.org",
1038           ap_id: "http://mastodon.example.org/users/admin",
1039           last_refreshed_at: a_week_ago
1040         )
1041
1042       assert orig_user.last_refreshed_at == a_week_ago
1043
1044       {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
1045
1046       assert user.inbox
1047
1048       refute user.last_refreshed_at == orig_user.last_refreshed_at
1049     end
1050
1051     test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
1052       a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
1053
1054       orig_user =
1055         insert(
1056           :user,
1057           local: false,
1058           nickname: "admin@mastodon.example.org",
1059           ap_id: "http://mastodon.example.org/users/harinezumigari",
1060           last_refreshed_at: a_week_ago
1061         )
1062
1063       assert orig_user.last_refreshed_at == a_week_ago
1064
1065       {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
1066
1067       assert user.inbox
1068
1069       refute user.id == orig_user.id
1070
1071       orig_user = User.get_by_id(orig_user.id)
1072
1073       assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
1074     end
1075
1076     @tag capture_log: true
1077     test "it returns the old user if stale, but unfetchable" do
1078       a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
1079
1080       orig_user =
1081         insert(
1082           :user,
1083           local: false,
1084           nickname: "admin@mastodon.example.org",
1085           ap_id: "http://mastodon.example.org/users/raymoo",
1086           last_refreshed_at: a_week_ago
1087         )
1088
1089       assert orig_user.last_refreshed_at == a_week_ago
1090
1091       {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
1092
1093       assert user.last_refreshed_at == orig_user.last_refreshed_at
1094     end
1095   end
1096
1097   test "returns an ap_id for a user" do
1098     user = insert(:user)
1099
1100     assert User.ap_id(user) ==
1101              Pleroma.Web.Router.Helpers.user_feed_url(
1102                Pleroma.Web.Endpoint,
1103                :feed_redirect,
1104                user.nickname
1105              )
1106   end
1107
1108   test "returns an ap_followers link for a user" do
1109     user = insert(:user)
1110
1111     assert User.ap_followers(user) ==
1112              Pleroma.Web.Router.Helpers.user_feed_url(
1113                Pleroma.Web.Endpoint,
1114                :feed_redirect,
1115                user.nickname
1116              ) <> "/followers"
1117   end
1118
1119   describe "remote user changeset" do
1120     @valid_remote %{
1121       bio: "hello",
1122       name: "Someone",
1123       nickname: "a@b.de",
1124       ap_id: "http...",
1125       avatar: %{some: "avatar"}
1126     }
1127     setup do: clear_config([:instance, :user_bio_length])
1128     setup do: clear_config([:instance, :user_name_length])
1129
1130     test "it confirms validity" do
1131       cs = User.remote_user_changeset(@valid_remote)
1132       assert cs.valid?
1133     end
1134
1135     test "it sets the follower_address" do
1136       cs = User.remote_user_changeset(@valid_remote)
1137       # remote users get a fake local follower address
1138       assert cs.changes.follower_address ==
1139                User.ap_followers(%User{nickname: @valid_remote[:nickname]})
1140     end
1141
1142     test "it enforces the fqn format for nicknames" do
1143       cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
1144       assert Ecto.Changeset.get_field(cs, :local) == false
1145       assert cs.changes.avatar
1146       refute cs.valid?
1147     end
1148
1149     test "it has required fields" do
1150       [:ap_id]
1151       |> Enum.each(fn field ->
1152         cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
1153         refute cs.valid?
1154       end)
1155     end
1156
1157     test "it is invalid given a local user" do
1158       user = insert(:user)
1159       cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
1160
1161       refute cs.valid?
1162     end
1163   end
1164
1165   describe "followers and friends" do
1166     test "gets all followers for a given user" do
1167       user = insert(:user)
1168       follower_one = insert(:user)
1169       follower_two = insert(:user)
1170       not_follower = insert(:user)
1171
1172       {:ok, follower_one, user} = User.follow(follower_one, user)
1173       {:ok, follower_two, user} = User.follow(follower_two, user)
1174
1175       res = User.get_followers(user)
1176
1177       assert Enum.member?(res, follower_one)
1178       assert Enum.member?(res, follower_two)
1179       refute Enum.member?(res, not_follower)
1180     end
1181
1182     test "gets all friends (followed users) for a given user" do
1183       user = insert(:user)
1184       followed_one = insert(:user)
1185       followed_two = insert(:user)
1186       not_followed = insert(:user)
1187
1188       {:ok, user, followed_one} = User.follow(user, followed_one)
1189       {:ok, user, followed_two} = User.follow(user, followed_two)
1190
1191       res = User.get_friends(user)
1192
1193       followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
1194       followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
1195       assert Enum.member?(res, followed_one)
1196       assert Enum.member?(res, followed_two)
1197       refute Enum.member?(res, not_followed)
1198     end
1199   end
1200
1201   describe "updating note and follower count" do
1202     test "it sets the note_count property" do
1203       note = insert(:note)
1204
1205       user = User.get_cached_by_ap_id(note.data["actor"])
1206
1207       assert user.note_count == 0
1208
1209       {:ok, user} = User.update_note_count(user)
1210
1211       assert user.note_count == 1
1212     end
1213
1214     test "it increases the note_count property" do
1215       note = insert(:note)
1216       user = User.get_cached_by_ap_id(note.data["actor"])
1217
1218       assert user.note_count == 0
1219
1220       {:ok, user} = User.increase_note_count(user)
1221
1222       assert user.note_count == 1
1223
1224       {:ok, user} = User.increase_note_count(user)
1225
1226       assert user.note_count == 2
1227     end
1228
1229     test "it decreases the note_count property" do
1230       note = insert(:note)
1231       user = User.get_cached_by_ap_id(note.data["actor"])
1232
1233       assert user.note_count == 0
1234
1235       {:ok, user} = User.increase_note_count(user)
1236
1237       assert user.note_count == 1
1238
1239       {:ok, user} = User.decrease_note_count(user)
1240
1241       assert user.note_count == 0
1242
1243       {:ok, user} = User.decrease_note_count(user)
1244
1245       assert user.note_count == 0
1246     end
1247
1248     test "it sets the follower_count property" do
1249       user = insert(:user)
1250       follower = insert(:user)
1251
1252       User.follow(follower, user)
1253
1254       assert user.follower_count == 0
1255
1256       {:ok, user} = User.update_follower_count(user)
1257
1258       assert user.follower_count == 1
1259     end
1260   end
1261
1262   describe "mutes" do
1263     test "it mutes people" do
1264       user = insert(:user)
1265       muted_user = insert(:user)
1266
1267       refute User.mutes?(user, muted_user)
1268       refute User.muted_notifications?(user, muted_user)
1269
1270       {:ok, _user_relationships} = User.mute(user, muted_user)
1271
1272       assert User.mutes?(user, muted_user)
1273       assert User.muted_notifications?(user, muted_user)
1274     end
1275
1276     test "expiring" do
1277       user = insert(:user)
1278       muted_user = insert(:user)
1279
1280       {:ok, _user_relationships} = User.mute(user, muted_user, %{duration: 60})
1281       assert User.mutes?(user, muted_user)
1282
1283       worker = Pleroma.Workers.MuteExpireWorker
1284       args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1285
1286       assert_enqueued(
1287         worker: worker,
1288         args: args
1289       )
1290
1291       assert :ok = perform_job(worker, args)
1292
1293       refute User.mutes?(user, muted_user)
1294       refute User.muted_notifications?(user, muted_user)
1295     end
1296
1297     test "it unmutes users" do
1298       user = insert(:user)
1299       muted_user = insert(:user)
1300
1301       {:ok, _user_relationships} = User.mute(user, muted_user)
1302       {:ok, _user_mute} = User.unmute(user, muted_user)
1303
1304       refute User.mutes?(user, muted_user)
1305       refute User.muted_notifications?(user, muted_user)
1306     end
1307
1308     test "it unmutes users by id" do
1309       user = insert(:user)
1310       muted_user = insert(:user)
1311
1312       {:ok, _user_relationships} = User.mute(user, muted_user)
1313       {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1314
1315       refute User.mutes?(user, muted_user)
1316       refute User.muted_notifications?(user, muted_user)
1317     end
1318
1319     test "it mutes user without notifications" do
1320       user = insert(:user)
1321       muted_user = insert(:user)
1322
1323       refute User.mutes?(user, muted_user)
1324       refute User.muted_notifications?(user, muted_user)
1325
1326       {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1327
1328       assert User.mutes?(user, muted_user)
1329       refute User.muted_notifications?(user, muted_user)
1330     end
1331   end
1332
1333   describe "blocks" do
1334     test "it blocks people" do
1335       user = insert(:user)
1336       blocked_user = insert(:user)
1337
1338       refute User.blocks?(user, blocked_user)
1339
1340       {:ok, _user_relationship} = User.block(user, blocked_user)
1341
1342       assert User.blocks?(user, blocked_user)
1343     end
1344
1345     test "it unblocks users" do
1346       user = insert(:user)
1347       blocked_user = insert(:user)
1348
1349       {:ok, _user_relationship} = User.block(user, blocked_user)
1350       {:ok, _user_block} = User.unblock(user, blocked_user)
1351
1352       refute User.blocks?(user, blocked_user)
1353     end
1354
1355     test "blocks tear down cyclical follow relationships" do
1356       blocker = insert(:user)
1357       blocked = insert(:user)
1358
1359       {:ok, blocker, blocked} = User.follow(blocker, blocked)
1360       {:ok, blocked, blocker} = User.follow(blocked, blocker)
1361
1362       assert User.following?(blocker, blocked)
1363       assert User.following?(blocked, blocker)
1364
1365       {:ok, _user_relationship} = User.block(blocker, blocked)
1366       blocked = User.get_cached_by_id(blocked.id)
1367
1368       assert User.blocks?(blocker, blocked)
1369
1370       refute User.following?(blocker, blocked)
1371       refute User.following?(blocked, blocker)
1372     end
1373
1374     test "blocks tear down blocker->blocked follow relationships" do
1375       blocker = insert(:user)
1376       blocked = insert(:user)
1377
1378       {:ok, blocker, blocked} = User.follow(blocker, blocked)
1379
1380       assert User.following?(blocker, blocked)
1381       refute User.following?(blocked, blocker)
1382
1383       {:ok, _user_relationship} = User.block(blocker, blocked)
1384       blocked = User.get_cached_by_id(blocked.id)
1385
1386       assert User.blocks?(blocker, blocked)
1387
1388       refute User.following?(blocker, blocked)
1389       refute User.following?(blocked, blocker)
1390     end
1391
1392     test "blocks tear down blocked->blocker follow relationships" do
1393       blocker = insert(:user)
1394       blocked = insert(:user)
1395
1396       {:ok, blocked, blocker} = User.follow(blocked, blocker)
1397
1398       refute User.following?(blocker, blocked)
1399       assert User.following?(blocked, blocker)
1400
1401       {:ok, _user_relationship} = User.block(blocker, blocked)
1402       blocked = User.get_cached_by_id(blocked.id)
1403
1404       assert User.blocks?(blocker, blocked)
1405
1406       refute User.following?(blocker, blocked)
1407       refute User.following?(blocked, blocker)
1408     end
1409
1410     test "blocks tear down blocked->blocker subscription relationships" do
1411       blocker = insert(:user)
1412       blocked = insert(:user)
1413
1414       {:ok, _subscription} = User.subscribe(blocked, blocker)
1415
1416       assert User.subscribed_to?(blocked, blocker)
1417       refute User.subscribed_to?(blocker, blocked)
1418
1419       {:ok, _user_relationship} = User.block(blocker, blocked)
1420
1421       assert User.blocks?(blocker, blocked)
1422       refute User.subscribed_to?(blocker, blocked)
1423       refute User.subscribed_to?(blocked, blocker)
1424     end
1425   end
1426
1427   describe "domain blocking" do
1428     test "blocks domains" do
1429       user = insert(:user)
1430       collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1431
1432       {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1433
1434       assert User.blocks?(user, collateral_user)
1435     end
1436
1437     test "does not block domain with same end" do
1438       user = insert(:user)
1439
1440       collateral_user =
1441         insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1442
1443       {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1444
1445       refute User.blocks?(user, collateral_user)
1446     end
1447
1448     test "does not block domain with same end if wildcard added" do
1449       user = insert(:user)
1450
1451       collateral_user =
1452         insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1453
1454       {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1455
1456       refute User.blocks?(user, collateral_user)
1457     end
1458
1459     test "blocks domain with wildcard for subdomain" do
1460       user = insert(:user)
1461
1462       user_from_subdomain =
1463         insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1464
1465       user_with_two_subdomains =
1466         insert(:user, %{
1467           ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1468         })
1469
1470       user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1471
1472       {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1473
1474       assert User.blocks?(user, user_from_subdomain)
1475       assert User.blocks?(user, user_with_two_subdomains)
1476       assert User.blocks?(user, user_domain)
1477     end
1478
1479     test "unblocks domains" do
1480       user = insert(:user)
1481       collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1482
1483       {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1484       {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1485
1486       refute User.blocks?(user, collateral_user)
1487     end
1488
1489     test "follows take precedence over domain blocks" do
1490       user = insert(:user)
1491       good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1492
1493       {:ok, user} = User.block_domain(user, "meanies.social")
1494       {:ok, user, good_eggo} = User.follow(user, good_eggo)
1495
1496       refute User.blocks?(user, good_eggo)
1497     end
1498   end
1499
1500   describe "get_recipients_from_activity" do
1501     test "works for announces" do
1502       actor = insert(:user)
1503       user = insert(:user, local: true)
1504
1505       {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1506       {:ok, announce} = CommonAPI.repeat(activity.id, user)
1507
1508       recipients = User.get_recipients_from_activity(announce)
1509
1510       assert user in recipients
1511     end
1512
1513     test "get recipients" do
1514       actor = insert(:user)
1515       user = insert(:user, local: true)
1516       user_two = insert(:user, local: false)
1517       addressed = insert(:user, local: true)
1518       addressed_remote = insert(:user, local: false)
1519
1520       {:ok, activity} =
1521         CommonAPI.post(actor, %{
1522           status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1523         })
1524
1525       assert Enum.map([actor, addressed], & &1.ap_id) --
1526                Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1527
1528       {:ok, user, actor} = User.follow(user, actor)
1529       {:ok, _user_two, _actor} = User.follow(user_two, actor)
1530       recipients = User.get_recipients_from_activity(activity)
1531       assert length(recipients) == 3
1532       assert user in recipients
1533       assert addressed in recipients
1534     end
1535
1536     test "has following" do
1537       actor = insert(:user)
1538       user = insert(:user)
1539       user_two = insert(:user)
1540       addressed = insert(:user, local: true)
1541
1542       {:ok, activity} =
1543         CommonAPI.post(actor, %{
1544           status: "hey @#{addressed.nickname}"
1545         })
1546
1547       assert Enum.map([actor, addressed], & &1.ap_id) --
1548                Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1549
1550       {:ok, _actor, _user} = User.follow(actor, user)
1551       {:ok, _actor, _user_two} = User.follow(actor, user_two)
1552       recipients = User.get_recipients_from_activity(activity)
1553       assert length(recipients) == 2
1554       assert addressed in recipients
1555     end
1556   end
1557
1558   describe ".set_activation" do
1559     test "can de-activate then re-activate a user" do
1560       user = insert(:user)
1561       assert user.is_active
1562       {:ok, user} = User.set_activation(user, false)
1563       refute user.is_active
1564       {:ok, user} = User.set_activation(user, true)
1565       assert user.is_active
1566     end
1567
1568     test "hide a user from followers" do
1569       user = insert(:user)
1570       user2 = insert(:user)
1571
1572       {:ok, user, user2} = User.follow(user, user2)
1573       {:ok, _user} = User.set_activation(user, false)
1574
1575       user2 = User.get_cached_by_id(user2.id)
1576
1577       assert user2.follower_count == 0
1578       assert [] = User.get_followers(user2)
1579     end
1580
1581     test "hide a user from friends" do
1582       user = insert(:user)
1583       user2 = insert(:user)
1584
1585       {:ok, user2, user} = User.follow(user2, user)
1586       assert user2.following_count == 1
1587       assert User.following_count(user2) == 1
1588
1589       {:ok, _user} = User.set_activation(user, false)
1590
1591       user2 = User.get_cached_by_id(user2.id)
1592
1593       assert refresh_record(user2).following_count == 0
1594       assert user2.following_count == 0
1595       assert User.following_count(user2) == 0
1596       assert [] = User.get_friends(user2)
1597     end
1598
1599     test "hide a user's statuses from timelines and notifications" do
1600       user = insert(:user)
1601       user2 = insert(:user)
1602
1603       {:ok, user2, user} = User.follow(user2, user)
1604
1605       {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1606
1607       activity = Repo.preload(activity, :bookmark)
1608
1609       [notification] = Pleroma.Notification.for_user(user2)
1610       assert notification.activity.id == activity.id
1611
1612       assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1613
1614       assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1615                ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1616                  user: user2
1617                })
1618
1619       {:ok, _user} = User.set_activation(user, false)
1620
1621       assert [] == ActivityPub.fetch_public_activities(%{})
1622       assert [] == Pleroma.Notification.for_user(user2)
1623
1624       assert [] ==
1625                ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1626                  user: user2
1627                })
1628     end
1629   end
1630
1631   describe "approve" do
1632     test "approves a user" do
1633       user = insert(:user, is_approved: false)
1634       refute user.is_approved
1635       {:ok, user} = User.approve(user)
1636       assert user.is_approved
1637     end
1638
1639     test "approves a list of users" do
1640       unapproved_users = [
1641         insert(:user, is_approved: false),
1642         insert(:user, is_approved: false),
1643         insert(:user, is_approved: false)
1644       ]
1645
1646       {:ok, users} = User.approve(unapproved_users)
1647
1648       assert Enum.count(users) == 3
1649
1650       Enum.each(users, fn user ->
1651         assert user.is_approved
1652       end)
1653     end
1654
1655     test "it sends welcome email if it is set" do
1656       clear_config([:welcome, :email, :enabled], true)
1657       clear_config([:welcome, :email, :sender], "tester@test.me")
1658
1659       user = insert(:user, is_approved: false)
1660       welcome_user = insert(:user, email: "tester@test.me")
1661       instance_name = Pleroma.Config.get([:instance, :name])
1662
1663       User.approve(user)
1664
1665       ObanHelpers.perform_all()
1666
1667       assert_email_sent(
1668         from: {instance_name, welcome_user.email},
1669         to: {user.name, user.email},
1670         html_body: "Welcome to #{instance_name}"
1671       )
1672     end
1673
1674     test "approving an approved user does not trigger post-register actions" do
1675       clear_config([:welcome, :email, :enabled], true)
1676
1677       user = insert(:user, is_approved: true)
1678       User.approve(user)
1679
1680       ObanHelpers.perform_all()
1681
1682       assert_no_email_sent()
1683     end
1684   end
1685
1686   describe "confirm" do
1687     test "confirms a user" do
1688       user = insert(:user, is_confirmed: false)
1689       refute user.is_confirmed
1690       {:ok, user} = User.confirm(user)
1691       assert user.is_confirmed
1692     end
1693
1694     test "confirms a list of users" do
1695       unconfirmed_users = [
1696         insert(:user, is_confirmed: false),
1697         insert(:user, is_confirmed: false),
1698         insert(:user, is_confirmed: false)
1699       ]
1700
1701       {:ok, users} = User.confirm(unconfirmed_users)
1702
1703       assert Enum.count(users) == 3
1704
1705       Enum.each(users, fn user ->
1706         assert user.is_confirmed
1707       end)
1708     end
1709
1710     test "sends approval emails when `is_approved: false`" do
1711       admin = insert(:user, is_admin: true)
1712       user = insert(:user, is_confirmed: false, is_approved: false)
1713       User.confirm(user)
1714
1715       ObanHelpers.perform_all()
1716
1717       user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1718       admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1719
1720       notify_email = Pleroma.Config.get([:instance, :notify_email])
1721       instance_name = Pleroma.Config.get([:instance, :name])
1722
1723       # User approval email
1724       assert_email_sent(
1725         from: {instance_name, notify_email},
1726         to: {user.name, user.email},
1727         html_body: user_email.html_body
1728       )
1729
1730       # Admin email
1731       assert_email_sent(
1732         from: {instance_name, notify_email},
1733         to: {admin.name, admin.email},
1734         html_body: admin_email.html_body
1735       )
1736     end
1737
1738     test "confirming a confirmed user does not trigger post-register actions" do
1739       user = insert(:user, is_confirmed: true, is_approved: false)
1740       User.confirm(user)
1741
1742       ObanHelpers.perform_all()
1743
1744       assert_no_email_sent()
1745     end
1746   end
1747
1748   describe "delete" do
1749     setup do
1750       {:ok, user} = insert(:user) |> User.set_cache()
1751
1752       [user: user]
1753     end
1754
1755     setup do: clear_config([:instance, :federating])
1756
1757     test ".delete_user_activities deletes all create activities", %{user: user} do
1758       {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1759
1760       User.delete_user_activities(user)
1761
1762       # TODO: Test removal favorites, repeats, delete activities.
1763       refute Activity.get_by_id(activity.id)
1764     end
1765
1766     test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1767       follower = insert(:user)
1768       {:ok, follower, user} = User.follow(follower, user)
1769
1770       locked_user = insert(:user, name: "locked", is_locked: true)
1771       {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1772
1773       object = insert(:note, user: user)
1774       activity = insert(:note_activity, user: user, note: object)
1775
1776       object_two = insert(:note, user: follower)
1777       activity_two = insert(:note_activity, user: follower, note: object_two)
1778
1779       {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1780       {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1781       {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1782
1783       {:ok, job} = User.delete(user)
1784       {:ok, _user} = ObanHelpers.perform(job)
1785
1786       follower = User.get_cached_by_id(follower.id)
1787
1788       refute User.following?(follower, user)
1789       assert %{is_active: false} = User.get_by_id(user.id)
1790
1791       assert [] == User.get_follow_requests(locked_user)
1792
1793       user_activities =
1794         user.ap_id
1795         |> Activity.Queries.by_actor()
1796         |> Repo.all()
1797         |> Enum.map(fn act -> act.data["type"] end)
1798
1799       assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1800
1801       refute Activity.get_by_id(activity.id)
1802       refute Activity.get_by_id(like.id)
1803       refute Activity.get_by_id(like_two.id)
1804       refute Activity.get_by_id(repeat.id)
1805     end
1806   end
1807
1808   test "delete/1 when confirmation is pending deletes the user" do
1809     clear_config([:instance, :account_activation_required], true)
1810     user = insert(:user, is_confirmed: false)
1811
1812     {:ok, job} = User.delete(user)
1813     {:ok, _} = ObanHelpers.perform(job)
1814
1815     refute User.get_cached_by_id(user.id)
1816     refute User.get_by_id(user.id)
1817   end
1818
1819   test "delete/1 when approval is pending deletes the user" do
1820     user = insert(:user, is_approved: false)
1821
1822     {:ok, job} = User.delete(user)
1823     {:ok, _} = ObanHelpers.perform(job)
1824
1825     refute User.get_cached_by_id(user.id)
1826     refute User.get_by_id(user.id)
1827   end
1828
1829   test "delete/1 purges a user when they wouldn't be fully deleted" do
1830     user =
1831       insert(:user, %{
1832         bio: "eyy lmao",
1833         name: "qqqqqqq",
1834         password_hash: "pdfk2$1b3n159001",
1835         keys: "RSA begin buplic key",
1836         public_key: "--PRIVATE KEYE--",
1837         avatar: %{"a" => "b"},
1838         tags: ["qqqqq"],
1839         banner: %{"a" => "b"},
1840         background: %{"a" => "b"},
1841         note_count: 9,
1842         follower_count: 9,
1843         following_count: 9001,
1844         is_locked: true,
1845         is_confirmed: true,
1846         password_reset_pending: true,
1847         is_approved: true,
1848         registration_reason: "ahhhhh",
1849         confirmation_token: "qqqq",
1850         domain_blocks: ["lain.com"],
1851         is_active: false,
1852         is_moderator: true,
1853         is_admin: true,
1854         mascot: %{"a" => "b"},
1855         emoji: %{"a" => "b"},
1856         pleroma_settings_store: %{"q" => "x"},
1857         fields: [%{"gg" => "qq"}],
1858         raw_fields: [%{"gg" => "qq"}],
1859         is_discoverable: true,
1860         also_known_as: ["https://lol.olo/users/loll"]
1861       })
1862
1863     {:ok, job} = User.delete(user)
1864     {:ok, _} = ObanHelpers.perform(job)
1865     user = User.get_by_id(user.id)
1866
1867     assert %User{
1868              bio: "",
1869              raw_bio: nil,
1870              email: nil,
1871              name: nil,
1872              password_hash: nil,
1873              keys: "RSA begin buplic key",
1874              public_key: "--PRIVATE KEYE--",
1875              avatar: %{},
1876              tags: [],
1877              last_refreshed_at: nil,
1878              last_digest_emailed_at: nil,
1879              banner: %{},
1880              background: %{},
1881              note_count: 0,
1882              follower_count: 0,
1883              following_count: 0,
1884              is_locked: false,
1885              is_confirmed: true,
1886              password_reset_pending: false,
1887              is_approved: true,
1888              registration_reason: nil,
1889              confirmation_token: nil,
1890              domain_blocks: [],
1891              is_active: false,
1892              is_moderator: false,
1893              is_admin: false,
1894              mascot: nil,
1895              emoji: %{},
1896              pleroma_settings_store: %{},
1897              fields: [],
1898              raw_fields: [],
1899              is_discoverable: false,
1900              also_known_as: []
1901            } = user
1902   end
1903
1904   test "delete/1 purges a remote user" do
1905     user =
1906       insert(:user, %{
1907         name: "qqqqqqq",
1908         avatar: %{"a" => "b"},
1909         banner: %{"a" => "b"},
1910         local: false
1911       })
1912
1913     {:ok, job} = User.delete(user)
1914     {:ok, _} = ObanHelpers.perform(job)
1915     user = User.get_by_id(user.id)
1916
1917     assert user.name == nil
1918     assert user.avatar == %{}
1919     assert user.banner == %{}
1920   end
1921
1922   describe "set_suggestion" do
1923     test "suggests a user" do
1924       user = insert(:user, is_suggested: false)
1925       refute user.is_suggested
1926       {:ok, user} = User.set_suggestion(user, true)
1927       assert user.is_suggested
1928     end
1929
1930     test "suggests a list of users" do
1931       unsuggested_users = [
1932         insert(:user, is_suggested: false),
1933         insert(:user, is_suggested: false),
1934         insert(:user, is_suggested: false)
1935       ]
1936
1937       {:ok, users} = User.set_suggestion(unsuggested_users, true)
1938
1939       assert Enum.count(users) == 3
1940
1941       Enum.each(users, fn user ->
1942         assert user.is_suggested
1943       end)
1944     end
1945
1946     test "unsuggests a user" do
1947       user = insert(:user, is_suggested: true)
1948       assert user.is_suggested
1949       {:ok, user} = User.set_suggestion(user, false)
1950       refute user.is_suggested
1951     end
1952   end
1953
1954   test "get_public_key_for_ap_id returns correctly for user that's not in the db" do
1955     assert :error = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1956   end
1957
1958   describe "per-user rich-text filtering" do
1959     test "html_filter_policy returns default policies, when rich-text is enabled" do
1960       user = insert(:user)
1961
1962       assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1963     end
1964
1965     test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1966       user = insert(:user, no_rich_text: true)
1967
1968       assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1969     end
1970   end
1971
1972   describe "caching" do
1973     test "invalidate_cache works" do
1974       user = insert(:user)
1975
1976       User.set_cache(user)
1977       User.invalidate_cache(user)
1978
1979       {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1980       {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1981     end
1982
1983     test "User.delete() plugs any possible zombie objects" do
1984       user = insert(:user)
1985
1986       {:ok, job} = User.delete(user)
1987       {:ok, _} = ObanHelpers.perform(job)
1988
1989       {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1990
1991       assert cached_user != user
1992
1993       {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1994
1995       assert cached_user != user
1996     end
1997   end
1998
1999   describe "account_status/1" do
2000     setup do: clear_config([:instance, :account_activation_required])
2001
2002     test "return confirmation_pending for unconfirm user" do
2003       clear_config([:instance, :account_activation_required], true)
2004       user = insert(:user, is_confirmed: false)
2005       assert User.account_status(user) == :confirmation_pending
2006     end
2007
2008     test "return active for confirmed user" do
2009       clear_config([:instance, :account_activation_required], true)
2010       user = insert(:user, is_confirmed: true)
2011       assert User.account_status(user) == :active
2012     end
2013
2014     test "return active for remote user" do
2015       user = insert(:user, local: false)
2016       assert User.account_status(user) == :active
2017     end
2018
2019     test "returns :password_reset_pending for user with reset password" do
2020       user = insert(:user, password_reset_pending: true)
2021       assert User.account_status(user) == :password_reset_pending
2022     end
2023
2024     test "returns :deactivated for deactivated user" do
2025       user = insert(:user, local: true, is_confirmed: true, is_active: false)
2026       assert User.account_status(user) == :deactivated
2027     end
2028
2029     test "returns :approval_pending for unapproved user" do
2030       user = insert(:user, local: true, is_approved: false)
2031       assert User.account_status(user) == :approval_pending
2032
2033       user = insert(:user, local: true, is_confirmed: false, is_approved: false)
2034       assert User.account_status(user) == :approval_pending
2035     end
2036   end
2037
2038   describe "privileged?/1" do
2039     setup do
2040       clear_config([:instance, :admin_privileges], [:cofe, :suya])
2041       clear_config([:instance, :moderator_privileges], [:cofe, :suya])
2042     end
2043
2044     test "returns false for unprivileged users" do
2045       user = insert(:user, local: true)
2046
2047       refute User.privileged?(user, :cofe)
2048     end
2049
2050     test "returns false for remote users" do
2051       user = insert(:user, local: false)
2052       remote_admin_user = insert(:user, local: false, is_admin: true)
2053
2054       refute User.privileged?(user, :cofe)
2055       refute User.privileged?(remote_admin_user, :cofe)
2056     end
2057
2058     test "returns true for local moderators if, and only if, they are privileged" do
2059       user = insert(:user, local: true, is_moderator: true)
2060
2061       assert User.privileged?(user, :cofe)
2062
2063       clear_config([:instance, :moderator_privileges], [])
2064
2065       refute User.privileged?(user, :cofe)
2066     end
2067
2068     test "returns true for local admins if, and only if, they are privileged" do
2069       user = insert(:user, local: true, is_admin: true)
2070
2071       assert User.privileged?(user, :cofe)
2072
2073       clear_config([:instance, :admin_privileges], [])
2074
2075       refute User.privileged?(user, :cofe)
2076     end
2077   end
2078
2079   describe "privileges/1" do
2080     setup do
2081       clear_config([:instance, :moderator_privileges], [:cofe, :only_moderator])
2082       clear_config([:instance, :admin_privileges], [:cofe, :only_admin])
2083     end
2084
2085     test "returns empty list for users without roles" do
2086       user = insert(:user, local: true)
2087
2088       assert [] == User.privileges(user)
2089     end
2090
2091     test "returns list of privileges for moderators" do
2092       moderator = insert(:user, is_moderator: true, local: true)
2093
2094       assert [:cofe, :only_moderator] == User.privileges(moderator) |> Enum.sort()
2095     end
2096
2097     test "returns list of privileges for admins" do
2098       admin = insert(:user, is_admin: true, local: true)
2099
2100       assert [:cofe, :only_admin] == User.privileges(admin) |> Enum.sort()
2101     end
2102
2103     test "returns list of unique privileges for users who are both moderator and admin" do
2104       moderator_admin = insert(:user, is_moderator: true, is_admin: true, local: true)
2105
2106       assert [:cofe, :only_admin, :only_moderator] ==
2107                User.privileges(moderator_admin) |> Enum.sort()
2108     end
2109
2110     test "returns empty list for remote users" do
2111       remote_moderator_admin = insert(:user, is_moderator: true, is_admin: true, local: false)
2112
2113       assert [] == User.privileges(remote_moderator_admin)
2114     end
2115   end
2116
2117   describe "invisible?/1" do
2118     test "returns true for an invisible user" do
2119       user = insert(:user, local: true, invisible: true)
2120
2121       assert User.invisible?(user)
2122     end
2123
2124     test "returns false for a non-invisible user" do
2125       user = insert(:user, local: true)
2126
2127       refute User.invisible?(user)
2128     end
2129   end
2130
2131   describe "visible_for/2" do
2132     test "returns true when the account is itself" do
2133       user = insert(:user, local: true)
2134
2135       assert User.visible_for(user, user) == :visible
2136     end
2137
2138     test "returns false when the account is unconfirmed and confirmation is required" do
2139       clear_config([:instance, :account_activation_required], true)
2140
2141       user = insert(:user, local: true, is_confirmed: false)
2142       other_user = insert(:user, local: true)
2143
2144       refute User.visible_for(user, other_user) == :visible
2145     end
2146
2147     test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
2148       clear_config([:instance, :account_activation_required], true)
2149
2150       user = insert(:user, local: false, is_confirmed: false)
2151       other_user = insert(:user, local: true)
2152
2153       assert User.visible_for(user, other_user) == :visible
2154     end
2155
2156     test "returns true when the account is unconfirmed and being viewed by a privileged account (privilege :users_manage_activation_state, confirmation required)" do
2157       clear_config([:instance, :account_activation_required], true)
2158       clear_config([:instance, :admin_privileges], [:users_manage_activation_state])
2159
2160       user = insert(:user, local: true, is_confirmed: false)
2161       other_user = insert(:user, local: true, is_admin: true)
2162
2163       assert User.visible_for(user, other_user) == :visible
2164
2165       clear_config([:instance, :admin_privileges], [])
2166
2167       refute User.visible_for(user, other_user) == :visible
2168     end
2169   end
2170
2171   describe "all_users_with_privilege/1" do
2172     setup do
2173       %{
2174         user: insert(:user, local: true, is_admin: false, is_moderator: false),
2175         moderator_user: insert(:user, local: true, is_admin: false, is_moderator: true),
2176         admin_user: insert(:user, local: true, is_admin: true, is_moderator: false),
2177         admin_moderator_user: insert(:user, local: true, is_admin: true, is_moderator: true),
2178         remote_user: insert(:user, local: false, is_admin: true, is_moderator: true),
2179         non_active_user:
2180           insert(:user, local: true, is_admin: true, is_moderator: true, is_active: false)
2181       }
2182     end
2183
2184     test "doesn't return any users when there are no privileged roles" do
2185       clear_config([:instance, :admin_privileges], [])
2186       clear_config([:instance, :moderator_privileges], [])
2187
2188       assert [] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2189     end
2190
2191     test "returns moderator users if they are privileged", %{
2192       moderator_user: moderator_user,
2193       admin_moderator_user: admin_moderator_user
2194     } do
2195       clear_config([:instance, :admin_privileges], [])
2196       clear_config([:instance, :moderator_privileges], [:cofe])
2197
2198       assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2199       assert moderator_user in User.all_users_with_privilege(:cofe)
2200       assert admin_moderator_user in User.all_users_with_privilege(:cofe)
2201     end
2202
2203     test "returns admin users if they are privileged", %{
2204       admin_user: admin_user,
2205       admin_moderator_user: admin_moderator_user
2206     } do
2207       clear_config([:instance, :admin_privileges], [:cofe])
2208       clear_config([:instance, :moderator_privileges], [])
2209
2210       assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2211       assert admin_user in User.all_users_with_privilege(:cofe)
2212       assert admin_moderator_user in User.all_users_with_privilege(:cofe)
2213     end
2214
2215     test "returns admin and moderator users if they are both privileged", %{
2216       moderator_user: moderator_user,
2217       admin_user: admin_user,
2218       admin_moderator_user: admin_moderator_user
2219     } do
2220       clear_config([:instance, :admin_privileges], [:cofe])
2221       clear_config([:instance, :moderator_privileges], [:cofe])
2222
2223       assert [_, _, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2224       assert admin_user in User.all_users_with_privilege(:cofe)
2225       assert moderator_user in User.all_users_with_privilege(:cofe)
2226       assert admin_moderator_user in User.all_users_with_privilege(:cofe)
2227     end
2228   end
2229
2230   describe "parse_bio/2" do
2231     test "preserves hosts in user links text" do
2232       remote_user = insert(:user, local: false, nickname: "nick@domain.com")
2233       user = insert(:user)
2234       bio = "A.k.a. @nick@domain.com"
2235
2236       expected_text =
2237         ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{remote_user.ap_id}" rel="ugc">@<span>nick@domain.com</span></a></span>)
2238
2239       assert expected_text == User.parse_bio(bio, user)
2240     end
2241
2242     test "Adds rel=me on linkbacked urls" do
2243       user = insert(:user, ap_id: "https://social.example.org/users/lain")
2244
2245       bio = "http://example.com/rel_me/null"
2246       expected_text = "<a href=\"#{bio}\">#{bio}</a>"
2247       assert expected_text == User.parse_bio(bio, user)
2248
2249       bio = "http://example.com/rel_me/link"
2250       expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2251       assert expected_text == User.parse_bio(bio, user)
2252
2253       bio = "http://example.com/rel_me/anchor"
2254       expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2255       assert expected_text == User.parse_bio(bio, user)
2256     end
2257   end
2258
2259   test "follower count is updated when a follower is blocked" do
2260     user = insert(:user)
2261     follower = insert(:user)
2262     follower2 = insert(:user)
2263     follower3 = insert(:user)
2264
2265     {:ok, follower, user} = User.follow(follower, user)
2266     {:ok, _follower2, _user} = User.follow(follower2, user)
2267     {:ok, _follower3, _user} = User.follow(follower3, user)
2268
2269     {:ok, _user_relationship} = User.block(user, follower)
2270     user = refresh_record(user)
2271
2272     assert user.follower_count == 2
2273   end
2274
2275   describe "list_inactive_users_query/1" do
2276     defp days_ago(days) do
2277       NaiveDateTime.add(
2278         NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
2279         -days * 60 * 60 * 24,
2280         :second
2281       )
2282     end
2283
2284     test "Users are inactive by default" do
2285       total = 10
2286
2287       users =
2288         Enum.map(1..total, fn _ ->
2289           insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2290         end)
2291
2292       inactive_users_ids =
2293         Pleroma.User.list_inactive_users_query()
2294         |> Pleroma.Repo.all()
2295         |> Enum.map(& &1.id)
2296
2297       Enum.each(users, fn user ->
2298         assert user.id in inactive_users_ids
2299       end)
2300     end
2301
2302     test "Only includes users who has no recent activity" do
2303       total = 10
2304
2305       users =
2306         Enum.map(1..total, fn _ ->
2307           insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2308         end)
2309
2310       {inactive, active} = Enum.split(users, trunc(total / 2))
2311
2312       Enum.map(active, fn user ->
2313         to = Enum.random(users -- [user])
2314
2315         {:ok, _} =
2316           CommonAPI.post(user, %{
2317             status: "hey @#{to.nickname}"
2318           })
2319       end)
2320
2321       inactive_users_ids =
2322         Pleroma.User.list_inactive_users_query()
2323         |> Pleroma.Repo.all()
2324         |> Enum.map(& &1.id)
2325
2326       Enum.each(active, fn user ->
2327         refute user.id in inactive_users_ids
2328       end)
2329
2330       Enum.each(inactive, fn user ->
2331         assert user.id in inactive_users_ids
2332       end)
2333     end
2334
2335     test "Only includes users with no read notifications" do
2336       total = 10
2337
2338       users =
2339         Enum.map(1..total, fn _ ->
2340           insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2341         end)
2342
2343       [sender | recipients] = users
2344       {inactive, active} = Enum.split(recipients, trunc(total / 2))
2345
2346       Enum.each(recipients, fn to ->
2347         {:ok, _} =
2348           CommonAPI.post(sender, %{
2349             status: "hey @#{to.nickname}"
2350           })
2351
2352         {:ok, _} =
2353           CommonAPI.post(sender, %{
2354             status: "hey again @#{to.nickname}"
2355           })
2356       end)
2357
2358       Enum.each(active, fn user ->
2359         [n1, _n2] = Pleroma.Notification.for_user(user)
2360         {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2361       end)
2362
2363       inactive_users_ids =
2364         Pleroma.User.list_inactive_users_query()
2365         |> Pleroma.Repo.all()
2366         |> Enum.map(& &1.id)
2367
2368       Enum.each(active, fn user ->
2369         refute user.id in inactive_users_ids
2370       end)
2371
2372       Enum.each(inactive, fn user ->
2373         assert user.id in inactive_users_ids
2374       end)
2375     end
2376   end
2377
2378   describe "get_ap_ids_by_nicknames" do
2379     test "it returns a list of AP ids for a given set of nicknames" do
2380       user = insert(:user)
2381       user_two = insert(:user)
2382
2383       ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2384       assert length(ap_ids) == 2
2385       assert user.ap_id in ap_ids
2386       assert user_two.ap_id in ap_ids
2387     end
2388
2389     test "it returns a list of AP ids in the same order" do
2390       user = insert(:user)
2391       user_two = insert(:user)
2392       user_three = insert(:user)
2393
2394       ap_ids =
2395         User.get_ap_ids_by_nicknames([user.nickname, user_three.nickname, user_two.nickname])
2396
2397       assert [user.ap_id, user_three.ap_id, user_two.ap_id] == ap_ids
2398     end
2399   end
2400
2401   describe "sync followers count" do
2402     setup do
2403       user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2404       user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2405       insert(:user, local: true)
2406       insert(:user, local: false, is_active: false)
2407       {:ok, user1: user1, user2: user2}
2408     end
2409
2410     test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2411       [fdb_user1] = User.external_users(limit: 1)
2412
2413       assert fdb_user1.ap_id
2414       assert fdb_user1.ap_id == user1.ap_id
2415       assert fdb_user1.id == user1.id
2416
2417       [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2418
2419       assert fdb_user2.ap_id
2420       assert fdb_user2.ap_id == user2.ap_id
2421       assert fdb_user2.id == user2.id
2422
2423       assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2424     end
2425   end
2426
2427   describe "internal?/1" do
2428     test "non-internal user returns false" do
2429       user = insert(:user)
2430       refute User.internal?(user)
2431     end
2432
2433     test "user with no nickname returns true" do
2434       user = insert(:user, %{nickname: nil})
2435       assert User.internal?(user)
2436     end
2437
2438     test "user with internal-prefixed nickname returns true" do
2439       user = insert(:user, %{nickname: "internal.test"})
2440       assert User.internal?(user)
2441     end
2442   end
2443
2444   describe "update_and_set_cache/1" do
2445     test "returns error when user is stale instead Ecto.StaleEntryError" do
2446       user = insert(:user)
2447
2448       changeset = Ecto.Changeset.change(user, bio: "test")
2449
2450       Repo.delete(user)
2451
2452       assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2453                User.update_and_set_cache(changeset)
2454     end
2455
2456     test "performs update cache if user updated" do
2457       user = insert(:user)
2458       assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2459
2460       changeset = Ecto.Changeset.change(user, bio: "test-bio")
2461
2462       assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2463       assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2464       assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2465     end
2466   end
2467
2468   describe "following/followers synchronization" do
2469     setup do: clear_config([:instance, :external_user_synchronization])
2470
2471     test "updates the counters normally on following/getting a follow when disabled" do
2472       clear_config([:instance, :external_user_synchronization], false)
2473       user = insert(:user)
2474
2475       other_user =
2476         insert(:user,
2477           local: false,
2478           follower_address: "http://localhost:4001/users/masto_closed/followers",
2479           following_address: "http://localhost:4001/users/masto_closed/following"
2480         )
2481
2482       assert other_user.following_count == 0
2483       assert other_user.follower_count == 0
2484
2485       {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2486
2487       assert user.following_count == 1
2488       assert other_user.follower_count == 1
2489     end
2490
2491     test "synchronizes the counters with the remote instance for the followed when enabled" do
2492       clear_config([:instance, :external_user_synchronization], false)
2493
2494       user = insert(:user)
2495
2496       other_user =
2497         insert(:user,
2498           local: false,
2499           follower_address: "http://localhost:4001/users/masto_closed/followers",
2500           following_address: "http://localhost:4001/users/masto_closed/following"
2501         )
2502
2503       assert other_user.following_count == 0
2504       assert other_user.follower_count == 0
2505
2506       clear_config([:instance, :external_user_synchronization], true)
2507       {:ok, _user, other_user} = User.follow(user, other_user)
2508
2509       assert other_user.follower_count == 437
2510     end
2511
2512     test "synchronizes the counters with the remote instance for the follower when enabled" do
2513       clear_config([:instance, :external_user_synchronization], false)
2514
2515       user = insert(:user)
2516
2517       other_user =
2518         insert(:user,
2519           local: false,
2520           follower_address: "http://localhost:4001/users/masto_closed/followers",
2521           following_address: "http://localhost:4001/users/masto_closed/following"
2522         )
2523
2524       assert other_user.following_count == 0
2525       assert other_user.follower_count == 0
2526
2527       clear_config([:instance, :external_user_synchronization], true)
2528       {:ok, other_user, _user} = User.follow(other_user, user)
2529
2530       assert other_user.following_count == 152
2531     end
2532   end
2533
2534   describe "change_email/2" do
2535     setup do
2536       [user: insert(:user)]
2537     end
2538
2539     test "blank email returns error if we require an email on registration", %{user: user} do
2540       orig_account_activation_required =
2541         Pleroma.Config.get([:instance, :account_activation_required])
2542
2543       Pleroma.Config.put([:instance, :account_activation_required], true)
2544
2545       on_exit(fn ->
2546         Pleroma.Config.put(
2547           [:instance, :account_activation_required],
2548           orig_account_activation_required
2549         )
2550       end)
2551
2552       assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2553       assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2554     end
2555
2556     test "blank email should be fine if we do not require an email on registration", %{user: user} do
2557       orig_account_activation_required =
2558         Pleroma.Config.get([:instance, :account_activation_required])
2559
2560       Pleroma.Config.put([:instance, :account_activation_required], false)
2561
2562       on_exit(fn ->
2563         Pleroma.Config.put(
2564           [:instance, :account_activation_required],
2565           orig_account_activation_required
2566         )
2567       end)
2568
2569       assert {:ok, %User{email: nil}} = User.change_email(user, "")
2570       assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2571     end
2572
2573     test "non unique email returns error", %{user: user} do
2574       %{email: email} = insert(:user)
2575
2576       assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2577                User.change_email(user, email)
2578     end
2579
2580     test "invalid email returns error", %{user: user} do
2581       assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2582                User.change_email(user, "cofe")
2583     end
2584
2585     test "changes email", %{user: user} do
2586       assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2587     end
2588
2589     test "adds email", %{user: user} do
2590       orig_account_activation_required =
2591         Pleroma.Config.get([:instance, :account_activation_required])
2592
2593       Pleroma.Config.put([:instance, :account_activation_required], false)
2594
2595       on_exit(fn ->
2596         Pleroma.Config.put(
2597           [:instance, :account_activation_required],
2598           orig_account_activation_required
2599         )
2600       end)
2601
2602       assert {:ok, _} = User.change_email(user, "")
2603       Pleroma.Config.put([:instance, :account_activation_required], true)
2604
2605       assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2606     end
2607   end
2608
2609   describe "get_cached_by_nickname_or_id" do
2610     setup do
2611       local_user = insert(:user)
2612       remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2613
2614       [local_user: local_user, remote_user: remote_user]
2615     end
2616
2617     setup do: clear_config([:instance, :limit_to_local_content])
2618
2619     test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2620       remote_user: remote_user
2621     } do
2622       clear_config([:instance, :limit_to_local_content], false)
2623       assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2624
2625       clear_config([:instance, :limit_to_local_content], true)
2626       assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2627
2628       clear_config([:instance, :limit_to_local_content], :unauthenticated)
2629       assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2630     end
2631
2632     test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2633          %{remote_user: remote_user} do
2634       clear_config([:instance, :limit_to_local_content], :unauthenticated)
2635       assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2636     end
2637
2638     test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2639          %{remote_user: remote_user, local_user: local_user} do
2640       clear_config([:instance, :limit_to_local_content], :unauthenticated)
2641       assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2642     end
2643
2644     test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2645          %{remote_user: remote_user} do
2646       clear_config([:instance, :limit_to_local_content], true)
2647       assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2648     end
2649
2650     test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2651          %{local_user: local_user} do
2652       clear_config([:instance, :limit_to_local_content], false)
2653       assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2654
2655       clear_config([:instance, :limit_to_local_content], true)
2656       assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2657
2658       clear_config([:instance, :limit_to_local_content], :unauthenticated)
2659       assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2660     end
2661   end
2662
2663   describe "update_email_notifications/2" do
2664     setup do
2665       user = insert(:user, email_notifications: %{"digest" => true})
2666
2667       {:ok, user: user}
2668     end
2669
2670     test "Notifications are updated", %{user: user} do
2671       true = user.email_notifications["digest"]
2672       assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2673       assert result.email_notifications["digest"] == false
2674     end
2675   end
2676
2677   describe "local_nickname/1" do
2678     test "returns nickname without host" do
2679       assert User.local_nickname("@mentioned") == "mentioned"
2680       assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2681       assert User.local_nickname("nickname@host.com") == "nickname"
2682     end
2683   end
2684
2685   describe "full_nickname/1" do
2686     test "returns fully qualified nickname for local users" do
2687       local_user = insert(:user, nickname: "local_user")
2688
2689       assert User.full_nickname(local_user) == "local_user@localhost"
2690     end
2691
2692     test "returns fully qualified nickname for local users when using different domain for webfinger" do
2693       clear_config([Pleroma.Web.WebFinger, :domain], "plemora.dev")
2694
2695       local_user = insert(:user, nickname: "local_user")
2696
2697       assert User.full_nickname(local_user) == "local_user@plemora.dev"
2698     end
2699
2700     test "returns fully qualified nickname for remote users" do
2701       remote_user = insert(:user, nickname: "remote@host.com", local: false)
2702
2703       assert User.full_nickname(remote_user) == "remote@host.com"
2704     end
2705
2706     test "strips leading @ from mentions" do
2707       assert User.full_nickname("@mentioned") == "mentioned"
2708       assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2709     end
2710
2711     test "does not modify nicknames" do
2712       assert User.full_nickname("nickname") == "nickname"
2713       assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2714     end
2715   end
2716
2717   test "avatar fallback" do
2718     user = insert(:user)
2719     assert User.avatar_url(user) =~ "/images/avi.png"
2720
2721     clear_config([:assets, :default_user_avatar], "avatar.png")
2722
2723     user = User.get_cached_by_nickname_or_id(user.nickname)
2724     assert User.avatar_url(user) =~ "avatar.png"
2725
2726     assert User.avatar_url(user, no_default: true) == nil
2727   end
2728
2729   test "get_host/1" do
2730     user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2731     assert User.get_host(user) == "lain.com"
2732   end
2733
2734   test "update_last_active_at/1" do
2735     user = insert(:user)
2736     assert is_nil(user.last_active_at)
2737
2738     test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2739
2740     assert {:ok, user} = User.update_last_active_at(user)
2741
2742     assert user.last_active_at >= test_started_at
2743     assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2744
2745     last_active_at =
2746       NaiveDateTime.utc_now()
2747       |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2748       |> NaiveDateTime.truncate(:second)
2749
2750     assert {:ok, user} =
2751              user
2752              |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2753              |> User.update_and_set_cache()
2754
2755     assert user.last_active_at == last_active_at
2756     assert {:ok, user} = User.update_last_active_at(user)
2757     assert user.last_active_at >= test_started_at
2758     assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2759   end
2760
2761   test "active_user_count/1" do
2762     insert(:user)
2763     insert(:user, %{local: false})
2764     insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2765     insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2766     insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2767     insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2768     insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2769
2770     assert User.active_user_count() == 2
2771     assert User.active_user_count(180) == 3
2772     assert User.active_user_count(365) == 4
2773     assert User.active_user_count(1000) == 5
2774   end
2775
2776   describe "pins" do
2777     setup do
2778       user = insert(:user)
2779
2780       [user: user, object_id: object_id_from_created_activity(user)]
2781     end
2782
2783     test "unique pins", %{user: user, object_id: object_id} do
2784       assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2785                User.add_pinned_object_id(user, object_id)
2786
2787       assert Enum.count(pins) == 1
2788
2789       assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2790                User.add_pinned_object_id(updated_user, object_id)
2791
2792       assert pinned_at1 == pinned_at2
2793
2794       assert Enum.count(pins) == 1
2795     end
2796
2797     test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2798       clear_config([:instance, :max_pinned_statuses], 1)
2799       {:ok, updated} = User.add_pinned_object_id(user, object_id)
2800
2801       object_id2 = object_id_from_created_activity(user)
2802
2803       {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2804       assert Keyword.has_key?(errors, :pinned_objects)
2805     end
2806
2807     test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2808       assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2809
2810       {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2811       assert after_remove.pinned_objects == %{}
2812     end
2813   end
2814
2815   defp object_id_from_created_activity(user) do
2816     %{id: id} = insert(:note_activity, user: user)
2817     %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2818     object_id
2819   end
2820
2821   describe "add_alias/2" do
2822     test "should add alias for another user" do
2823       user = insert(:user)
2824       user2 = insert(:user)
2825
2826       assert {:ok, user_updated} = user |> User.add_alias(user2)
2827
2828       assert user_updated.also_known_as |> length() == 1
2829       assert user2.ap_id in user_updated.also_known_as
2830     end
2831
2832     test "should add multiple aliases" do
2833       user = insert(:user)
2834       user2 = insert(:user)
2835       user3 = insert(:user)
2836
2837       assert {:ok, user} = user |> User.add_alias(user2)
2838       assert {:ok, user_updated} = user |> User.add_alias(user3)
2839
2840       assert user_updated.also_known_as |> length() == 2
2841       assert user2.ap_id in user_updated.also_known_as
2842       assert user3.ap_id in user_updated.also_known_as
2843     end
2844
2845     test "should not add duplicate aliases" do
2846       user = insert(:user)
2847       user2 = insert(:user)
2848
2849       assert {:ok, user} = user |> User.add_alias(user2)
2850
2851       assert {:ok, user_updated} = user |> User.add_alias(user2)
2852
2853       assert user_updated.also_known_as |> length() == 1
2854       assert user2.ap_id in user_updated.also_known_as
2855     end
2856   end
2857
2858   describe "alias_users/1" do
2859     test "should get aliases for a user" do
2860       user = insert(:user)
2861       user2 = insert(:user, also_known_as: [user.ap_id])
2862
2863       aliases = user2 |> User.alias_users()
2864
2865       assert aliases |> length() == 1
2866
2867       alias_user = aliases |> Enum.at(0)
2868
2869       assert alias_user.ap_id == user.ap_id
2870     end
2871   end
2872
2873   describe "delete_alias/2" do
2874     test "should delete existing alias" do
2875       user = insert(:user)
2876       user2 = insert(:user, also_known_as: [user.ap_id])
2877
2878       assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2879
2880       assert user_updated.also_known_as == []
2881     end
2882
2883     test "should report error on non-existing alias" do
2884       user = insert(:user)
2885       user2 = insert(:user)
2886       user3 = insert(:user, also_known_as: [user.ap_id])
2887
2888       assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2889
2890       user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2891
2892       assert user3_updated.also_known_as |> length() == 1
2893       assert user.ap_id in user3_updated.also_known_as
2894     end
2895   end
2896
2897   describe "account endorsements" do
2898     test "it pins people" do
2899       user = insert(:user)
2900       pinned_user = insert(:user)
2901
2902       {:ok, _pinned_user, _user} = User.follow(user, pinned_user)
2903
2904       refute User.endorses?(user, pinned_user)
2905
2906       {:ok, _user_relationship} = User.endorse(user, pinned_user)
2907
2908       assert User.endorses?(user, pinned_user)
2909     end
2910
2911     test "it unpins users" do
2912       user = insert(:user)
2913       pinned_user = insert(:user)
2914
2915       {:ok, _pinned_user, _user} = User.follow(user, pinned_user)
2916       {:ok, _user_relationship} = User.endorse(user, pinned_user)
2917       {:ok, _user_pin} = User.unendorse(user, pinned_user)
2918
2919       refute User.endorses?(user, pinned_user)
2920     end
2921
2922     test "it doesn't pin users you do not follow" do
2923       user = insert(:user)
2924       pinned_user = insert(:user)
2925
2926       assert {:error, _message} = User.endorse(user, pinned_user)
2927
2928       refute User.endorses?(user, pinned_user)
2929     end
2930   end
2931
2932   test "it checks fields links for a backlink" do
2933     user = insert(:user, ap_id: "https://social.example.org/users/lain")
2934
2935     fields = [
2936       %{"name" => "Link", "value" => "http://example.com/rel_me/null"},
2937       %{"name" => "Verified link", "value" => "http://example.com/rel_me/link"},
2938       %{"name" => "Not a link", "value" => "i'm not a link"}
2939     ]
2940
2941     user
2942     |> User.update_and_set_cache(%{raw_fields: fields})
2943
2944     ObanHelpers.perform_all()
2945
2946     user = User.get_cached_by_id(user.id)
2947
2948     assert [
2949              %{"verified_at" => nil},
2950              %{"verified_at" => verified_at},
2951              %{"verified_at" => nil}
2952            ] = user.fields
2953
2954     assert is_binary(verified_at)
2955   end
2956
2957   test "updating fields does not invalidate previously validated links" do
2958     user = insert(:user, ap_id: "https://social.example.org/users/lain")
2959
2960     user
2961     |> User.update_and_set_cache(%{
2962       raw_fields: [%{"name" => "verified link", "value" => "http://example.com/rel_me/link"}]
2963     })
2964
2965     ObanHelpers.perform_all()
2966
2967     %User{fields: [%{"verified_at" => verified_at}]} = user = User.get_cached_by_id(user.id)
2968
2969     user
2970     |> User.update_and_set_cache(%{
2971       raw_fields: [%{"name" => "Verified link", "value" => "http://example.com/rel_me/link"}]
2972     })
2973
2974     user = User.get_cached_by_id(user.id)
2975
2976     assert [%{"verified_at" => ^verified_at}] = user.fields
2977   end
2978 end