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 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
27 setup do: clear_config([:instance, :account_activation_required])
29 describe "service actors" do
30 test "returns updated invisible actor" do
31 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
32 followers_uri = "#{uri}/followers"
41 follower_address: followers_uri
45 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
46 assert actor.invisible
49 test "returns relay user" do
50 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
51 followers_uri = "#{uri}/followers"
58 follower_address: ^followers_uri
59 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
61 assert capture_log(fn ->
62 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
63 end) =~ "Cannot create service actor:"
66 test "returns invisible actor" do
67 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
68 followers_uri = "#{uri}/followers"
69 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
72 nickname: "internal.fetch-test",
76 follower_address: ^followers_uri
79 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
80 assert user.id == user2.id
84 describe "AP ID user relationships" do
86 {:ok, user: insert(:user)}
89 test "outgoing_relationships_ap_ids/1", %{user: user} do
90 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
98 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
100 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
101 {rel_type, Enum.sort(ap_ids)}
105 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
106 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
108 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
109 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
111 assert ap_ids_by_rel[:notification_mute] ==
112 Enum.sort(User.notification_muted_users_ap_ids(user))
114 assert ap_ids_by_rel[:notification_mute] ==
115 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
117 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
119 assert ap_ids_by_rel[:reblog_mute] ==
120 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
122 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
124 assert ap_ids_by_rel[:inverse_subscription] ==
125 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
127 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
129 assert ap_ids_by_rel ==
130 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
134 describe "when tags are nil" do
135 test "tagging a user" do
136 user = insert(:user, %{tags: nil})
137 user = User.tag(user, ["cool", "dude"])
139 assert "cool" in user.tags
140 assert "dude" in user.tags
143 test "untagging a user" do
144 user = insert(:user, %{tags: nil})
145 user = User.untag(user, ["cool", "dude"])
147 assert user.tags == []
151 test "ap_id returns the activity pub id for the user" do
152 user = UserBuilder.build()
154 expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}"
156 assert expected_ap_id == User.ap_id(user)
159 test "ap_followers returns the followers collection for the user" do
160 user = UserBuilder.build()
162 expected_followers_collection = "#{User.ap_id(user)}/followers"
164 assert expected_followers_collection == User.ap_followers(user)
167 test "ap_following returns the following collection for the user" do
168 user = UserBuilder.build()
170 expected_followers_collection = "#{User.ap_id(user)}/following"
172 assert expected_followers_collection == User.ap_following(user)
175 test "returns all pending follow requests" do
176 unlocked = insert(:user)
177 locked = insert(:user, is_locked: true)
178 follower = insert(:user)
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, is_locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
200 assert [^pending_follower] = User.get_follow_requests(locked)
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, is_locked: true)
205 pending_follower = insert(:user, %{is_active: false})
207 CommonAPI.follow(pending_follower, locked)
209 refute pending_follower.is_active
210 assert [] = User.get_follow_requests(locked)
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, is_locked: true)
215 follower = insert(:user)
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
224 test "follow_all follows mutliple users" do
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
236 {:ok, user, followed_zero} = User.follow(user, followed_zero)
238 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
240 assert User.following?(user, followed_one)
241 assert User.following?(user, followed_two)
242 assert User.following?(user, followed_zero)
243 refute User.following?(user, not_followed)
244 refute User.following?(user, blocked)
245 refute User.following?(user, reverse_blocked)
248 test "follow_all follows mutliple users without duplicating" do
250 followed_zero = insert(:user)
251 followed_one = insert(:user)
252 followed_two = insert(:user)
254 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
255 assert length(User.following(user)) == 3
257 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
258 assert length(User.following(user)) == 4
261 test "follow takes a user and another user" do
263 followed = insert(:user)
265 {:ok, user, followed} = User.follow(user, followed)
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
270 assert followed.follower_count == 1
271 assert user.following_count == 1
273 assert User.ap_followers(followed) in User.following(user)
276 test "can't follow a deactivated users" do
278 followed = insert(:user, %{is_active: false})
280 {:error, _} = User.follow(user, followed)
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
287 {:ok, _user_relationship} = User.block(blocker, blockee)
289 {:error, _} = User.follow(blockee, blocker)
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
296 {:ok, _user_relationship} = User.block(blocker, blocked)
298 {:error, _} = User.subscribe(blocked, blocker)
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, is_locked: true)
303 followed = insert(:user, is_locked: true)
305 {:ok, follower, followed} = User.maybe_direct_follow(follower, followed)
307 refute User.following?(follower, followed)
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
313 test "unfollow with synchronizes external user" do
314 clear_config([:instance, :external_user_synchronization], true)
319 follower_address: "http://localhost:4001/users/fuser1/followers",
320 following_address: "http://localhost:4001/users/fuser1/following",
321 ap_id: "http://localhost:4001/users/fuser1"
328 ap_id: "http://localhost:4001/users/fuser2",
329 follower_address: "http://localhost:4001/users/fuser2/followers",
330 following_address: "http://localhost:4001/users/fuser2/following"
333 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
335 {:ok, user, _activity} = User.unfollow(user, followed)
337 user = User.get_cached_by_id(user.id)
339 assert User.following(user) == []
342 test "unfollow takes a user and another user" do
343 followed = insert(:user)
346 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
348 assert User.following(user) == [user.follower_address, followed.follower_address]
350 {:ok, user, _activity} = User.unfollow(user, followed)
352 assert User.following(user) == [user.follower_address]
355 test "unfollow doesn't unfollow yourself" do
358 {:error, _} = User.unfollow(user, user)
360 assert User.following(user) == [user.follower_address]
364 test "test if a user is following another user" do
365 followed = insert(:user)
367 User.follow(user, followed, :follow_accept)
369 assert User.following?(user, followed)
370 refute User.following?(followed, user)
373 test "fetches correct profile for nickname beginning with number" do
374 # Use old-style integer ID to try to reproduce the problem
375 user = insert(:user, %{id: 1080})
376 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
377 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
380 describe "user registration" do
386 password_confirmation: "test",
387 email: "email@example.com"
390 setup do: clear_config([:instance, :autofollowed_nicknames])
391 setup do: clear_config([:instance, :autofollowing_nicknames])
392 setup do: clear_config([:welcome])
393 setup do: clear_config([:instance, :account_activation_required])
395 test "it autofollows accounts that are set for it" do
397 remote_user = insert(:user, %{local: false})
399 clear_config([:instance, :autofollowed_nicknames], [
404 cng = User.register_changeset(%User{}, @full_user_data)
406 {:ok, registered_user} = User.register(cng)
408 assert User.following?(registered_user, user)
409 refute User.following?(registered_user, remote_user)
412 test "it adds automatic followers for new registered accounts" do
413 user1 = insert(:user)
414 user2 = insert(:user)
416 clear_config([:instance, :autofollowing_nicknames], [
421 cng = User.register_changeset(%User{}, @full_user_data)
423 {:ok, registered_user} = User.register(cng)
425 assert User.following?(user1, registered_user)
426 assert User.following?(user2, registered_user)
429 test "it sends a welcome message if it is set" do
430 welcome_user = insert(:user)
431 clear_config([:welcome, :direct_message, :enabled], true)
432 clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
433 clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message")
435 cng = User.register_changeset(%User{}, @full_user_data)
436 {:ok, registered_user} = User.register(cng)
437 ObanHelpers.perform_all()
439 activity = Repo.one(Pleroma.Activity)
440 assert registered_user.ap_id in activity.recipients
441 assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message"
442 assert activity.actor == welcome_user.ap_id
445 test "it sends a welcome chat message if it is set" do
446 welcome_user = insert(:user)
447 clear_config([:welcome, :chat_message, :enabled], true)
448 clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
449 clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
451 cng = User.register_changeset(%User{}, @full_user_data)
452 {:ok, registered_user} = User.register(cng)
453 ObanHelpers.perform_all()
455 activity = Repo.one(Pleroma.Activity)
456 assert registered_user.ap_id in activity.recipients
457 assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
458 assert activity.actor == welcome_user.ap_id
462 clear_config(:mrf_simple,
465 federated_timeline_removal: [],
475 setup do: clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
477 test "it sends a welcome chat message when Simple policy applied to local instance" do
478 clear_config([:mrf_simple, :media_nsfw], [{"localhost", ""}])
480 welcome_user = insert(:user)
481 clear_config([:welcome, :chat_message, :enabled], true)
482 clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
483 clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
485 cng = User.register_changeset(%User{}, @full_user_data)
486 {:ok, registered_user} = User.register(cng)
487 ObanHelpers.perform_all()
489 activity = Repo.one(Pleroma.Activity)
490 assert registered_user.ap_id in activity.recipients
491 assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
492 assert activity.actor == welcome_user.ap_id
495 test "it sends a welcome email message if it is set" do
496 welcome_user = insert(:user)
497 clear_config([:welcome, :email, :enabled], true)
498 clear_config([:welcome, :email, :sender], welcome_user.email)
501 [:welcome, :email, :subject],
502 "Hello, welcome to cool site: <%= instance_name %>"
505 instance_name = Pleroma.Config.get([:instance, :name])
507 cng = User.register_changeset(%User{}, @full_user_data)
508 {:ok, registered_user} = User.register(cng)
509 ObanHelpers.perform_all()
512 from: {instance_name, welcome_user.email},
513 to: {registered_user.name, registered_user.email},
514 subject: "Hello, welcome to cool site: #{instance_name}",
515 html_body: "Welcome to #{instance_name}"
519 test "it sends a confirm email" do
520 clear_config([:instance, :account_activation_required], true)
522 cng = User.register_changeset(%User{}, @full_user_data)
523 {:ok, registered_user} = User.register(cng)
524 ObanHelpers.perform_all()
526 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
527 # temporary hackney fix until hackney max_connections bug is fixed
528 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
529 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
530 |> assert_email_sent()
533 test "sends a pending approval email" do
534 clear_config([:instance, :account_approval_required], true)
537 User.register_changeset(%User{}, @full_user_data)
540 ObanHelpers.perform_all()
543 from: Pleroma.Config.Helpers.sender(),
544 to: {user.name, user.email},
545 subject: "Your account is awaiting approval"
549 test "it sends a registration confirmed email if no others will be sent" do
550 clear_config([:welcome, :email, :enabled], false)
551 clear_config([:instance, :account_activation_required], false)
552 clear_config([:instance, :account_approval_required], false)
555 User.register_changeset(%User{}, @full_user_data)
558 ObanHelpers.perform_all()
560 instance_name = Pleroma.Config.get([:instance, :name])
561 sender = Pleroma.Config.get([:instance, :notify_email])
564 from: {instance_name, sender},
565 to: {user.name, user.email},
566 subject: "Account registered on #{instance_name}"
570 test "it fails gracefully with invalid email config" do
571 cng = User.register_changeset(%User{}, @full_user_data)
573 # Disable the mailer but enable all the things that want to send emails
574 clear_config([Pleroma.Emails.Mailer, :enabled], false)
575 clear_config([:instance, :account_activation_required], true)
576 clear_config([:instance, :account_approval_required], true)
577 clear_config([:welcome, :email, :enabled], true)
578 clear_config([:welcome, :email, :sender], "lain@lain.com")
580 # The user is still created
581 assert {:ok, %User{nickname: "nick"}} = User.register(cng)
584 ObanHelpers.perform_all()
588 test "it works when the registering user does not provide an email" do
589 clear_config([Pleroma.Emails.Mailer, :enabled], false)
590 clear_config([:instance, :account_activation_required], false)
591 clear_config([:instance, :account_approval_required], true)
593 cng = User.register_changeset(%User{}, @full_user_data |> Map.put(:email, ""))
595 # The user is still created
596 assert {:ok, %User{nickname: "nick"}} = User.register(cng)
599 ObanHelpers.perform_all()
603 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
604 clear_config([:instance, :account_activation_required], true)
608 |> Enum.each(fn key ->
609 params = Map.delete(@full_user_data, key)
610 changeset = User.register_changeset(%User{}, params)
612 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
616 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
617 clear_config([:instance, :account_activation_required], false)
621 |> Enum.each(fn key ->
622 params = Map.delete(@full_user_data, key)
623 changeset = User.register_changeset(%User{}, params)
625 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
629 test "it restricts certain nicknames" do
630 clear_config([User, :restricted_nicknames], ["about"])
631 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
633 assert is_binary(restricted_name)
637 |> Map.put(:nickname, restricted_name)
639 changeset = User.register_changeset(%User{}, params)
641 refute changeset.valid?
644 test "it is case-insensitive when restricting nicknames" do
645 clear_config([User, :restricted_nicknames], ["about"])
646 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
648 assert is_binary(restricted_name)
650 restricted_upcase_name = String.upcase(restricted_name)
654 |> Map.put(:nickname, restricted_upcase_name)
656 changeset = User.register_changeset(%User{}, params)
658 refute changeset.valid?
661 test "it blocks blacklisted email domains" do
662 clear_config([User, :email_blacklist], ["trolling.world"])
665 params = Map.put(@full_user_data, :email, "troll@trolling.world")
666 changeset = User.register_changeset(%User{}, params)
667 refute changeset.valid?
669 # Block with case-insensitive match
670 params = Map.put(@full_user_data, :email, "troll@TrOlLing.wOrld")
671 changeset = User.register_changeset(%User{}, params)
672 refute changeset.valid?
674 # Block with subdomain match
675 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
676 changeset = User.register_changeset(%User{}, params)
677 refute changeset.valid?
679 # Pass with different domains that are similar
680 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
681 changeset = User.register_changeset(%User{}, params)
682 assert changeset.valid?
684 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
685 changeset = User.register_changeset(%User{}, params)
686 assert changeset.valid?
689 test "it sets the password_hash, ap_id, private key and followers collection address" do
690 changeset = User.register_changeset(%User{}, @full_user_data)
692 assert changeset.valid?
694 assert is_binary(changeset.changes[:password_hash])
695 assert is_binary(changeset.changes[:keys])
696 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
697 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
700 test "it sets the 'accepts_chat_messages' set to true" do
701 changeset = User.register_changeset(%User{}, @full_user_data)
702 assert changeset.valid?
704 {:ok, user} = Repo.insert(changeset)
706 assert user.accepts_chat_messages
709 test "it creates a confirmed user" do
710 changeset = User.register_changeset(%User{}, @full_user_data)
711 assert changeset.valid?
713 {:ok, user} = Repo.insert(changeset)
715 assert user.is_confirmed
719 describe "user registration, with :account_activation_required" do
725 password_confirmation: "test",
726 email: "email@example.com"
728 setup do: clear_config([:instance, :account_activation_required], true)
730 test "it creates unconfirmed user" do
731 changeset = User.register_changeset(%User{}, @full_user_data)
732 assert changeset.valid?
734 {:ok, user} = Repo.insert(changeset)
736 refute user.is_confirmed
737 assert user.confirmation_token
740 test "it creates confirmed user if :confirmed option is given" do
741 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
742 assert changeset.valid?
744 {:ok, user} = Repo.insert(changeset)
746 assert user.is_confirmed
747 refute user.confirmation_token
751 describe "user registration, with :account_approval_required" do
757 password_confirmation: "test",
758 email: "email@example.com",
759 registration_reason: "I'm a cool guy :)"
761 setup do: clear_config([:instance, :account_approval_required], true)
763 test "it creates unapproved user" do
764 changeset = User.register_changeset(%User{}, @full_user_data)
765 assert changeset.valid?
767 {:ok, user} = Repo.insert(changeset)
769 refute user.is_approved
770 assert user.registration_reason == "I'm a cool guy :)"
773 test "it restricts length of registration reason" do
774 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
776 assert is_integer(reason_limit)
781 :registration_reason,
782 "Quia et nesciunt dolores numquam ipsam nisi sapiente soluta. Ullam repudiandae nisi quam porro officiis officiis ad. Consequatur animi velit ex quia. Odit voluptatem perferendis quia ut nisi. Dignissimos sit soluta atque aliquid dolorem ut dolorum ut. Labore voluptates iste iusto amet voluptatum earum. Ad fugit illum nam eos ut nemo. Pariatur ea fuga non aspernatur. Dignissimos debitis officia corporis est nisi ab et. Atque itaque alias eius voluptas minus. Accusamus numquam tempore occaecati in."
785 changeset = User.register_changeset(%User{}, params)
787 refute changeset.valid?
791 describe "user registration, with :birthday_required and :birthday_min_age" do
797 password_confirmation: "test",
798 email: "email@example.com"
802 clear_config([:instance, :birthday_required], true)
803 clear_config([:instance, :birthday_min_age], 18 * 365)
806 test "it passes when correct birth date is provided" do
807 today = Date.utc_today()
808 birthday = Date.add(today, -19 * 365)
812 |> Map.put(:birthday, birthday)
814 changeset = User.register_changeset(%User{}, params)
816 assert changeset.valid?
819 test "it fails when birth date is not provided" do
820 changeset = User.register_changeset(%User{}, @full_user_data)
822 refute changeset.valid?
825 test "it fails when provided invalid birth date" do
826 today = Date.utc_today()
827 birthday = Date.add(today, -17 * 365)
831 |> Map.put(:birthday, birthday)
833 changeset = User.register_changeset(%User{}, params)
835 refute changeset.valid?
839 describe "get_or_fetch/1" do
840 test "gets an existing user by nickname" do
842 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
844 assert user == fetched_user
847 test "gets an existing user by ap_id" do
848 ap_id = "http://mastodon.example.org/users/admin"
854 nickname: "admin@mastodon.example.org",
858 {:ok, fetched_user} = User.get_or_fetch(ap_id)
859 freshed_user = refresh_record(user)
860 assert freshed_user == fetched_user
863 test "gets an existing user by nickname starting with http" do
864 user = insert(:user, nickname: "httpssome")
865 {:ok, fetched_user} = User.get_or_fetch("httpssome")
867 assert user == fetched_user
871 describe "get_or_fetch/1 remote users with tld, while BE is runned on subdomain" do
872 setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
874 test "for mastodon" do
876 %{url: "https://example.com/.well-known/host-meta"} ->
879 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
882 %{url: "https://sub.example.com/.well-known/host-meta"} ->
886 "test/fixtures/webfinger/masto-host-meta.xml"
888 |> String.replace("{{domain}}", "sub.example.com")
891 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
895 "test/fixtures/webfinger/masto-webfinger.json"
897 |> String.replace("{{nickname}}", "a")
898 |> String.replace("{{domain}}", "example.com")
899 |> String.replace("{{subdomain}}", "sub.example.com"),
900 headers: [{"content-type", "application/jrd+json"}]
903 %{url: "https://sub.example.com/users/a"} ->
907 "test/fixtures/webfinger/masto-user.json"
909 |> String.replace("{{nickname}}", "a")
910 |> String.replace("{{domain}}", "sub.example.com"),
911 headers: [{"content-type", "application/activity+json"}]
914 %{url: "https://sub.example.com/users/a/collections/featured"} ->
918 File.read!("test/fixtures/users_mock/masto_featured.json")
919 |> String.replace("{{domain}}", "sub.example.com")
920 |> String.replace("{{nickname}}", "a"),
921 headers: [{"content-type", "application/activity+json"}]
925 ap_id = "a@example.com"
926 {:ok, fetched_user} = User.get_or_fetch(ap_id)
928 assert fetched_user.ap_id == "https://sub.example.com/users/a"
929 assert fetched_user.nickname == "a@example.com"
932 test "for pleroma" do
934 %{url: "https://example.com/.well-known/host-meta"} ->
937 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
940 %{url: "https://sub.example.com/.well-known/host-meta"} ->
944 "test/fixtures/webfinger/pleroma-host-meta.xml"
946 |> String.replace("{{domain}}", "sub.example.com")
949 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
953 "test/fixtures/webfinger/pleroma-webfinger.json"
955 |> String.replace("{{nickname}}", "a")
956 |> String.replace("{{domain}}", "example.com")
957 |> String.replace("{{subdomain}}", "sub.example.com"),
958 headers: [{"content-type", "application/jrd+json"}]
961 %{url: "https://sub.example.com/users/a"} ->
965 "test/fixtures/webfinger/pleroma-user.json"
967 |> String.replace("{{nickname}}", "a")
968 |> String.replace("{{domain}}", "sub.example.com"),
969 headers: [{"content-type", "application/activity+json"}]
973 ap_id = "a@example.com"
974 {:ok, fetched_user} = User.get_or_fetch(ap_id)
976 assert fetched_user.ap_id == "https://sub.example.com/users/a"
977 assert fetched_user.nickname == "a@example.com"
981 describe "fetching a user from nickname or trying to build one" do
982 test "gets an existing user" do
984 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
986 assert user == fetched_user
989 test "gets an existing user, case insensitive" do
990 user = insert(:user, nickname: "nick")
991 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
993 assert user == fetched_user
996 test "gets an existing user by fully qualified nickname" do
999 {:ok, fetched_user} =
1000 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
1002 assert user == fetched_user
1005 test "gets an existing user by fully qualified nickname, case insensitive" do
1006 user = insert(:user, nickname: "nick")
1007 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
1009 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
1011 assert user == fetched_user
1014 @tag capture_log: true
1015 test "returns nil if no user could be fetched" do
1016 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
1017 assert fetched_user == "not found nonexistant@social.heldscal.la"
1020 test "returns nil for nonexistant local user" do
1021 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
1022 assert fetched_user == "not found nonexistant"
1025 test "updates an existing user, if stale" do
1026 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
1032 nickname: "admin@mastodon.example.org",
1033 ap_id: "http://mastodon.example.org/users/admin",
1034 last_refreshed_at: a_week_ago
1037 assert orig_user.last_refreshed_at == a_week_ago
1039 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
1043 refute user.last_refreshed_at == orig_user.last_refreshed_at
1046 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
1047 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
1053 nickname: "admin@mastodon.example.org",
1054 ap_id: "http://mastodon.example.org/users/harinezumigari",
1055 last_refreshed_at: a_week_ago
1058 assert orig_user.last_refreshed_at == a_week_ago
1060 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
1064 refute user.id == orig_user.id
1066 orig_user = User.get_by_id(orig_user.id)
1068 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
1071 @tag capture_log: true
1072 test "it returns the old user if stale, but unfetchable" do
1073 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
1079 nickname: "admin@mastodon.example.org",
1080 ap_id: "http://mastodon.example.org/users/raymoo",
1081 last_refreshed_at: a_week_ago
1084 assert orig_user.last_refreshed_at == a_week_ago
1086 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
1088 assert user.last_refreshed_at == orig_user.last_refreshed_at
1092 test "returns an ap_id for a user" do
1093 user = insert(:user)
1095 assert User.ap_id(user) ==
1096 Pleroma.Web.Router.Helpers.user_feed_url(
1097 Pleroma.Web.Endpoint,
1103 test "returns an ap_followers link for a user" do
1104 user = insert(:user)
1106 assert User.ap_followers(user) ==
1107 Pleroma.Web.Router.Helpers.user_feed_url(
1108 Pleroma.Web.Endpoint,
1114 describe "remote user changeset" do
1120 avatar: %{some: "avatar"}
1122 setup do: clear_config([:instance, :user_bio_length])
1123 setup do: clear_config([:instance, :user_name_length])
1125 test "it confirms validity" do
1126 cs = User.remote_user_changeset(@valid_remote)
1130 test "it sets the follower_adress" do
1131 cs = User.remote_user_changeset(@valid_remote)
1132 # remote users get a fake local follower address
1133 assert cs.changes.follower_address ==
1134 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
1137 test "it enforces the fqn format for nicknames" do
1138 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
1139 assert Ecto.Changeset.get_field(cs, :local) == false
1140 assert cs.changes.avatar
1144 test "it has required fields" do
1146 |> Enum.each(fn field ->
1147 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
1152 test "it is invalid given a local user" do
1153 user = insert(:user)
1154 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
1160 describe "followers and friends" do
1161 test "gets all followers for a given user" do
1162 user = insert(:user)
1163 follower_one = insert(:user)
1164 follower_two = insert(:user)
1165 not_follower = insert(:user)
1167 {:ok, follower_one, user} = User.follow(follower_one, user)
1168 {:ok, follower_two, user} = User.follow(follower_two, user)
1170 res = User.get_followers(user)
1172 assert Enum.member?(res, follower_one)
1173 assert Enum.member?(res, follower_two)
1174 refute Enum.member?(res, not_follower)
1177 test "gets all friends (followed users) for a given user" do
1178 user = insert(:user)
1179 followed_one = insert(:user)
1180 followed_two = insert(:user)
1181 not_followed = insert(:user)
1183 {:ok, user, followed_one} = User.follow(user, followed_one)
1184 {:ok, user, followed_two} = User.follow(user, followed_two)
1186 res = User.get_friends(user)
1188 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
1189 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
1190 assert Enum.member?(res, followed_one)
1191 assert Enum.member?(res, followed_two)
1192 refute Enum.member?(res, not_followed)
1196 describe "updating note and follower count" do
1197 test "it sets the note_count property" do
1198 note = insert(:note)
1200 user = User.get_cached_by_ap_id(note.data["actor"])
1202 assert user.note_count == 0
1204 {:ok, user} = User.update_note_count(user)
1206 assert user.note_count == 1
1209 test "it increases the note_count property" do
1210 note = insert(:note)
1211 user = User.get_cached_by_ap_id(note.data["actor"])
1213 assert user.note_count == 0
1215 {:ok, user} = User.increase_note_count(user)
1217 assert user.note_count == 1
1219 {:ok, user} = User.increase_note_count(user)
1221 assert user.note_count == 2
1224 test "it decreases the note_count property" do
1225 note = insert(:note)
1226 user = User.get_cached_by_ap_id(note.data["actor"])
1228 assert user.note_count == 0
1230 {:ok, user} = User.increase_note_count(user)
1232 assert user.note_count == 1
1234 {:ok, user} = User.decrease_note_count(user)
1236 assert user.note_count == 0
1238 {:ok, user} = User.decrease_note_count(user)
1240 assert user.note_count == 0
1243 test "it sets the follower_count property" do
1244 user = insert(:user)
1245 follower = insert(:user)
1247 User.follow(follower, user)
1249 assert user.follower_count == 0
1251 {:ok, user} = User.update_follower_count(user)
1253 assert user.follower_count == 1
1258 test "it mutes people" do
1259 user = insert(:user)
1260 muted_user = insert(:user)
1262 refute User.mutes?(user, muted_user)
1263 refute User.muted_notifications?(user, muted_user)
1265 {:ok, _user_relationships} = User.mute(user, muted_user)
1267 assert User.mutes?(user, muted_user)
1268 assert User.muted_notifications?(user, muted_user)
1272 user = insert(:user)
1273 muted_user = insert(:user)
1275 {:ok, _user_relationships} = User.mute(user, muted_user, %{duration: 60})
1276 assert User.mutes?(user, muted_user)
1278 worker = Pleroma.Workers.MuteExpireWorker
1279 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1286 assert :ok = perform_job(worker, args)
1288 refute User.mutes?(user, muted_user)
1289 refute User.muted_notifications?(user, muted_user)
1292 test "it unmutes users" do
1293 user = insert(:user)
1294 muted_user = insert(:user)
1296 {:ok, _user_relationships} = User.mute(user, muted_user)
1297 {:ok, _user_mute} = User.unmute(user, muted_user)
1299 refute User.mutes?(user, muted_user)
1300 refute User.muted_notifications?(user, muted_user)
1303 test "it unmutes users by id" do
1304 user = insert(:user)
1305 muted_user = insert(:user)
1307 {:ok, _user_relationships} = User.mute(user, muted_user)
1308 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1310 refute User.mutes?(user, muted_user)
1311 refute User.muted_notifications?(user, muted_user)
1314 test "it mutes user without notifications" do
1315 user = insert(:user)
1316 muted_user = insert(:user)
1318 refute User.mutes?(user, muted_user)
1319 refute User.muted_notifications?(user, muted_user)
1321 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1323 assert User.mutes?(user, muted_user)
1324 refute User.muted_notifications?(user, muted_user)
1328 describe "blocks" do
1329 test "it blocks people" do
1330 user = insert(:user)
1331 blocked_user = insert(:user)
1333 refute User.blocks?(user, blocked_user)
1335 {:ok, _user_relationship} = User.block(user, blocked_user)
1337 assert User.blocks?(user, blocked_user)
1340 test "it unblocks users" do
1341 user = insert(:user)
1342 blocked_user = insert(:user)
1344 {:ok, _user_relationship} = User.block(user, blocked_user)
1345 {:ok, _user_block} = User.unblock(user, blocked_user)
1347 refute User.blocks?(user, blocked_user)
1350 test "blocks tear down cyclical follow relationships" do
1351 blocker = insert(:user)
1352 blocked = insert(:user)
1354 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1355 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1357 assert User.following?(blocker, blocked)
1358 assert User.following?(blocked, blocker)
1360 {:ok, _user_relationship} = User.block(blocker, blocked)
1361 blocked = User.get_cached_by_id(blocked.id)
1363 assert User.blocks?(blocker, blocked)
1365 refute User.following?(blocker, blocked)
1366 refute User.following?(blocked, blocker)
1369 test "blocks tear down blocker->blocked follow relationships" do
1370 blocker = insert(:user)
1371 blocked = insert(:user)
1373 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1375 assert User.following?(blocker, blocked)
1376 refute User.following?(blocked, blocker)
1378 {:ok, _user_relationship} = User.block(blocker, blocked)
1379 blocked = User.get_cached_by_id(blocked.id)
1381 assert User.blocks?(blocker, blocked)
1383 refute User.following?(blocker, blocked)
1384 refute User.following?(blocked, blocker)
1387 test "blocks tear down blocked->blocker follow relationships" do
1388 blocker = insert(:user)
1389 blocked = insert(:user)
1391 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1393 refute User.following?(blocker, blocked)
1394 assert User.following?(blocked, blocker)
1396 {:ok, _user_relationship} = User.block(blocker, blocked)
1397 blocked = User.get_cached_by_id(blocked.id)
1399 assert User.blocks?(blocker, blocked)
1401 refute User.following?(blocker, blocked)
1402 refute User.following?(blocked, blocker)
1405 test "blocks tear down blocked->blocker subscription relationships" do
1406 blocker = insert(:user)
1407 blocked = insert(:user)
1409 {:ok, _subscription} = User.subscribe(blocked, blocker)
1411 assert User.subscribed_to?(blocked, blocker)
1412 refute User.subscribed_to?(blocker, blocked)
1414 {:ok, _user_relationship} = User.block(blocker, blocked)
1416 assert User.blocks?(blocker, blocked)
1417 refute User.subscribed_to?(blocker, blocked)
1418 refute User.subscribed_to?(blocked, blocker)
1422 describe "domain blocking" do
1423 test "blocks domains" do
1424 user = insert(:user)
1425 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1427 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1429 assert User.blocks?(user, collateral_user)
1432 test "does not block domain with same end" do
1433 user = insert(:user)
1436 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1438 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1440 refute User.blocks?(user, collateral_user)
1443 test "does not block domain with same end if wildcard added" do
1444 user = insert(:user)
1447 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1449 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1451 refute User.blocks?(user, collateral_user)
1454 test "blocks domain with wildcard for subdomain" do
1455 user = insert(:user)
1457 user_from_subdomain =
1458 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1460 user_with_two_subdomains =
1462 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1465 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1467 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1469 assert User.blocks?(user, user_from_subdomain)
1470 assert User.blocks?(user, user_with_two_subdomains)
1471 assert User.blocks?(user, user_domain)
1474 test "unblocks domains" do
1475 user = insert(:user)
1476 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1478 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1479 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1481 refute User.blocks?(user, collateral_user)
1484 test "follows take precedence over domain blocks" do
1485 user = insert(:user)
1486 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1488 {:ok, user} = User.block_domain(user, "meanies.social")
1489 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1491 refute User.blocks?(user, good_eggo)
1495 describe "get_recipients_from_activity" do
1496 test "works for announces" do
1497 actor = insert(:user)
1498 user = insert(:user, local: true)
1500 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1501 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1503 recipients = User.get_recipients_from_activity(announce)
1505 assert user in recipients
1508 test "get recipients" do
1509 actor = insert(:user)
1510 user = insert(:user, local: true)
1511 user_two = insert(:user, local: false)
1512 addressed = insert(:user, local: true)
1513 addressed_remote = insert(:user, local: false)
1516 CommonAPI.post(actor, %{
1517 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1520 assert Enum.map([actor, addressed], & &1.ap_id) --
1521 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1523 {:ok, user, actor} = User.follow(user, actor)
1524 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1525 recipients = User.get_recipients_from_activity(activity)
1526 assert length(recipients) == 3
1527 assert user in recipients
1528 assert addressed in recipients
1531 test "has following" do
1532 actor = insert(:user)
1533 user = insert(:user)
1534 user_two = insert(:user)
1535 addressed = insert(:user, local: true)
1538 CommonAPI.post(actor, %{
1539 status: "hey @#{addressed.nickname}"
1542 assert Enum.map([actor, addressed], & &1.ap_id) --
1543 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1545 {:ok, _actor, _user} = User.follow(actor, user)
1546 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1547 recipients = User.get_recipients_from_activity(activity)
1548 assert length(recipients) == 2
1549 assert addressed in recipients
1553 describe ".set_activation" do
1554 test "can de-activate then re-activate a user" do
1555 user = insert(:user)
1556 assert user.is_active
1557 {:ok, user} = User.set_activation(user, false)
1558 refute user.is_active
1559 {:ok, user} = User.set_activation(user, true)
1560 assert user.is_active
1563 test "hide a user from followers" do
1564 user = insert(:user)
1565 user2 = insert(:user)
1567 {:ok, user, user2} = User.follow(user, user2)
1568 {:ok, _user} = User.set_activation(user, false)
1570 user2 = User.get_cached_by_id(user2.id)
1572 assert user2.follower_count == 0
1573 assert [] = User.get_followers(user2)
1576 test "hide a user from friends" do
1577 user = insert(:user)
1578 user2 = insert(:user)
1580 {:ok, user2, user} = User.follow(user2, user)
1581 assert user2.following_count == 1
1582 assert User.following_count(user2) == 1
1584 {:ok, _user} = User.set_activation(user, false)
1586 user2 = User.get_cached_by_id(user2.id)
1588 assert refresh_record(user2).following_count == 0
1589 assert user2.following_count == 0
1590 assert User.following_count(user2) == 0
1591 assert [] = User.get_friends(user2)
1594 test "hide a user's statuses from timelines and notifications" do
1595 user = insert(:user)
1596 user2 = insert(:user)
1598 {:ok, user2, user} = User.follow(user2, user)
1600 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1602 activity = Repo.preload(activity, :bookmark)
1604 [notification] = Pleroma.Notification.for_user(user2)
1605 assert notification.activity.id == activity.id
1607 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1609 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1610 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1614 {:ok, _user} = User.set_activation(user, false)
1616 assert [] == ActivityPub.fetch_public_activities(%{})
1617 assert [] == Pleroma.Notification.for_user(user2)
1620 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1626 describe "approve" do
1627 test "approves a user" do
1628 user = insert(:user, is_approved: false)
1629 refute user.is_approved
1630 {:ok, user} = User.approve(user)
1631 assert user.is_approved
1634 test "approves a list of users" do
1635 unapproved_users = [
1636 insert(:user, is_approved: false),
1637 insert(:user, is_approved: false),
1638 insert(:user, is_approved: false)
1641 {:ok, users} = User.approve(unapproved_users)
1643 assert Enum.count(users) == 3
1645 Enum.each(users, fn user ->
1646 assert user.is_approved
1650 test "it sends welcome email if it is set" do
1651 clear_config([:welcome, :email, :enabled], true)
1652 clear_config([:welcome, :email, :sender], "tester@test.me")
1654 user = insert(:user, is_approved: false)
1655 welcome_user = insert(:user, email: "tester@test.me")
1656 instance_name = Pleroma.Config.get([:instance, :name])
1660 ObanHelpers.perform_all()
1663 from: {instance_name, welcome_user.email},
1664 to: {user.name, user.email},
1665 html_body: "Welcome to #{instance_name}"
1669 test "approving an approved user does not trigger post-register actions" do
1670 clear_config([:welcome, :email, :enabled], true)
1672 user = insert(:user, is_approved: true)
1675 ObanHelpers.perform_all()
1677 assert_no_email_sent()
1681 describe "confirm" do
1682 test "confirms a user" do
1683 user = insert(:user, is_confirmed: false)
1684 refute user.is_confirmed
1685 {:ok, user} = User.confirm(user)
1686 assert user.is_confirmed
1689 test "confirms a list of users" do
1690 unconfirmed_users = [
1691 insert(:user, is_confirmed: false),
1692 insert(:user, is_confirmed: false),
1693 insert(:user, is_confirmed: false)
1696 {:ok, users} = User.confirm(unconfirmed_users)
1698 assert Enum.count(users) == 3
1700 Enum.each(users, fn user ->
1701 assert user.is_confirmed
1705 test "sends approval emails when `is_approved: false`" do
1706 admin = insert(:user, is_admin: true)
1707 user = insert(:user, is_confirmed: false, is_approved: false)
1710 ObanHelpers.perform_all()
1712 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1713 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1715 notify_email = Pleroma.Config.get([:instance, :notify_email])
1716 instance_name = Pleroma.Config.get([:instance, :name])
1718 # User approval email
1720 from: {instance_name, notify_email},
1721 to: {user.name, user.email},
1722 html_body: user_email.html_body
1727 from: {instance_name, notify_email},
1728 to: {admin.name, admin.email},
1729 html_body: admin_email.html_body
1733 test "confirming a confirmed user does not trigger post-register actions" do
1734 user = insert(:user, is_confirmed: true, is_approved: false)
1737 ObanHelpers.perform_all()
1739 assert_no_email_sent()
1743 describe "delete" do
1745 {:ok, user} = insert(:user) |> User.set_cache()
1750 setup do: clear_config([:instance, :federating])
1752 test ".delete_user_activities deletes all create activities", %{user: user} do
1753 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1755 User.delete_user_activities(user)
1757 # TODO: Test removal favorites, repeats, delete activities.
1758 refute Activity.get_by_id(activity.id)
1761 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1762 follower = insert(:user)
1763 {:ok, follower, user} = User.follow(follower, user)
1765 locked_user = insert(:user, name: "locked", is_locked: true)
1766 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1768 object = insert(:note, user: user)
1769 activity = insert(:note_activity, user: user, note: object)
1771 object_two = insert(:note, user: follower)
1772 activity_two = insert(:note_activity, user: follower, note: object_two)
1774 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1775 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1776 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1778 {:ok, job} = User.delete(user)
1779 {:ok, _user} = ObanHelpers.perform(job)
1781 follower = User.get_cached_by_id(follower.id)
1783 refute User.following?(follower, user)
1784 assert %{is_active: false} = User.get_by_id(user.id)
1786 assert [] == User.get_follow_requests(locked_user)
1790 |> Activity.Queries.by_actor()
1792 |> Enum.map(fn act -> act.data["type"] end)
1794 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1796 refute Activity.get_by_id(activity.id)
1797 refute Activity.get_by_id(like.id)
1798 refute Activity.get_by_id(like_two.id)
1799 refute Activity.get_by_id(repeat.id)
1803 test "delete/1 when confirmation is pending deletes the user" do
1804 clear_config([:instance, :account_activation_required], true)
1805 user = insert(:user, is_confirmed: false)
1807 {:ok, job} = User.delete(user)
1808 {:ok, _} = ObanHelpers.perform(job)
1810 refute User.get_cached_by_id(user.id)
1811 refute User.get_by_id(user.id)
1814 test "delete/1 when approval is pending deletes the user" do
1815 user = insert(:user, is_approved: false)
1817 {:ok, job} = User.delete(user)
1818 {:ok, _} = ObanHelpers.perform(job)
1820 refute User.get_cached_by_id(user.id)
1821 refute User.get_by_id(user.id)
1824 test "delete/1 purges a user when they wouldn't be fully deleted" do
1829 password_hash: "pdfk2$1b3n159001",
1830 keys: "RSA begin buplic key",
1831 public_key: "--PRIVATE KEYE--",
1832 avatar: %{"a" => "b"},
1834 banner: %{"a" => "b"},
1835 background: %{"a" => "b"},
1838 following_count: 9001,
1841 password_reset_pending: true,
1843 registration_reason: "ahhhhh",
1844 confirmation_token: "qqqq",
1845 domain_blocks: ["lain.com"],
1850 mascot: %{"a" => "b"},
1851 emoji: %{"a" => "b"},
1852 pleroma_settings_store: %{"q" => "x"},
1853 fields: [%{"gg" => "qq"}],
1854 raw_fields: [%{"gg" => "qq"}],
1855 is_discoverable: true,
1856 also_known_as: ["https://lol.olo/users/loll"]
1859 {:ok, job} = User.delete(user)
1860 {:ok, _} = ObanHelpers.perform(job)
1861 user = User.get_by_id(user.id)
1869 keys: "RSA begin buplic key",
1870 public_key: "--PRIVATE KEYE--",
1873 last_refreshed_at: nil,
1874 last_digest_emailed_at: nil,
1882 password_reset_pending: false,
1884 registration_reason: nil,
1885 confirmation_token: nil,
1889 is_moderator: false,
1893 pleroma_settings_store: %{},
1896 is_discoverable: false,
1901 test "delete/1 purges a remote user" do
1905 avatar: %{"a" => "b"},
1906 banner: %{"a" => "b"},
1910 {:ok, job} = User.delete(user)
1911 {:ok, _} = ObanHelpers.perform(job)
1912 user = User.get_by_id(user.id)
1914 assert user.name == nil
1915 assert user.avatar == %{}
1916 assert user.banner == %{}
1919 describe "set_suggestion" do
1920 test "suggests a user" do
1921 user = insert(:user, is_suggested: false)
1922 refute user.is_suggested
1923 {:ok, user} = User.set_suggestion(user, true)
1924 assert user.is_suggested
1927 test "suggests a list of users" do
1928 unsuggested_users = [
1929 insert(:user, is_suggested: false),
1930 insert(:user, is_suggested: false),
1931 insert(:user, is_suggested: false)
1934 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1936 assert Enum.count(users) == 3
1938 Enum.each(users, fn user ->
1939 assert user.is_suggested
1943 test "unsuggests a user" do
1944 user = insert(:user, is_suggested: true)
1945 assert user.is_suggested
1946 {:ok, user} = User.set_suggestion(user, false)
1947 refute user.is_suggested
1951 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1952 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1955 describe "per-user rich-text filtering" do
1956 test "html_filter_policy returns default policies, when rich-text is enabled" do
1957 user = insert(:user)
1959 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1962 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1963 user = insert(:user, no_rich_text: true)
1965 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1969 describe "caching" do
1970 test "invalidate_cache works" do
1971 user = insert(:user)
1973 User.set_cache(user)
1974 User.invalidate_cache(user)
1976 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1977 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1980 test "User.delete() plugs any possible zombie objects" do
1981 user = insert(:user)
1983 {:ok, job} = User.delete(user)
1984 {:ok, _} = ObanHelpers.perform(job)
1986 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1988 assert cached_user != user
1990 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1992 assert cached_user != user
1996 describe "account_status/1" do
1997 setup do: clear_config([:instance, :account_activation_required])
1999 test "return confirmation_pending for unconfirm user" do
2000 clear_config([:instance, :account_activation_required], true)
2001 user = insert(:user, is_confirmed: false)
2002 assert User.account_status(user) == :confirmation_pending
2005 test "return active for confirmed user" do
2006 clear_config([:instance, :account_activation_required], true)
2007 user = insert(:user, is_confirmed: true)
2008 assert User.account_status(user) == :active
2011 test "return active for remote user" do
2012 user = insert(:user, local: false)
2013 assert User.account_status(user) == :active
2016 test "returns :password_reset_pending for user with reset password" do
2017 user = insert(:user, password_reset_pending: true)
2018 assert User.account_status(user) == :password_reset_pending
2021 test "returns :deactivated for deactivated user" do
2022 user = insert(:user, local: true, is_confirmed: true, is_active: false)
2023 assert User.account_status(user) == :deactivated
2026 test "returns :approval_pending for unapproved user" do
2027 user = insert(:user, local: true, is_approved: false)
2028 assert User.account_status(user) == :approval_pending
2030 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
2031 assert User.account_status(user) == :approval_pending
2035 describe "privileged?/1" do
2037 clear_config([:instance, :admin_privileges], [:cofe, :suya])
2038 clear_config([:instance, :moderator_privileges], [:cofe, :suya])
2041 test "returns false for unprivileged users" do
2042 user = insert(:user, local: true)
2044 refute User.privileged?(user, :cofe)
2047 test "returns false for remote users" do
2048 user = insert(:user, local: false)
2049 remote_admin_user = insert(:user, local: false, is_admin: true)
2051 refute User.privileged?(user, :cofe)
2052 refute User.privileged?(remote_admin_user, :cofe)
2055 test "returns true for local moderators if, and only if, they are privileged" do
2056 user = insert(:user, local: true, is_moderator: true)
2058 assert User.privileged?(user, :cofe)
2060 clear_config([:instance, :moderator_privileges], [])
2062 refute User.privileged?(user, :cofe)
2065 test "returns true for local admins if, and only if, they are privileged" do
2066 user = insert(:user, local: true, is_admin: true)
2068 assert User.privileged?(user, :cofe)
2070 clear_config([:instance, :admin_privileges], [])
2072 refute User.privileged?(user, :cofe)
2076 describe "privileges/1" do
2078 clear_config([:instance, :moderator_privileges], [:cofe, :only_moderator])
2079 clear_config([:instance, :admin_privileges], [:cofe, :only_admin])
2082 test "returns empty list for users without roles" do
2083 user = insert(:user, local: true)
2085 assert [] == User.privileges(user)
2088 test "returns list of privileges for moderators" do
2089 moderator = insert(:user, is_moderator: true, local: true)
2091 assert [:cofe, :only_moderator] == User.privileges(moderator) |> Enum.sort()
2094 test "returns list of privileges for admins" do
2095 admin = insert(:user, is_admin: true, local: true)
2097 assert [:cofe, :only_admin] == User.privileges(admin) |> Enum.sort()
2100 test "returns list of unique privileges for users who are both moderator and admin" do
2101 moderator_admin = insert(:user, is_moderator: true, is_admin: true, local: true)
2103 assert [:cofe, :only_admin, :only_moderator] ==
2104 User.privileges(moderator_admin) |> Enum.sort()
2107 test "returns empty list for remote users" do
2108 remote_moderator_admin = insert(:user, is_moderator: true, is_admin: true, local: false)
2110 assert [] == User.privileges(remote_moderator_admin)
2114 describe "invisible?/1" do
2115 test "returns true for an invisible user" do
2116 user = insert(:user, local: true, invisible: true)
2118 assert User.invisible?(user)
2121 test "returns false for a non-invisible user" do
2122 user = insert(:user, local: true)
2124 refute User.invisible?(user)
2128 describe "visible_for/2" do
2129 test "returns true when the account is itself" do
2130 user = insert(:user, local: true)
2132 assert User.visible_for(user, user) == :visible
2135 test "returns false when the account is unconfirmed and confirmation is required" do
2136 clear_config([:instance, :account_activation_required], true)
2138 user = insert(:user, local: true, is_confirmed: false)
2139 other_user = insert(:user, local: true)
2141 refute User.visible_for(user, other_user) == :visible
2144 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
2145 clear_config([:instance, :account_activation_required], true)
2147 user = insert(:user, local: false, is_confirmed: false)
2148 other_user = insert(:user, local: true)
2150 assert User.visible_for(user, other_user) == :visible
2153 test "returns true when the account is unconfirmed and being viewed by a privileged account (privilege :users_manage_activation_state, confirmation required)" do
2154 clear_config([:instance, :account_activation_required], true)
2155 clear_config([:instance, :admin_privileges], [:users_manage_activation_state])
2157 user = insert(:user, local: true, is_confirmed: false)
2158 other_user = insert(:user, local: true, is_admin: true)
2160 assert User.visible_for(user, other_user) == :visible
2162 clear_config([:instance, :admin_privileges], [])
2164 refute User.visible_for(user, other_user) == :visible
2168 describe "all_users_with_privilege/1" do
2171 user: insert(:user, local: true, is_admin: false, is_moderator: false),
2172 moderator_user: insert(:user, local: true, is_admin: false, is_moderator: true),
2173 admin_user: insert(:user, local: true, is_admin: true, is_moderator: false),
2174 admin_moderator_user: insert(:user, local: true, is_admin: true, is_moderator: true),
2175 remote_user: insert(:user, local: false, is_admin: true, is_moderator: true),
2177 insert(:user, local: true, is_admin: true, is_moderator: true, is_active: false)
2181 test "doesn't return any users when there are no privileged roles" do
2182 clear_config([:instance, :admin_privileges], [])
2183 clear_config([:instance, :moderator_privileges], [])
2185 assert [] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2188 test "returns moderator users if they are privileged", %{
2189 moderator_user: moderator_user,
2190 admin_moderator_user: admin_moderator_user
2192 clear_config([:instance, :admin_privileges], [])
2193 clear_config([:instance, :moderator_privileges], [:cofe])
2195 assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2196 assert moderator_user in User.all_users_with_privilege(:cofe)
2197 assert admin_moderator_user in User.all_users_with_privilege(:cofe)
2200 test "returns admin users if they are privileged", %{
2201 admin_user: admin_user,
2202 admin_moderator_user: admin_moderator_user
2204 clear_config([:instance, :admin_privileges], [:cofe])
2205 clear_config([:instance, :moderator_privileges], [])
2207 assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2208 assert admin_user in User.all_users_with_privilege(:cofe)
2209 assert admin_moderator_user in User.all_users_with_privilege(:cofe)
2212 test "returns admin and moderator users if they are both privileged", %{
2213 moderator_user: moderator_user,
2214 admin_user: admin_user,
2215 admin_moderator_user: admin_moderator_user
2217 clear_config([:instance, :admin_privileges], [:cofe])
2218 clear_config([:instance, :moderator_privileges], [:cofe])
2220 assert [_, _, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all()
2221 assert admin_user in User.all_users_with_privilege(:cofe)
2222 assert moderator_user in User.all_users_with_privilege(:cofe)
2223 assert admin_moderator_user in User.all_users_with_privilege(:cofe)
2227 describe "parse_bio/2" do
2228 test "preserves hosts in user links text" do
2229 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
2230 user = insert(:user)
2231 bio = "A.k.a. @nick@domain.com"
2234 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{remote_user.ap_id}" rel="ugc">@<span>nick@domain.com</span></a></span>)
2236 assert expected_text == User.parse_bio(bio, user)
2239 test "Adds rel=me on linkbacked urls" do
2240 user = insert(:user, ap_id: "https://social.example.org/users/lain")
2242 bio = "http://example.com/rel_me/null"
2243 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
2244 assert expected_text == User.parse_bio(bio, user)
2246 bio = "http://example.com/rel_me/link"
2247 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2248 assert expected_text == User.parse_bio(bio, user)
2250 bio = "http://example.com/rel_me/anchor"
2251 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2252 assert expected_text == User.parse_bio(bio, user)
2256 test "follower count is updated when a follower is blocked" do
2257 user = insert(:user)
2258 follower = insert(:user)
2259 follower2 = insert(:user)
2260 follower3 = insert(:user)
2262 {:ok, follower, user} = User.follow(follower, user)
2263 {:ok, _follower2, _user} = User.follow(follower2, user)
2264 {:ok, _follower3, _user} = User.follow(follower3, user)
2266 {:ok, _user_relationship} = User.block(user, follower)
2267 user = refresh_record(user)
2269 assert user.follower_count == 2
2272 describe "list_inactive_users_query/1" do
2273 defp days_ago(days) do
2275 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
2276 -days * 60 * 60 * 24,
2281 test "Users are inactive by default" do
2285 Enum.map(1..total, fn _ ->
2286 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2289 inactive_users_ids =
2290 Pleroma.User.list_inactive_users_query()
2291 |> Pleroma.Repo.all()
2292 |> Enum.map(& &1.id)
2294 Enum.each(users, fn user ->
2295 assert user.id in inactive_users_ids
2299 test "Only includes users who has no recent activity" do
2303 Enum.map(1..total, fn _ ->
2304 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2307 {inactive, active} = Enum.split(users, trunc(total / 2))
2309 Enum.map(active, fn user ->
2310 to = Enum.random(users -- [user])
2313 CommonAPI.post(user, %{
2314 status: "hey @#{to.nickname}"
2318 inactive_users_ids =
2319 Pleroma.User.list_inactive_users_query()
2320 |> Pleroma.Repo.all()
2321 |> Enum.map(& &1.id)
2323 Enum.each(active, fn user ->
2324 refute user.id in inactive_users_ids
2327 Enum.each(inactive, fn user ->
2328 assert user.id in inactive_users_ids
2332 test "Only includes users with no read notifications" do
2336 Enum.map(1..total, fn _ ->
2337 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2340 [sender | recipients] = users
2341 {inactive, active} = Enum.split(recipients, trunc(total / 2))
2343 Enum.each(recipients, fn to ->
2345 CommonAPI.post(sender, %{
2346 status: "hey @#{to.nickname}"
2350 CommonAPI.post(sender, %{
2351 status: "hey again @#{to.nickname}"
2355 Enum.each(active, fn user ->
2356 [n1, _n2] = Pleroma.Notification.for_user(user)
2357 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2360 inactive_users_ids =
2361 Pleroma.User.list_inactive_users_query()
2362 |> Pleroma.Repo.all()
2363 |> Enum.map(& &1.id)
2365 Enum.each(active, fn user ->
2366 refute user.id in inactive_users_ids
2369 Enum.each(inactive, fn user ->
2370 assert user.id in inactive_users_ids
2375 describe "get_ap_ids_by_nicknames" do
2376 test "it returns a list of AP ids for a given set of nicknames" do
2377 user = insert(:user)
2378 user_two = insert(:user)
2380 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2381 assert length(ap_ids) == 2
2382 assert user.ap_id in ap_ids
2383 assert user_two.ap_id in ap_ids
2386 test "it returns a list of AP ids in the same order" do
2387 user = insert(:user)
2388 user_two = insert(:user)
2389 user_three = insert(:user)
2392 User.get_ap_ids_by_nicknames([user.nickname, user_three.nickname, user_two.nickname])
2394 assert [user.ap_id, user_three.ap_id, user_two.ap_id] == ap_ids
2398 describe "sync followers count" do
2400 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2401 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2402 insert(:user, local: true)
2403 insert(:user, local: false, is_active: false)
2404 {:ok, user1: user1, user2: user2}
2407 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2408 [fdb_user1] = User.external_users(limit: 1)
2410 assert fdb_user1.ap_id
2411 assert fdb_user1.ap_id == user1.ap_id
2412 assert fdb_user1.id == user1.id
2414 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2416 assert fdb_user2.ap_id
2417 assert fdb_user2.ap_id == user2.ap_id
2418 assert fdb_user2.id == user2.id
2420 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2424 describe "is_internal_user?/1" do
2425 test "non-internal user returns false" do
2426 user = insert(:user)
2427 refute User.is_internal_user?(user)
2430 test "user with no nickname returns true" do
2431 user = insert(:user, %{nickname: nil})
2432 assert User.is_internal_user?(user)
2435 test "user with internal-prefixed nickname returns true" do
2436 user = insert(:user, %{nickname: "internal.test"})
2437 assert User.is_internal_user?(user)
2441 describe "update_and_set_cache/1" do
2442 test "returns error when user is stale instead Ecto.StaleEntryError" do
2443 user = insert(:user)
2445 changeset = Ecto.Changeset.change(user, bio: "test")
2449 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2450 User.update_and_set_cache(changeset)
2453 test "performs update cache if user updated" do
2454 user = insert(:user)
2455 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2457 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2459 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2460 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2461 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2465 describe "following/followers synchronization" do
2466 setup do: clear_config([:instance, :external_user_synchronization])
2468 test "updates the counters normally on following/getting a follow when disabled" do
2469 clear_config([:instance, :external_user_synchronization], false)
2470 user = insert(:user)
2475 follower_address: "http://localhost:4001/users/masto_closed/followers",
2476 following_address: "http://localhost:4001/users/masto_closed/following",
2480 assert other_user.following_count == 0
2481 assert other_user.follower_count == 0
2483 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2485 assert user.following_count == 1
2486 assert other_user.follower_count == 1
2489 test "synchronizes the counters with the remote instance for the followed when enabled" do
2490 clear_config([:instance, :external_user_synchronization], false)
2492 user = insert(:user)
2497 follower_address: "http://localhost:4001/users/masto_closed/followers",
2498 following_address: "http://localhost:4001/users/masto_closed/following",
2502 assert other_user.following_count == 0
2503 assert other_user.follower_count == 0
2505 clear_config([:instance, :external_user_synchronization], true)
2506 {:ok, _user, other_user} = User.follow(user, other_user)
2508 assert other_user.follower_count == 437
2511 test "synchronizes the counters with the remote instance for the follower when enabled" do
2512 clear_config([:instance, :external_user_synchronization], false)
2514 user = insert(:user)
2519 follower_address: "http://localhost:4001/users/masto_closed/followers",
2520 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 and remote users" do
2688 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2690 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2692 assert User.full_nickname(local_user) == "local_user@somehost.com"
2693 assert User.full_nickname(remote_user) == "remote@host.com"
2696 test "strips leading @ from mentions" do
2697 assert User.full_nickname("@mentioned") == "mentioned"
2698 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2701 test "does not modify nicknames" do
2702 assert User.full_nickname("nickname") == "nickname"
2703 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2707 test "avatar fallback" do
2708 user = insert(:user)
2709 assert User.avatar_url(user) =~ "/images/avi.png"
2711 clear_config([:assets, :default_user_avatar], "avatar.png")
2713 user = User.get_cached_by_nickname_or_id(user.nickname)
2714 assert User.avatar_url(user) =~ "avatar.png"
2716 assert User.avatar_url(user, no_default: true) == nil
2719 test "get_host/1" do
2720 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2721 assert User.get_host(user) == "lain.com"
2724 test "update_last_active_at/1" do
2725 user = insert(:user)
2726 assert is_nil(user.last_active_at)
2728 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2730 assert {:ok, user} = User.update_last_active_at(user)
2732 assert user.last_active_at >= test_started_at
2733 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2736 NaiveDateTime.utc_now()
2737 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2738 |> NaiveDateTime.truncate(:second)
2740 assert {:ok, user} =
2742 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2743 |> User.update_and_set_cache()
2745 assert user.last_active_at == last_active_at
2746 assert {:ok, user} = User.update_last_active_at(user)
2747 assert user.last_active_at >= test_started_at
2748 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2751 test "active_user_count/1" do
2753 insert(:user, %{local: false})
2754 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2755 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2756 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2757 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2758 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2760 assert User.active_user_count() == 2
2761 assert User.active_user_count(180) == 3
2762 assert User.active_user_count(365) == 4
2763 assert User.active_user_count(1000) == 5
2768 user = insert(:user)
2770 [user: user, object_id: object_id_from_created_activity(user)]
2773 test "unique pins", %{user: user, object_id: object_id} do
2774 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2775 User.add_pinned_object_id(user, object_id)
2777 assert Enum.count(pins) == 1
2779 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2780 User.add_pinned_object_id(updated_user, object_id)
2782 assert pinned_at1 == pinned_at2
2784 assert Enum.count(pins) == 1
2787 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2788 clear_config([:instance, :max_pinned_statuses], 1)
2789 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2791 object_id2 = object_id_from_created_activity(user)
2793 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2794 assert Keyword.has_key?(errors, :pinned_objects)
2797 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2798 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2800 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2801 assert after_remove.pinned_objects == %{}
2805 defp object_id_from_created_activity(user) do
2806 %{id: id} = insert(:note_activity, user: user)
2807 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2811 describe "add_alias/2" do
2812 test "should add alias for another user" do
2813 user = insert(:user)
2814 user2 = insert(:user)
2816 assert {:ok, user_updated} = user |> User.add_alias(user2)
2818 assert user_updated.also_known_as |> length() == 1
2819 assert user2.ap_id in user_updated.also_known_as
2822 test "should add multiple aliases" do
2823 user = insert(:user)
2824 user2 = insert(:user)
2825 user3 = insert(:user)
2827 assert {:ok, user} = user |> User.add_alias(user2)
2828 assert {:ok, user_updated} = user |> User.add_alias(user3)
2830 assert user_updated.also_known_as |> length() == 2
2831 assert user2.ap_id in user_updated.also_known_as
2832 assert user3.ap_id in user_updated.also_known_as
2835 test "should not add duplicate aliases" do
2836 user = insert(:user)
2837 user2 = insert(:user)
2839 assert {:ok, user} = user |> User.add_alias(user2)
2841 assert {:ok, user_updated} = user |> User.add_alias(user2)
2843 assert user_updated.also_known_as |> length() == 1
2844 assert user2.ap_id in user_updated.also_known_as
2848 describe "alias_users/1" do
2849 test "should get aliases for a user" do
2850 user = insert(:user)
2851 user2 = insert(:user, also_known_as: [user.ap_id])
2853 aliases = user2 |> User.alias_users()
2855 assert aliases |> length() == 1
2857 alias_user = aliases |> Enum.at(0)
2859 assert alias_user.ap_id == user.ap_id
2863 describe "delete_alias/2" do
2864 test "should delete existing alias" do
2865 user = insert(:user)
2866 user2 = insert(:user, also_known_as: [user.ap_id])
2868 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2870 assert user_updated.also_known_as == []
2873 test "should report error on non-existing alias" do
2874 user = insert(:user)
2875 user2 = insert(:user)
2876 user3 = insert(:user, also_known_as: [user.ap_id])
2878 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2880 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2882 assert user3_updated.also_known_as |> length() == 1
2883 assert user.ap_id in user3_updated.also_known_as
2887 describe "account endorsements" do
2888 test "it pins people" do
2889 user = insert(:user)
2890 pinned_user = insert(:user)
2892 {:ok, _pinned_user, _user} = User.follow(user, pinned_user)
2894 refute User.endorses?(user, pinned_user)
2896 {:ok, _user_relationship} = User.endorse(user, pinned_user)
2898 assert User.endorses?(user, pinned_user)
2901 test "it unpins users" do
2902 user = insert(:user)
2903 pinned_user = insert(:user)
2905 {:ok, _pinned_user, _user} = User.follow(user, pinned_user)
2906 {:ok, _user_relationship} = User.endorse(user, pinned_user)
2907 {:ok, _user_pin} = User.unendorse(user, pinned_user)
2909 refute User.endorses?(user, pinned_user)
2912 test "it doesn't pin users you do not follow" do
2913 user = insert(:user)
2914 pinned_user = insert(:user)
2916 assert {:error, _message} = User.endorse(user, pinned_user)
2918 refute User.endorses?(user, pinned_user)