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, %{deactivated: true})
207 CommonAPI.follow(pending_follower, locked)
209 assert true == pending_follower.deactivated
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, %{deactivated: true})
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 Pleroma.Config.put([: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 Pleroma.Config.put([: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 Pleroma.Config.put([: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 Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
432 Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
433 Pleroma.Config.put([: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 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
448 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
449 Pleroma.Config.put([: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 Pleroma.Config.put([:mrf_simple, :media_nsfw], ["localhost"])
485 welcome_user = insert(:user)
486 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
487 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
488 Pleroma.Config.put([: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 Pleroma.Config.put([:welcome, :email, :enabled], true)
503 Pleroma.Config.put([: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 Pleroma.Config.put([: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 requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
555 Pleroma.Config.put([:instance, :account_activation_required], true)
559 |> Enum.each(fn key ->
560 params = Map.delete(@full_user_data, key)
561 changeset = User.register_changeset(%User{}, params)
563 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
567 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
568 Pleroma.Config.put([:instance, :account_activation_required], false)
572 |> Enum.each(fn key ->
573 params = Map.delete(@full_user_data, key)
574 changeset = User.register_changeset(%User{}, params)
576 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
580 test "it restricts certain nicknames" do
581 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
583 assert is_bitstring(restricted_name)
587 |> Map.put(:nickname, restricted_name)
589 changeset = User.register_changeset(%User{}, params)
591 refute changeset.valid?
594 test "it blocks blacklisted email domains" do
595 clear_config([User, :email_blacklist], ["trolling.world"])
598 params = Map.put(@full_user_data, :email, "troll@trolling.world")
599 changeset = User.register_changeset(%User{}, params)
600 refute changeset.valid?
602 # Block with subdomain match
603 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
604 changeset = User.register_changeset(%User{}, params)
605 refute changeset.valid?
607 # Pass with different domains that are similar
608 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
609 changeset = User.register_changeset(%User{}, params)
610 assert changeset.valid?
612 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
613 changeset = User.register_changeset(%User{}, params)
614 assert changeset.valid?
617 test "it sets the password_hash and ap_id" do
618 changeset = User.register_changeset(%User{}, @full_user_data)
620 assert changeset.valid?
622 assert is_binary(changeset.changes[:password_hash])
623 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
625 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
628 test "it sets the 'accepts_chat_messages' set to true" do
629 changeset = User.register_changeset(%User{}, @full_user_data)
630 assert changeset.valid?
632 {:ok, user} = Repo.insert(changeset)
634 assert user.accepts_chat_messages
637 test "it creates a confirmed user" do
638 changeset = User.register_changeset(%User{}, @full_user_data)
639 assert changeset.valid?
641 {:ok, user} = Repo.insert(changeset)
643 assert user.is_confirmed
647 describe "user registration, with :account_activation_required" do
653 password_confirmation: "test",
654 email: "email@example.com"
656 setup do: clear_config([:instance, :account_activation_required], true)
658 test "it creates unconfirmed user" do
659 changeset = User.register_changeset(%User{}, @full_user_data)
660 assert changeset.valid?
662 {:ok, user} = Repo.insert(changeset)
664 refute user.is_confirmed
665 assert user.confirmation_token
668 test "it creates confirmed user if :confirmed option is given" do
669 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
670 assert changeset.valid?
672 {:ok, user} = Repo.insert(changeset)
674 assert user.is_confirmed
675 refute user.confirmation_token
679 describe "user registration, with :account_approval_required" do
685 password_confirmation: "test",
686 email: "email@example.com",
687 registration_reason: "I'm a cool guy :)"
689 setup do: clear_config([:instance, :account_approval_required], true)
691 test "it creates unapproved user" do
692 changeset = User.register_changeset(%User{}, @full_user_data)
693 assert changeset.valid?
695 {:ok, user} = Repo.insert(changeset)
697 refute user.is_approved
698 assert user.registration_reason == "I'm a cool guy :)"
701 test "it restricts length of registration reason" do
702 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
704 assert is_integer(reason_limit)
709 :registration_reason,
710 "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."
713 changeset = User.register_changeset(%User{}, params)
715 refute changeset.valid?
719 describe "get_or_fetch/1" do
720 test "gets an existing user by nickname" do
722 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
724 assert user == fetched_user
727 test "gets an existing user by ap_id" do
728 ap_id = "http://mastodon.example.org/users/admin"
734 nickname: "admin@mastodon.example.org",
738 {:ok, fetched_user} = User.get_or_fetch(ap_id)
739 freshed_user = refresh_record(user)
740 assert freshed_user == fetched_user
744 describe "fetching a user from nickname or trying to build one" do
745 test "gets an existing user" do
747 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
749 assert user == fetched_user
752 test "gets an existing user, case insensitive" do
753 user = insert(:user, nickname: "nick")
754 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
756 assert user == fetched_user
759 test "gets an existing user by fully qualified nickname" do
762 {:ok, fetched_user} =
763 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
765 assert user == fetched_user
768 test "gets an existing user by fully qualified nickname, case insensitive" do
769 user = insert(:user, nickname: "nick")
770 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
772 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
774 assert user == fetched_user
777 @tag capture_log: true
778 test "returns nil if no user could be fetched" do
779 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
780 assert fetched_user == "not found nonexistant@social.heldscal.la"
783 test "returns nil for nonexistant local user" do
784 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
785 assert fetched_user == "not found nonexistant"
788 test "updates an existing user, if stale" do
789 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
795 nickname: "admin@mastodon.example.org",
796 ap_id: "http://mastodon.example.org/users/admin",
797 last_refreshed_at: a_week_ago
800 assert orig_user.last_refreshed_at == a_week_ago
802 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
806 refute user.last_refreshed_at == orig_user.last_refreshed_at
809 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" 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/harinezumigari",
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.id == orig_user.id
829 orig_user = User.get_by_id(orig_user.id)
831 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
834 @tag capture_log: true
835 test "it returns the old user if stale, but unfetchable" do
836 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
842 nickname: "admin@mastodon.example.org",
843 ap_id: "http://mastodon.example.org/users/raymoo",
844 last_refreshed_at: a_week_ago
847 assert orig_user.last_refreshed_at == a_week_ago
849 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
851 assert user.last_refreshed_at == orig_user.last_refreshed_at
855 test "returns an ap_id for a user" do
858 assert User.ap_id(user) ==
859 Pleroma.Web.Router.Helpers.user_feed_url(
860 Pleroma.Web.Endpoint,
866 test "returns an ap_followers link for a user" do
869 assert User.ap_followers(user) ==
870 Pleroma.Web.Router.Helpers.user_feed_url(
871 Pleroma.Web.Endpoint,
877 describe "remote user changeset" do
883 avatar: %{some: "avatar"}
885 setup do: clear_config([:instance, :user_bio_length])
886 setup do: clear_config([:instance, :user_name_length])
888 test "it confirms validity" do
889 cs = User.remote_user_changeset(@valid_remote)
893 test "it sets the follower_adress" do
894 cs = User.remote_user_changeset(@valid_remote)
895 # remote users get a fake local follower address
896 assert cs.changes.follower_address ==
897 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
900 test "it enforces the fqn format for nicknames" do
901 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
902 assert Ecto.Changeset.get_field(cs, :local) == false
903 assert cs.changes.avatar
907 test "it has required fields" do
909 |> Enum.each(fn field ->
910 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
915 test "it is invalid given a local user" do
917 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
923 describe "followers and friends" do
924 test "gets all followers for a given user" do
926 follower_one = insert(:user)
927 follower_two = insert(:user)
928 not_follower = insert(:user)
930 {:ok, follower_one, user} = User.follow(follower_one, user)
931 {:ok, follower_two, user} = User.follow(follower_two, user)
933 res = User.get_followers(user)
935 assert Enum.member?(res, follower_one)
936 assert Enum.member?(res, follower_two)
937 refute Enum.member?(res, not_follower)
940 test "gets all friends (followed users) for a given user" do
942 followed_one = insert(:user)
943 followed_two = insert(:user)
944 not_followed = insert(:user)
946 {:ok, user, followed_one} = User.follow(user, followed_one)
947 {:ok, user, followed_two} = User.follow(user, followed_two)
949 res = User.get_friends(user)
951 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
952 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
953 assert Enum.member?(res, followed_one)
954 assert Enum.member?(res, followed_two)
955 refute Enum.member?(res, not_followed)
959 describe "updating note and follower count" do
960 test "it sets the note_count property" do
963 user = User.get_cached_by_ap_id(note.data["actor"])
965 assert user.note_count == 0
967 {:ok, user} = User.update_note_count(user)
969 assert user.note_count == 1
972 test "it increases the note_count property" do
974 user = User.get_cached_by_ap_id(note.data["actor"])
976 assert user.note_count == 0
978 {:ok, user} = User.increase_note_count(user)
980 assert user.note_count == 1
982 {:ok, user} = User.increase_note_count(user)
984 assert user.note_count == 2
987 test "it decreases the note_count property" do
989 user = User.get_cached_by_ap_id(note.data["actor"])
991 assert user.note_count == 0
993 {:ok, user} = User.increase_note_count(user)
995 assert user.note_count == 1
997 {:ok, user} = User.decrease_note_count(user)
999 assert user.note_count == 0
1001 {:ok, user} = User.decrease_note_count(user)
1003 assert user.note_count == 0
1006 test "it sets the follower_count property" do
1007 user = insert(:user)
1008 follower = insert(:user)
1010 User.follow(follower, user)
1012 assert user.follower_count == 0
1014 {:ok, user} = User.update_follower_count(user)
1016 assert user.follower_count == 1
1021 test "it mutes people" do
1022 user = insert(:user)
1023 muted_user = insert(:user)
1025 refute User.mutes?(user, muted_user)
1026 refute User.muted_notifications?(user, muted_user)
1028 {:ok, _user_relationships} = User.mute(user, muted_user)
1030 assert User.mutes?(user, muted_user)
1031 assert User.muted_notifications?(user, muted_user)
1035 user = insert(:user)
1036 muted_user = insert(:user)
1038 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1039 assert User.mutes?(user, muted_user)
1041 worker = Pleroma.Workers.MuteExpireWorker
1042 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1049 assert :ok = perform_job(worker, args)
1051 refute User.mutes?(user, muted_user)
1052 refute User.muted_notifications?(user, muted_user)
1055 test "it unmutes users" do
1056 user = insert(:user)
1057 muted_user = insert(:user)
1059 {:ok, _user_relationships} = User.mute(user, muted_user)
1060 {:ok, _user_mute} = User.unmute(user, muted_user)
1062 refute User.mutes?(user, muted_user)
1063 refute User.muted_notifications?(user, muted_user)
1066 test "it unmutes users by id" do
1067 user = insert(:user)
1068 muted_user = insert(:user)
1070 {:ok, _user_relationships} = User.mute(user, muted_user)
1071 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1073 refute User.mutes?(user, muted_user)
1074 refute User.muted_notifications?(user, muted_user)
1077 test "it mutes user without notifications" do
1078 user = insert(:user)
1079 muted_user = insert(:user)
1081 refute User.mutes?(user, muted_user)
1082 refute User.muted_notifications?(user, muted_user)
1084 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1086 assert User.mutes?(user, muted_user)
1087 refute User.muted_notifications?(user, muted_user)
1091 describe "blocks" do
1092 test "it blocks people" do
1093 user = insert(:user)
1094 blocked_user = insert(:user)
1096 refute User.blocks?(user, blocked_user)
1098 {:ok, _user_relationship} = User.block(user, blocked_user)
1100 assert User.blocks?(user, blocked_user)
1103 test "it unblocks users" do
1104 user = insert(:user)
1105 blocked_user = insert(:user)
1107 {:ok, _user_relationship} = User.block(user, blocked_user)
1108 {:ok, _user_block} = User.unblock(user, blocked_user)
1110 refute User.blocks?(user, blocked_user)
1113 test "blocks tear down cyclical follow relationships" do
1114 blocker = insert(:user)
1115 blocked = insert(:user)
1117 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1118 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1120 assert User.following?(blocker, blocked)
1121 assert User.following?(blocked, blocker)
1123 {:ok, _user_relationship} = User.block(blocker, blocked)
1124 blocked = User.get_cached_by_id(blocked.id)
1126 assert User.blocks?(blocker, blocked)
1128 refute User.following?(blocker, blocked)
1129 refute User.following?(blocked, blocker)
1132 test "blocks tear down blocker->blocked follow relationships" do
1133 blocker = insert(:user)
1134 blocked = insert(:user)
1136 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1138 assert User.following?(blocker, blocked)
1139 refute User.following?(blocked, blocker)
1141 {:ok, _user_relationship} = User.block(blocker, blocked)
1142 blocked = User.get_cached_by_id(blocked.id)
1144 assert User.blocks?(blocker, blocked)
1146 refute User.following?(blocker, blocked)
1147 refute User.following?(blocked, blocker)
1150 test "blocks tear down blocked->blocker follow relationships" do
1151 blocker = insert(:user)
1152 blocked = insert(:user)
1154 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1156 refute User.following?(blocker, blocked)
1157 assert User.following?(blocked, blocker)
1159 {:ok, _user_relationship} = User.block(blocker, blocked)
1160 blocked = User.get_cached_by_id(blocked.id)
1162 assert User.blocks?(blocker, blocked)
1164 refute User.following?(blocker, blocked)
1165 refute User.following?(blocked, blocker)
1168 test "blocks tear down blocked->blocker subscription relationships" do
1169 blocker = insert(:user)
1170 blocked = insert(:user)
1172 {:ok, _subscription} = User.subscribe(blocked, blocker)
1174 assert User.subscribed_to?(blocked, blocker)
1175 refute User.subscribed_to?(blocker, blocked)
1177 {:ok, _user_relationship} = User.block(blocker, blocked)
1179 assert User.blocks?(blocker, blocked)
1180 refute User.subscribed_to?(blocker, blocked)
1181 refute User.subscribed_to?(blocked, blocker)
1185 describe "domain blocking" do
1186 test "blocks domains" do
1187 user = insert(:user)
1188 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1190 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1192 assert User.blocks?(user, collateral_user)
1195 test "does not block domain with same end" do
1196 user = insert(:user)
1199 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1201 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1203 refute User.blocks?(user, collateral_user)
1206 test "does not block domain with same end if wildcard added" do
1207 user = insert(:user)
1210 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1212 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1214 refute User.blocks?(user, collateral_user)
1217 test "blocks domain with wildcard for subdomain" do
1218 user = insert(:user)
1220 user_from_subdomain =
1221 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1223 user_with_two_subdomains =
1225 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1228 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1230 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1232 assert User.blocks?(user, user_from_subdomain)
1233 assert User.blocks?(user, user_with_two_subdomains)
1234 assert User.blocks?(user, user_domain)
1237 test "unblocks domains" do
1238 user = insert(:user)
1239 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1241 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1242 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1244 refute User.blocks?(user, collateral_user)
1247 test "follows take precedence over domain blocks" do
1248 user = insert(:user)
1249 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1251 {:ok, user} = User.block_domain(user, "meanies.social")
1252 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1254 refute User.blocks?(user, good_eggo)
1258 describe "get_recipients_from_activity" do
1259 test "works for announces" do
1260 actor = insert(:user)
1261 user = insert(:user, local: true)
1263 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1264 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1266 recipients = User.get_recipients_from_activity(announce)
1268 assert user in recipients
1271 test "get recipients" do
1272 actor = insert(:user)
1273 user = insert(:user, local: true)
1274 user_two = insert(:user, local: false)
1275 addressed = insert(:user, local: true)
1276 addressed_remote = insert(:user, local: false)
1279 CommonAPI.post(actor, %{
1280 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1283 assert Enum.map([actor, addressed], & &1.ap_id) --
1284 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1286 {:ok, user, actor} = User.follow(user, actor)
1287 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1288 recipients = User.get_recipients_from_activity(activity)
1289 assert length(recipients) == 3
1290 assert user in recipients
1291 assert addressed in recipients
1294 test "has following" do
1295 actor = insert(:user)
1296 user = insert(:user)
1297 user_two = insert(:user)
1298 addressed = insert(:user, local: true)
1301 CommonAPI.post(actor, %{
1302 status: "hey @#{addressed.nickname}"
1305 assert Enum.map([actor, addressed], & &1.ap_id) --
1306 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1308 {:ok, _actor, _user} = User.follow(actor, user)
1309 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1310 recipients = User.get_recipients_from_activity(activity)
1311 assert length(recipients) == 2
1312 assert addressed in recipients
1316 describe ".deactivate" do
1317 test "can de-activate then re-activate a user" do
1318 user = insert(:user)
1319 assert false == user.deactivated
1320 {:ok, user} = User.deactivate(user)
1321 assert true == user.deactivated
1322 {:ok, user} = User.deactivate(user, false)
1323 assert false == user.deactivated
1326 test "hide a user from followers" do
1327 user = insert(:user)
1328 user2 = insert(:user)
1330 {:ok, user, user2} = User.follow(user, user2)
1331 {:ok, _user} = User.deactivate(user)
1333 user2 = User.get_cached_by_id(user2.id)
1335 assert user2.follower_count == 0
1336 assert [] = User.get_followers(user2)
1339 test "hide a user from friends" do
1340 user = insert(:user)
1341 user2 = insert(:user)
1343 {:ok, user2, user} = User.follow(user2, user)
1344 assert user2.following_count == 1
1345 assert User.following_count(user2) == 1
1347 {:ok, _user} = User.deactivate(user)
1349 user2 = User.get_cached_by_id(user2.id)
1351 assert refresh_record(user2).following_count == 0
1352 assert user2.following_count == 0
1353 assert User.following_count(user2) == 0
1354 assert [] = User.get_friends(user2)
1357 test "hide a user's statuses from timelines and notifications" do
1358 user = insert(:user)
1359 user2 = insert(:user)
1361 {:ok, user2, user} = User.follow(user2, user)
1363 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1365 activity = Repo.preload(activity, :bookmark)
1367 [notification] = Pleroma.Notification.for_user(user2)
1368 assert notification.activity.id == activity.id
1370 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1372 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1373 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1377 {:ok, _user} = User.deactivate(user)
1379 assert [] == ActivityPub.fetch_public_activities(%{})
1380 assert [] == Pleroma.Notification.for_user(user2)
1383 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1389 describe "approve" do
1390 test "approves a user" do
1391 user = insert(:user, is_approved: false)
1392 refute user.is_approved
1393 {:ok, user} = User.approve(user)
1394 assert user.is_approved
1397 test "approves a list of users" do
1398 unapproved_users = [
1399 insert(:user, is_approved: false),
1400 insert(:user, is_approved: false),
1401 insert(:user, is_approved: false)
1404 {:ok, users} = User.approve(unapproved_users)
1406 assert Enum.count(users) == 3
1408 Enum.each(users, fn user ->
1409 assert user.is_approved
1413 test "it sends welcome email if it is set" do
1414 clear_config([:welcome, :email, :enabled], true)
1415 clear_config([:welcome, :email, :sender], "tester@test.me")
1417 user = insert(:user, is_approved: false)
1418 welcome_user = insert(:user, email: "tester@test.me")
1419 instance_name = Pleroma.Config.get([:instance, :name])
1423 ObanHelpers.perform_all()
1426 from: {instance_name, welcome_user.email},
1427 to: {user.name, user.email},
1428 html_body: "Welcome to #{instance_name}"
1432 test "approving an approved user does not trigger post-register actions" do
1433 clear_config([:welcome, :email, :enabled], true)
1435 user = insert(:user, is_approved: true)
1438 ObanHelpers.perform_all()
1440 assert_no_email_sent()
1444 describe "confirm" do
1445 test "confirms a user" do
1446 user = insert(:user, is_confirmed: false)
1447 refute user.is_confirmed
1448 {:ok, user} = User.confirm(user)
1449 assert user.is_confirmed
1452 test "confirms a list of users" do
1453 unconfirmed_users = [
1454 insert(:user, is_confirmed: false),
1455 insert(:user, is_confirmed: false),
1456 insert(:user, is_confirmed: false)
1459 {:ok, users} = User.confirm(unconfirmed_users)
1461 assert Enum.count(users) == 3
1463 Enum.each(users, fn user ->
1464 assert user.is_confirmed
1468 test "sends approval emails when `is_approved: false`" do
1469 admin = insert(:user, is_admin: true)
1470 user = insert(:user, is_confirmed: false, is_approved: false)
1473 ObanHelpers.perform_all()
1475 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1476 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1478 notify_email = Pleroma.Config.get([:instance, :notify_email])
1479 instance_name = Pleroma.Config.get([:instance, :name])
1481 # User approval email
1483 from: {instance_name, notify_email},
1484 to: {user.name, user.email},
1485 html_body: user_email.html_body
1490 from: {instance_name, notify_email},
1491 to: {admin.name, admin.email},
1492 html_body: admin_email.html_body
1496 test "confirming a confirmed user does not trigger post-register actions" do
1497 user = insert(:user, is_confirmed: true, is_approved: false)
1500 ObanHelpers.perform_all()
1502 assert_no_email_sent()
1506 describe "delete" do
1508 {:ok, user} = insert(:user) |> User.set_cache()
1513 setup do: clear_config([:instance, :federating])
1515 test ".delete_user_activities deletes all create activities", %{user: user} do
1516 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1518 User.delete_user_activities(user)
1520 # TODO: Test removal favorites, repeats, delete activities.
1521 refute Activity.get_by_id(activity.id)
1524 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1525 follower = insert(:user)
1526 {:ok, follower, user} = User.follow(follower, user)
1528 locked_user = insert(:user, name: "locked", is_locked: true)
1529 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1531 object = insert(:note, user: user)
1532 activity = insert(:note_activity, user: user, note: object)
1534 object_two = insert(:note, user: follower)
1535 activity_two = insert(:note_activity, user: follower, note: object_two)
1537 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1538 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1539 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1541 {:ok, job} = User.delete(user)
1542 {:ok, _user} = ObanHelpers.perform(job)
1544 follower = User.get_cached_by_id(follower.id)
1546 refute User.following?(follower, user)
1547 assert %{deactivated: true} = User.get_by_id(user.id)
1549 assert [] == User.get_follow_requests(locked_user)
1553 |> Activity.Queries.by_actor()
1555 |> Enum.map(fn act -> act.data["type"] end)
1557 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1559 refute Activity.get_by_id(activity.id)
1560 refute Activity.get_by_id(like.id)
1561 refute Activity.get_by_id(like_two.id)
1562 refute Activity.get_by_id(repeat.id)
1566 describe "delete/1 when confirmation is pending" do
1568 user = insert(:user, is_confirmed: false)
1572 test "deletes user from database when activation required", %{user: user} do
1573 clear_config([:instance, :account_activation_required], true)
1575 {:ok, job} = User.delete(user)
1576 {:ok, _} = ObanHelpers.perform(job)
1578 refute User.get_cached_by_id(user.id)
1579 refute User.get_by_id(user.id)
1582 test "deactivates user when activation is not required", %{user: user} do
1583 clear_config([:instance, :account_activation_required], false)
1585 {:ok, job} = User.delete(user)
1586 {:ok, _} = ObanHelpers.perform(job)
1588 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1589 assert %{deactivated: true} = User.get_by_id(user.id)
1593 test "delete/1 when approval is pending deletes the user" do
1594 user = insert(:user, is_approved: false)
1596 {:ok, job} = User.delete(user)
1597 {:ok, _} = ObanHelpers.perform(job)
1599 refute User.get_cached_by_id(user.id)
1600 refute User.get_by_id(user.id)
1603 test "delete/1 purges a user when they wouldn't be fully deleted" do
1608 password_hash: "pdfk2$1b3n159001",
1609 keys: "RSA begin buplic key",
1610 public_key: "--PRIVATE KEYE--",
1611 avatar: %{"a" => "b"},
1613 banner: %{"a" => "b"},
1614 background: %{"a" => "b"},
1617 following_count: 9001,
1619 is_confirmed: false,
1620 password_reset_pending: true,
1622 registration_reason: "ahhhhh",
1623 confirmation_token: "qqqq",
1624 domain_blocks: ["lain.com"],
1629 mastofe_settings: %{"a" => "b"},
1630 mascot: %{"a" => "b"},
1631 emoji: %{"a" => "b"},
1632 pleroma_settings_store: %{"q" => "x"},
1633 fields: [%{"gg" => "qq"}],
1634 raw_fields: [%{"gg" => "qq"}],
1635 is_discoverable: true,
1636 also_known_as: ["https://lol.olo/users/loll"]
1639 {:ok, job} = User.delete(user)
1640 {:ok, _} = ObanHelpers.perform(job)
1641 user = User.get_by_id(user.id)
1653 last_refreshed_at: nil,
1654 last_digest_emailed_at: nil,
1662 password_reset_pending: false,
1664 registration_reason: nil,
1665 confirmation_token: nil,
1669 is_moderator: false,
1671 mastofe_settings: nil,
1674 pleroma_settings_store: %{},
1677 is_discoverable: false,
1682 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1683 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1686 describe "per-user rich-text filtering" do
1687 test "html_filter_policy returns default policies, when rich-text is enabled" do
1688 user = insert(:user)
1690 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1693 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1694 user = insert(:user, no_rich_text: true)
1696 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1700 describe "caching" do
1701 test "invalidate_cache works" do
1702 user = insert(:user)
1704 User.set_cache(user)
1705 User.invalidate_cache(user)
1707 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1708 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1711 test "User.delete() plugs any possible zombie objects" do
1712 user = insert(:user)
1714 {:ok, job} = User.delete(user)
1715 {:ok, _} = ObanHelpers.perform(job)
1717 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1719 assert cached_user != user
1721 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1723 assert cached_user != user
1727 describe "account_status/1" do
1728 setup do: clear_config([:instance, :account_activation_required])
1730 test "return confirmation_pending for unconfirm user" do
1731 Pleroma.Config.put([:instance, :account_activation_required], true)
1732 user = insert(:user, is_confirmed: false)
1733 assert User.account_status(user) == :confirmation_pending
1736 test "return active for confirmed user" do
1737 Pleroma.Config.put([:instance, :account_activation_required], true)
1738 user = insert(:user, is_confirmed: true)
1739 assert User.account_status(user) == :active
1742 test "return active for remote user" do
1743 user = insert(:user, local: false)
1744 assert User.account_status(user) == :active
1747 test "returns :password_reset_pending for user with reset password" do
1748 user = insert(:user, password_reset_pending: true)
1749 assert User.account_status(user) == :password_reset_pending
1752 test "returns :deactivated for deactivated user" do
1753 user = insert(:user, local: true, is_confirmed: true, deactivated: true)
1754 assert User.account_status(user) == :deactivated
1757 test "returns :approval_pending for unapproved user" do
1758 user = insert(:user, local: true, is_approved: false)
1759 assert User.account_status(user) == :approval_pending
1761 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1762 assert User.account_status(user) == :approval_pending
1766 describe "superuser?/1" do
1767 test "returns false for unprivileged users" do
1768 user = insert(:user, local: true)
1770 refute User.superuser?(user)
1773 test "returns false for remote users" do
1774 user = insert(:user, local: false)
1775 remote_admin_user = insert(:user, local: false, is_admin: true)
1777 refute User.superuser?(user)
1778 refute User.superuser?(remote_admin_user)
1781 test "returns true for local moderators" do
1782 user = insert(:user, local: true, is_moderator: true)
1784 assert User.superuser?(user)
1787 test "returns true for local admins" do
1788 user = insert(:user, local: true, is_admin: true)
1790 assert User.superuser?(user)
1794 describe "invisible?/1" do
1795 test "returns true for an invisible user" do
1796 user = insert(:user, local: true, invisible: true)
1798 assert User.invisible?(user)
1801 test "returns false for a non-invisible user" do
1802 user = insert(:user, local: true)
1804 refute User.invisible?(user)
1808 describe "visible_for/2" do
1809 test "returns true when the account is itself" do
1810 user = insert(:user, local: true)
1812 assert User.visible_for(user, user) == :visible
1815 test "returns false when the account is unconfirmed and confirmation is required" do
1816 Pleroma.Config.put([:instance, :account_activation_required], true)
1818 user = insert(:user, local: true, is_confirmed: false)
1819 other_user = insert(:user, local: true)
1821 refute User.visible_for(user, other_user) == :visible
1824 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1825 Pleroma.Config.put([:instance, :account_activation_required], true)
1827 user = insert(:user, local: false, is_confirmed: false)
1828 other_user = insert(:user, local: true)
1830 assert User.visible_for(user, other_user) == :visible
1833 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1834 Pleroma.Config.put([:instance, :account_activation_required], true)
1836 user = insert(:user, local: true, is_confirmed: false)
1837 other_user = insert(:user, local: true, is_admin: true)
1839 assert User.visible_for(user, other_user) == :visible
1843 describe "parse_bio/2" do
1844 test "preserves hosts in user links text" do
1845 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1846 user = insert(:user)
1847 bio = "A.k.a. @nick@domain.com"
1850 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1852 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1854 assert expected_text == User.parse_bio(bio, user)
1857 test "Adds rel=me on linkbacked urls" do
1858 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1860 bio = "http://example.com/rel_me/null"
1861 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1862 assert expected_text == User.parse_bio(bio, user)
1864 bio = "http://example.com/rel_me/link"
1865 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1866 assert expected_text == User.parse_bio(bio, user)
1868 bio = "http://example.com/rel_me/anchor"
1869 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1870 assert expected_text == User.parse_bio(bio, user)
1874 test "follower count is updated when a follower is blocked" do
1875 user = insert(:user)
1876 follower = insert(:user)
1877 follower2 = insert(:user)
1878 follower3 = insert(:user)
1880 {:ok, follower, user} = User.follow(follower, user)
1881 {:ok, _follower2, _user} = User.follow(follower2, user)
1882 {:ok, _follower3, _user} = User.follow(follower3, user)
1884 {:ok, _user_relationship} = User.block(user, follower)
1885 user = refresh_record(user)
1887 assert user.follower_count == 2
1890 describe "list_inactive_users_query/1" do
1891 defp days_ago(days) do
1893 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1894 -days * 60 * 60 * 24,
1899 test "Users are inactive by default" do
1903 Enum.map(1..total, fn _ ->
1904 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1907 inactive_users_ids =
1908 Pleroma.User.list_inactive_users_query()
1909 |> Pleroma.Repo.all()
1910 |> Enum.map(& &1.id)
1912 Enum.each(users, fn user ->
1913 assert user.id in inactive_users_ids
1917 test "Only includes users who has no recent activity" do
1921 Enum.map(1..total, fn _ ->
1922 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1925 {inactive, active} = Enum.split(users, trunc(total / 2))
1927 Enum.map(active, fn user ->
1928 to = Enum.random(users -- [user])
1931 CommonAPI.post(user, %{
1932 status: "hey @#{to.nickname}"
1936 inactive_users_ids =
1937 Pleroma.User.list_inactive_users_query()
1938 |> Pleroma.Repo.all()
1939 |> Enum.map(& &1.id)
1941 Enum.each(active, fn user ->
1942 refute user.id in inactive_users_ids
1945 Enum.each(inactive, fn user ->
1946 assert user.id in inactive_users_ids
1950 test "Only includes users with no read notifications" do
1954 Enum.map(1..total, fn _ ->
1955 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1958 [sender | recipients] = users
1959 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1961 Enum.each(recipients, fn to ->
1963 CommonAPI.post(sender, %{
1964 status: "hey @#{to.nickname}"
1968 CommonAPI.post(sender, %{
1969 status: "hey again @#{to.nickname}"
1973 Enum.each(active, fn user ->
1974 [n1, _n2] = Pleroma.Notification.for_user(user)
1975 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1978 inactive_users_ids =
1979 Pleroma.User.list_inactive_users_query()
1980 |> Pleroma.Repo.all()
1981 |> Enum.map(& &1.id)
1983 Enum.each(active, fn user ->
1984 refute user.id in inactive_users_ids
1987 Enum.each(inactive, fn user ->
1988 assert user.id in inactive_users_ids
1993 describe "ensure_keys_present" do
1994 test "it creates keys for a user and stores them in info" do
1995 user = insert(:user)
1996 refute is_binary(user.keys)
1997 {:ok, user} = User.ensure_keys_present(user)
1998 assert is_binary(user.keys)
2001 test "it doesn't create keys if there already are some" do
2002 user = insert(:user, keys: "xxx")
2003 {:ok, user} = User.ensure_keys_present(user)
2004 assert user.keys == "xxx"
2008 describe "get_ap_ids_by_nicknames" do
2009 test "it returns a list of AP ids for a given set of nicknames" do
2010 user = insert(:user)
2011 user_two = insert(:user)
2013 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2014 assert length(ap_ids) == 2
2015 assert user.ap_id in ap_ids
2016 assert user_two.ap_id in ap_ids
2020 describe "sync followers count" do
2022 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2023 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2024 insert(:user, local: true)
2025 insert(:user, local: false, deactivated: true)
2026 {:ok, user1: user1, user2: user2}
2029 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2030 [fdb_user1] = User.external_users(limit: 1)
2032 assert fdb_user1.ap_id
2033 assert fdb_user1.ap_id == user1.ap_id
2034 assert fdb_user1.id == user1.id
2036 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2038 assert fdb_user2.ap_id
2039 assert fdb_user2.ap_id == user2.ap_id
2040 assert fdb_user2.id == user2.id
2042 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2046 describe "is_internal_user?/1" do
2047 test "non-internal user returns false" do
2048 user = insert(:user)
2049 refute User.is_internal_user?(user)
2052 test "user with no nickname returns true" do
2053 user = insert(:user, %{nickname: nil})
2054 assert User.is_internal_user?(user)
2057 test "user with internal-prefixed nickname returns true" do
2058 user = insert(:user, %{nickname: "internal.test"})
2059 assert User.is_internal_user?(user)
2063 describe "update_and_set_cache/1" do
2064 test "returns error when user is stale instead Ecto.StaleEntryError" do
2065 user = insert(:user)
2067 changeset = Ecto.Changeset.change(user, bio: "test")
2071 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2072 User.update_and_set_cache(changeset)
2075 test "performs update cache if user updated" do
2076 user = insert(:user)
2077 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2079 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2081 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2082 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2083 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2087 describe "following/followers synchronization" do
2088 setup do: clear_config([:instance, :external_user_synchronization])
2090 test "updates the counters normally on following/getting a follow when disabled" do
2091 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2092 user = insert(:user)
2097 follower_address: "http://localhost:4001/users/masto_closed/followers",
2098 following_address: "http://localhost:4001/users/masto_closed/following",
2102 assert other_user.following_count == 0
2103 assert other_user.follower_count == 0
2105 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2107 assert user.following_count == 1
2108 assert other_user.follower_count == 1
2111 test "syncronizes the counters with the remote instance for the followed when enabled" do
2112 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2114 user = insert(:user)
2119 follower_address: "http://localhost:4001/users/masto_closed/followers",
2120 following_address: "http://localhost:4001/users/masto_closed/following",
2124 assert other_user.following_count == 0
2125 assert other_user.follower_count == 0
2127 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2128 {:ok, _user, other_user} = User.follow(user, other_user)
2130 assert other_user.follower_count == 437
2133 test "syncronizes the counters with the remote instance for the follower when enabled" do
2134 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2136 user = insert(:user)
2141 follower_address: "http://localhost:4001/users/masto_closed/followers",
2142 following_address: "http://localhost:4001/users/masto_closed/following",
2146 assert other_user.following_count == 0
2147 assert other_user.follower_count == 0
2149 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2150 {:ok, other_user, _user} = User.follow(other_user, user)
2152 assert other_user.following_count == 152
2156 describe "change_email/2" do
2158 [user: insert(:user)]
2161 test "blank email returns error", %{user: user} do
2162 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2163 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2166 test "non unique email returns error", %{user: user} do
2167 %{email: email} = insert(:user)
2169 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2170 User.change_email(user, email)
2173 test "invalid email returns error", %{user: user} do
2174 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2175 User.change_email(user, "cofe")
2178 test "changes email", %{user: user} do
2179 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2183 describe "get_cached_by_nickname_or_id" do
2185 local_user = insert(:user)
2186 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2188 [local_user: local_user, remote_user: remote_user]
2191 setup do: clear_config([:instance, :limit_to_local_content])
2193 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2194 remote_user: remote_user
2196 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2197 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2199 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2200 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2202 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2203 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2206 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2207 %{remote_user: remote_user} do
2208 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2209 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2212 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2213 %{remote_user: remote_user, local_user: local_user} do
2214 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2215 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2218 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2219 %{remote_user: remote_user} do
2220 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2221 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2224 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2225 %{local_user: local_user} do
2226 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2227 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2229 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2230 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2232 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2233 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2237 describe "update_email_notifications/2" do
2239 user = insert(:user, email_notifications: %{"digest" => true})
2244 test "Notifications are updated", %{user: user} do
2245 true = user.email_notifications["digest"]
2246 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2247 assert result.email_notifications["digest"] == false
2251 test "avatar fallback" do
2252 user = insert(:user)
2253 assert User.avatar_url(user) =~ "/images/avi.png"
2255 clear_config([:assets, :default_user_avatar], "avatar.png")
2257 user = User.get_cached_by_nickname_or_id(user.nickname)
2258 assert User.avatar_url(user) =~ "avatar.png"
2260 assert User.avatar_url(user, no_default: true) == nil
2263 test "get_host/1" do
2264 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2265 assert User.get_host(user) == "lain.com"