1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.UserTest do
7 alias Pleroma.Builders.UserBuilder
8 alias Pleroma.Notification
11 alias Pleroma.Tests.ObanHelpers
13 alias Pleroma.Web.ActivityPub.ActivityPub
14 alias Pleroma.Web.CommonAPI
17 use Oban.Testing, repo: Pleroma.Repo
19 import Pleroma.Factory
20 import ExUnit.CaptureLog
21 import Swoosh.TestAssertions
24 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
28 setup do: clear_config([:instance, :account_activation_required])
30 describe "service actors" do
31 test "returns updated invisible actor" do
32 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
33 followers_uri = "#{uri}/followers"
42 follower_address: followers_uri
46 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
47 assert actor.invisible
50 test "returns relay user" do
51 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
52 followers_uri = "#{uri}/followers"
59 follower_address: ^followers_uri
60 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
62 assert capture_log(fn ->
63 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
64 end) =~ "Cannot create service actor:"
67 test "returns invisible actor" do
68 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
69 followers_uri = "#{uri}/followers"
70 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
73 nickname: "internal.fetch-test",
77 follower_address: ^followers_uri
80 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
81 assert user.id == user2.id
85 describe "AP ID user relationships" do
87 {:ok, user: insert(:user)}
90 test "outgoing_relationships_ap_ids/1", %{user: user} do
91 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
99 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
101 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
102 {rel_type, Enum.sort(ap_ids)}
106 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
107 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
109 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
110 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
112 assert ap_ids_by_rel[:notification_mute] ==
113 Enum.sort(User.notification_muted_users_ap_ids(user))
115 assert ap_ids_by_rel[:notification_mute] ==
116 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
118 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
120 assert ap_ids_by_rel[:reblog_mute] ==
121 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
123 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
125 assert ap_ids_by_rel[:inverse_subscription] ==
126 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
128 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
130 assert ap_ids_by_rel ==
131 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
135 describe "when tags are nil" do
136 test "tagging a user" do
137 user = insert(:user, %{tags: nil})
138 user = User.tag(user, ["cool", "dude"])
140 assert "cool" in user.tags
141 assert "dude" in user.tags
144 test "untagging a user" do
145 user = insert(:user, %{tags: nil})
146 user = User.untag(user, ["cool", "dude"])
148 assert user.tags == []
152 test "ap_id returns the activity pub id for the user" do
153 user = UserBuilder.build()
155 expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}"
157 assert expected_ap_id == User.ap_id(user)
160 test "ap_followers returns the followers collection for the user" do
161 user = UserBuilder.build()
163 expected_followers_collection = "#{User.ap_id(user)}/followers"
165 assert expected_followers_collection == User.ap_followers(user)
168 test "ap_following returns the following collection for the user" do
169 user = UserBuilder.build()
171 expected_followers_collection = "#{User.ap_id(user)}/following"
173 assert expected_followers_collection == User.ap_following(user)
176 test "returns all pending follow requests" do
177 unlocked = insert(:user)
178 locked = insert(:user, is_locked: true)
179 follower = insert(:user)
181 CommonAPI.follow(follower, unlocked)
182 CommonAPI.follow(follower, locked)
184 assert [] = User.get_follow_requests(unlocked)
185 assert [activity] = User.get_follow_requests(locked)
190 test "doesn't return already accepted or duplicate follow requests" do
191 locked = insert(:user, is_locked: true)
192 pending_follower = insert(:user)
193 accepted_follower = insert(:user)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(pending_follower, locked)
197 CommonAPI.follow(accepted_follower, locked)
199 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
201 assert [^pending_follower] = User.get_follow_requests(locked)
204 test "doesn't return follow requests for deactivated accounts" do
205 locked = insert(:user, is_locked: true)
206 pending_follower = insert(:user, %{is_active: false})
208 CommonAPI.follow(pending_follower, locked)
210 refute pending_follower.is_active
211 assert [] = User.get_follow_requests(locked)
214 test "clears follow requests when requester is blocked" do
215 followed = insert(:user, is_locked: true)
216 follower = insert(:user)
218 CommonAPI.follow(follower, followed)
219 assert [_activity] = User.get_follow_requests(followed)
221 {:ok, _user_relationship} = User.block(followed, follower)
222 assert [] = User.get_follow_requests(followed)
225 test "follow_all follows mutliple users" do
227 followed_zero = insert(:user)
228 followed_one = insert(:user)
229 followed_two = insert(:user)
230 blocked = insert(:user)
231 not_followed = insert(:user)
232 reverse_blocked = insert(:user)
234 {:ok, _user_relationship} = User.block(user, blocked)
235 {:ok, _user_relationship} = User.block(reverse_blocked, user)
237 {:ok, user, followed_zero} = User.follow(user, followed_zero)
239 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
241 assert User.following?(user, followed_one)
242 assert User.following?(user, followed_two)
243 assert User.following?(user, followed_zero)
244 refute User.following?(user, not_followed)
245 refute User.following?(user, blocked)
246 refute User.following?(user, reverse_blocked)
249 test "follow_all follows mutliple users without duplicating" do
251 followed_zero = insert(:user)
252 followed_one = insert(:user)
253 followed_two = insert(:user)
255 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
256 assert length(User.following(user)) == 3
258 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
259 assert length(User.following(user)) == 4
262 test "follow takes a user and another user" do
264 followed = insert(:user)
266 {:ok, user, followed} = User.follow(user, followed)
268 user = User.get_cached_by_id(user.id)
269 followed = User.get_cached_by_ap_id(followed.ap_id)
271 assert followed.follower_count == 1
272 assert user.following_count == 1
274 assert User.ap_followers(followed) in User.following(user)
277 test "can't follow a deactivated users" do
279 followed = insert(:user, %{is_active: false})
281 {:error, _} = User.follow(user, followed)
284 test "can't follow a user who blocked us" do
285 blocker = insert(:user)
286 blockee = insert(:user)
288 {:ok, _user_relationship} = User.block(blocker, blockee)
290 {:error, _} = User.follow(blockee, blocker)
293 test "can't subscribe to a user who blocked us" do
294 blocker = insert(:user)
295 blocked = insert(:user)
297 {:ok, _user_relationship} = User.block(blocker, blocked)
299 {:error, _} = User.subscribe(blocked, blocker)
302 test "local users do not automatically follow local locked accounts" do
303 follower = insert(:user, is_locked: true)
304 followed = insert(:user, is_locked: true)
306 {:ok, follower, followed} = User.maybe_direct_follow(follower, followed)
308 refute User.following?(follower, followed)
311 describe "unfollow/2" do
312 setup do: clear_config([:instance, :external_user_synchronization])
314 test "unfollow with syncronizes external user" do
315 clear_config([:instance, :external_user_synchronization], true)
320 follower_address: "http://localhost:4001/users/fuser1/followers",
321 following_address: "http://localhost:4001/users/fuser1/following",
322 ap_id: "http://localhost:4001/users/fuser1"
329 ap_id: "http://localhost:4001/users/fuser2",
330 follower_address: "http://localhost:4001/users/fuser2/followers",
331 following_address: "http://localhost:4001/users/fuser2/following"
334 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
336 {:ok, user, _activity} = User.unfollow(user, followed)
338 user = User.get_cached_by_id(user.id)
340 assert User.following(user) == []
343 test "unfollow takes a user and another user" do
344 followed = insert(:user)
347 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
349 assert User.following(user) == [user.follower_address, followed.follower_address]
351 {:ok, user, _activity} = User.unfollow(user, followed)
353 assert User.following(user) == [user.follower_address]
356 test "unfollow doesn't unfollow yourself" do
359 {:error, _} = User.unfollow(user, user)
361 assert User.following(user) == [user.follower_address]
365 test "test if a user is following another user" do
366 followed = insert(:user)
368 User.follow(user, followed, :follow_accept)
370 assert User.following?(user, followed)
371 refute User.following?(followed, user)
374 test "fetches correct profile for nickname beginning with number" do
375 # Use old-style integer ID to try to reproduce the problem
376 user = insert(:user, %{id: 1080})
377 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
378 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
381 describe "user registration" do
387 password_confirmation: "test",
388 email: "email@example.com"
391 setup do: clear_config([:instance, :autofollowed_nicknames])
392 setup do: clear_config([:instance, :autofollowing_nicknames])
393 setup do: clear_config([:welcome])
394 setup do: clear_config([:instance, :account_activation_required])
396 test "it autofollows accounts that are set for it" do
398 remote_user = insert(:user, %{local: false})
400 clear_config([:instance, :autofollowed_nicknames], [
405 cng = User.register_changeset(%User{}, @full_user_data)
407 {:ok, registered_user} = User.register(cng)
409 assert User.following?(registered_user, user)
410 refute User.following?(registered_user, remote_user)
413 test "it adds automatic followers for new registered accounts" do
414 user1 = insert(:user)
415 user2 = insert(:user)
417 clear_config([:instance, :autofollowing_nicknames], [
422 cng = User.register_changeset(%User{}, @full_user_data)
424 {:ok, registered_user} = User.register(cng)
426 assert User.following?(user1, registered_user)
427 assert User.following?(user2, registered_user)
430 test "it sends a welcome message if it is set" do
431 welcome_user = insert(:user)
432 clear_config([:welcome, :direct_message, :enabled], true)
433 clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
434 clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message")
436 cng = User.register_changeset(%User{}, @full_user_data)
437 {:ok, registered_user} = User.register(cng)
438 ObanHelpers.perform_all()
440 activity = Repo.one(Pleroma.Activity)
441 assert registered_user.ap_id in activity.recipients
442 assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message"
443 assert activity.actor == welcome_user.ap_id
447 clear_config(:mrf_simple,
450 federated_timeline_removal: [],
463 Pleroma.Web.ActivityPub.MRF.SimplePolicy
467 test "it sends a welcome email message if it is set" do
468 welcome_user = insert(:user)
469 clear_config([:welcome, :email, :enabled], true)
470 clear_config([:welcome, :email, :sender], welcome_user.email)
473 [:welcome, :email, :subject],
474 "Hello, welcome to cool site: <%= instance_name %>"
477 instance_name = Pleroma.Config.get([:instance, :name])
479 cng = User.register_changeset(%User{}, @full_user_data)
480 {:ok, registered_user} = User.register(cng)
481 ObanHelpers.perform_all()
484 from: {instance_name, welcome_user.email},
485 to: {registered_user.name, registered_user.email},
486 subject: "Hello, welcome to cool site: #{instance_name}",
487 html_body: "Welcome to #{instance_name}"
491 test "it sends a confirm email" do
492 clear_config([:instance, :account_activation_required], true)
494 cng = User.register_changeset(%User{}, @full_user_data)
495 {:ok, registered_user} = User.register(cng)
496 ObanHelpers.perform_all()
498 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
499 # temporary hackney fix until hackney max_connections bug is fixed
500 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
501 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
502 |> assert_email_sent()
505 test "sends a pending approval email" do
506 clear_config([:instance, :account_approval_required], true)
509 User.register_changeset(%User{}, @full_user_data)
512 ObanHelpers.perform_all()
515 from: Pleroma.Config.Helpers.sender(),
516 to: {user.name, user.email},
517 subject: "Your account is awaiting approval"
521 test "it sends a registration confirmed email if no others will be sent" do
522 clear_config([:welcome, :email, :enabled], false)
523 clear_config([:instance, :account_activation_required], false)
524 clear_config([:instance, :account_approval_required], false)
527 User.register_changeset(%User{}, @full_user_data)
530 ObanHelpers.perform_all()
532 instance_name = Pleroma.Config.get([:instance, :name])
533 sender = Pleroma.Config.get([:instance, :notify_email])
536 from: {instance_name, sender},
537 to: {user.name, user.email},
538 subject: "Account registered on #{instance_name}"
542 test "it fails gracefully with invalid email config" do
543 cng = User.register_changeset(%User{}, @full_user_data)
545 # Disable the mailer but enable all the things that want to send emails
546 clear_config([Pleroma.Emails.Mailer, :enabled], false)
547 clear_config([:instance, :account_activation_required], true)
548 clear_config([:instance, :account_approval_required], true)
549 clear_config([:welcome, :email, :enabled], true)
550 clear_config([:welcome, :email, :sender], "lain@lain.com")
552 # The user is still created
553 assert {:ok, %User{nickname: "nick"}} = User.register(cng)
556 ObanHelpers.perform_all()
560 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
561 clear_config([:instance, :account_activation_required], true)
565 |> Enum.each(fn key ->
566 params = Map.delete(@full_user_data, key)
567 changeset = User.register_changeset(%User{}, params)
569 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
573 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
574 clear_config([:instance, :account_activation_required], false)
578 |> Enum.each(fn key ->
579 params = Map.delete(@full_user_data, key)
580 changeset = User.register_changeset(%User{}, params)
582 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
586 test "it restricts certain nicknames" do
587 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
589 assert is_bitstring(restricted_name)
593 |> Map.put(:nickname, restricted_name)
595 changeset = User.register_changeset(%User{}, params)
597 refute changeset.valid?
600 test "it blocks blacklisted email domains" do
601 clear_config([User, :email_blacklist], ["trolling.world"])
604 params = Map.put(@full_user_data, :email, "troll@trolling.world")
605 changeset = User.register_changeset(%User{}, params)
606 refute changeset.valid?
608 # Block with subdomain match
609 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
610 changeset = User.register_changeset(%User{}, params)
611 refute changeset.valid?
613 # Pass with different domains that are similar
614 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
615 changeset = User.register_changeset(%User{}, params)
616 assert changeset.valid?
618 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
619 changeset = User.register_changeset(%User{}, params)
620 assert changeset.valid?
623 test "it sets the password_hash and ap_id" do
624 changeset = User.register_changeset(%User{}, @full_user_data)
626 assert changeset.valid?
628 assert is_binary(changeset.changes[:password_hash])
629 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
631 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
634 test "it creates a confirmed user" do
635 changeset = User.register_changeset(%User{}, @full_user_data)
636 assert changeset.valid?
638 {:ok, user} = Repo.insert(changeset)
640 assert user.is_confirmed
644 describe "user registration, with :account_activation_required" do
650 password_confirmation: "test",
651 email: "email@example.com"
653 setup do: clear_config([:instance, :account_activation_required], true)
655 test "it creates unconfirmed user" do
656 changeset = User.register_changeset(%User{}, @full_user_data)
657 assert changeset.valid?
659 {:ok, user} = Repo.insert(changeset)
661 refute user.is_confirmed
662 assert user.confirmation_token
665 test "it creates confirmed user if :confirmed option is given" do
666 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
667 assert changeset.valid?
669 {:ok, user} = Repo.insert(changeset)
671 assert user.is_confirmed
672 refute user.confirmation_token
676 describe "user registration, with :account_approval_required" do
682 password_confirmation: "test",
683 email: "email@example.com",
684 registration_reason: "I'm a cool guy :)"
686 setup do: clear_config([:instance, :account_approval_required], true)
688 test "it creates unapproved user" do
689 changeset = User.register_changeset(%User{}, @full_user_data)
690 assert changeset.valid?
692 {:ok, user} = Repo.insert(changeset)
694 refute user.is_approved
695 assert user.registration_reason == "I'm a cool guy :)"
698 test "it restricts length of registration reason" do
699 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
701 assert is_integer(reason_limit)
706 :registration_reason,
707 "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."
710 changeset = User.register_changeset(%User{}, params)
712 refute changeset.valid?
716 describe "get_or_fetch/1" do
717 test "gets an existing user by nickname" do
719 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
721 assert user == fetched_user
724 test "gets an existing user by ap_id" do
725 ap_id = "http://mastodon.example.org/users/admin"
731 nickname: "admin@mastodon.example.org",
735 {:ok, fetched_user} = User.get_or_fetch(ap_id)
736 freshed_user = refresh_record(user)
737 assert freshed_user == fetched_user
741 describe "fetching a user from nickname or trying to build one" do
742 test "gets an existing user" do
744 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
746 assert user == fetched_user
749 test "gets an existing user, case insensitive" do
750 user = insert(:user, nickname: "nick")
751 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
753 assert user == fetched_user
756 test "gets an existing user by fully qualified nickname" do
759 {:ok, fetched_user} =
760 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
762 assert user == fetched_user
765 test "gets an existing user by fully qualified nickname, case insensitive" do
766 user = insert(:user, nickname: "nick")
767 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
769 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
771 assert user == fetched_user
774 @tag capture_log: true
775 test "returns nil if no user could be fetched" do
776 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
777 assert fetched_user == "not found nonexistant@social.heldscal.la"
780 test "returns nil for nonexistant local user" do
781 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
782 assert fetched_user == "not found nonexistant"
785 test "updates an existing user, if stale" do
786 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
792 nickname: "admin@mastodon.example.org",
793 ap_id: "http://mastodon.example.org/users/admin",
794 last_refreshed_at: a_week_ago
797 assert orig_user.last_refreshed_at == a_week_ago
799 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
803 refute user.last_refreshed_at == orig_user.last_refreshed_at
806 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
807 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
813 nickname: "admin@mastodon.example.org",
814 ap_id: "http://mastodon.example.org/users/harinezumigari",
815 last_refreshed_at: a_week_ago
818 assert orig_user.last_refreshed_at == a_week_ago
820 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
824 refute user.id == orig_user.id
826 orig_user = User.get_by_id(orig_user.id)
828 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
831 @tag capture_log: true
832 test "it returns the old user if stale, but unfetchable" do
833 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
839 nickname: "admin@mastodon.example.org",
840 ap_id: "http://mastodon.example.org/users/raymoo",
841 last_refreshed_at: a_week_ago
844 assert orig_user.last_refreshed_at == a_week_ago
846 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
848 assert user.last_refreshed_at == orig_user.last_refreshed_at
852 test "returns an ap_id for a user" do
855 assert User.ap_id(user) ==
856 Pleroma.Web.Router.Helpers.user_feed_url(
857 Pleroma.Web.Endpoint,
863 test "returns an ap_followers link for a user" do
866 assert User.ap_followers(user) ==
867 Pleroma.Web.Router.Helpers.user_feed_url(
868 Pleroma.Web.Endpoint,
874 describe "remote user changeset" do
880 avatar: %{some: "avatar"}
882 setup do: clear_config([:instance, :user_bio_length])
883 setup do: clear_config([:instance, :user_name_length])
885 test "it confirms validity" do
886 cs = User.remote_user_changeset(@valid_remote)
890 test "it sets the follower_adress" do
891 cs = User.remote_user_changeset(@valid_remote)
892 # remote users get a fake local follower address
893 assert cs.changes.follower_address ==
894 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
897 test "it enforces the fqn format for nicknames" do
898 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
899 assert Ecto.Changeset.get_field(cs, :local) == false
900 assert cs.changes.avatar
904 test "it has required fields" do
906 |> Enum.each(fn field ->
907 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
912 test "it is invalid given a local user" do
914 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
920 describe "followers and friends" do
921 test "gets all followers for a given user" do
923 follower_one = insert(:user)
924 follower_two = insert(:user)
925 not_follower = insert(:user)
927 {:ok, follower_one, user} = User.follow(follower_one, user)
928 {:ok, follower_two, user} = User.follow(follower_two, user)
930 res = User.get_followers(user)
932 assert Enum.member?(res, follower_one)
933 assert Enum.member?(res, follower_two)
934 refute Enum.member?(res, not_follower)
937 test "gets all friends (followed users) for a given user" do
939 followed_one = insert(:user)
940 followed_two = insert(:user)
941 not_followed = insert(:user)
943 {:ok, user, followed_one} = User.follow(user, followed_one)
944 {:ok, user, followed_two} = User.follow(user, followed_two)
946 res = User.get_friends(user)
948 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
949 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
950 assert Enum.member?(res, followed_one)
951 assert Enum.member?(res, followed_two)
952 refute Enum.member?(res, not_followed)
956 describe "updating note and follower count" do
957 test "it sets the note_count property" do
960 user = User.get_cached_by_ap_id(note.data["actor"])
962 assert user.note_count == 0
964 {:ok, user} = User.update_note_count(user)
966 assert user.note_count == 1
969 test "it increases the note_count property" do
971 user = User.get_cached_by_ap_id(note.data["actor"])
973 assert user.note_count == 0
975 {:ok, user} = User.increase_note_count(user)
977 assert user.note_count == 1
979 {:ok, user} = User.increase_note_count(user)
981 assert user.note_count == 2
984 test "it decreases the note_count property" do
986 user = User.get_cached_by_ap_id(note.data["actor"])
988 assert user.note_count == 0
990 {:ok, user} = User.increase_note_count(user)
992 assert user.note_count == 1
994 {:ok, user} = User.decrease_note_count(user)
996 assert user.note_count == 0
998 {:ok, user} = User.decrease_note_count(user)
1000 assert user.note_count == 0
1003 test "it sets the follower_count property" do
1004 user = insert(:user)
1005 follower = insert(:user)
1007 User.follow(follower, user)
1009 assert user.follower_count == 0
1011 {:ok, user} = User.update_follower_count(user)
1013 assert user.follower_count == 1
1018 test "it mutes people" do
1019 user = insert(:user)
1020 muted_user = insert(:user)
1022 refute User.mutes?(user, muted_user)
1023 refute User.muted_notifications?(user, muted_user)
1025 {:ok, _user_relationships} = User.mute(user, muted_user)
1027 assert User.mutes?(user, muted_user)
1028 assert User.muted_notifications?(user, muted_user)
1032 user = insert(:user)
1033 muted_user = insert(:user)
1035 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1036 assert User.mutes?(user, muted_user)
1038 worker = Pleroma.Workers.MuteExpireWorker
1039 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1046 assert :ok = perform_job(worker, args)
1048 refute User.mutes?(user, muted_user)
1049 refute User.muted_notifications?(user, muted_user)
1052 test "it unmutes users" do
1053 user = insert(:user)
1054 muted_user = insert(:user)
1056 {:ok, _user_relationships} = User.mute(user, muted_user)
1057 {:ok, _user_mute} = User.unmute(user, muted_user)
1059 refute User.mutes?(user, muted_user)
1060 refute User.muted_notifications?(user, muted_user)
1063 test "it unmutes users by id" do
1064 user = insert(:user)
1065 muted_user = insert(:user)
1067 {:ok, _user_relationships} = User.mute(user, muted_user)
1068 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1070 refute User.mutes?(user, muted_user)
1071 refute User.muted_notifications?(user, muted_user)
1074 test "it mutes user without notifications" do
1075 user = insert(:user)
1076 muted_user = insert(:user)
1078 refute User.mutes?(user, muted_user)
1079 refute User.muted_notifications?(user, muted_user)
1081 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1083 assert User.mutes?(user, muted_user)
1084 refute User.muted_notifications?(user, muted_user)
1088 describe "blocks" do
1089 test "it blocks people" do
1090 user = insert(:user)
1091 blocked_user = insert(:user)
1093 refute User.blocks?(user, blocked_user)
1095 {:ok, _user_relationship} = User.block(user, blocked_user)
1097 assert User.blocks?(user, blocked_user)
1100 test "it unblocks users" do
1101 user = insert(:user)
1102 blocked_user = insert(:user)
1104 {:ok, _user_relationship} = User.block(user, blocked_user)
1105 {:ok, _user_block} = User.unblock(user, blocked_user)
1107 refute User.blocks?(user, blocked_user)
1110 test "blocks tear down cyclical follow relationships" do
1111 blocker = insert(:user)
1112 blocked = insert(:user)
1114 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1115 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1117 assert User.following?(blocker, blocked)
1118 assert User.following?(blocked, blocker)
1120 {:ok, _user_relationship} = User.block(blocker, blocked)
1121 blocked = User.get_cached_by_id(blocked.id)
1123 assert User.blocks?(blocker, blocked)
1125 refute User.following?(blocker, blocked)
1126 refute User.following?(blocked, blocker)
1129 test "blocks tear down blocker->blocked follow relationships" do
1130 blocker = insert(:user)
1131 blocked = insert(:user)
1133 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1135 assert User.following?(blocker, blocked)
1136 refute User.following?(blocked, blocker)
1138 {:ok, _user_relationship} = User.block(blocker, blocked)
1139 blocked = User.get_cached_by_id(blocked.id)
1141 assert User.blocks?(blocker, blocked)
1143 refute User.following?(blocker, blocked)
1144 refute User.following?(blocked, blocker)
1147 test "blocks tear down blocked->blocker follow relationships" do
1148 blocker = insert(:user)
1149 blocked = insert(:user)
1151 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1153 refute User.following?(blocker, blocked)
1154 assert User.following?(blocked, blocker)
1156 {:ok, _user_relationship} = User.block(blocker, blocked)
1157 blocked = User.get_cached_by_id(blocked.id)
1159 assert User.blocks?(blocker, blocked)
1161 refute User.following?(blocker, blocked)
1162 refute User.following?(blocked, blocker)
1165 test "blocks tear down blocked->blocker subscription relationships" do
1166 blocker = insert(:user)
1167 blocked = insert(:user)
1169 {:ok, _subscription} = User.subscribe(blocked, blocker)
1171 assert User.subscribed_to?(blocked, blocker)
1172 refute User.subscribed_to?(blocker, blocked)
1174 {:ok, _user_relationship} = User.block(blocker, blocked)
1176 assert User.blocks?(blocker, blocked)
1177 refute User.subscribed_to?(blocker, blocked)
1178 refute User.subscribed_to?(blocked, blocker)
1182 describe "domain blocking" do
1183 test "blocks domains" do
1184 user = insert(:user)
1185 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1187 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1189 assert User.blocks?(user, collateral_user)
1192 test "does not block domain with same end" do
1193 user = insert(:user)
1196 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1198 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1200 refute User.blocks?(user, collateral_user)
1203 test "does not block domain with same end if wildcard added" do
1204 user = insert(:user)
1207 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1209 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1211 refute User.blocks?(user, collateral_user)
1214 test "blocks domain with wildcard for subdomain" do
1215 user = insert(:user)
1217 user_from_subdomain =
1218 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1220 user_with_two_subdomains =
1222 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1225 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1227 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1229 assert User.blocks?(user, user_from_subdomain)
1230 assert User.blocks?(user, user_with_two_subdomains)
1231 assert User.blocks?(user, user_domain)
1234 test "unblocks domains" do
1235 user = insert(:user)
1236 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1238 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1239 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1241 refute User.blocks?(user, collateral_user)
1244 test "follows take precedence over domain blocks" do
1245 user = insert(:user)
1246 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1248 {:ok, user} = User.block_domain(user, "meanies.social")
1249 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1251 refute User.blocks?(user, good_eggo)
1255 describe "get_recipients_from_activity" do
1256 test "works for announces" do
1257 actor = insert(:user)
1258 user = insert(:user, local: true)
1260 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1261 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1263 recipients = User.get_recipients_from_activity(announce)
1265 assert user in recipients
1268 test "get recipients" do
1269 actor = insert(:user)
1270 user = insert(:user, local: true)
1271 user_two = insert(:user, local: false)
1272 addressed = insert(:user, local: true)
1273 addressed_remote = insert(:user, local: false)
1276 CommonAPI.post(actor, %{
1277 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1280 assert Enum.map([actor, addressed], & &1.ap_id) --
1281 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1283 {:ok, user, actor} = User.follow(user, actor)
1284 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1285 recipients = User.get_recipients_from_activity(activity)
1286 assert length(recipients) == 3
1287 assert user in recipients
1288 assert addressed in recipients
1291 test "has following" do
1292 actor = insert(:user)
1293 user = insert(:user)
1294 user_two = insert(:user)
1295 addressed = insert(:user, local: true)
1298 CommonAPI.post(actor, %{
1299 status: "hey @#{addressed.nickname}"
1302 assert Enum.map([actor, addressed], & &1.ap_id) --
1303 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1305 {:ok, _actor, _user} = User.follow(actor, user)
1306 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1307 recipients = User.get_recipients_from_activity(activity)
1308 assert length(recipients) == 2
1309 assert addressed in recipients
1313 describe ".set_activation" do
1314 test "can de-activate then re-activate a user" do
1315 user = insert(:user)
1316 assert user.is_active
1317 {:ok, user} = User.set_activation(user, false)
1318 refute user.is_active
1319 {:ok, user} = User.set_activation(user, true)
1320 assert user.is_active
1323 test "hide a user from followers" do
1324 user = insert(:user)
1325 user2 = insert(:user)
1327 {:ok, user, user2} = User.follow(user, user2)
1328 {:ok, _user} = User.set_activation(user, false)
1330 user2 = User.get_cached_by_id(user2.id)
1332 assert user2.follower_count == 0
1333 assert [] = User.get_followers(user2)
1336 test "hide a user from friends" do
1337 user = insert(:user)
1338 user2 = insert(:user)
1340 {:ok, user2, user} = User.follow(user2, user)
1341 assert user2.following_count == 1
1342 assert User.following_count(user2) == 1
1344 {:ok, _user} = User.set_activation(user, false)
1346 user2 = User.get_cached_by_id(user2.id)
1348 assert refresh_record(user2).following_count == 0
1349 assert user2.following_count == 0
1350 assert User.following_count(user2) == 0
1351 assert [] = User.get_friends(user2)
1354 test "hide a user's statuses from timelines and notifications" do
1355 user = insert(:user)
1356 user2 = insert(:user)
1358 {:ok, user2, user} = User.follow(user2, user)
1360 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1362 activity = Repo.preload(activity, :bookmark)
1364 [notification] = Pleroma.Notification.for_user(user2)
1365 assert notification.activity.id == activity.id
1367 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1369 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1370 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1374 {:ok, _user} = User.set_activation(user, false)
1376 assert [] == ActivityPub.fetch_public_activities(%{})
1377 assert [] == Pleroma.Notification.for_user(user2)
1380 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1386 describe "approve" do
1387 test "approves a user" do
1388 user = insert(:user, is_approved: false)
1389 refute user.is_approved
1390 {:ok, user} = User.approve(user)
1391 assert user.is_approved
1394 test "approves a list of users" do
1395 unapproved_users = [
1396 insert(:user, is_approved: false),
1397 insert(:user, is_approved: false),
1398 insert(:user, is_approved: false)
1401 {:ok, users} = User.approve(unapproved_users)
1403 assert Enum.count(users) == 3
1405 Enum.each(users, fn user ->
1406 assert user.is_approved
1410 test "it sends welcome email if it is set" do
1411 clear_config([:welcome, :email, :enabled], true)
1412 clear_config([:welcome, :email, :sender], "tester@test.me")
1414 user = insert(:user, is_approved: false)
1415 welcome_user = insert(:user, email: "tester@test.me")
1416 instance_name = Pleroma.Config.get([:instance, :name])
1420 ObanHelpers.perform_all()
1423 from: {instance_name, welcome_user.email},
1424 to: {user.name, user.email},
1425 html_body: "Welcome to #{instance_name}"
1429 test "approving an approved user does not trigger post-register actions" do
1430 clear_config([:welcome, :email, :enabled], true)
1432 user = insert(:user, is_approved: true)
1435 ObanHelpers.perform_all()
1437 assert_no_email_sent()
1441 describe "confirm" do
1442 test "confirms a user" do
1443 user = insert(:user, is_confirmed: false)
1444 refute user.is_confirmed
1445 {:ok, user} = User.confirm(user)
1446 assert user.is_confirmed
1449 test "confirms a list of users" do
1450 unconfirmed_users = [
1451 insert(:user, is_confirmed: false),
1452 insert(:user, is_confirmed: false),
1453 insert(:user, is_confirmed: false)
1456 {:ok, users} = User.confirm(unconfirmed_users)
1458 assert Enum.count(users) == 3
1460 Enum.each(users, fn user ->
1461 assert user.is_confirmed
1465 test "sends approval emails when `is_approved: false`" do
1466 admin = insert(:user, is_admin: true)
1467 user = insert(:user, is_confirmed: false, is_approved: false)
1470 ObanHelpers.perform_all()
1472 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1473 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1475 notify_email = Pleroma.Config.get([:instance, :notify_email])
1476 instance_name = Pleroma.Config.get([:instance, :name])
1478 # User approval email
1480 from: {instance_name, notify_email},
1481 to: {user.name, user.email},
1482 html_body: user_email.html_body
1487 from: {instance_name, notify_email},
1488 to: {admin.name, admin.email},
1489 html_body: admin_email.html_body
1493 test "confirming a confirmed user does not trigger post-register actions" do
1494 user = insert(:user, is_confirmed: true, is_approved: false)
1497 ObanHelpers.perform_all()
1499 assert_no_email_sent()
1503 describe "delete" do
1505 {:ok, user} = insert(:user) |> User.set_cache()
1510 setup do: clear_config([:instance, :federating])
1512 test ".delete_user_activities deletes all create activities", %{user: user} do
1513 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1515 User.delete_user_activities(user)
1517 # TODO: Test removal favorites, repeats, delete activities.
1518 refute Activity.get_by_id(activity.id)
1521 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1522 follower = insert(:user)
1523 {:ok, follower, user} = User.follow(follower, user)
1525 locked_user = insert(:user, name: "locked", is_locked: true)
1526 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1528 object = insert(:note, user: user)
1529 activity = insert(:note_activity, user: user, note: object)
1531 object_two = insert(:note, user: follower)
1532 activity_two = insert(:note_activity, user: follower, note: object_two)
1534 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1535 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1536 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1538 {:ok, job} = User.delete(user)
1539 {:ok, _user} = ObanHelpers.perform(job)
1541 follower = User.get_cached_by_id(follower.id)
1543 refute User.following?(follower, user)
1544 assert %{is_active: false} = User.get_by_id(user.id)
1546 assert [] == User.get_follow_requests(locked_user)
1550 |> Activity.Queries.by_actor()
1552 |> Enum.map(fn act -> act.data["type"] end)
1554 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1556 refute Activity.get_by_id(activity.id)
1557 refute Activity.get_by_id(like.id)
1558 refute Activity.get_by_id(like_two.id)
1559 refute Activity.get_by_id(repeat.id)
1563 test "delete/1 when confirmation is pending deletes the user" do
1564 clear_config([:instance, :account_activation_required], true)
1565 user = insert(:user, is_confirmed: false)
1567 {:ok, job} = User.delete(user)
1568 {:ok, _} = ObanHelpers.perform(job)
1570 refute User.get_cached_by_id(user.id)
1571 refute User.get_by_id(user.id)
1574 test "delete/1 when approval is pending deletes the user" do
1575 user = insert(:user, is_approved: false)
1577 {:ok, job} = User.delete(user)
1578 {:ok, _} = ObanHelpers.perform(job)
1580 refute User.get_cached_by_id(user.id)
1581 refute User.get_by_id(user.id)
1584 test "delete/1 purges a user when they wouldn't be fully deleted" do
1589 password_hash: "pdfk2$1b3n159001",
1590 keys: "RSA begin buplic key",
1591 public_key: "--PRIVATE KEYE--",
1592 avatar: %{"a" => "b"},
1594 banner: %{"a" => "b"},
1595 background: %{"a" => "b"},
1598 following_count: 9001,
1601 password_reset_pending: true,
1603 registration_reason: "ahhhhh",
1604 confirmation_token: "qqqq",
1605 domain_blocks: ["lain.com"],
1610 mastofe_settings: %{"a" => "b"},
1611 mascot: %{"a" => "b"},
1612 emoji: %{"a" => "b"},
1613 pleroma_settings_store: %{"q" => "x"},
1614 fields: [%{"gg" => "qq"}],
1615 raw_fields: [%{"gg" => "qq"}],
1616 is_discoverable: true,
1617 also_known_as: ["https://lol.olo/users/loll"]
1620 {:ok, job} = User.delete(user)
1621 {:ok, _} = ObanHelpers.perform(job)
1622 user = User.get_by_id(user.id)
1630 keys: "RSA begin buplic key",
1631 public_key: "--PRIVATE KEYE--",
1634 last_refreshed_at: nil,
1635 last_digest_emailed_at: nil,
1643 password_reset_pending: false,
1645 registration_reason: nil,
1646 confirmation_token: nil,
1650 is_moderator: false,
1652 mastofe_settings: nil,
1655 pleroma_settings_store: %{},
1658 is_discoverable: false,
1663 test "delete/1 purges a remote user" do
1667 avatar: %{"a" => "b"},
1668 banner: %{"a" => "b"},
1672 {:ok, job} = User.delete(user)
1673 {:ok, _} = ObanHelpers.perform(job)
1674 user = User.get_by_id(user.id)
1676 assert user.name == nil
1677 assert user.avatar == %{}
1678 assert user.banner == %{}
1681 describe "set_suggestion" do
1682 test "suggests a user" do
1683 user = insert(:user, is_suggested: false)
1684 refute user.is_suggested
1685 {:ok, user} = User.set_suggestion(user, true)
1686 assert user.is_suggested
1689 test "suggests a list of users" do
1690 unsuggested_users = [
1691 insert(:user, is_suggested: false),
1692 insert(:user, is_suggested: false),
1693 insert(:user, is_suggested: false)
1696 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1698 assert Enum.count(users) == 3
1700 Enum.each(users, fn user ->
1701 assert user.is_suggested
1705 test "unsuggests a user" do
1706 user = insert(:user, is_suggested: true)
1707 assert user.is_suggested
1708 {:ok, user} = User.set_suggestion(user, false)
1709 refute user.is_suggested
1713 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1714 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1717 describe "per-user rich-text filtering" do
1718 test "html_filter_policy returns default policies, when rich-text is enabled" do
1719 user = insert(:user)
1721 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1724 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1725 user = insert(:user, no_rich_text: true)
1727 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1731 describe "caching" do
1732 test "invalidate_cache works" do
1733 user = insert(:user)
1735 User.set_cache(user)
1736 User.invalidate_cache(user)
1738 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1739 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1742 test "User.delete() plugs any possible zombie objects" do
1743 user = insert(:user)
1745 {:ok, job} = User.delete(user)
1746 {:ok, _} = ObanHelpers.perform(job)
1748 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1750 assert cached_user != user
1752 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1754 assert cached_user != user
1758 describe "account_status/1" do
1759 setup do: clear_config([:instance, :account_activation_required])
1761 test "return confirmation_pending for unconfirm user" do
1762 clear_config([:instance, :account_activation_required], true)
1763 user = insert(:user, is_confirmed: false)
1764 assert User.account_status(user) == :confirmation_pending
1767 test "return active for confirmed user" do
1768 clear_config([:instance, :account_activation_required], true)
1769 user = insert(:user, is_confirmed: true)
1770 assert User.account_status(user) == :active
1773 test "return active for remote user" do
1774 user = insert(:user, local: false)
1775 assert User.account_status(user) == :active
1778 test "returns :password_reset_pending for user with reset password" do
1779 user = insert(:user, password_reset_pending: true)
1780 assert User.account_status(user) == :password_reset_pending
1783 test "returns :deactivated for deactivated user" do
1784 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1785 assert User.account_status(user) == :deactivated
1788 test "returns :approval_pending for unapproved user" do
1789 user = insert(:user, local: true, is_approved: false)
1790 assert User.account_status(user) == :approval_pending
1792 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1793 assert User.account_status(user) == :approval_pending
1797 describe "superuser?/1" do
1798 test "returns false for unprivileged users" do
1799 user = insert(:user, local: true)
1801 refute User.superuser?(user)
1804 test "returns false for remote users" do
1805 user = insert(:user, local: false)
1806 remote_admin_user = insert(:user, local: false, is_admin: true)
1808 refute User.superuser?(user)
1809 refute User.superuser?(remote_admin_user)
1812 test "returns true for local moderators" do
1813 user = insert(:user, local: true, is_moderator: true)
1815 assert User.superuser?(user)
1818 test "returns true for local admins" do
1819 user = insert(:user, local: true, is_admin: true)
1821 assert User.superuser?(user)
1825 describe "invisible?/1" do
1826 test "returns true for an invisible user" do
1827 user = insert(:user, local: true, invisible: true)
1829 assert User.invisible?(user)
1832 test "returns false for a non-invisible user" do
1833 user = insert(:user, local: true)
1835 refute User.invisible?(user)
1839 describe "visible_for/2" do
1840 test "returns true when the account is itself" do
1841 user = insert(:user, local: true)
1843 assert User.visible_for(user, user) == :visible
1846 test "returns false when the account is unconfirmed and confirmation is required" do
1847 clear_config([:instance, :account_activation_required], true)
1849 user = insert(:user, local: true, is_confirmed: false)
1850 other_user = insert(:user, local: true)
1852 refute User.visible_for(user, other_user) == :visible
1855 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1856 clear_config([:instance, :account_activation_required], true)
1858 user = insert(:user, local: false, is_confirmed: false)
1859 other_user = insert(:user, local: true)
1861 assert User.visible_for(user, other_user) == :visible
1864 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1865 clear_config([:instance, :account_activation_required], true)
1867 user = insert(:user, local: true, is_confirmed: false)
1868 other_user = insert(:user, local: true, is_admin: true)
1870 assert User.visible_for(user, other_user) == :visible
1874 describe "parse_bio/2" do
1875 test "preserves hosts in user links text" do
1876 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1877 user = insert(:user)
1878 bio = "A.k.a. @nick@domain.com"
1881 ~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>)
1883 assert expected_text == User.parse_bio(bio, user)
1886 test "Adds rel=me on linkbacked urls" do
1887 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1889 bio = "http://example.com/rel_me/null"
1890 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1891 assert expected_text == User.parse_bio(bio, user)
1893 bio = "http://example.com/rel_me/link"
1894 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1895 assert expected_text == User.parse_bio(bio, user)
1897 bio = "http://example.com/rel_me/anchor"
1898 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1899 assert expected_text == User.parse_bio(bio, user)
1903 test "follower count is updated when a follower is blocked" do
1904 user = insert(:user)
1905 follower = insert(:user)
1906 follower2 = insert(:user)
1907 follower3 = insert(:user)
1909 {:ok, follower, user} = User.follow(follower, user)
1910 {:ok, _follower2, _user} = User.follow(follower2, user)
1911 {:ok, _follower3, _user} = User.follow(follower3, user)
1913 {:ok, _user_relationship} = User.block(user, follower)
1914 user = refresh_record(user)
1916 assert user.follower_count == 2
1919 describe "list_inactive_users_query/1" do
1920 defp days_ago(days) do
1922 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1923 -days * 60 * 60 * 24,
1928 test "Users are inactive by default" do
1932 Enum.map(1..total, fn _ ->
1933 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1936 inactive_users_ids =
1937 Pleroma.User.list_inactive_users_query()
1938 |> Pleroma.Repo.all()
1939 |> Enum.map(& &1.id)
1941 Enum.each(users, fn user ->
1942 assert user.id in inactive_users_ids
1946 test "Only includes users who has no recent activity" do
1950 Enum.map(1..total, fn _ ->
1951 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1954 {inactive, active} = Enum.split(users, trunc(total / 2))
1956 Enum.map(active, fn user ->
1957 to = Enum.random(users -- [user])
1960 CommonAPI.post(user, %{
1961 status: "hey @#{to.nickname}"
1965 inactive_users_ids =
1966 Pleroma.User.list_inactive_users_query()
1967 |> Pleroma.Repo.all()
1968 |> Enum.map(& &1.id)
1970 Enum.each(active, fn user ->
1971 refute user.id in inactive_users_ids
1974 Enum.each(inactive, fn user ->
1975 assert user.id in inactive_users_ids
1979 test "Only includes users with no read notifications" do
1983 Enum.map(1..total, fn _ ->
1984 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1987 [sender | recipients] = users
1988 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1990 Enum.each(recipients, fn to ->
1992 CommonAPI.post(sender, %{
1993 status: "hey @#{to.nickname}"
1997 CommonAPI.post(sender, %{
1998 status: "hey again @#{to.nickname}"
2002 Enum.each(active, fn user ->
2003 [n1, _n2] = Pleroma.Notification.for_user(user)
2004 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2007 inactive_users_ids =
2008 Pleroma.User.list_inactive_users_query()
2009 |> Pleroma.Repo.all()
2010 |> Enum.map(& &1.id)
2012 Enum.each(active, fn user ->
2013 refute user.id in inactive_users_ids
2016 Enum.each(inactive, fn user ->
2017 assert user.id in inactive_users_ids
2022 describe "ensure_keys_present" do
2023 test "it creates keys for a user and stores them in info" do
2024 user = insert(:user)
2025 refute is_binary(user.keys)
2026 {:ok, user} = User.ensure_keys_present(user)
2027 assert is_binary(user.keys)
2030 test "it doesn't create keys if there already are some" do
2031 user = insert(:user, keys: "xxx")
2032 {:ok, user} = User.ensure_keys_present(user)
2033 assert user.keys == "xxx"
2037 describe "get_ap_ids_by_nicknames" do
2038 test "it returns a list of AP ids for a given set of nicknames" do
2039 user = insert(:user)
2040 user_two = insert(:user)
2042 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2043 assert length(ap_ids) == 2
2044 assert user.ap_id in ap_ids
2045 assert user_two.ap_id in ap_ids
2049 describe "sync followers count" do
2051 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2052 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2053 insert(:user, local: true)
2054 insert(:user, local: false, is_active: false)
2055 {:ok, user1: user1, user2: user2}
2058 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2059 [fdb_user1] = User.external_users(limit: 1)
2061 assert fdb_user1.ap_id
2062 assert fdb_user1.ap_id == user1.ap_id
2063 assert fdb_user1.id == user1.id
2065 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2067 assert fdb_user2.ap_id
2068 assert fdb_user2.ap_id == user2.ap_id
2069 assert fdb_user2.id == user2.id
2071 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2075 describe "is_internal_user?/1" do
2076 test "non-internal user returns false" do
2077 user = insert(:user)
2078 refute User.is_internal_user?(user)
2081 test "user with no nickname returns true" do
2082 user = insert(:user, %{nickname: nil})
2083 assert User.is_internal_user?(user)
2086 test "user with internal-prefixed nickname returns true" do
2087 user = insert(:user, %{nickname: "internal.test"})
2088 assert User.is_internal_user?(user)
2092 describe "update_and_set_cache/1" do
2093 test "returns error when user is stale instead Ecto.StaleEntryError" do
2094 user = insert(:user)
2096 changeset = Ecto.Changeset.change(user, bio: "test")
2100 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2101 User.update_and_set_cache(changeset)
2104 test "performs update cache if user updated" do
2105 user = insert(:user)
2106 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2108 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2110 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2111 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2112 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2115 test "removes report notifs when user isn't superuser any more" do
2116 report_activity = insert(:report_activity)
2117 user = insert(:user, is_moderator: true, is_admin: true)
2118 {:ok, _} = Notification.create_notifications(report_activity)
2120 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2122 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2123 # is still superuser because still admin
2124 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2126 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false})
2127 # is still superuser because still moderator
2128 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2130 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2131 # is not a superuser any more
2132 assert [] = Notification.for_user(user)
2136 describe "following/followers synchronization" do
2137 setup do: clear_config([:instance, :external_user_synchronization])
2139 test "updates the counters normally on following/getting a follow when disabled" do
2140 clear_config([:instance, :external_user_synchronization], false)
2141 user = insert(:user)
2146 follower_address: "http://localhost:4001/users/masto_closed/followers",
2147 following_address: "http://localhost:4001/users/masto_closed/following",
2151 assert other_user.following_count == 0
2152 assert other_user.follower_count == 0
2154 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2156 assert user.following_count == 1
2157 assert other_user.follower_count == 1
2160 test "syncronizes the counters with the remote instance for the followed when enabled" do
2161 clear_config([:instance, :external_user_synchronization], false)
2163 user = insert(:user)
2168 follower_address: "http://localhost:4001/users/masto_closed/followers",
2169 following_address: "http://localhost:4001/users/masto_closed/following",
2173 assert other_user.following_count == 0
2174 assert other_user.follower_count == 0
2176 clear_config([:instance, :external_user_synchronization], true)
2177 {:ok, _user, other_user} = User.follow(user, other_user)
2179 assert other_user.follower_count == 437
2182 test "syncronizes the counters with the remote instance for the follower when enabled" do
2183 clear_config([:instance, :external_user_synchronization], false)
2185 user = insert(:user)
2190 follower_address: "http://localhost:4001/users/masto_closed/followers",
2191 following_address: "http://localhost:4001/users/masto_closed/following",
2195 assert other_user.following_count == 0
2196 assert other_user.follower_count == 0
2198 clear_config([:instance, :external_user_synchronization], true)
2199 {:ok, other_user, _user} = User.follow(other_user, user)
2201 assert other_user.following_count == 152
2205 describe "change_email/2" do
2207 [user: insert(:user)]
2210 test "blank email returns error if we require an email on registration", %{user: user} do
2211 orig_account_activation_required =
2212 Pleroma.Config.get([:instance, :account_activation_required])
2214 Pleroma.Config.put([:instance, :account_activation_required], true)
2218 [:instance, :account_activation_required],
2219 orig_account_activation_required
2223 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2224 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2227 test "blank email should be fine if we do not require an email on registration", %{user: user} do
2228 orig_account_activation_required =
2229 Pleroma.Config.get([:instance, :account_activation_required])
2231 Pleroma.Config.put([:instance, :account_activation_required], false)
2235 [:instance, :account_activation_required],
2236 orig_account_activation_required
2240 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2241 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2244 test "non unique email returns error", %{user: user} do
2245 %{email: email} = insert(:user)
2247 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2248 User.change_email(user, email)
2251 test "invalid email returns error", %{user: user} do
2252 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2253 User.change_email(user, "cofe")
2256 test "changes email", %{user: user} do
2257 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2260 test "adds email", %{user: user} do
2261 orig_account_activation_required =
2262 Pleroma.Config.get([:instance, :account_activation_required])
2264 Pleroma.Config.put([:instance, :account_activation_required], false)
2268 [:instance, :account_activation_required],
2269 orig_account_activation_required
2273 assert {:ok, _} = User.change_email(user, "")
2274 Pleroma.Config.put([:instance, :account_activation_required], true)
2276 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2280 describe "get_cached_by_nickname_or_id" do
2282 local_user = insert(:user)
2283 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2285 [local_user: local_user, remote_user: remote_user]
2288 setup do: clear_config([:instance, :limit_to_local_content])
2290 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2291 remote_user: remote_user
2293 clear_config([:instance, :limit_to_local_content], false)
2294 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2296 clear_config([:instance, :limit_to_local_content], true)
2297 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2299 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2300 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2303 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2304 %{remote_user: remote_user} do
2305 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2306 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2309 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2310 %{remote_user: remote_user, local_user: local_user} do
2311 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2312 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2315 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2316 %{remote_user: remote_user} do
2317 clear_config([:instance, :limit_to_local_content], true)
2318 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2321 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2322 %{local_user: local_user} do
2323 clear_config([:instance, :limit_to_local_content], false)
2324 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2326 clear_config([:instance, :limit_to_local_content], true)
2327 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2329 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2330 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2334 describe "update_email_notifications/2" do
2336 user = insert(:user, email_notifications: %{"digest" => true})
2341 test "Notifications are updated", %{user: user} do
2342 true = user.email_notifications["digest"]
2343 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2344 assert result.email_notifications["digest"] == false
2348 describe "local_nickname/1" do
2349 test "returns nickname without host" do
2350 assert User.local_nickname("@mentioned") == "mentioned"
2351 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2352 assert User.local_nickname("nickname@host.com") == "nickname"
2356 describe "full_nickname/1" do
2357 test "returns fully qualified nickname for local and remote users" do
2359 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2361 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2363 assert User.full_nickname(local_user) == "local_user@somehost.com"
2364 assert User.full_nickname(remote_user) == "remote@host.com"
2367 test "strips leading @ from mentions" do
2368 assert User.full_nickname("@mentioned") == "mentioned"
2369 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2372 test "does not modify nicknames" do
2373 assert User.full_nickname("nickname") == "nickname"
2374 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2378 test "avatar fallback" do
2379 user = insert(:user)
2380 assert User.avatar_url(user) =~ "/images/avi.png"
2382 clear_config([:assets, :default_user_avatar], "avatar.png")
2384 user = User.get_cached_by_nickname_or_id(user.nickname)
2385 assert User.avatar_url(user) =~ "avatar.png"
2387 assert User.avatar_url(user, no_default: true) == nil
2390 test "get_host/1" do
2391 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2392 assert User.get_host(user) == "lain.com"
2395 test "update_last_active_at/1" do
2396 user = insert(:user)
2397 assert is_nil(user.last_active_at)
2399 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2401 assert {:ok, user} = User.update_last_active_at(user)
2403 assert user.last_active_at >= test_started_at
2404 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2407 NaiveDateTime.utc_now()
2408 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2409 |> NaiveDateTime.truncate(:second)
2411 assert {:ok, user} =
2413 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2414 |> User.update_and_set_cache()
2416 assert user.last_active_at == last_active_at
2417 assert {:ok, user} = User.update_last_active_at(user)
2418 assert user.last_active_at >= test_started_at
2419 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2422 test "active_user_count/1" do
2424 insert(:user, %{local: false})
2425 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2426 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2427 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2428 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2429 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2431 assert User.active_user_count() == 2
2432 assert User.active_user_count(180) == 3
2433 assert User.active_user_count(365) == 4
2434 assert User.active_user_count(1000) == 5
2439 user = insert(:user)
2441 [user: user, object_id: object_id_from_created_activity(user)]
2444 test "unique pins", %{user: user, object_id: object_id} do
2445 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2446 User.add_pinned_object_id(user, object_id)
2448 assert Enum.count(pins) == 1
2450 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2451 User.add_pinned_object_id(updated_user, object_id)
2453 assert pinned_at1 == pinned_at2
2455 assert Enum.count(pins) == 1
2458 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2459 clear_config([:instance, :max_pinned_statuses], 1)
2460 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2462 object_id2 = object_id_from_created_activity(user)
2464 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2465 assert Keyword.has_key?(errors, :pinned_objects)
2468 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2469 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2471 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2472 assert after_remove.pinned_objects == %{}
2476 defp object_id_from_created_activity(user) do
2477 %{id: id} = insert(:note_activity, user: user)
2478 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2482 describe "add_alias/2" do
2483 test "should add alias for another user" do
2484 user = insert(:user)
2485 user2 = insert(:user)
2487 assert {:ok, user_updated} = user |> User.add_alias(user2)
2489 assert user_updated.also_known_as |> length() == 1
2490 assert user2.ap_id in user_updated.also_known_as
2493 test "should add multiple aliases" do
2494 user = insert(:user)
2495 user2 = insert(:user)
2496 user3 = insert(:user)
2498 assert {:ok, user} = user |> User.add_alias(user2)
2499 assert {:ok, user_updated} = user |> User.add_alias(user3)
2501 assert user_updated.also_known_as |> length() == 2
2502 assert user2.ap_id in user_updated.also_known_as
2503 assert user3.ap_id in user_updated.also_known_as
2506 test "should not add duplicate aliases" do
2507 user = insert(:user)
2508 user2 = insert(:user)
2510 assert {:ok, user} = user |> User.add_alias(user2)
2512 assert {:ok, user_updated} = user |> User.add_alias(user2)
2514 assert user_updated.also_known_as |> length() == 1
2515 assert user2.ap_id in user_updated.also_known_as
2519 describe "alias_users/1" do
2520 test "should get aliases for a user" do
2521 user = insert(:user)
2522 user2 = insert(:user, also_known_as: [user.ap_id])
2524 aliases = user2 |> User.alias_users()
2526 assert aliases |> length() == 1
2528 alias_user = aliases |> Enum.at(0)
2530 assert alias_user.ap_id == user.ap_id
2534 describe "delete_alias/2" do
2535 test "should delete existing alias" do
2536 user = insert(:user)
2537 user2 = insert(:user, also_known_as: [user.ap_id])
2539 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2541 assert user_updated.also_known_as == []
2544 test "should report error on non-existing alias" do
2545 user = insert(:user)
2546 user2 = insert(:user)
2547 user3 = insert(:user, also_known_as: [user.ap_id])
2549 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2551 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2553 assert user3_updated.also_known_as |> length() == 1
2554 assert user.ap_id in user3_updated.also_known_as