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