1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.UserTest do
7 alias Pleroma.Builders.UserBuilder
10 alias Pleroma.Tests.ObanHelpers
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.CommonAPI
15 use Pleroma.DataCase, async: false
16 use Oban.Testing, repo: Pleroma.Repo
18 import Pleroma.Factory
19 import ExUnit.CaptureLog
20 import Swoosh.TestAssertions
23 Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
28 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
32 setup do: clear_config([:instance, :account_activation_required])
34 describe "service actors" do
35 test "returns updated invisible actor" do
36 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
37 followers_uri = "#{uri}/followers"
46 follower_address: followers_uri
50 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
51 assert actor.invisible
54 test "returns relay user" do
55 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
56 followers_uri = "#{uri}/followers"
63 follower_address: ^followers_uri
64 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
66 assert capture_log(fn ->
67 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
68 end) =~ "Cannot create service actor:"
71 test "returns invisible actor" do
72 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
73 followers_uri = "#{uri}/followers"
74 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
77 nickname: "internal.fetch-test",
81 follower_address: ^followers_uri
84 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
85 assert user.id == user2.id
89 describe "AP ID user relationships" do
91 {:ok, user: insert(:user)}
94 test "outgoing_relationships_ap_ids/1", %{user: user} do
95 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
103 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
105 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
106 {rel_type, Enum.sort(ap_ids)}
110 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
111 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
113 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
114 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
116 assert ap_ids_by_rel[:notification_mute] ==
117 Enum.sort(User.notification_muted_users_ap_ids(user))
119 assert ap_ids_by_rel[:notification_mute] ==
120 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
122 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
124 assert ap_ids_by_rel[:reblog_mute] ==
125 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
127 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
129 assert ap_ids_by_rel[:inverse_subscription] ==
130 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
132 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
134 assert ap_ids_by_rel ==
135 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
139 describe "when tags are nil" do
140 test "tagging a user" do
141 user = insert(:user, %{tags: nil})
142 user = User.tag(user, ["cool", "dude"])
144 assert "cool" in user.tags
145 assert "dude" in user.tags
148 test "untagging a user" do
149 user = insert(:user, %{tags: nil})
150 user = User.untag(user, ["cool", "dude"])
152 assert user.tags == []
156 test "ap_id returns the activity pub id for the user" do
157 user = UserBuilder.build()
159 expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}"
161 assert expected_ap_id == User.ap_id(user)
164 test "ap_followers returns the followers collection for the user" do
165 user = UserBuilder.build()
167 expected_followers_collection = "#{User.ap_id(user)}/followers"
169 assert expected_followers_collection == User.ap_followers(user)
172 test "ap_following returns the following collection for the user" do
173 user = UserBuilder.build()
175 expected_followers_collection = "#{User.ap_id(user)}/following"
177 assert expected_followers_collection == User.ap_following(user)
180 test "returns all pending follow requests" do
181 unlocked = insert(:user)
182 locked = insert(:user, is_locked: true)
183 follower = insert(:user)
185 CommonAPI.follow(follower, unlocked)
186 CommonAPI.follow(follower, locked)
188 assert [] = User.get_follow_requests(unlocked)
189 assert [activity] = User.get_follow_requests(locked)
194 test "doesn't return already accepted or duplicate follow requests" do
195 locked = insert(:user, is_locked: true)
196 pending_follower = insert(:user)
197 accepted_follower = insert(:user)
199 CommonAPI.follow(pending_follower, locked)
200 CommonAPI.follow(pending_follower, locked)
201 CommonAPI.follow(accepted_follower, locked)
203 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
205 assert [^pending_follower] = User.get_follow_requests(locked)
208 test "doesn't return follow requests for deactivated accounts" do
209 locked = insert(:user, is_locked: true)
210 pending_follower = insert(:user, %{is_active: false})
212 CommonAPI.follow(pending_follower, locked)
214 refute pending_follower.is_active
215 assert [] = User.get_follow_requests(locked)
218 test "clears follow requests when requester is blocked" do
219 followed = insert(:user, is_locked: true)
220 follower = insert(:user)
222 CommonAPI.follow(follower, followed)
223 assert [_activity] = User.get_follow_requests(followed)
225 {:ok, _user_relationship} = User.block(followed, follower)
226 assert [] = User.get_follow_requests(followed)
229 test "follow_all follows multiple users" do
231 followed_zero = insert(:user)
232 followed_one = insert(:user)
233 followed_two = insert(:user)
234 blocked = insert(:user)
235 not_followed = insert(:user)
236 reverse_blocked = insert(:user)
238 {:ok, _user_relationship} = User.block(user, blocked)
239 {:ok, _user_relationship} = User.block(reverse_blocked, user)
241 {:ok, user, followed_zero} = User.follow(user, followed_zero)
243 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
245 assert User.following?(user, followed_one)
246 assert User.following?(user, followed_two)
247 assert User.following?(user, followed_zero)
248 refute User.following?(user, not_followed)
249 refute User.following?(user, blocked)
250 refute User.following?(user, reverse_blocked)
253 test "follow_all follows multiple users without duplicating" do
255 followed_zero = insert(:user)
256 followed_one = insert(:user)
257 followed_two = insert(:user)
259 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
260 assert length(User.following(user)) == 3
262 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
263 assert length(User.following(user)) == 4
266 test "follow takes a user and another user" do
268 followed = insert(:user)
270 {:ok, user, followed} = User.follow(user, followed)
272 user = User.get_cached_by_id(user.id)
273 followed = User.get_cached_by_ap_id(followed.ap_id)
275 assert followed.follower_count == 1
276 assert user.following_count == 1
278 assert User.ap_followers(followed) in User.following(user)
281 test "can't follow a deactivated users" do
283 followed = insert(:user, %{is_active: false})
285 {:error, _} = User.follow(user, followed)
288 test "can't follow a user who blocked us" do
289 blocker = insert(:user)
290 blockee = insert(:user)
292 {:ok, _user_relationship} = User.block(blocker, blockee)
294 {:error, _} = User.follow(blockee, blocker)
297 test "can't subscribe to a user who blocked us" do
298 blocker = insert(:user)
299 blocked = insert(:user)
301 {:ok, _user_relationship} = User.block(blocker, blocked)
303 {:error, _} = User.subscribe(blocked, blocker)
306 test "local users do not automatically follow local locked accounts" do
307 follower = insert(:user, is_locked: true)
308 followed = insert(:user, is_locked: true)
310 {:ok, follower, followed} = User.maybe_direct_follow(follower, followed)
312 refute User.following?(follower, followed)
315 describe "unfollow/2" do
316 setup do: clear_config([:instance, :external_user_synchronization])
318 test "unfollow with synchronizes external user" do
319 clear_config([:instance, :external_user_synchronization], true)
324 follower_address: "http://localhost:4001/users/fuser1/followers",
325 following_address: "http://localhost:4001/users/fuser1/following",
326 ap_id: "http://localhost:4001/users/fuser1"
333 ap_id: "http://localhost:4001/users/fuser2",
334 follower_address: "http://localhost:4001/users/fuser2/followers",
335 following_address: "http://localhost:4001/users/fuser2/following"
338 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
340 {:ok, user, _activity} = User.unfollow(user, followed)
342 user = User.get_cached_by_id(user.id)
344 assert User.following(user) == []
347 test "unfollow takes a user and another user" do
348 followed = insert(:user)
351 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
353 assert User.following(user) == [user.follower_address, followed.follower_address]
355 {:ok, user, _activity} = User.unfollow(user, followed)
357 assert User.following(user) == [user.follower_address]
360 test "unfollow doesn't unfollow yourself" do
363 {:error, _} = User.unfollow(user, user)
365 assert User.following(user) == [user.follower_address]
369 test "test if a user is following another user" do
370 followed = insert(:user)
372 User.follow(user, followed, :follow_accept)
374 assert User.following?(user, followed)
375 refute User.following?(followed, user)
378 test "fetches correct profile for nickname beginning with number" do
379 # Use old-style integer ID to try to reproduce the problem
380 user = insert(:user, %{id: 1080})
381 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
382 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
385 describe "user registration" do
391 password_confirmation: "test",
392 email: "email@example.com"
395 setup do: clear_config([:instance, :autofollowed_nicknames])
396 setup do: clear_config([:instance, :autofollowing_nicknames])
397 setup do: clear_config([:welcome])
398 setup do: clear_config([:instance, :account_activation_required])
400 test "it autofollows accounts that are set for it" do
402 remote_user = insert(:user, %{local: false})
404 clear_config([:instance, :autofollowed_nicknames], [
409 cng = User.register_changeset(%User{}, @full_user_data)
411 {:ok, registered_user} = User.register(cng)
413 assert User.following?(registered_user, user)
414 refute User.following?(registered_user, remote_user)
417 test "it adds automatic followers for new registered accounts" do
418 user1 = insert(:user)
419 user2 = insert(:user)
421 clear_config([:instance, :autofollowing_nicknames], [
426 cng = User.register_changeset(%User{}, @full_user_data)
428 {:ok, registered_user} = User.register(cng)
430 assert User.following?(user1, registered_user)
431 assert User.following?(user2, registered_user)
434 test "it sends a welcome message if it is set" do
435 welcome_user = insert(:user)
436 clear_config([:welcome, :direct_message, :enabled], true)
437 clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
438 clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message")
440 cng = User.register_changeset(%User{}, @full_user_data)
441 {:ok, registered_user} = User.register(cng)
442 ObanHelpers.perform_all()
444 activity = Repo.one(Pleroma.Activity)
445 assert registered_user.ap_id in activity.recipients
446 assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message"
447 assert activity.actor == welcome_user.ap_id
450 test "it sends a welcome chat message if it is set" do
451 welcome_user = insert(:user)
452 clear_config([:welcome, :chat_message, :enabled], true)
453 clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
454 clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
456 cng = User.register_changeset(%User{}, @full_user_data)
457 {:ok, registered_user} = User.register(cng)
458 ObanHelpers.perform_all()
460 activity = Repo.one(Pleroma.Activity)
461 assert registered_user.ap_id in activity.recipients
462 assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
463 assert activity.actor == welcome_user.ap_id
467 clear_config(:mrf_simple,
470 federated_timeline_removal: [],
480 setup do: clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
482 test "it sends a welcome chat message when Simple policy applied to local instance" do
483 clear_config([:mrf_simple, :media_nsfw], [{"localhost", ""}])
485 welcome_user = insert(:user)
486 clear_config([:welcome, :chat_message, :enabled], true)
487 clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
488 clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
490 cng = User.register_changeset(%User{}, @full_user_data)
491 {:ok, registered_user} = User.register(cng)
492 ObanHelpers.perform_all()
494 activity = Repo.one(Pleroma.Activity)
495 assert registered_user.ap_id in activity.recipients
496 assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
497 assert activity.actor == welcome_user.ap_id
500 test "it sends a welcome email message if it is set" do
501 welcome_user = insert(:user)
502 clear_config([:welcome, :email, :enabled], true)
503 clear_config([:welcome, :email, :sender], welcome_user.email)
506 [:welcome, :email, :subject],
507 "Hello, welcome to cool site: <%= instance_name %>"
510 instance_name = Pleroma.Config.get([:instance, :name])
512 cng = User.register_changeset(%User{}, @full_user_data)
513 {:ok, registered_user} = User.register(cng)
514 ObanHelpers.perform_all()
517 from: {instance_name, welcome_user.email},
518 to: {registered_user.name, registered_user.email},
519 subject: "Hello, welcome to cool site: #{instance_name}",
520 html_body: "Welcome to #{instance_name}"
524 test "it sends a confirm email" do
525 clear_config([:instance, :account_activation_required], true)
527 cng = User.register_changeset(%User{}, @full_user_data)
528 {:ok, registered_user} = User.register(cng)
529 ObanHelpers.perform_all()
531 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
532 # temporary hackney fix until hackney max_connections bug is fixed
533 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
534 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
535 |> assert_email_sent()
538 test "sends a pending approval email" do
539 clear_config([:instance, :account_approval_required], true)
542 User.register_changeset(%User{}, @full_user_data)
545 ObanHelpers.perform_all()
548 from: Pleroma.Config.Helpers.sender(),
549 to: {user.name, user.email},
550 subject: "Your account is awaiting approval"
554 test "it sends a registration confirmed email if no others will be sent" do
555 clear_config([:welcome, :email, :enabled], false)
556 clear_config([:instance, :account_activation_required], false)
557 clear_config([:instance, :account_approval_required], false)
560 User.register_changeset(%User{}, @full_user_data)
563 ObanHelpers.perform_all()
565 instance_name = Pleroma.Config.get([:instance, :name])
566 sender = Pleroma.Config.get([:instance, :notify_email])
569 from: {instance_name, sender},
570 to: {user.name, user.email},
571 subject: "Account registered on #{instance_name}"
575 test "it fails gracefully with invalid email config" do
576 cng = User.register_changeset(%User{}, @full_user_data)
578 # Disable the mailer but enable all the things that want to send emails
579 clear_config([Pleroma.Emails.Mailer, :enabled], false)
580 clear_config([:instance, :account_activation_required], true)
581 clear_config([:instance, :account_approval_required], true)
582 clear_config([:welcome, :email, :enabled], true)
583 clear_config([:welcome, :email, :sender], "lain@lain.com")
585 # The user is still created
586 assert {:ok, %User{nickname: "nick"}} = User.register(cng)
589 ObanHelpers.perform_all()
593 test "it works when the registering user does not provide an email" do
594 clear_config([Pleroma.Emails.Mailer, :enabled], false)
595 clear_config([:instance, :account_activation_required], false)
596 clear_config([:instance, :account_approval_required], true)
598 cng = User.register_changeset(%User{}, @full_user_data |> Map.put(:email, ""))
600 # The user is still created
601 assert {:ok, %User{nickname: "nick"}} = User.register(cng)
604 ObanHelpers.perform_all()
608 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
609 clear_config([:instance, :account_activation_required], true)
613 |> Enum.each(fn key ->
614 params = Map.delete(@full_user_data, key)
615 changeset = User.register_changeset(%User{}, params)
617 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
621 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
622 clear_config([:instance, :account_activation_required], false)
626 |> Enum.each(fn key ->
627 params = Map.delete(@full_user_data, key)
628 changeset = User.register_changeset(%User{}, params)
630 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
634 test "it restricts certain nicknames" do
635 clear_config([User, :restricted_nicknames], ["about"])
636 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
638 assert is_binary(restricted_name)
642 |> Map.put(:nickname, restricted_name)
644 changeset = User.register_changeset(%User{}, params)
646 refute changeset.valid?
649 test "it is case-insensitive when restricting nicknames" do
650 clear_config([User, :restricted_nicknames], ["about"])
651 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
653 assert is_binary(restricted_name)
655 restricted_upcase_name = String.upcase(restricted_name)
659 |> Map.put(:nickname, restricted_upcase_name)
661 changeset = User.register_changeset(%User{}, params)
663 refute changeset.valid?
666 test "it blocks blacklisted email domains" do
667 clear_config([User, :email_blacklist], ["trolling.world"])
670 params = Map.put(@full_user_data, :email, "troll@trolling.world")
671 changeset = User.register_changeset(%User{}, params)
672 refute changeset.valid?
674 # Block with case-insensitive match
675 params = Map.put(@full_user_data, :email, "troll@TrOlLing.wOrld")
676 changeset = User.register_changeset(%User{}, params)
677 refute changeset.valid?
679 # Block with subdomain match
680 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
681 changeset = User.register_changeset(%User{}, params)
682 refute changeset.valid?
684 # Pass with different domains that are similar
685 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
686 changeset = User.register_changeset(%User{}, params)
687 assert changeset.valid?
689 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
690 changeset = User.register_changeset(%User{}, params)
691 assert changeset.valid?
694 test "it sets the password_hash, ap_id, private key and followers collection address" do
695 changeset = User.register_changeset(%User{}, @full_user_data)
697 assert changeset.valid?
699 assert is_binary(changeset.changes[:password_hash])
700 assert is_binary(changeset.changes[:keys])
701 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
702 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
705 test "it sets the 'accepts_chat_messages' set to true" do
706 changeset = User.register_changeset(%User{}, @full_user_data)
707 assert changeset.valid?
709 {:ok, user} = Repo.insert(changeset)
711 assert user.accepts_chat_messages
714 test "it creates a confirmed user" do
715 changeset = User.register_changeset(%User{}, @full_user_data)
716 assert changeset.valid?
718 {:ok, user} = Repo.insert(changeset)
720 assert user.is_confirmed
724 describe "user registration, with :account_activation_required" do
730 password_confirmation: "test",
731 email: "email@example.com"
733 setup do: clear_config([:instance, :account_activation_required], true)
735 test "it creates unconfirmed user" do
736 changeset = User.register_changeset(%User{}, @full_user_data)
737 assert changeset.valid?
739 {:ok, user} = Repo.insert(changeset)
741 refute user.is_confirmed
742 assert user.confirmation_token
745 test "it creates confirmed user if :confirmed option is given" do
746 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
747 assert changeset.valid?
749 {:ok, user} = Repo.insert(changeset)
751 assert user.is_confirmed
752 refute user.confirmation_token
756 describe "user registration, with :account_approval_required" do
762 password_confirmation: "test",
763 email: "email@example.com",
764 registration_reason: "I'm a cool guy :)"
766 setup do: clear_config([:instance, :account_approval_required], true)
768 test "it creates unapproved user" do
769 changeset = User.register_changeset(%User{}, @full_user_data)
770 assert changeset.valid?
772 {:ok, user} = Repo.insert(changeset)
774 refute user.is_approved
775 assert user.registration_reason == "I'm a cool guy :)"
778 test "it restricts length of registration reason" do
779 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
781 assert is_integer(reason_limit)
786 :registration_reason,
787 "Quia et nesciunt dolores numquam ipsam nisi sapiente soluta. Ullam repudiandae nisi quam porro officiis officiis ad. Consequatur animi velit ex quia. Odit voluptatem perferendis quia ut nisi. Dignissimos sit soluta atque aliquid dolorem ut dolorum ut. Labore voluptates iste iusto amet voluptatum earum. Ad fugit illum nam eos ut nemo. Pariatur ea fuga non aspernatur. Dignissimos debitis officia corporis est nisi ab et. Atque itaque alias eius voluptas minus. Accusamus numquam tempore occaecati in."
790 changeset = User.register_changeset(%User{}, params)
792 refute changeset.valid?
796 describe "user registration, with :birthday_required and :birthday_min_age" do
802 password_confirmation: "test",
803 email: "email@example.com"
807 clear_config([:instance, :birthday_required], true)
808 clear_config([:instance, :birthday_min_age], 18 * 365)
811 test "it passes when correct birth date is provided" do
812 today = Date.utc_today()
813 birthday = Date.add(today, -19 * 365)
817 |> Map.put(:birthday, birthday)
819 changeset = User.register_changeset(%User{}, params)
821 assert changeset.valid?
824 test "it fails when birth date is not provided" do
825 changeset = User.register_changeset(%User{}, @full_user_data)
827 refute changeset.valid?
830 test "it fails when provided invalid birth date" do
831 today = Date.utc_today()
832 birthday = Date.add(today, -17 * 365)
836 |> Map.put(:birthday, birthday)
838 changeset = User.register_changeset(%User{}, params)
840 refute changeset.valid?
844 describe "get_or_fetch/1" do
845 test "gets an existing user by nickname" do
847 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
849 assert user == fetched_user
852 test "gets an existing user by ap_id" do
853 ap_id = "http://mastodon.example.org/users/admin"
859 nickname: "admin@mastodon.example.org",
863 {:ok, fetched_user} = User.get_or_fetch(ap_id)
864 freshed_user = refresh_record(user)
865 assert freshed_user == fetched_user
868 test "gets an existing user by nickname starting with http" do
869 user = insert(:user, nickname: "httpssome")
870 {:ok, fetched_user} = User.get_or_fetch("httpssome")
872 assert user == fetched_user
876 describe "get_or_fetch/1 remote users with tld, while BE is running on a subdomain" do
877 setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
879 test "for mastodon" do
881 %{url: "https://example.com/.well-known/host-meta"} ->
884 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
887 %{url: "https://sub.example.com/.well-known/host-meta"} ->
891 "test/fixtures/webfinger/masto-host-meta.xml"
893 |> String.replace("{{domain}}", "sub.example.com")
896 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
900 "test/fixtures/webfinger/masto-webfinger.json"
902 |> String.replace("{{nickname}}", "a")
903 |> String.replace("{{domain}}", "example.com")
904 |> String.replace("{{subdomain}}", "sub.example.com"),
905 headers: [{"content-type", "application/jrd+json"}]
908 %{url: "https://sub.example.com/users/a"} ->
912 "test/fixtures/webfinger/masto-user.json"
914 |> String.replace("{{nickname}}", "a")
915 |> String.replace("{{domain}}", "sub.example.com"),
916 headers: [{"content-type", "application/activity+json"}]
919 %{url: "https://sub.example.com/users/a/collections/featured"} ->
923 File.read!("test/fixtures/users_mock/masto_featured.json")
924 |> String.replace("{{domain}}", "sub.example.com")
925 |> String.replace("{{nickname}}", "a"),
926 headers: [{"content-type", "application/activity+json"}]
930 ap_id = "a@example.com"
931 {:ok, fetched_user} = User.get_or_fetch(ap_id)
933 assert fetched_user.ap_id == "https://sub.example.com/users/a"
934 assert fetched_user.nickname == "a@example.com"
937 test "for pleroma" do
939 %{url: "https://example.com/.well-known/host-meta"} ->
942 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
945 %{url: "https://sub.example.com/.well-known/host-meta"} ->
949 "test/fixtures/webfinger/pleroma-host-meta.xml"
951 |> String.replace("{{domain}}", "sub.example.com")
954 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
958 "test/fixtures/webfinger/pleroma-webfinger.json"
960 |> String.replace("{{nickname}}", "a")
961 |> String.replace("{{domain}}", "example.com")
962 |> String.replace("{{subdomain}}", "sub.example.com"),
963 headers: [{"content-type", "application/jrd+json"}]
966 %{url: "https://sub.example.com/users/a"} ->
970 "test/fixtures/webfinger/pleroma-user.json"
972 |> String.replace("{{nickname}}", "a")
973 |> String.replace("{{domain}}", "sub.example.com"),
974 headers: [{"content-type", "application/activity+json"}]
978 ap_id = "a@example.com"
979 {:ok, fetched_user} = User.get_or_fetch(ap_id)
981 assert fetched_user.ap_id == "https://sub.example.com/users/a"
982 assert fetched_user.nickname == "a@example.com"
986 describe "fetching a user from nickname or trying to build one" do
987 test "gets an existing user" do
989 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
991 assert user == fetched_user
994 test "gets an existing user, case insensitive" do
995 user = insert(:user, nickname: "nick")
996 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
998 assert user == fetched_user
1001 test "gets an existing user by fully qualified nickname" do
1002 user = insert(:user)
1004 {:ok, fetched_user} =
1005 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
1007 assert user == fetched_user
1010 test "gets an existing user by fully qualified nickname, case insensitive" do
1011 user = insert(:user, nickname: "nick")
1012 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
1014 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
1016 assert user == fetched_user
1019 @tag capture_log: true
1020 test "returns nil if no user could be fetched" do
1021 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistent@social.heldscal.la")
1022 assert fetched_user == "not found nonexistent@social.heldscal.la"
1025 test "returns nil for nonexistent local user" do
1026 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistent")
1027 assert fetched_user == "not found nonexistent"
1030 test "updates an existing user, if stale" do
1031 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
1037 nickname: "admin@mastodon.example.org",
1038 ap_id: "http://mastodon.example.org/users/admin",
1039 last_refreshed_at: a_week_ago
1042 assert orig_user.last_refreshed_at == a_week_ago
1044 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
1048 refute user.last_refreshed_at == orig_user.last_refreshed_at
1051 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
1052 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
1058 nickname: "admin@mastodon.example.org",
1059 ap_id: "http://mastodon.example.org/users/harinezumigari",
1060 last_refreshed_at: a_week_ago
1063 assert orig_user.last_refreshed_at == a_week_ago
1065 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
1069 refute user.id == orig_user.id
1071 orig_user = User.get_by_id(orig_user.id)
1073 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
1076 @tag capture_log: true
1077 test "it returns the old user if stale, but unfetchable" do
1078 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
1084 nickname: "admin@mastodon.example.org",
1085 ap_id: "http://mastodon.example.org/users/raymoo",
1086 last_refreshed_at: a_week_ago
1089 assert orig_user.last_refreshed_at == a_week_ago
1091 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
1093 assert user.last_refreshed_at == orig_user.last_refreshed_at
1097 test "returns an ap_id for a user" do
1098 user = insert(:user)
1100 assert User.ap_id(user) ==
1101 Pleroma.Web.Router.Helpers.user_feed_url(
1102 Pleroma.Web.Endpoint,
1108 test "returns an ap_followers link for a user" do
1109 user = insert(:user)
1111 assert User.ap_followers(user) ==
1112 Pleroma.Web.Router.Helpers.user_feed_url(
1113 Pleroma.Web.Endpoint,
1119 describe "remote user changeset" do
1125 avatar: %{some: "avatar"}
1127 setup do: clear_config([:instance, :user_bio_length])
1128 setup do: clear_config([:instance, :user_name_length])
1130 test "it confirms validity" do
1131 cs = User.remote_user_changeset(@valid_remote)
1135 test "it sets the follower_address" do
1136 cs = User.remote_user_changeset(@valid_remote)
1137 # remote users get a fake local follower address
1138 assert cs.changes.follower_address ==
1139 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
1142 test "it enforces the fqn format for nicknames" do
1143 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
1144 assert Ecto.Changeset.get_field(cs, :local) == false
1145 assert cs.changes.avatar
1149 test "it has required fields" do
1151 |> Enum.each(fn field ->
1152 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
1157 test "it is invalid given a local user" do
1158 user = insert(:user)
1159 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
1165 describe "followers and friends" do
1166 test "gets all followers for a given user" do
1167 user = insert(:user)
1168 follower_one = insert(:user)
1169 follower_two = insert(:user)
1170 not_follower = insert(:user)
1172 {:ok, follower_one, user} = User.follow(follower_one, user)
1173 {:ok, follower_two, user} = User.follow(follower_two, user)
1175 res = User.get_followers(user)
1177 assert Enum.member?(res, follower_one)
1178 assert Enum.member?(res, follower_two)
1179 refute Enum.member?(res, not_follower)
1182 test "gets all friends (followed users) for a given user" do
1183 user = insert(:user)
1184 followed_one = insert(:user)
1185 followed_two = insert(:user)
1186 not_followed = insert(:user)
1188 {:ok, user, followed_one} = User.follow(user, followed_one)
1189 {:ok, user, followed_two} = User.follow(user, followed_two)
1191 res = User.get_friends(user)
1193 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
1194 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
1195 assert Enum.member?(res, followed_one)
1196 assert Enum.member?(res, followed_two)
1197 refute Enum.member?(res, not_followed)
1201 describe "updating note and follower count" do
1202 test "it sets the note_count property" do
1203 note = insert(:note)
1205 user = User.get_cached_by_ap_id(note.data["actor"])
1207 assert user.note_count == 0
1209 {:ok, user} = User.update_note_count(user)
1211 assert user.note_count == 1
1214 test "it increases the note_count property" do
1215 note = insert(:note)
1216 user = User.get_cached_by_ap_id(note.data["actor"])
1218 assert user.note_count == 0
1220 {:ok, user} = User.increase_note_count(user)
1222 assert user.note_count == 1
1224 {:ok, user} = User.increase_note_count(user)
1226 assert user.note_count == 2
1229 test "it decreases the note_count property" do
1230 note = insert(:note)
1231 user = User.get_cached_by_ap_id(note.data["actor"])
1233 assert user.note_count == 0
1235 {:ok, user} = User.increase_note_count(user)
1237 assert user.note_count == 1
1239 {:ok, user} = User.decrease_note_count(user)
1241 assert user.note_count == 0
1243 {:ok, user} = User.decrease_note_count(user)
1245 assert user.note_count == 0
1248 test "it sets the follower_count property" do
1249 user = insert(:user)
1250 follower = insert(:user)
1252 User.follow(follower, user)
1254 assert user.follower_count == 0
1256 {:ok, user} = User.update_follower_count(user)
1258 assert user.follower_count == 1
1263 test "it mutes people" do
1264 user = insert(:user)
1265 muted_user = insert(:user)
1267 refute User.mutes?(user, muted_user)
1268 refute User.muted_notifications?(user, muted_user)
1270 {:ok, _user_relationships} = User.mute(user, muted_user)
1272 assert User.mutes?(user, muted_user)
1273 assert User.muted_notifications?(user, muted_user)
1277 user = insert(:user)
1278 muted_user = insert(:user)
1280 {:ok, _user_relationships} = User.mute(user, muted_user, %{duration: 60})
1281 assert User.mutes?(user, muted_user)
1283 worker = Pleroma.Workers.MuteExpireWorker
1284 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1291 assert :ok = perform_job(worker, args)
1293 refute User.mutes?(user, muted_user)
1294 refute User.muted_notifications?(user, muted_user)
1297 test "it unmutes users" do
1298 user = insert(:user)
1299 muted_user = insert(:user)
1301 {:ok, _user_relationships} = User.mute(user, muted_user)
1302 {:ok, _user_mute} = User.unmute(user, muted_user)
1304 refute User.mutes?(user, muted_user)
1305 refute User.muted_notifications?(user, muted_user)
1308 test "it unmutes users by id" do
1309 user = insert(:user)
1310 muted_user = insert(:user)
1312 {:ok, _user_relationships} = User.mute(user, muted_user)
1313 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1315 refute User.mutes?(user, muted_user)
1316 refute User.muted_notifications?(user, muted_user)
1319 test "it mutes user without notifications" do
1320 user = insert(:user)
1321 muted_user = insert(:user)
1323 refute User.mutes?(user, muted_user)
1324 refute User.muted_notifications?(user, muted_user)
1326 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1328 assert User.mutes?(user, muted_user)
1329 refute User.muted_notifications?(user, muted_user)
1333 describe "blocks" do
1334 test "it blocks people" do
1335 user = insert(:user)
1336 blocked_user = insert(:user)
1338 refute User.blocks?(user, blocked_user)
1340 {:ok, _user_relationship} = User.block(user, blocked_user)
1342 assert User.blocks?(user, blocked_user)
1345 test "it unblocks users" do
1346 user = insert(:user)
1347 blocked_user = insert(:user)
1349 {:ok, _user_relationship} = User.block(user, blocked_user)
1350 {:ok, _user_block} = User.unblock(user, blocked_user)
1352 refute User.blocks?(user, blocked_user)
1355 test "blocks tear down cyclical follow relationships" do
1356 blocker = insert(:user)
1357 blocked = insert(:user)
1359 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1360 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1362 assert User.following?(blocker, blocked)
1363 assert User.following?(blocked, blocker)
1365 {:ok, _user_relationship} = User.block(blocker, blocked)
1366 blocked = User.get_cached_by_id(blocked.id)
1368 assert User.blocks?(blocker, blocked)
1370 refute User.following?(blocker, blocked)
1371 refute User.following?(blocked, blocker)
1374 test "blocks tear down blocker->blocked follow relationships" do
1375 blocker = insert(:user)
1376 blocked = insert(:user)
1378 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1380 assert User.following?(blocker, blocked)
1381 refute User.following?(blocked, blocker)
1383 {:ok, _user_relationship} = User.block(blocker, blocked)
1384 blocked = User.get_cached_by_id(blocked.id)
1386 assert User.blocks?(blocker, blocked)
1388 refute User.following?(blocker, blocked)
1389 refute User.following?(blocked, blocker)
1392 test "blocks tear down blocked->blocker follow relationships" do
1393 blocker = insert(:user)
1394 blocked = insert(:user)
1396 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1398 refute User.following?(blocker, blocked)
1399 assert User.following?(blocked, blocker)
1401 {:ok, _user_relationship} = User.block(blocker, blocked)
1402 blocked = User.get_cached_by_id(blocked.id)
1404 assert User.blocks?(blocker, blocked)
1406 refute User.following?(blocker, blocked)
1407 refute User.following?(blocked, blocker)
1410 test "blocks tear down blocked->blocker subscription relationships" do
1411 blocker = insert(:user)
1412 blocked = insert(:user)
1414 {:ok, _subscription} = User.subscribe(blocked, blocker)
1416 assert User.subscribed_to?(blocked, blocker)
1417 refute User.subscribed_to?(blocker, blocked)
1419 {:ok, _user_relationship} = User.block(blocker, blocked)
1421 assert User.blocks?(blocker, blocked)
1422 refute User.subscribed_to?(blocker, blocked)
1423 refute User.subscribed_to?(blocked, blocker)
1427 describe "domain blocking" do
1428 test "blocks domains" do
1429 user = insert(:user)
1430 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1432 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1434 assert User.blocks?(user, collateral_user)
1437 test "does not block domain with same end" do
1438 user = insert(:user)
1441 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1443 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1445 refute User.blocks?(user, collateral_user)
1448 test "does not block domain with same end if wildcard added" do
1449 user = insert(:user)
1452 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1454 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1456 refute User.blocks?(user, collateral_user)
1459 test "blocks domain with wildcard for subdomain" do
1460 user = insert(:user)
1462 user_from_subdomain =
1463 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1465 user_with_two_subdomains =
1467 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1470 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1472 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1474 assert User.blocks?(user, user_from_subdomain)
1475 assert User.blocks?(user, user_with_two_subdomains)
1476 assert User.blocks?(user, user_domain)
1479 test "unblocks domains" do
1480 user = insert(:user)
1481 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1483 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1484 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1486 refute User.blocks?(user, collateral_user)
1489 test "follows take precedence over domain blocks" do
1490 user = insert(:user)
1491 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1493 {:ok, user} = User.block_domain(user, "meanies.social")
1494 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1496 refute User.blocks?(user, good_eggo)
1500 describe "get_recipients_from_activity" do
1501 test "works for announces" do
1502 actor = insert(:user)
1503 user = insert(:user, local: true)
1505 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1506 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1508 recipients = User.get_recipients_from_activity(announce)
1510 assert user in recipients
1513 test "get recipients" do
1514 actor = insert(:user)
1515 user = insert(:user, local: true)
1516 user_two = insert(:user, local: false)
1517 addressed = insert(:user, local: true)
1518 addressed_remote = insert(:user, local: false)
1521 CommonAPI.post(actor, %{
1522 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1525 assert Enum.map([actor, addressed], & &1.ap_id) --
1526 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1528 {:ok, user, actor} = User.follow(user, actor)
1529 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1530 recipients = User.get_recipients_from_activity(activity)
1531 assert length(recipients) == 3
1532 assert user in recipients
1533 assert addressed in recipients
1536 test "has following" do
1537 actor = insert(:user)
1538 user = insert(:user)
1539 user_two = insert(:user)
1540 addressed = insert(:user, local: true)
1543 CommonAPI.post(actor, %{
1544 status: "hey @#{addressed.nickname}"
1547 assert Enum.map([actor, addressed], & &1.ap_id) --
1548 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1550 {:ok, _actor, _user} = User.follow(actor, user)
1551 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1552 recipients = User.get_recipients_from_activity(activity)
1553 assert length(recipients) == 2
1554 assert addressed in recipients
1558 describe ".set_activation" do
1559 test "can de-activate then re-activate a user" do
1560 user = insert(:user)
1561 assert user.is_active
1562 {:ok, user} = User.set_activation(user, false)
1563 refute user.is_active
1564 {:ok, user} = User.set_activation(user, true)
1565 assert user.is_active
1568 test "hide a user from followers" do
1569 user = insert(:user)
1570 user2 = insert(:user)
1572 {:ok, user, user2} = User.follow(user, user2)
1573 {:ok, _user} = User.set_activation(user, false)
1575 user2 = User.get_cached_by_id(user2.id)
1577 assert user2.follower_count == 0
1578 assert [] = User.get_followers(user2)
1581 test "hide a user from friends" do
1582 user = insert(:user)
1583 user2 = insert(:user)
1585 {:ok, user2, user} = User.follow(user2, user)
1586 assert user2.following_count == 1
1587 assert User.following_count(user2) == 1
1589 {:ok, _user} = User.set_activation(user, false)
1591 user2 = User.get_cached_by_id(user2.id)
1593 assert refresh_record(user2).following_count == 0
1594 assert user2.following_count == 0
1595 assert User.following_count(user2) == 0
1596 assert [] = User.get_friends(user2)
1599 test "hide a user's statuses from timelines and notifications" do
1600 user = insert(:user)
1601 user2 = insert(:user)
1603 {:ok, user2, user} = User.follow(user2, user)
1605 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1607 activity = Repo.preload(activity, :bookmark)
1609 [notification] = Pleroma.Notification.for_user(user2)
1610 assert notification.activity.id == activity.id
1612 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1614 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1615 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1619 {:ok, _user} = User.set_activation(user, false)
1621 assert [] == ActivityPub.fetch_public_activities(%{})
1622 assert [] == Pleroma.Notification.for_user(user2)
1625 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1631 describe "approve" do
1632 test "approves a user" do
1633 user = insert(:user, is_approved: false)
1634 refute user.is_approved
1635 {:ok, user} = User.approve(user)
1636 assert user.is_approved
1639 test "approves a list of users" do
1640 unapproved_users = [
1641 insert(:user, is_approved: false),
1642 insert(:user, is_approved: false),
1643 insert(:user, is_approved: false)
1646 {:ok, users} = User.approve(unapproved_users)
1648 assert Enum.count(users) == 3
1650 Enum.each(users, fn user ->
1651 assert user.is_approved
1655 test "it sends welcome email if it is set" do
1656 clear_config([:welcome, :email, :enabled], true)
1657 clear_config([:welcome, :email, :sender], "tester@test.me")
1659 user = insert(:user, is_approved: false)
1660 welcome_user = insert(:user, email: "tester@test.me")
1661 instance_name = Pleroma.Config.get([:instance, :name])
1665 ObanHelpers.perform_all()
1668 from: {instance_name, welcome_user.email},
1669 to: {user.name, user.email},
1670 html_body: "Welcome to #{instance_name}"
1674 test "approving an approved user does not trigger post-register actions" do
1675 clear_config([:welcome, :email, :enabled], true)
1677 user = insert(:user, is_approved: true)
1680 ObanHelpers.perform_all()
1682 assert_no_email_sent()
1686 describe "confirm" do
1687 test "confirms a user" do
1688 user = insert(:user, is_confirmed: false)
1689 refute user.is_confirmed
1690 {:ok, user} = User.confirm(user)
1691 assert user.is_confirmed
1694 test "confirms a list of users" do
1695 unconfirmed_users = [
1696 insert(:user, is_confirmed: false),
1697 insert(:user, is_confirmed: false),
1698 insert(:user, is_confirmed: false)
1701 {:ok, users} = User.confirm(unconfirmed_users)
1703 assert Enum.count(users) == 3
1705 Enum.each(users, fn user ->
1706 assert user.is_confirmed
1710 test "sends approval emails when `is_approved: false`" do
1711 admin = insert(:user, is_admin: true)
1712 user = insert(:user, is_confirmed: false, is_approved: false)
1715 ObanHelpers.perform_all()
1717 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1718 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1720 notify_email = Pleroma.Config.get([:instance, :notify_email])
1721 instance_name = Pleroma.Config.get([:instance, :name])
1723 # User approval email
1725 from: {instance_name, notify_email},
1726 to: {user.name, user.email},
1727 html_body: user_email.html_body
1732 from: {instance_name, notify_email},
1733 to: {admin.name, admin.email},
1734 html_body: admin_email.html_body
1738 test "confirming a confirmed user does not trigger post-register actions" do
1739 user = insert(:user, is_confirmed: true, is_approved: false)
1742 ObanHelpers.perform_all()
1744 assert_no_email_sent()
1748 describe "delete" do
1750 {:ok, user} = insert(:user) |> User.set_cache()
1755 setup do: clear_config([:instance, :federating])
1757 test ".delete_user_activities deletes all create activities", %{user: user} do
1758 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1760 User.delete_user_activities(user)
1762 # TODO: Test removal favorites, repeats, delete activities.
1763 refute Activity.get_by_id(activity.id)
1766 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1767 follower = insert(:user)
1768 {:ok, follower, user} = User.follow(follower, user)
1770 locked_user = insert(:user, name: "locked", is_locked: true)
1771 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1773 object = insert(:note, user: user)
1774 activity = insert(:note_activity, user: user, note: object)
1776 object_two = insert(:note, user: follower)
1777 activity_two = insert(:note_activity, user: follower, note: object_two)
1779 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1780 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1781 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1783 {:ok, job} = User.delete(user)
1784 {:ok, _user} = ObanHelpers.perform(job)
1786 follower = User.get_cached_by_id(follower.id)
1788 refute User.following?(follower, user)
1789 assert %{is_active: false} = User.get_by_id(user.id)
1791 assert [] == User.get_follow_requests(locked_user)
1795 |> Activity.Queries.by_actor()
1797 |> Enum.map(fn act -> act.data["type"] end)
1799 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1801 refute Activity.get_by_id(activity.id)
1802 refute Activity.get_by_id(like.id)
1803 refute Activity.get_by_id(like_two.id)
1804 refute Activity.get_by_id(repeat.id)
1808 test "delete/1 when confirmation is pending deletes the user" do
1809 clear_config([:instance, :account_activation_required], true)
1810 user = insert(:user, is_confirmed: false)
1812 {:ok, job} = User.delete(user)
1813 {:ok, _} = ObanHelpers.perform(job)
1815 refute User.get_cached_by_id(user.id)
1816 refute User.get_by_id(user.id)
1819 test "delete/1 when approval is pending deletes the user" do
1820 user = insert(:user, is_approved: false)
1822 {:ok, job} = User.delete(user)
1823 {:ok, _} = ObanHelpers.perform(job)
1825 refute User.get_cached_by_id(user.id)
1826 refute User.get_by_id(user.id)
1829 test "delete/1 purges a user when they wouldn't be fully deleted" do
1834 password_hash: "pdfk2$1b3n159001",
1835 keys: "RSA begin buplic key",
1836 public_key: "--PRIVATE KEYE--",
1837 avatar: %{"a" => "b"},
1839 banner: %{"a" => "b"},
1840 background: %{"a" => "b"},
1843 following_count: 9001,
1846 password_reset_pending: true,
1848 registration_reason: "ahhhhh",
1849 confirmation_token: "qqqq",
1850 domain_blocks: ["lain.com"],
1854 mascot: %{"a" => "b"},
1855 emoji: %{"a" => "b"},
1856 pleroma_settings_store: %{"q" => "x"},
1857 fields: [%{"gg" => "qq"}],
1858 raw_fields: [%{"gg" => "qq"}],
1859 is_discoverable: true,
1860 also_known_as: ["https://lol.olo/users/loll"]
1863 {:ok, job} = User.delete(user)
1864 {:ok, _} = ObanHelpers.perform(job)
1865 user = User.get_by_id(user.id)
1873 keys: "RSA begin buplic key",
1874 public_key: "--PRIVATE KEYE--",
1877 last_refreshed_at: nil,
1878 last_digest_emailed_at: nil,
1886 password_reset_pending: false,
1888 registration_reason: nil,
1889 confirmation_token: nil,
1892 is_moderator: false,
1896 pleroma_settings_store: %{},
1899 is_discoverable: false,
1904 test "delete/1 purges a remote user" do
1908 avatar: %{"a" => "b"},
1909 banner: %{"a" => "b"},
1913 {:ok, job} = User.delete(user)
1914 {:ok, _} = ObanHelpers.perform(job)
1915 user = User.get_by_id(user.id)
1917 assert user.name == nil
1918 assert user.avatar == %{}
1919 assert user.banner == %{}
1922 describe "set_suggestion" do
1923 test "suggests a user" do
1924 user = insert(:user, is_suggested: false)
1925 refute user.is_suggested
1926 {:ok, user} = User.set_suggestion(user, true)
1927 assert user.is_suggested
1930 test "suggests a list of users" do
1931 unsuggested_users = [
1932 insert(:user, is_suggested: false),
1933 insert(:user, is_suggested: false),
1934 insert(:user, is_suggested: false)
1937 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1939 assert Enum.count(users) == 3
1941 Enum.each(users, fn user ->
1942 assert user.is_suggested
1946 test "unsuggests a user" do
1947 user = insert(:user, is_suggested: true)
1948 assert user.is_suggested
1949 {:ok, user} = User.set_suggestion(user, false)
1950 refute user.is_suggested
1954 test "get_public_key_for_ap_id returns correctly for user that's not in the db" do
1955 assert :error = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1958 describe "per-user rich-text filtering" do
1959 test "html_filter_policy returns default policies, when rich-text is enabled" do
1960 user = insert(:user)
1962 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1965 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1966 user = insert(:user, no_rich_text: true)
1968 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1972 describe "caching" do
1973 test "invalidate_cache works" do
1974 user = insert(:user)
1976 User.set_cache(user)
1977 User.invalidate_cache(user)
1979 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1980 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1983 test "User.delete() plugs any possible zombie objects" do
1984 user = insert(:user)
1986 {:ok, job} = User.delete(user)
1987 {:ok, _} = ObanHelpers.perform(job)
1989 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1991 assert cached_user != user
1993 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1995 assert cached_user != user
1999 describe "account_status/1" do
2000 setup do: clear_config([:instance, :account_activation_required])
2002 test "return confirmation_pending for unconfirm user" do
2003 clear_config([:instance, :account_activation_required], true)
2004 user = insert(:user, is_confirmed: false)
2005 assert User.account_status(user) == :confirmation_pending
2008 test "return active for confirmed user" do
2009 clear_config([:instance, :account_activation_required], true)
2010 user = insert(:user, is_confirmed: true)
2011 assert User.account_status(user) == :active
2014 test "return active for remote user" do
2015 user = insert(:user, local: false)
2016 assert User.account_status(user) == :active
2019 test "returns :password_reset_pending for user with reset password" do
2020 user = insert(:user, password_reset_pending: true)
2021 assert User.account_status(user) == :password_reset_pending
2024 test "returns :deactivated for deactivated user" do
2025 user = insert(:user, local: true, is_confirmed: true, is_active: false)
2026 assert User.account_status(user) == :deactivated
2029 test "returns :approval_pending for unapproved user" do
2030 user = insert(:user, local: true, is_approved: false)
2031 assert User.account_status(user) == :approval_pending
2033 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
2034 assert User.account_status(user) == :approval_pending
2038 describe "privileged?/1" do
2040 clear_config([:instance, :admin_privileges], [:cofe, :suya])
2041 clear_config([:instance, :moderator_privileges], [:cofe, :suya])
2044 test "returns false for unprivileged users" do
2045 user = insert(:user, local: true)
2047 refute User.privileged?(user, :cofe)
2050 test "returns false for remote users" do
2051 user = insert(:user, local: false)
2052 remote_admin_user = insert(:user, local: false, is_admin: true)
2054 refute User.privileged?(user, :cofe)
2055 refute User.privileged?(remote_admin_user, :cofe)
2058 test "returns true for local moderators if, and only if, they are privileged" do
2059 user = insert(:user, local: true, is_moderator: true)
2061 assert User.privileged?(user, :cofe)
2063 clear_config([:instance, :moderator_privileges], [])
2065 refute User.privileged?(user, :cofe)
2068 test "returns true for local admins if, and only if, they are privileged" do
2069 user = insert(:user, local: true, is_admin: true)
2071 assert User.privileged?(user, :cofe)
2073 clear_config([:instance, :admin_privileges], [])
2075 refute User.privileged?(user, :cofe)
2079 describe "privileges/1" do
2081 clear_config([:instance, :moderator_privileges], [:cofe, :only_moderator])
2082 clear_config([:instance, :admin_privileges], [:cofe, :only_admin])
2085 test "returns empty list for users without roles" do
2086 user = insert(:user, local: true)
2088 assert [] == User.privileges(user)
2091 test "returns list of privileges for moderators" do
2092 moderator = insert(:user, is_moderator: true, local: true)
2094 assert [:cofe, :only_moderator] == User.privileges(moderator) |> Enum.sort()
2097 test "returns list of privileges for admins" do
2098 admin = insert(:user, is_admin: true, local: true)
2100 assert [:cofe, :only_admin] == User.privileges(admin) |> Enum.sort()
2103 test "returns list of unique privileges for users who are both moderator and admin" do
2104 moderator_admin = insert(:user, is_moderator: true, is_admin: true, local: true)
2106 assert [:cofe, :only_admin, :only_moderator] ==
2107 User.privileges(moderator_admin) |> Enum.sort()
2110 test "returns empty list for remote users" do
2111 remote_moderator_admin = insert(:user, is_moderator: true, is_admin: true, local: false)
2113 assert [] == User.privileges(remote_moderator_admin)
2117 describe "invisible?/1" do
2118 test "returns true for an invisible user" do
2119 user = insert(:user, local: true, invisible: true)
2121 assert User.invisible?(user)
2124 test "returns false for a non-invisible user" do
2125 user = insert(:user, local: true)
2127 refute User.invisible?(user)
2131 describe "visible_for/2" do
2132 test "returns true when the account is itself" do
2133 user = insert(:user, local: true)
2135 assert User.visible_for(user, user) == :visible
2138 test "returns false when the account is unconfirmed and confirmation is required" do
2139 clear_config([:instance, :account_activation_required], true)
2141 user = insert(:user, local: true, is_confirmed: false)
2142 other_user = insert(:user, local: true)
2144 refute User.visible_for(user, other_user) == :visible
2147 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
2148 clear_config([:instance, :account_activation_required], true)
2150 user = insert(:user, local: false, is_confirmed: false)
2151 other_user = insert(:user, local: true)
2153 assert User.visible_for(user, other_user) == :visible
2156 test "returns true when the account is unconfirmed and being viewed by a privileged account (privilege :users_manage_activation_state, confirmation required)" do
2157 clear_config([:instance, :account_activation_required], true)
2158 clear_config([:instance, :admin_privileges], [:users_manage_activation_state])
2160 user = insert(:user, local: true, is_confirmed: false)
2161 other_user = insert(:user, local: true, is_admin: true)
2163 assert User.visible_for(user, other_user) == :visible
2165 clear_config([:instance, :admin_privileges], [])
2167 refute User.visible_for(user, other_user) == :visible
2171 describe "all_users_with_privilege/1" do
2174 user: insert(:user, local: true, is_admin: false, is_moderator: false),
2175 moderator_user: insert(:user, local: true, is_admin: false, is_moderator: true),
2176 admin_user: insert(:user, local: true, is_admin: true, is_moderator: false),
2177 admin_moderator_user: insert(:user, local: true, is_admin: true, is_moderator: true),
2178 remote_user: insert(:user, local: false, is_admin: true, is_moderator: true),
2180 insert(:user, local: true, is_admin: true, is_moderator: true, is_active: false)
2184 test "doesn't return any users when there are no privileged roles" do
2185 clear_config([:instance, :admin_privileges], [])
2186 clear_config([:instance, :moderator_privileges], [])
2188 assert [] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2191 test "returns moderator users if they are privileged", %{
2192 moderator_user: moderator_user,
2193 admin_moderator_user: admin_moderator_user
2195 clear_config([:instance, :admin_privileges], [])
2196 clear_config([:instance, :moderator_privileges], [:cofe])
2198 assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2199 assert moderator_user in User.all_users_with_privilege(:cofe)
2200 assert admin_moderator_user in User.all_users_with_privilege(:cofe)
2203 test "returns admin users if they are privileged", %{
2204 admin_user: admin_user,
2205 admin_moderator_user: admin_moderator_user
2207 clear_config([:instance, :admin_privileges], [:cofe])
2208 clear_config([:instance, :moderator_privileges], [])
2210 assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2211 assert admin_user in User.all_users_with_privilege(:cofe)
2212 assert admin_moderator_user in User.all_users_with_privilege(:cofe)
2215 test "returns admin and moderator users if they are both privileged", %{
2216 moderator_user: moderator_user,
2217 admin_user: admin_user,
2218 admin_moderator_user: admin_moderator_user
2220 clear_config([:instance, :admin_privileges], [:cofe])
2221 clear_config([:instance, :moderator_privileges], [:cofe])
2223 assert [_, _, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2224 assert admin_user in User.all_users_with_privilege(:cofe)
2225 assert moderator_user in User.all_users_with_privilege(:cofe)
2226 assert admin_moderator_user in User.all_users_with_privilege(:cofe)
2230 describe "parse_bio/2" do
2231 test "preserves hosts in user links text" do
2232 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
2233 user = insert(:user)
2234 bio = "A.k.a. @nick@domain.com"
2237 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{remote_user.ap_id}" rel="ugc">@<span>nick@domain.com</span></a></span>)
2239 assert expected_text == User.parse_bio(bio, user)
2242 test "Adds rel=me on linkbacked urls" do
2243 user = insert(:user, ap_id: "https://social.example.org/users/lain")
2245 bio = "http://example.com/rel_me/null"
2246 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
2247 assert expected_text == User.parse_bio(bio, user)
2249 bio = "http://example.com/rel_me/link"
2250 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2251 assert expected_text == User.parse_bio(bio, user)
2253 bio = "http://example.com/rel_me/anchor"
2254 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2255 assert expected_text == User.parse_bio(bio, user)
2259 test "follower count is updated when a follower is blocked" do
2260 user = insert(:user)
2261 follower = insert(:user)
2262 follower2 = insert(:user)
2263 follower3 = insert(:user)
2265 {:ok, follower, user} = User.follow(follower, user)
2266 {:ok, _follower2, _user} = User.follow(follower2, user)
2267 {:ok, _follower3, _user} = User.follow(follower3, user)
2269 {:ok, _user_relationship} = User.block(user, follower)
2270 user = refresh_record(user)
2272 assert user.follower_count == 2
2275 describe "list_inactive_users_query/1" do
2276 defp days_ago(days) do
2278 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
2279 -days * 60 * 60 * 24,
2284 test "Users are inactive by default" do
2288 Enum.map(1..total, fn _ ->
2289 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2292 inactive_users_ids =
2293 Pleroma.User.list_inactive_users_query()
2294 |> Pleroma.Repo.all()
2295 |> Enum.map(& &1.id)
2297 Enum.each(users, fn user ->
2298 assert user.id in inactive_users_ids
2302 test "Only includes users who has no recent activity" do
2306 Enum.map(1..total, fn _ ->
2307 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2310 {inactive, active} = Enum.split(users, trunc(total / 2))
2312 Enum.map(active, fn user ->
2313 to = Enum.random(users -- [user])
2316 CommonAPI.post(user, %{
2317 status: "hey @#{to.nickname}"
2321 inactive_users_ids =
2322 Pleroma.User.list_inactive_users_query()
2323 |> Pleroma.Repo.all()
2324 |> Enum.map(& &1.id)
2326 Enum.each(active, fn user ->
2327 refute user.id in inactive_users_ids
2330 Enum.each(inactive, fn user ->
2331 assert user.id in inactive_users_ids
2335 test "Only includes users with no read notifications" do
2339 Enum.map(1..total, fn _ ->
2340 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2343 [sender | recipients] = users
2344 {inactive, active} = Enum.split(recipients, trunc(total / 2))
2346 Enum.each(recipients, fn to ->
2348 CommonAPI.post(sender, %{
2349 status: "hey @#{to.nickname}"
2353 CommonAPI.post(sender, %{
2354 status: "hey again @#{to.nickname}"
2358 Enum.each(active, fn user ->
2359 [n1, _n2] = Pleroma.Notification.for_user(user)
2360 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2363 inactive_users_ids =
2364 Pleroma.User.list_inactive_users_query()
2365 |> Pleroma.Repo.all()
2366 |> Enum.map(& &1.id)
2368 Enum.each(active, fn user ->
2369 refute user.id in inactive_users_ids
2372 Enum.each(inactive, fn user ->
2373 assert user.id in inactive_users_ids
2378 describe "get_ap_ids_by_nicknames" do
2379 test "it returns a list of AP ids for a given set of nicknames" do
2380 user = insert(:user)
2381 user_two = insert(:user)
2383 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2384 assert length(ap_ids) == 2
2385 assert user.ap_id in ap_ids
2386 assert user_two.ap_id in ap_ids
2389 test "it returns a list of AP ids in the same order" do
2390 user = insert(:user)
2391 user_two = insert(:user)
2392 user_three = insert(:user)
2395 User.get_ap_ids_by_nicknames([user.nickname, user_three.nickname, user_two.nickname])
2397 assert [user.ap_id, user_three.ap_id, user_two.ap_id] == ap_ids
2401 describe "sync followers count" do
2403 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2404 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2405 insert(:user, local: true)
2406 insert(:user, local: false, is_active: false)
2407 {:ok, user1: user1, user2: user2}
2410 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2411 [fdb_user1] = User.external_users(limit: 1)
2413 assert fdb_user1.ap_id
2414 assert fdb_user1.ap_id == user1.ap_id
2415 assert fdb_user1.id == user1.id
2417 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2419 assert fdb_user2.ap_id
2420 assert fdb_user2.ap_id == user2.ap_id
2421 assert fdb_user2.id == user2.id
2423 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2427 describe "internal?/1" do
2428 test "non-internal user returns false" do
2429 user = insert(:user)
2430 refute User.internal?(user)
2433 test "user with no nickname returns true" do
2434 user = insert(:user, %{nickname: nil})
2435 assert User.internal?(user)
2438 test "user with internal-prefixed nickname returns true" do
2439 user = insert(:user, %{nickname: "internal.test"})
2440 assert User.internal?(user)
2444 describe "update_and_set_cache/1" do
2445 test "returns error when user is stale instead Ecto.StaleEntryError" do
2446 user = insert(:user)
2448 changeset = Ecto.Changeset.change(user, bio: "test")
2452 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2453 User.update_and_set_cache(changeset)
2456 test "performs update cache if user updated" do
2457 user = insert(:user)
2458 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2460 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2462 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2463 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2464 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2468 describe "following/followers synchronization" do
2469 setup do: clear_config([:instance, :external_user_synchronization])
2471 test "updates the counters normally on following/getting a follow when disabled" do
2472 clear_config([:instance, :external_user_synchronization], false)
2473 user = insert(:user)
2478 follower_address: "http://localhost:4001/users/masto_closed/followers",
2479 following_address: "http://localhost:4001/users/masto_closed/following"
2482 assert other_user.following_count == 0
2483 assert other_user.follower_count == 0
2485 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2487 assert user.following_count == 1
2488 assert other_user.follower_count == 1
2491 test "synchronizes the counters with the remote instance for the followed when enabled" do
2492 clear_config([:instance, :external_user_synchronization], false)
2494 user = insert(:user)
2499 follower_address: "http://localhost:4001/users/masto_closed/followers",
2500 following_address: "http://localhost:4001/users/masto_closed/following"
2503 assert other_user.following_count == 0
2504 assert other_user.follower_count == 0
2506 clear_config([:instance, :external_user_synchronization], true)
2507 {:ok, _user, other_user} = User.follow(user, other_user)
2509 assert other_user.follower_count == 437
2512 test "synchronizes the counters with the remote instance for the follower when enabled" do
2513 clear_config([:instance, :external_user_synchronization], false)
2515 user = insert(:user)
2520 follower_address: "http://localhost:4001/users/masto_closed/followers",
2521 following_address: "http://localhost:4001/users/masto_closed/following"
2524 assert other_user.following_count == 0
2525 assert other_user.follower_count == 0
2527 clear_config([:instance, :external_user_synchronization], true)
2528 {:ok, other_user, _user} = User.follow(other_user, user)
2530 assert other_user.following_count == 152
2534 describe "change_email/2" do
2536 [user: insert(:user)]
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])
2543 Pleroma.Config.put([:instance, :account_activation_required], true)
2547 [:instance, :account_activation_required],
2548 orig_account_activation_required
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)
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])
2560 Pleroma.Config.put([:instance, :account_activation_required], false)
2564 [:instance, :account_activation_required],
2565 orig_account_activation_required
2569 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2570 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2573 test "non unique email returns error", %{user: user} do
2574 %{email: email} = insert(:user)
2576 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2577 User.change_email(user, email)
2580 test "invalid email returns error", %{user: user} do
2581 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2582 User.change_email(user, "cofe")
2585 test "changes email", %{user: user} do
2586 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2589 test "adds email", %{user: user} do
2590 orig_account_activation_required =
2591 Pleroma.Config.get([:instance, :account_activation_required])
2593 Pleroma.Config.put([:instance, :account_activation_required], false)
2597 [:instance, :account_activation_required],
2598 orig_account_activation_required
2602 assert {:ok, _} = User.change_email(user, "")
2603 Pleroma.Config.put([:instance, :account_activation_required], true)
2605 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2609 describe "get_cached_by_nickname_or_id" do
2611 local_user = insert(:user)
2612 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2614 [local_user: local_user, remote_user: remote_user]
2617 setup do: clear_config([:instance, :limit_to_local_content])
2619 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2620 remote_user: remote_user
2622 clear_config([:instance, :limit_to_local_content], false)
2623 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2625 clear_config([:instance, :limit_to_local_content], true)
2626 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2628 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2629 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
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)
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)
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)
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)
2655 clear_config([:instance, :limit_to_local_content], true)
2656 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2658 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2659 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2663 describe "update_email_notifications/2" do
2665 user = insert(:user, email_notifications: %{"digest" => true})
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
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"
2685 describe "full_nickname/1" do
2686 test "returns fully qualified nickname for local users" do
2687 local_user = insert(:user, nickname: "local_user")
2689 assert User.full_nickname(local_user) == "local_user@localhost"
2692 test "returns fully qualified nickname for local users when using different domain for webfinger" do
2693 clear_config([Pleroma.Web.WebFinger, :domain], "plemora.dev")
2695 local_user = insert(:user, nickname: "local_user")
2697 assert User.full_nickname(local_user) == "local_user@plemora.dev"
2700 test "returns fully qualified nickname for remote users" do
2701 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2703 assert User.full_nickname(remote_user) == "remote@host.com"
2706 test "strips leading @ from mentions" do
2707 assert User.full_nickname("@mentioned") == "mentioned"
2708 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2711 test "does not modify nicknames" do
2712 assert User.full_nickname("nickname") == "nickname"
2713 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2717 test "avatar fallback" do
2718 user = insert(:user)
2719 assert User.avatar_url(user) =~ "/images/avi.png"
2721 clear_config([:assets, :default_user_avatar], "avatar.png")
2723 user = User.get_cached_by_nickname_or_id(user.nickname)
2724 assert User.avatar_url(user) =~ "avatar.png"
2726 assert User.avatar_url(user, no_default: true) == nil
2729 test "get_host/1" do
2730 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2731 assert User.get_host(user) == "lain.com"
2734 test "update_last_active_at/1" do
2735 user = insert(:user)
2736 assert is_nil(user.last_active_at)
2738 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2740 assert {:ok, user} = User.update_last_active_at(user)
2742 assert user.last_active_at >= test_started_at
2743 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2746 NaiveDateTime.utc_now()
2747 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2748 |> NaiveDateTime.truncate(:second)
2750 assert {:ok, user} =
2752 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2753 |> User.update_and_set_cache()
2755 assert user.last_active_at == last_active_at
2756 assert {:ok, user} = User.update_last_active_at(user)
2757 assert user.last_active_at >= test_started_at
2758 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2761 test "active_user_count/1" do
2763 insert(:user, %{local: false})
2764 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2765 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2766 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2767 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2768 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2770 assert User.active_user_count() == 2
2771 assert User.active_user_count(180) == 3
2772 assert User.active_user_count(365) == 4
2773 assert User.active_user_count(1000) == 5
2778 user = insert(:user)
2780 [user: user, object_id: object_id_from_created_activity(user)]
2783 test "unique pins", %{user: user, object_id: object_id} do
2784 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2785 User.add_pinned_object_id(user, object_id)
2787 assert Enum.count(pins) == 1
2789 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2790 User.add_pinned_object_id(updated_user, object_id)
2792 assert pinned_at1 == pinned_at2
2794 assert Enum.count(pins) == 1
2797 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2798 clear_config([:instance, :max_pinned_statuses], 1)
2799 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2801 object_id2 = object_id_from_created_activity(user)
2803 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2804 assert Keyword.has_key?(errors, :pinned_objects)
2807 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2808 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2810 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2811 assert after_remove.pinned_objects == %{}
2815 defp object_id_from_created_activity(user) do
2816 %{id: id} = insert(:note_activity, user: user)
2817 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2821 describe "add_alias/2" do
2822 test "should add alias for another user" do
2823 user = insert(:user)
2824 user2 = insert(:user)
2826 assert {:ok, user_updated} = user |> User.add_alias(user2)
2828 assert user_updated.also_known_as |> length() == 1
2829 assert user2.ap_id in user_updated.also_known_as
2832 test "should add multiple aliases" do
2833 user = insert(:user)
2834 user2 = insert(:user)
2835 user3 = insert(:user)
2837 assert {:ok, user} = user |> User.add_alias(user2)
2838 assert {:ok, user_updated} = user |> User.add_alias(user3)
2840 assert user_updated.also_known_as |> length() == 2
2841 assert user2.ap_id in user_updated.also_known_as
2842 assert user3.ap_id in user_updated.also_known_as
2845 test "should not add duplicate aliases" do
2846 user = insert(:user)
2847 user2 = insert(:user)
2849 assert {:ok, user} = user |> User.add_alias(user2)
2851 assert {:ok, user_updated} = user |> User.add_alias(user2)
2853 assert user_updated.also_known_as |> length() == 1
2854 assert user2.ap_id in user_updated.also_known_as
2858 describe "alias_users/1" do
2859 test "should get aliases for a user" do
2860 user = insert(:user)
2861 user2 = insert(:user, also_known_as: [user.ap_id])
2863 aliases = user2 |> User.alias_users()
2865 assert aliases |> length() == 1
2867 alias_user = aliases |> Enum.at(0)
2869 assert alias_user.ap_id == user.ap_id
2873 describe "delete_alias/2" do
2874 test "should delete existing alias" do
2875 user = insert(:user)
2876 user2 = insert(:user, also_known_as: [user.ap_id])
2878 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2880 assert user_updated.also_known_as == []
2883 test "should report error on non-existing alias" do
2884 user = insert(:user)
2885 user2 = insert(:user)
2886 user3 = insert(:user, also_known_as: [user.ap_id])
2888 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2890 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2892 assert user3_updated.also_known_as |> length() == 1
2893 assert user.ap_id in user3_updated.also_known_as
2897 describe "account endorsements" do
2898 test "it pins people" do
2899 user = insert(:user)
2900 pinned_user = insert(:user)
2902 {:ok, _pinned_user, _user} = User.follow(user, pinned_user)
2904 refute User.endorses?(user, pinned_user)
2906 {:ok, _user_relationship} = User.endorse(user, pinned_user)
2908 assert User.endorses?(user, pinned_user)
2911 test "it unpins users" do
2912 user = insert(:user)
2913 pinned_user = insert(:user)
2915 {:ok, _pinned_user, _user} = User.follow(user, pinned_user)
2916 {:ok, _user_relationship} = User.endorse(user, pinned_user)
2917 {:ok, _user_pin} = User.unendorse(user, pinned_user)
2919 refute User.endorses?(user, pinned_user)
2922 test "it doesn't pin users you do not follow" do
2923 user = insert(:user)
2924 pinned_user = insert(:user)
2926 assert {:error, _message} = User.endorse(user, pinned_user)
2928 refute User.endorses?(user, pinned_user)
2932 test "it checks fields links for a backlink" do
2933 user = insert(:user, ap_id: "https://social.example.org/users/lain")
2936 %{"name" => "Link", "value" => "http://example.com/rel_me/null"},
2937 %{"name" => "Verified link", "value" => "http://example.com/rel_me/link"},
2938 %{"name" => "Not a link", "value" => "i'm not a link"}
2942 |> User.update_and_set_cache(%{raw_fields: fields})
2944 ObanHelpers.perform_all()
2946 user = User.get_cached_by_id(user.id)
2949 %{"verified_at" => nil},
2950 %{"verified_at" => verified_at},
2951 %{"verified_at" => nil}
2954 assert is_binary(verified_at)
2957 test "updating fields does not invalidate previously validated links" do
2958 user = insert(:user, ap_id: "https://social.example.org/users/lain")
2961 |> User.update_and_set_cache(%{
2962 raw_fields: [%{"name" => "verified link", "value" => "http://example.com/rel_me/link"}]
2965 ObanHelpers.perform_all()
2967 %User{fields: [%{"verified_at" => verified_at}]} = user = User.get_cached_by_id(user.id)
2970 |> User.update_and_set_cache(%{
2971 raw_fields: [%{"name" => "Verified link", "value" => "http://example.com/rel_me/link"}]
2974 user = User.get_cached_by_id(user.id)
2976 assert [%{"verified_at" => ^verified_at}] = user.fields