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
10 alias Pleroma.Tests.ObanHelpers
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.CommonAPI
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.base_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 syncronizes 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: [],
478 Pleroma.Web.ActivityPub.MRF.SimplePolicy
482 test "it sends a welcome chat message when Simple policy applied to local instance" do
483 clear_config([:mrf_simple, :media_nsfw], ["localhost"])
485 welcome_user = insert(:user)
486 clear_config([:welcome, :chat_message, :enabled], true)
487 clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
488 clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
490 cng = User.register_changeset(%User{}, @full_user_data)
491 {:ok, registered_user} = User.register(cng)
492 ObanHelpers.perform_all()
494 activity = Repo.one(Pleroma.Activity)
495 assert registered_user.ap_id in activity.recipients
496 assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
497 assert activity.actor == welcome_user.ap_id
500 test "it sends a welcome email message if it is set" do
501 welcome_user = insert(:user)
502 clear_config([:welcome, :email, :enabled], true)
503 clear_config([:welcome, :email, :sender], welcome_user.email)
506 [:welcome, :email, :subject],
507 "Hello, welcome to cool site: <%= instance_name %>"
510 instance_name = Pleroma.Config.get([:instance, :name])
512 cng = User.register_changeset(%User{}, @full_user_data)
513 {:ok, registered_user} = User.register(cng)
514 ObanHelpers.perform_all()
517 from: {instance_name, welcome_user.email},
518 to: {registered_user.name, registered_user.email},
519 subject: "Hello, welcome to cool site: #{instance_name}",
520 html_body: "Welcome to #{instance_name}"
524 test "it sends a confirm email" do
525 clear_config([:instance, :account_activation_required], true)
527 cng = User.register_changeset(%User{}, @full_user_data)
528 {:ok, registered_user} = User.register(cng)
529 ObanHelpers.perform_all()
531 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
532 # temporary hackney fix until hackney max_connections bug is fixed
533 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
534 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
535 |> assert_email_sent()
538 test "sends a pending approval email" do
539 clear_config([:instance, :account_approval_required], true)
542 User.register_changeset(%User{}, @full_user_data)
545 ObanHelpers.perform_all()
548 from: Pleroma.Config.Helpers.sender(),
549 to: {user.name, user.email},
550 subject: "Your account is awaiting approval"
554 test "it sends a registration confirmed email if no others will be sent" do
555 clear_config([:welcome, :email, :enabled], false)
556 clear_config([:instance, :account_activation_required], false)
557 clear_config([:instance, :account_approval_required], false)
560 User.register_changeset(%User{}, @full_user_data)
563 ObanHelpers.perform_all()
565 instance_name = Pleroma.Config.get([:instance, :name])
566 sender = Pleroma.Config.get([:instance, :notify_email])
569 from: {instance_name, sender},
570 to: {user.name, user.email},
571 subject: "Account registered on #{instance_name}"
575 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
576 clear_config([:instance, :account_activation_required], true)
580 |> Enum.each(fn key ->
581 params = Map.delete(@full_user_data, key)
582 changeset = User.register_changeset(%User{}, params)
584 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
588 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
589 clear_config([:instance, :account_activation_required], false)
593 |> Enum.each(fn key ->
594 params = Map.delete(@full_user_data, key)
595 changeset = User.register_changeset(%User{}, params)
597 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
601 test "it restricts certain nicknames" do
602 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
604 assert is_bitstring(restricted_name)
608 |> Map.put(:nickname, restricted_name)
610 changeset = User.register_changeset(%User{}, params)
612 refute changeset.valid?
615 test "it blocks blacklisted email domains" do
616 clear_config([User, :email_blacklist], ["trolling.world"])
619 params = Map.put(@full_user_data, :email, "troll@trolling.world")
620 changeset = User.register_changeset(%User{}, params)
621 refute changeset.valid?
623 # Block with subdomain match
624 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
625 changeset = User.register_changeset(%User{}, params)
626 refute changeset.valid?
628 # Pass with different domains that are similar
629 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
630 changeset = User.register_changeset(%User{}, params)
631 assert changeset.valid?
633 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
634 changeset = User.register_changeset(%User{}, params)
635 assert changeset.valid?
638 test "it sets the password_hash and ap_id" do
639 changeset = User.register_changeset(%User{}, @full_user_data)
641 assert changeset.valid?
643 assert is_binary(changeset.changes[:password_hash])
644 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
646 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
649 test "it sets the 'accepts_chat_messages' set to true" do
650 changeset = User.register_changeset(%User{}, @full_user_data)
651 assert changeset.valid?
653 {:ok, user} = Repo.insert(changeset)
655 assert user.accepts_chat_messages
658 test "it creates a confirmed user" do
659 changeset = User.register_changeset(%User{}, @full_user_data)
660 assert changeset.valid?
662 {:ok, user} = Repo.insert(changeset)
664 assert user.is_confirmed
668 describe "user registration, with :account_activation_required" do
674 password_confirmation: "test",
675 email: "email@example.com"
677 setup do: clear_config([:instance, :account_activation_required], true)
679 test "it creates unconfirmed user" do
680 changeset = User.register_changeset(%User{}, @full_user_data)
681 assert changeset.valid?
683 {:ok, user} = Repo.insert(changeset)
685 refute user.is_confirmed
686 assert user.confirmation_token
689 test "it creates confirmed user if :confirmed option is given" do
690 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
691 assert changeset.valid?
693 {:ok, user} = Repo.insert(changeset)
695 assert user.is_confirmed
696 refute user.confirmation_token
700 describe "user registration, with :account_approval_required" do
706 password_confirmation: "test",
707 email: "email@example.com",
708 registration_reason: "I'm a cool guy :)"
710 setup do: clear_config([:instance, :account_approval_required], true)
712 test "it creates unapproved user" do
713 changeset = User.register_changeset(%User{}, @full_user_data)
714 assert changeset.valid?
716 {:ok, user} = Repo.insert(changeset)
718 refute user.is_approved
719 assert user.registration_reason == "I'm a cool guy :)"
722 test "it restricts length of registration reason" do
723 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
725 assert is_integer(reason_limit)
730 :registration_reason,
731 "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."
734 changeset = User.register_changeset(%User{}, params)
736 refute changeset.valid?
740 describe "get_or_fetch/1" do
741 test "gets an existing user by nickname" do
743 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
745 assert user == fetched_user
748 test "gets an existing user by ap_id" do
749 ap_id = "http://mastodon.example.org/users/admin"
755 nickname: "admin@mastodon.example.org",
759 {:ok, fetched_user} = User.get_or_fetch(ap_id)
760 freshed_user = refresh_record(user)
761 assert freshed_user == fetched_user
765 describe "fetching a user from nickname or trying to build one" do
766 test "gets an existing user" do
768 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
770 assert user == fetched_user
773 test "gets an existing user, case insensitive" do
774 user = insert(:user, nickname: "nick")
775 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
777 assert user == fetched_user
780 test "gets an existing user by fully qualified nickname" do
783 {:ok, fetched_user} =
784 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
786 assert user == fetched_user
789 test "gets an existing user by fully qualified nickname, case insensitive" do
790 user = insert(:user, nickname: "nick")
791 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
793 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
795 assert user == fetched_user
798 @tag capture_log: true
799 test "returns nil if no user could be fetched" do
800 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
801 assert fetched_user == "not found nonexistant@social.heldscal.la"
804 test "returns nil for nonexistant local user" do
805 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
806 assert fetched_user == "not found nonexistant"
809 test "updates an existing user, if stale" do
810 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
816 nickname: "admin@mastodon.example.org",
817 ap_id: "http://mastodon.example.org/users/admin",
818 last_refreshed_at: a_week_ago
821 assert orig_user.last_refreshed_at == a_week_ago
823 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
827 refute user.last_refreshed_at == orig_user.last_refreshed_at
830 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
831 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
837 nickname: "admin@mastodon.example.org",
838 ap_id: "http://mastodon.example.org/users/harinezumigari",
839 last_refreshed_at: a_week_ago
842 assert orig_user.last_refreshed_at == a_week_ago
844 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
848 refute user.id == orig_user.id
850 orig_user = User.get_by_id(orig_user.id)
852 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
855 @tag capture_log: true
856 test "it returns the old user if stale, but unfetchable" do
857 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
863 nickname: "admin@mastodon.example.org",
864 ap_id: "http://mastodon.example.org/users/raymoo",
865 last_refreshed_at: a_week_ago
868 assert orig_user.last_refreshed_at == a_week_ago
870 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
872 assert user.last_refreshed_at == orig_user.last_refreshed_at
876 test "returns an ap_id for a user" do
879 assert User.ap_id(user) ==
880 Pleroma.Web.Router.Helpers.user_feed_url(
881 Pleroma.Web.Endpoint,
887 test "returns an ap_followers link for a user" do
890 assert User.ap_followers(user) ==
891 Pleroma.Web.Router.Helpers.user_feed_url(
892 Pleroma.Web.Endpoint,
898 describe "remote user changeset" do
904 avatar: %{some: "avatar"}
906 setup do: clear_config([:instance, :user_bio_length])
907 setup do: clear_config([:instance, :user_name_length])
909 test "it confirms validity" do
910 cs = User.remote_user_changeset(@valid_remote)
914 test "it sets the follower_adress" do
915 cs = User.remote_user_changeset(@valid_remote)
916 # remote users get a fake local follower address
917 assert cs.changes.follower_address ==
918 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
921 test "it enforces the fqn format for nicknames" do
922 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
923 assert Ecto.Changeset.get_field(cs, :local) == false
924 assert cs.changes.avatar
928 test "it has required fields" do
930 |> Enum.each(fn field ->
931 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
936 test "it is invalid given a local user" do
938 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
944 describe "followers and friends" do
945 test "gets all followers for a given user" do
947 follower_one = insert(:user)
948 follower_two = insert(:user)
949 not_follower = insert(:user)
951 {:ok, follower_one, user} = User.follow(follower_one, user)
952 {:ok, follower_two, user} = User.follow(follower_two, user)
954 res = User.get_followers(user)
956 assert Enum.member?(res, follower_one)
957 assert Enum.member?(res, follower_two)
958 refute Enum.member?(res, not_follower)
961 test "gets all friends (followed users) for a given user" do
963 followed_one = insert(:user)
964 followed_two = insert(:user)
965 not_followed = insert(:user)
967 {:ok, user, followed_one} = User.follow(user, followed_one)
968 {:ok, user, followed_two} = User.follow(user, followed_two)
970 res = User.get_friends(user)
972 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
973 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
974 assert Enum.member?(res, followed_one)
975 assert Enum.member?(res, followed_two)
976 refute Enum.member?(res, not_followed)
980 describe "updating note and follower count" do
981 test "it sets the note_count property" do
984 user = User.get_cached_by_ap_id(note.data["actor"])
986 assert user.note_count == 0
988 {:ok, user} = User.update_note_count(user)
990 assert user.note_count == 1
993 test "it increases the note_count property" do
995 user = User.get_cached_by_ap_id(note.data["actor"])
997 assert user.note_count == 0
999 {:ok, user} = User.increase_note_count(user)
1001 assert user.note_count == 1
1003 {:ok, user} = User.increase_note_count(user)
1005 assert user.note_count == 2
1008 test "it decreases the note_count property" do
1009 note = insert(:note)
1010 user = User.get_cached_by_ap_id(note.data["actor"])
1012 assert user.note_count == 0
1014 {:ok, user} = User.increase_note_count(user)
1016 assert user.note_count == 1
1018 {:ok, user} = User.decrease_note_count(user)
1020 assert user.note_count == 0
1022 {:ok, user} = User.decrease_note_count(user)
1024 assert user.note_count == 0
1027 test "it sets the follower_count property" do
1028 user = insert(:user)
1029 follower = insert(:user)
1031 User.follow(follower, user)
1033 assert user.follower_count == 0
1035 {:ok, user} = User.update_follower_count(user)
1037 assert user.follower_count == 1
1042 test "it mutes people" do
1043 user = insert(:user)
1044 muted_user = insert(:user)
1046 refute User.mutes?(user, muted_user)
1047 refute User.muted_notifications?(user, muted_user)
1049 {:ok, _user_relationships} = User.mute(user, muted_user)
1051 assert User.mutes?(user, muted_user)
1052 assert User.muted_notifications?(user, muted_user)
1056 user = insert(:user)
1057 muted_user = insert(:user)
1059 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1060 assert User.mutes?(user, muted_user)
1062 worker = Pleroma.Workers.MuteExpireWorker
1063 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1070 assert :ok = perform_job(worker, args)
1072 refute User.mutes?(user, muted_user)
1073 refute User.muted_notifications?(user, muted_user)
1076 test "it unmutes users" do
1077 user = insert(:user)
1078 muted_user = insert(:user)
1080 {:ok, _user_relationships} = User.mute(user, muted_user)
1081 {:ok, _user_mute} = User.unmute(user, muted_user)
1083 refute User.mutes?(user, muted_user)
1084 refute User.muted_notifications?(user, muted_user)
1087 test "it unmutes users by id" do
1088 user = insert(:user)
1089 muted_user = insert(:user)
1091 {:ok, _user_relationships} = User.mute(user, muted_user)
1092 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1094 refute User.mutes?(user, muted_user)
1095 refute User.muted_notifications?(user, muted_user)
1098 test "it mutes user without notifications" do
1099 user = insert(:user)
1100 muted_user = insert(:user)
1102 refute User.mutes?(user, muted_user)
1103 refute User.muted_notifications?(user, muted_user)
1105 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1107 assert User.mutes?(user, muted_user)
1108 refute User.muted_notifications?(user, muted_user)
1112 describe "blocks" do
1113 test "it blocks people" do
1114 user = insert(:user)
1115 blocked_user = insert(:user)
1117 refute User.blocks?(user, blocked_user)
1119 {:ok, _user_relationship} = User.block(user, blocked_user)
1121 assert User.blocks?(user, blocked_user)
1124 test "it unblocks users" do
1125 user = insert(:user)
1126 blocked_user = insert(:user)
1128 {:ok, _user_relationship} = User.block(user, blocked_user)
1129 {:ok, _user_block} = User.unblock(user, blocked_user)
1131 refute User.blocks?(user, blocked_user)
1134 test "blocks tear down cyclical follow relationships" do
1135 blocker = insert(:user)
1136 blocked = insert(:user)
1138 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1139 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1141 assert User.following?(blocker, blocked)
1142 assert User.following?(blocked, blocker)
1144 {:ok, _user_relationship} = User.block(blocker, blocked)
1145 blocked = User.get_cached_by_id(blocked.id)
1147 assert User.blocks?(blocker, blocked)
1149 refute User.following?(blocker, blocked)
1150 refute User.following?(blocked, blocker)
1153 test "blocks tear down blocker->blocked follow relationships" do
1154 blocker = insert(:user)
1155 blocked = insert(:user)
1157 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1159 assert User.following?(blocker, blocked)
1160 refute User.following?(blocked, blocker)
1162 {:ok, _user_relationship} = User.block(blocker, blocked)
1163 blocked = User.get_cached_by_id(blocked.id)
1165 assert User.blocks?(blocker, blocked)
1167 refute User.following?(blocker, blocked)
1168 refute User.following?(blocked, blocker)
1171 test "blocks tear down blocked->blocker follow relationships" do
1172 blocker = insert(:user)
1173 blocked = insert(:user)
1175 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1177 refute User.following?(blocker, blocked)
1178 assert User.following?(blocked, blocker)
1180 {:ok, _user_relationship} = User.block(blocker, blocked)
1181 blocked = User.get_cached_by_id(blocked.id)
1183 assert User.blocks?(blocker, blocked)
1185 refute User.following?(blocker, blocked)
1186 refute User.following?(blocked, blocker)
1189 test "blocks tear down blocked->blocker subscription relationships" do
1190 blocker = insert(:user)
1191 blocked = insert(:user)
1193 {:ok, _subscription} = User.subscribe(blocked, blocker)
1195 assert User.subscribed_to?(blocked, blocker)
1196 refute User.subscribed_to?(blocker, blocked)
1198 {:ok, _user_relationship} = User.block(blocker, blocked)
1200 assert User.blocks?(blocker, blocked)
1201 refute User.subscribed_to?(blocker, blocked)
1202 refute User.subscribed_to?(blocked, blocker)
1206 describe "domain blocking" do
1207 test "blocks domains" do
1208 user = insert(:user)
1209 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1211 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1213 assert User.blocks?(user, collateral_user)
1216 test "does not block domain with same end" do
1217 user = insert(:user)
1220 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1222 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1224 refute User.blocks?(user, collateral_user)
1227 test "does not block domain with same end if wildcard added" do
1228 user = insert(:user)
1231 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1233 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1235 refute User.blocks?(user, collateral_user)
1238 test "blocks domain with wildcard for subdomain" do
1239 user = insert(:user)
1241 user_from_subdomain =
1242 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1244 user_with_two_subdomains =
1246 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1249 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1251 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1253 assert User.blocks?(user, user_from_subdomain)
1254 assert User.blocks?(user, user_with_two_subdomains)
1255 assert User.blocks?(user, user_domain)
1258 test "unblocks domains" do
1259 user = insert(:user)
1260 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1262 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1263 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1265 refute User.blocks?(user, collateral_user)
1268 test "follows take precedence over domain blocks" do
1269 user = insert(:user)
1270 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1272 {:ok, user} = User.block_domain(user, "meanies.social")
1273 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1275 refute User.blocks?(user, good_eggo)
1279 describe "get_recipients_from_activity" do
1280 test "works for announces" do
1281 actor = insert(:user)
1282 user = insert(:user, local: true)
1284 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1285 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1287 recipients = User.get_recipients_from_activity(announce)
1289 assert user in recipients
1292 test "get recipients" do
1293 actor = insert(:user)
1294 user = insert(:user, local: true)
1295 user_two = insert(:user, local: false)
1296 addressed = insert(:user, local: true)
1297 addressed_remote = insert(:user, local: false)
1300 CommonAPI.post(actor, %{
1301 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1304 assert Enum.map([actor, addressed], & &1.ap_id) --
1305 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1307 {:ok, user, actor} = User.follow(user, actor)
1308 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1309 recipients = User.get_recipients_from_activity(activity)
1310 assert length(recipients) == 3
1311 assert user in recipients
1312 assert addressed in recipients
1315 test "has following" do
1316 actor = insert(:user)
1317 user = insert(:user)
1318 user_two = insert(:user)
1319 addressed = insert(:user, local: true)
1322 CommonAPI.post(actor, %{
1323 status: "hey @#{addressed.nickname}"
1326 assert Enum.map([actor, addressed], & &1.ap_id) --
1327 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1329 {:ok, _actor, _user} = User.follow(actor, user)
1330 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1331 recipients = User.get_recipients_from_activity(activity)
1332 assert length(recipients) == 2
1333 assert addressed in recipients
1337 describe ".set_activation" do
1338 test "can de-activate then re-activate a user" do
1339 user = insert(:user)
1340 assert user.is_active
1341 {:ok, user} = User.set_activation(user, false)
1342 refute user.is_active
1343 {:ok, user} = User.set_activation(user, true)
1344 assert user.is_active
1347 test "hide a user from followers" do
1348 user = insert(:user)
1349 user2 = insert(:user)
1351 {:ok, user, user2} = User.follow(user, user2)
1352 {:ok, _user} = User.set_activation(user, false)
1354 user2 = User.get_cached_by_id(user2.id)
1356 assert user2.follower_count == 0
1357 assert [] = User.get_followers(user2)
1360 test "hide a user from friends" do
1361 user = insert(:user)
1362 user2 = insert(:user)
1364 {:ok, user2, user} = User.follow(user2, user)
1365 assert user2.following_count == 1
1366 assert User.following_count(user2) == 1
1368 {:ok, _user} = User.set_activation(user, false)
1370 user2 = User.get_cached_by_id(user2.id)
1372 assert refresh_record(user2).following_count == 0
1373 assert user2.following_count == 0
1374 assert User.following_count(user2) == 0
1375 assert [] = User.get_friends(user2)
1378 test "hide a user's statuses from timelines and notifications" do
1379 user = insert(:user)
1380 user2 = insert(:user)
1382 {:ok, user2, user} = User.follow(user2, user)
1384 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1386 activity = Repo.preload(activity, :bookmark)
1388 [notification] = Pleroma.Notification.for_user(user2)
1389 assert notification.activity.id == activity.id
1391 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1393 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1394 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1398 {:ok, _user} = User.set_activation(user, false)
1400 assert [] == ActivityPub.fetch_public_activities(%{})
1401 assert [] == Pleroma.Notification.for_user(user2)
1404 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1410 describe "approve" do
1411 test "approves a user" do
1412 user = insert(:user, is_approved: false)
1413 refute user.is_approved
1414 {:ok, user} = User.approve(user)
1415 assert user.is_approved
1418 test "approves a list of users" do
1419 unapproved_users = [
1420 insert(:user, is_approved: false),
1421 insert(:user, is_approved: false),
1422 insert(:user, is_approved: false)
1425 {:ok, users} = User.approve(unapproved_users)
1427 assert Enum.count(users) == 3
1429 Enum.each(users, fn user ->
1430 assert user.is_approved
1434 test "it sends welcome email if it is set" do
1435 clear_config([:welcome, :email, :enabled], true)
1436 clear_config([:welcome, :email, :sender], "tester@test.me")
1438 user = insert(:user, is_approved: false)
1439 welcome_user = insert(:user, email: "tester@test.me")
1440 instance_name = Pleroma.Config.get([:instance, :name])
1444 ObanHelpers.perform_all()
1447 from: {instance_name, welcome_user.email},
1448 to: {user.name, user.email},
1449 html_body: "Welcome to #{instance_name}"
1453 test "approving an approved user does not trigger post-register actions" do
1454 clear_config([:welcome, :email, :enabled], true)
1456 user = insert(:user, is_approved: true)
1459 ObanHelpers.perform_all()
1461 assert_no_email_sent()
1465 describe "confirm" do
1466 test "confirms a user" do
1467 user = insert(:user, is_confirmed: false)
1468 refute user.is_confirmed
1469 {:ok, user} = User.confirm(user)
1470 assert user.is_confirmed
1473 test "confirms a list of users" do
1474 unconfirmed_users = [
1475 insert(:user, is_confirmed: false),
1476 insert(:user, is_confirmed: false),
1477 insert(:user, is_confirmed: false)
1480 {:ok, users} = User.confirm(unconfirmed_users)
1482 assert Enum.count(users) == 3
1484 Enum.each(users, fn user ->
1485 assert user.is_confirmed
1489 test "sends approval emails when `is_approved: false`" do
1490 admin = insert(:user, is_admin: true)
1491 user = insert(:user, is_confirmed: false, is_approved: false)
1494 ObanHelpers.perform_all()
1496 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1497 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1499 notify_email = Pleroma.Config.get([:instance, :notify_email])
1500 instance_name = Pleroma.Config.get([:instance, :name])
1502 # User approval email
1504 from: {instance_name, notify_email},
1505 to: {user.name, user.email},
1506 html_body: user_email.html_body
1511 from: {instance_name, notify_email},
1512 to: {admin.name, admin.email},
1513 html_body: admin_email.html_body
1517 test "confirming a confirmed user does not trigger post-register actions" do
1518 user = insert(:user, is_confirmed: true, is_approved: false)
1521 ObanHelpers.perform_all()
1523 assert_no_email_sent()
1527 describe "delete" do
1529 {:ok, user} = insert(:user) |> User.set_cache()
1534 setup do: clear_config([:instance, :federating])
1536 test ".delete_user_activities deletes all create activities", %{user: user} do
1537 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1539 User.delete_user_activities(user)
1541 # TODO: Test removal favorites, repeats, delete activities.
1542 refute Activity.get_by_id(activity.id)
1545 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1546 follower = insert(:user)
1547 {:ok, follower, user} = User.follow(follower, user)
1549 locked_user = insert(:user, name: "locked", is_locked: true)
1550 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1552 object = insert(:note, user: user)
1553 activity = insert(:note_activity, user: user, note: object)
1555 object_two = insert(:note, user: follower)
1556 activity_two = insert(:note_activity, user: follower, note: object_two)
1558 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1559 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1560 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1562 {:ok, job} = User.delete(user)
1563 {:ok, _user} = ObanHelpers.perform(job)
1565 follower = User.get_cached_by_id(follower.id)
1567 refute User.following?(follower, user)
1568 assert %{is_active: false} = User.get_by_id(user.id)
1570 assert [] == User.get_follow_requests(locked_user)
1574 |> Activity.Queries.by_actor()
1576 |> Enum.map(fn act -> act.data["type"] end)
1578 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1580 refute Activity.get_by_id(activity.id)
1581 refute Activity.get_by_id(like.id)
1582 refute Activity.get_by_id(like_two.id)
1583 refute Activity.get_by_id(repeat.id)
1587 test "delete/1 when confirmation is pending deletes the user" do
1588 clear_config([:instance, :account_activation_required], true)
1589 user = insert(:user, is_confirmed: false)
1591 {:ok, job} = User.delete(user)
1592 {:ok, _} = ObanHelpers.perform(job)
1594 refute User.get_cached_by_id(user.id)
1595 refute User.get_by_id(user.id)
1598 test "delete/1 when approval is pending deletes the user" do
1599 user = insert(:user, is_approved: false)
1601 {:ok, job} = User.delete(user)
1602 {:ok, _} = ObanHelpers.perform(job)
1604 refute User.get_cached_by_id(user.id)
1605 refute User.get_by_id(user.id)
1608 test "delete/1 purges a user when they wouldn't be fully deleted" do
1613 password_hash: "pdfk2$1b3n159001",
1614 keys: "RSA begin buplic key",
1615 public_key: "--PRIVATE KEYE--",
1616 avatar: %{"a" => "b"},
1618 banner: %{"a" => "b"},
1619 background: %{"a" => "b"},
1622 following_count: 9001,
1624 is_confirmed: false,
1625 password_reset_pending: true,
1627 registration_reason: "ahhhhh",
1628 confirmation_token: "qqqq",
1629 domain_blocks: ["lain.com"],
1634 mastofe_settings: %{"a" => "b"},
1635 mascot: %{"a" => "b"},
1636 emoji: %{"a" => "b"},
1637 pleroma_settings_store: %{"q" => "x"},
1638 fields: [%{"gg" => "qq"}],
1639 raw_fields: [%{"gg" => "qq"}],
1640 is_discoverable: true,
1641 also_known_as: ["https://lol.olo/users/loll"]
1644 {:ok, job} = User.delete(user)
1645 {:ok, _} = ObanHelpers.perform(job)
1646 user = User.get_by_id(user.id)
1658 last_refreshed_at: nil,
1659 last_digest_emailed_at: nil,
1667 password_reset_pending: false,
1669 registration_reason: nil,
1670 confirmation_token: nil,
1674 is_moderator: false,
1676 mastofe_settings: nil,
1679 pleroma_settings_store: %{},
1682 is_discoverable: false,
1687 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1688 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1691 describe "per-user rich-text filtering" do
1692 test "html_filter_policy returns default policies, when rich-text is enabled" do
1693 user = insert(:user)
1695 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1698 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1699 user = insert(:user, no_rich_text: true)
1701 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1705 describe "caching" do
1706 test "invalidate_cache works" do
1707 user = insert(:user)
1709 User.set_cache(user)
1710 User.invalidate_cache(user)
1712 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1713 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1716 test "User.delete() plugs any possible zombie objects" do
1717 user = insert(:user)
1719 {:ok, job} = User.delete(user)
1720 {:ok, _} = ObanHelpers.perform(job)
1722 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1724 assert cached_user != user
1726 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1728 assert cached_user != user
1732 describe "account_status/1" do
1733 setup do: clear_config([:instance, :account_activation_required])
1735 test "return confirmation_pending for unconfirm user" do
1736 clear_config([:instance, :account_activation_required], true)
1737 user = insert(:user, is_confirmed: false)
1738 assert User.account_status(user) == :confirmation_pending
1741 test "return active for confirmed user" do
1742 clear_config([:instance, :account_activation_required], true)
1743 user = insert(:user, is_confirmed: true)
1744 assert User.account_status(user) == :active
1747 test "return active for remote user" do
1748 user = insert(:user, local: false)
1749 assert User.account_status(user) == :active
1752 test "returns :password_reset_pending for user with reset password" do
1753 user = insert(:user, password_reset_pending: true)
1754 assert User.account_status(user) == :password_reset_pending
1757 test "returns :deactivated for deactivated user" do
1758 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1759 assert User.account_status(user) == :deactivated
1762 test "returns :approval_pending for unapproved user" do
1763 user = insert(:user, local: true, is_approved: false)
1764 assert User.account_status(user) == :approval_pending
1766 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1767 assert User.account_status(user) == :approval_pending
1771 describe "superuser?/1" do
1772 test "returns false for unprivileged users" do
1773 user = insert(:user, local: true)
1775 refute User.superuser?(user)
1778 test "returns false for remote users" do
1779 user = insert(:user, local: false)
1780 remote_admin_user = insert(:user, local: false, is_admin: true)
1782 refute User.superuser?(user)
1783 refute User.superuser?(remote_admin_user)
1786 test "returns true for local moderators" do
1787 user = insert(:user, local: true, is_moderator: true)
1789 assert User.superuser?(user)
1792 test "returns true for local admins" do
1793 user = insert(:user, local: true, is_admin: true)
1795 assert User.superuser?(user)
1799 describe "invisible?/1" do
1800 test "returns true for an invisible user" do
1801 user = insert(:user, local: true, invisible: true)
1803 assert User.invisible?(user)
1806 test "returns false for a non-invisible user" do
1807 user = insert(:user, local: true)
1809 refute User.invisible?(user)
1813 describe "visible_for/2" do
1814 test "returns true when the account is itself" do
1815 user = insert(:user, local: true)
1817 assert User.visible_for(user, user) == :visible
1820 test "returns false when the account is unconfirmed and confirmation is required" do
1821 clear_config([:instance, :account_activation_required], true)
1823 user = insert(:user, local: true, is_confirmed: false)
1824 other_user = insert(:user, local: true)
1826 refute User.visible_for(user, other_user) == :visible
1829 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1830 clear_config([:instance, :account_activation_required], true)
1832 user = insert(:user, local: false, is_confirmed: false)
1833 other_user = insert(:user, local: true)
1835 assert User.visible_for(user, other_user) == :visible
1838 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1839 clear_config([:instance, :account_activation_required], true)
1841 user = insert(:user, local: true, is_confirmed: false)
1842 other_user = insert(:user, local: true, is_admin: true)
1844 assert User.visible_for(user, other_user) == :visible
1848 describe "parse_bio/2" do
1849 test "preserves hosts in user links text" do
1850 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1851 user = insert(:user)
1852 bio = "A.k.a. @nick@domain.com"
1855 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1857 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1859 assert expected_text == User.parse_bio(bio, user)
1862 test "Adds rel=me on linkbacked urls" do
1863 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1865 bio = "http://example.com/rel_me/null"
1866 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1867 assert expected_text == User.parse_bio(bio, user)
1869 bio = "http://example.com/rel_me/link"
1870 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1871 assert expected_text == User.parse_bio(bio, user)
1873 bio = "http://example.com/rel_me/anchor"
1874 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1875 assert expected_text == User.parse_bio(bio, user)
1879 test "follower count is updated when a follower is blocked" do
1880 user = insert(:user)
1881 follower = insert(:user)
1882 follower2 = insert(:user)
1883 follower3 = insert(:user)
1885 {:ok, follower, user} = User.follow(follower, user)
1886 {:ok, _follower2, _user} = User.follow(follower2, user)
1887 {:ok, _follower3, _user} = User.follow(follower3, user)
1889 {:ok, _user_relationship} = User.block(user, follower)
1890 user = refresh_record(user)
1892 assert user.follower_count == 2
1895 describe "list_inactive_users_query/1" do
1896 defp days_ago(days) do
1898 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1899 -days * 60 * 60 * 24,
1904 test "Users are inactive by default" do
1908 Enum.map(1..total, fn _ ->
1909 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1912 inactive_users_ids =
1913 Pleroma.User.list_inactive_users_query()
1914 |> Pleroma.Repo.all()
1915 |> Enum.map(& &1.id)
1917 Enum.each(users, fn user ->
1918 assert user.id in inactive_users_ids
1922 test "Only includes users who has no recent activity" do
1926 Enum.map(1..total, fn _ ->
1927 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1930 {inactive, active} = Enum.split(users, trunc(total / 2))
1932 Enum.map(active, fn user ->
1933 to = Enum.random(users -- [user])
1936 CommonAPI.post(user, %{
1937 status: "hey @#{to.nickname}"
1941 inactive_users_ids =
1942 Pleroma.User.list_inactive_users_query()
1943 |> Pleroma.Repo.all()
1944 |> Enum.map(& &1.id)
1946 Enum.each(active, fn user ->
1947 refute user.id in inactive_users_ids
1950 Enum.each(inactive, fn user ->
1951 assert user.id in inactive_users_ids
1955 test "Only includes users with no read notifications" do
1959 Enum.map(1..total, fn _ ->
1960 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1963 [sender | recipients] = users
1964 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1966 Enum.each(recipients, fn to ->
1968 CommonAPI.post(sender, %{
1969 status: "hey @#{to.nickname}"
1973 CommonAPI.post(sender, %{
1974 status: "hey again @#{to.nickname}"
1978 Enum.each(active, fn user ->
1979 [n1, _n2] = Pleroma.Notification.for_user(user)
1980 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1983 inactive_users_ids =
1984 Pleroma.User.list_inactive_users_query()
1985 |> Pleroma.Repo.all()
1986 |> Enum.map(& &1.id)
1988 Enum.each(active, fn user ->
1989 refute user.id in inactive_users_ids
1992 Enum.each(inactive, fn user ->
1993 assert user.id in inactive_users_ids
1998 describe "ensure_keys_present" do
1999 test "it creates keys for a user and stores them in info" do
2000 user = insert(:user)
2001 refute is_binary(user.keys)
2002 {:ok, user} = User.ensure_keys_present(user)
2003 assert is_binary(user.keys)
2006 test "it doesn't create keys if there already are some" do
2007 user = insert(:user, keys: "xxx")
2008 {:ok, user} = User.ensure_keys_present(user)
2009 assert user.keys == "xxx"
2013 describe "get_ap_ids_by_nicknames" do
2014 test "it returns a list of AP ids for a given set of nicknames" do
2015 user = insert(:user)
2016 user_two = insert(:user)
2018 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2019 assert length(ap_ids) == 2
2020 assert user.ap_id in ap_ids
2021 assert user_two.ap_id in ap_ids
2025 describe "sync followers count" do
2027 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2028 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2029 insert(:user, local: true)
2030 insert(:user, local: false, is_active: false)
2031 {:ok, user1: user1, user2: user2}
2034 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2035 [fdb_user1] = User.external_users(limit: 1)
2037 assert fdb_user1.ap_id
2038 assert fdb_user1.ap_id == user1.ap_id
2039 assert fdb_user1.id == user1.id
2041 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2043 assert fdb_user2.ap_id
2044 assert fdb_user2.ap_id == user2.ap_id
2045 assert fdb_user2.id == user2.id
2047 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2051 describe "is_internal_user?/1" do
2052 test "non-internal user returns false" do
2053 user = insert(:user)
2054 refute User.is_internal_user?(user)
2057 test "user with no nickname returns true" do
2058 user = insert(:user, %{nickname: nil})
2059 assert User.is_internal_user?(user)
2062 test "user with internal-prefixed nickname returns true" do
2063 user = insert(:user, %{nickname: "internal.test"})
2064 assert User.is_internal_user?(user)
2068 describe "update_and_set_cache/1" do
2069 test "returns error when user is stale instead Ecto.StaleEntryError" do
2070 user = insert(:user)
2072 changeset = Ecto.Changeset.change(user, bio: "test")
2076 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2077 User.update_and_set_cache(changeset)
2080 test "performs update cache if user updated" do
2081 user = insert(:user)
2082 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2084 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2086 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2087 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2088 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2092 describe "following/followers synchronization" do
2093 setup do: clear_config([:instance, :external_user_synchronization])
2095 test "updates the counters normally on following/getting a follow when disabled" do
2096 clear_config([:instance, :external_user_synchronization], false)
2097 user = insert(:user)
2102 follower_address: "http://localhost:4001/users/masto_closed/followers",
2103 following_address: "http://localhost:4001/users/masto_closed/following",
2107 assert other_user.following_count == 0
2108 assert other_user.follower_count == 0
2110 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2112 assert user.following_count == 1
2113 assert other_user.follower_count == 1
2116 test "syncronizes the counters with the remote instance for the followed when enabled" do
2117 clear_config([:instance, :external_user_synchronization], false)
2119 user = insert(:user)
2124 follower_address: "http://localhost:4001/users/masto_closed/followers",
2125 following_address: "http://localhost:4001/users/masto_closed/following",
2129 assert other_user.following_count == 0
2130 assert other_user.follower_count == 0
2132 clear_config([:instance, :external_user_synchronization], true)
2133 {:ok, _user, other_user} = User.follow(user, other_user)
2135 assert other_user.follower_count == 437
2138 test "syncronizes the counters with the remote instance for the follower when enabled" do
2139 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 clear_config([:instance, :external_user_synchronization], true)
2155 {:ok, other_user, _user} = User.follow(other_user, user)
2157 assert other_user.following_count == 152
2161 describe "change_email/2" do
2163 [user: insert(:user)]
2166 test "blank email returns error", %{user: user} do
2167 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2168 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2171 test "non unique email returns error", %{user: user} do
2172 %{email: email} = insert(:user)
2174 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2175 User.change_email(user, email)
2178 test "invalid email returns error", %{user: user} do
2179 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2180 User.change_email(user, "cofe")
2183 test "changes email", %{user: user} do
2184 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2188 describe "get_cached_by_nickname_or_id" do
2190 local_user = insert(:user)
2191 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2193 [local_user: local_user, remote_user: remote_user]
2196 setup do: clear_config([:instance, :limit_to_local_content])
2198 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2199 remote_user: remote_user
2201 clear_config([:instance, :limit_to_local_content], false)
2202 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2204 clear_config([:instance, :limit_to_local_content], true)
2205 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2207 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2208 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2211 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2212 %{remote_user: remote_user} do
2213 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2214 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2217 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2218 %{remote_user: remote_user, local_user: local_user} do
2219 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2220 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2223 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2224 %{remote_user: remote_user} do
2225 clear_config([:instance, :limit_to_local_content], true)
2226 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2229 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2230 %{local_user: local_user} do
2231 clear_config([:instance, :limit_to_local_content], false)
2232 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2234 clear_config([:instance, :limit_to_local_content], true)
2235 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2237 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2238 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2242 describe "update_email_notifications/2" do
2244 user = insert(:user, email_notifications: %{"digest" => true})
2249 test "Notifications are updated", %{user: user} do
2250 true = user.email_notifications["digest"]
2251 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2252 assert result.email_notifications["digest"] == false
2256 describe "local_nickname/1" do
2257 test "returns nickname without host" do
2258 assert User.local_nickname("@mentioned") == "mentioned"
2259 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2260 assert User.local_nickname("nickname@host.com") == "nickname"
2264 describe "full_nickname/1" do
2265 test "returns fully qualified nickname for local and remote users" do
2267 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2269 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2271 assert User.full_nickname(local_user) == "local_user@somehost.com"
2272 assert User.full_nickname(remote_user) == "remote@host.com"
2275 test "strips leading @ from mentions" do
2276 assert User.full_nickname("@mentioned") == "mentioned"
2277 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2280 test "does not modify nicknames" do
2281 assert User.full_nickname("nickname") == "nickname"
2282 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2286 test "avatar fallback" do
2287 user = insert(:user)
2288 assert User.avatar_url(user) =~ "/images/avi.png"
2290 clear_config([:assets, :default_user_avatar], "avatar.png")
2292 user = User.get_cached_by_nickname_or_id(user.nickname)
2293 assert User.avatar_url(user) =~ "avatar.png"
2295 assert User.avatar_url(user, no_default: true) == nil
2298 test "get_host/1" do
2299 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2300 assert User.get_host(user) == "lain.com"
2303 test "update_last_active_at/1" do
2304 user = insert(:user)
2305 assert is_nil(user.last_active_at)
2307 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2309 assert {:ok, user} = User.update_last_active_at(user)
2311 assert user.last_active_at >= test_started_at
2312 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2315 NaiveDateTime.utc_now()
2316 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2317 |> NaiveDateTime.truncate(:second)
2319 assert {:ok, user} =
2321 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2322 |> User.update_and_set_cache()
2324 assert user.last_active_at == last_active_at
2325 assert {:ok, user} = User.update_last_active_at(user)
2326 assert user.last_active_at >= test_started_at
2327 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2330 test "active_user_count/1" do
2332 insert(:user, %{local: false})
2333 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -5)})
2334 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -3)})
2335 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2337 assert User.active_user_count() == 2
2338 assert User.active_user_count(6) == 3
2339 assert User.active_user_count(1) == 1
2344 user = insert(:user)
2346 [user: user, object_id: object_id_from_created_activity(user)]
2349 test "unique pins", %{user: user, object_id: object_id} do
2350 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2351 User.add_pinned_object_id(user, object_id)
2353 assert Enum.count(pins) == 1
2355 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2356 User.add_pinned_object_id(updated_user, object_id)
2358 assert pinned_at1 == pinned_at2
2360 assert Enum.count(pins) == 1
2363 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2364 clear_config([:instance, :max_pinned_statuses], 1)
2365 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2367 object_id2 = object_id_from_created_activity(user)
2369 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2370 assert Keyword.has_key?(errors, :pinned_objects)
2373 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2374 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2376 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2377 assert after_remove.pinned_objects == %{}
2381 defp object_id_from_created_activity(user) do
2382 %{id: id} = insert(:note_activity, user: user)
2383 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)