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.Endpoint.url()}/users/#{user.nickname}"
156 assert expected_ap_id == User.ap_id(user)
159 test "ap_followers returns the followers collection for the user" do
160 user = UserBuilder.build()
162 expected_followers_collection = "#{User.ap_id(user)}/followers"
164 assert expected_followers_collection == User.ap_followers(user)
167 test "ap_following returns the following collection for the user" do
168 user = UserBuilder.build()
170 expected_followers_collection = "#{User.ap_id(user)}/following"
172 assert expected_followers_collection == User.ap_following(user)
175 test "returns all pending follow requests" do
176 unlocked = insert(:user)
177 locked = insert(:user, is_locked: true)
178 follower = insert(:user)
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, is_locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
200 assert [^pending_follower] = User.get_follow_requests(locked)
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, is_locked: true)
205 pending_follower = insert(:user, %{is_active: false})
207 CommonAPI.follow(pending_follower, locked)
209 refute pending_follower.is_active
210 assert [] = User.get_follow_requests(locked)
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, is_locked: true)
215 follower = insert(:user)
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
224 test "follow_all follows mutliple users" do
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
236 {:ok, user, followed_zero} = User.follow(user, followed_zero)
238 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
240 assert User.following?(user, followed_one)
241 assert User.following?(user, followed_two)
242 assert User.following?(user, followed_zero)
243 refute User.following?(user, not_followed)
244 refute User.following?(user, blocked)
245 refute User.following?(user, reverse_blocked)
248 test "follow_all follows mutliple users without duplicating" do
250 followed_zero = insert(:user)
251 followed_one = insert(:user)
252 followed_two = insert(:user)
254 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
255 assert length(User.following(user)) == 3
257 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
258 assert length(User.following(user)) == 4
261 test "follow takes a user and another user" do
263 followed = insert(:user)
265 {:ok, user, followed} = User.follow(user, followed)
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
270 assert followed.follower_count == 1
271 assert user.following_count == 1
273 assert User.ap_followers(followed) in User.following(user)
276 test "can't follow a deactivated users" do
278 followed = insert(:user, %{is_active: false})
280 {:error, _} = User.follow(user, followed)
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
287 {:ok, _user_relationship} = User.block(blocker, blockee)
289 {:error, _} = User.follow(blockee, blocker)
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
296 {:ok, _user_relationship} = User.block(blocker, blocked)
298 {:error, _} = User.subscribe(blocked, blocker)
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, is_locked: true)
303 followed = insert(:user, is_locked: true)
305 {:ok, follower, followed} = User.maybe_direct_follow(follower, followed)
307 refute User.following?(follower, followed)
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
313 test "unfollow with 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 fails gracefully with invalid email config" do
576 cng = User.register_changeset(%User{}, @full_user_data)
578 # Disable the mailer but enable all the things that want to send emails
579 clear_config([Pleroma.Emails.Mailer, :enabled], false)
580 clear_config([:instance, :account_activation_required], true)
581 clear_config([:instance, :account_approval_required], true)
582 clear_config([:welcome, :email, :enabled], true)
583 clear_config([:welcome, :email, :sender], "lain@lain.com")
585 # The user is still created
586 assert {:ok, %User{nickname: "nick"}} = User.register(cng)
589 ObanHelpers.perform_all()
593 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
594 clear_config([:instance, :account_activation_required], true)
598 |> Enum.each(fn key ->
599 params = Map.delete(@full_user_data, key)
600 changeset = User.register_changeset(%User{}, params)
602 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
606 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
607 clear_config([:instance, :account_activation_required], false)
611 |> Enum.each(fn key ->
612 params = Map.delete(@full_user_data, key)
613 changeset = User.register_changeset(%User{}, params)
615 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
619 test "it restricts certain nicknames" do
620 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
622 assert is_bitstring(restricted_name)
626 |> Map.put(:nickname, restricted_name)
628 changeset = User.register_changeset(%User{}, params)
630 refute changeset.valid?
633 test "it blocks blacklisted email domains" do
634 clear_config([User, :email_blacklist], ["trolling.world"])
637 params = Map.put(@full_user_data, :email, "troll@trolling.world")
638 changeset = User.register_changeset(%User{}, params)
639 refute changeset.valid?
641 # Block with subdomain match
642 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
643 changeset = User.register_changeset(%User{}, params)
644 refute changeset.valid?
646 # Pass with different domains that are similar
647 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
648 changeset = User.register_changeset(%User{}, params)
649 assert changeset.valid?
651 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
652 changeset = User.register_changeset(%User{}, params)
653 assert changeset.valid?
656 test "it sets the password_hash and ap_id" do
657 changeset = User.register_changeset(%User{}, @full_user_data)
659 assert changeset.valid?
661 assert is_binary(changeset.changes[:password_hash])
662 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
664 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
667 test "it sets the 'accepts_chat_messages' set to true" do
668 changeset = User.register_changeset(%User{}, @full_user_data)
669 assert changeset.valid?
671 {:ok, user} = Repo.insert(changeset)
673 assert user.accepts_chat_messages
676 test "it creates a confirmed user" do
677 changeset = User.register_changeset(%User{}, @full_user_data)
678 assert changeset.valid?
680 {:ok, user} = Repo.insert(changeset)
682 assert user.is_confirmed
686 describe "user registration, with :account_activation_required" do
692 password_confirmation: "test",
693 email: "email@example.com"
695 setup do: clear_config([:instance, :account_activation_required], true)
697 test "it creates unconfirmed user" do
698 changeset = User.register_changeset(%User{}, @full_user_data)
699 assert changeset.valid?
701 {:ok, user} = Repo.insert(changeset)
703 refute user.is_confirmed
704 assert user.confirmation_token
707 test "it creates confirmed user if :confirmed option is given" do
708 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
709 assert changeset.valid?
711 {:ok, user} = Repo.insert(changeset)
713 assert user.is_confirmed
714 refute user.confirmation_token
718 describe "user registration, with :account_approval_required" do
724 password_confirmation: "test",
725 email: "email@example.com",
726 registration_reason: "I'm a cool guy :)"
728 setup do: clear_config([:instance, :account_approval_required], true)
730 test "it creates unapproved user" do
731 changeset = User.register_changeset(%User{}, @full_user_data)
732 assert changeset.valid?
734 {:ok, user} = Repo.insert(changeset)
736 refute user.is_approved
737 assert user.registration_reason == "I'm a cool guy :)"
740 test "it restricts length of registration reason" do
741 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
743 assert is_integer(reason_limit)
748 :registration_reason,
749 "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."
752 changeset = User.register_changeset(%User{}, params)
754 refute changeset.valid?
758 describe "get_or_fetch/1" do
759 test "gets an existing user by nickname" do
761 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
763 assert user == fetched_user
766 test "gets an existing user by ap_id" do
767 ap_id = "http://mastodon.example.org/users/admin"
773 nickname: "admin@mastodon.example.org",
777 {:ok, fetched_user} = User.get_or_fetch(ap_id)
778 freshed_user = refresh_record(user)
779 assert freshed_user == fetched_user
783 describe "fetching a user from nickname or trying to build one" do
784 test "gets an existing user" do
786 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
788 assert user == fetched_user
791 test "gets an existing user, case insensitive" do
792 user = insert(:user, nickname: "nick")
793 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
795 assert user == fetched_user
798 test "gets an existing user by fully qualified nickname" do
801 {:ok, fetched_user} =
802 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
804 assert user == fetched_user
807 test "gets an existing user by fully qualified nickname, case insensitive" do
808 user = insert(:user, nickname: "nick")
809 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
811 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
813 assert user == fetched_user
816 @tag capture_log: true
817 test "returns nil if no user could be fetched" do
818 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
819 assert fetched_user == "not found nonexistant@social.heldscal.la"
822 test "returns nil for nonexistant local user" do
823 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
824 assert fetched_user == "not found nonexistant"
827 test "updates an existing user, if stale" do
828 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
834 nickname: "admin@mastodon.example.org",
835 ap_id: "http://mastodon.example.org/users/admin",
836 last_refreshed_at: a_week_ago
839 assert orig_user.last_refreshed_at == a_week_ago
841 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
845 refute user.last_refreshed_at == orig_user.last_refreshed_at
848 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
849 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
855 nickname: "admin@mastodon.example.org",
856 ap_id: "http://mastodon.example.org/users/harinezumigari",
857 last_refreshed_at: a_week_ago
860 assert orig_user.last_refreshed_at == a_week_ago
862 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
866 refute user.id == orig_user.id
868 orig_user = User.get_by_id(orig_user.id)
870 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
873 @tag capture_log: true
874 test "it returns the old user if stale, but unfetchable" do
875 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
881 nickname: "admin@mastodon.example.org",
882 ap_id: "http://mastodon.example.org/users/raymoo",
883 last_refreshed_at: a_week_ago
886 assert orig_user.last_refreshed_at == a_week_ago
888 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
890 assert user.last_refreshed_at == orig_user.last_refreshed_at
894 test "returns an ap_id for a user" do
897 assert User.ap_id(user) ==
898 Pleroma.Web.Router.Helpers.user_feed_url(
899 Pleroma.Web.Endpoint,
905 test "returns an ap_followers link for a user" do
908 assert User.ap_followers(user) ==
909 Pleroma.Web.Router.Helpers.user_feed_url(
910 Pleroma.Web.Endpoint,
916 describe "remote user changeset" do
922 avatar: %{some: "avatar"}
924 setup do: clear_config([:instance, :user_bio_length])
925 setup do: clear_config([:instance, :user_name_length])
927 test "it confirms validity" do
928 cs = User.remote_user_changeset(@valid_remote)
932 test "it sets the follower_adress" do
933 cs = User.remote_user_changeset(@valid_remote)
934 # remote users get a fake local follower address
935 assert cs.changes.follower_address ==
936 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
939 test "it enforces the fqn format for nicknames" do
940 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
941 assert Ecto.Changeset.get_field(cs, :local) == false
942 assert cs.changes.avatar
946 test "it has required fields" do
948 |> Enum.each(fn field ->
949 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
954 test "it is invalid given a local user" do
956 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
962 describe "followers and friends" do
963 test "gets all followers for a given user" do
965 follower_one = insert(:user)
966 follower_two = insert(:user)
967 not_follower = insert(:user)
969 {:ok, follower_one, user} = User.follow(follower_one, user)
970 {:ok, follower_two, user} = User.follow(follower_two, user)
972 res = User.get_followers(user)
974 assert Enum.member?(res, follower_one)
975 assert Enum.member?(res, follower_two)
976 refute Enum.member?(res, not_follower)
979 test "gets all friends (followed users) for a given user" do
981 followed_one = insert(:user)
982 followed_two = insert(:user)
983 not_followed = insert(:user)
985 {:ok, user, followed_one} = User.follow(user, followed_one)
986 {:ok, user, followed_two} = User.follow(user, followed_two)
988 res = User.get_friends(user)
990 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
991 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
992 assert Enum.member?(res, followed_one)
993 assert Enum.member?(res, followed_two)
994 refute Enum.member?(res, not_followed)
998 describe "updating note and follower count" do
999 test "it sets the note_count property" do
1000 note = insert(:note)
1002 user = User.get_cached_by_ap_id(note.data["actor"])
1004 assert user.note_count == 0
1006 {:ok, user} = User.update_note_count(user)
1008 assert user.note_count == 1
1011 test "it increases the note_count property" do
1012 note = insert(:note)
1013 user = User.get_cached_by_ap_id(note.data["actor"])
1015 assert user.note_count == 0
1017 {:ok, user} = User.increase_note_count(user)
1019 assert user.note_count == 1
1021 {:ok, user} = User.increase_note_count(user)
1023 assert user.note_count == 2
1026 test "it decreases the note_count property" do
1027 note = insert(:note)
1028 user = User.get_cached_by_ap_id(note.data["actor"])
1030 assert user.note_count == 0
1032 {:ok, user} = User.increase_note_count(user)
1034 assert user.note_count == 1
1036 {:ok, user} = User.decrease_note_count(user)
1038 assert user.note_count == 0
1040 {:ok, user} = User.decrease_note_count(user)
1042 assert user.note_count == 0
1045 test "it sets the follower_count property" do
1046 user = insert(:user)
1047 follower = insert(:user)
1049 User.follow(follower, user)
1051 assert user.follower_count == 0
1053 {:ok, user} = User.update_follower_count(user)
1055 assert user.follower_count == 1
1060 test "it mutes people" do
1061 user = insert(:user)
1062 muted_user = insert(:user)
1064 refute User.mutes?(user, muted_user)
1065 refute User.muted_notifications?(user, muted_user)
1067 {:ok, _user_relationships} = User.mute(user, muted_user)
1069 assert User.mutes?(user, muted_user)
1070 assert User.muted_notifications?(user, muted_user)
1074 user = insert(:user)
1075 muted_user = insert(:user)
1077 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1078 assert User.mutes?(user, muted_user)
1080 worker = Pleroma.Workers.MuteExpireWorker
1081 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1088 assert :ok = perform_job(worker, args)
1090 refute User.mutes?(user, muted_user)
1091 refute User.muted_notifications?(user, muted_user)
1094 test "it unmutes users" do
1095 user = insert(:user)
1096 muted_user = insert(:user)
1098 {:ok, _user_relationships} = User.mute(user, muted_user)
1099 {:ok, _user_mute} = User.unmute(user, muted_user)
1101 refute User.mutes?(user, muted_user)
1102 refute User.muted_notifications?(user, muted_user)
1105 test "it unmutes users by id" do
1106 user = insert(:user)
1107 muted_user = insert(:user)
1109 {:ok, _user_relationships} = User.mute(user, muted_user)
1110 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1112 refute User.mutes?(user, muted_user)
1113 refute User.muted_notifications?(user, muted_user)
1116 test "it mutes user without notifications" do
1117 user = insert(:user)
1118 muted_user = insert(:user)
1120 refute User.mutes?(user, muted_user)
1121 refute User.muted_notifications?(user, muted_user)
1123 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1125 assert User.mutes?(user, muted_user)
1126 refute User.muted_notifications?(user, muted_user)
1130 describe "blocks" do
1131 test "it blocks people" do
1132 user = insert(:user)
1133 blocked_user = insert(:user)
1135 refute User.blocks?(user, blocked_user)
1137 {:ok, _user_relationship} = User.block(user, blocked_user)
1139 assert User.blocks?(user, blocked_user)
1142 test "it unblocks users" do
1143 user = insert(:user)
1144 blocked_user = insert(:user)
1146 {:ok, _user_relationship} = User.block(user, blocked_user)
1147 {:ok, _user_block} = User.unblock(user, blocked_user)
1149 refute User.blocks?(user, blocked_user)
1152 test "blocks tear down cyclical follow relationships" do
1153 blocker = insert(:user)
1154 blocked = insert(:user)
1156 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1157 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1159 assert User.following?(blocker, blocked)
1160 assert 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 blocker->blocked follow relationships" do
1172 blocker = insert(:user)
1173 blocked = insert(:user)
1175 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1177 assert User.following?(blocker, blocked)
1178 refute 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 follow relationships" do
1190 blocker = insert(:user)
1191 blocked = insert(:user)
1193 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1195 refute User.following?(blocker, blocked)
1196 assert User.following?(blocked, blocker)
1198 {:ok, _user_relationship} = User.block(blocker, blocked)
1199 blocked = User.get_cached_by_id(blocked.id)
1201 assert User.blocks?(blocker, blocked)
1203 refute User.following?(blocker, blocked)
1204 refute User.following?(blocked, blocker)
1207 test "blocks tear down blocked->blocker subscription relationships" do
1208 blocker = insert(:user)
1209 blocked = insert(:user)
1211 {:ok, _subscription} = User.subscribe(blocked, blocker)
1213 assert User.subscribed_to?(blocked, blocker)
1214 refute User.subscribed_to?(blocker, blocked)
1216 {:ok, _user_relationship} = User.block(blocker, blocked)
1218 assert User.blocks?(blocker, blocked)
1219 refute User.subscribed_to?(blocker, blocked)
1220 refute User.subscribed_to?(blocked, blocker)
1224 describe "domain blocking" do
1225 test "blocks domains" do
1226 user = insert(:user)
1227 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1229 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1231 assert User.blocks?(user, collateral_user)
1234 test "does not block domain with same end" do
1235 user = insert(:user)
1238 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1240 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1242 refute User.blocks?(user, collateral_user)
1245 test "does not block domain with same end if wildcard added" do
1246 user = insert(:user)
1249 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1251 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1253 refute User.blocks?(user, collateral_user)
1256 test "blocks domain with wildcard for subdomain" do
1257 user = insert(:user)
1259 user_from_subdomain =
1260 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1262 user_with_two_subdomains =
1264 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1267 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1269 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1271 assert User.blocks?(user, user_from_subdomain)
1272 assert User.blocks?(user, user_with_two_subdomains)
1273 assert User.blocks?(user, user_domain)
1276 test "unblocks domains" do
1277 user = insert(:user)
1278 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1280 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1281 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1283 refute User.blocks?(user, collateral_user)
1286 test "follows take precedence over domain blocks" do
1287 user = insert(:user)
1288 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1290 {:ok, user} = User.block_domain(user, "meanies.social")
1291 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1293 refute User.blocks?(user, good_eggo)
1297 describe "get_recipients_from_activity" do
1298 test "works for announces" do
1299 actor = insert(:user)
1300 user = insert(:user, local: true)
1302 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1303 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1305 recipients = User.get_recipients_from_activity(announce)
1307 assert user in recipients
1310 test "get recipients" do
1311 actor = insert(:user)
1312 user = insert(:user, local: true)
1313 user_two = insert(:user, local: false)
1314 addressed = insert(:user, local: true)
1315 addressed_remote = insert(:user, local: false)
1318 CommonAPI.post(actor, %{
1319 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1322 assert Enum.map([actor, addressed], & &1.ap_id) --
1323 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1325 {:ok, user, actor} = User.follow(user, actor)
1326 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1327 recipients = User.get_recipients_from_activity(activity)
1328 assert length(recipients) == 3
1329 assert user in recipients
1330 assert addressed in recipients
1333 test "has following" do
1334 actor = insert(:user)
1335 user = insert(:user)
1336 user_two = insert(:user)
1337 addressed = insert(:user, local: true)
1340 CommonAPI.post(actor, %{
1341 status: "hey @#{addressed.nickname}"
1344 assert Enum.map([actor, addressed], & &1.ap_id) --
1345 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1347 {:ok, _actor, _user} = User.follow(actor, user)
1348 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1349 recipients = User.get_recipients_from_activity(activity)
1350 assert length(recipients) == 2
1351 assert addressed in recipients
1355 describe ".set_activation" do
1356 test "can de-activate then re-activate a user" do
1357 user = insert(:user)
1358 assert user.is_active
1359 {:ok, user} = User.set_activation(user, false)
1360 refute user.is_active
1361 {:ok, user} = User.set_activation(user, true)
1362 assert user.is_active
1365 test "hide a user from followers" do
1366 user = insert(:user)
1367 user2 = insert(:user)
1369 {:ok, user, user2} = User.follow(user, user2)
1370 {:ok, _user} = User.set_activation(user, false)
1372 user2 = User.get_cached_by_id(user2.id)
1374 assert user2.follower_count == 0
1375 assert [] = User.get_followers(user2)
1378 test "hide a user from friends" do
1379 user = insert(:user)
1380 user2 = insert(:user)
1382 {:ok, user2, user} = User.follow(user2, user)
1383 assert user2.following_count == 1
1384 assert User.following_count(user2) == 1
1386 {:ok, _user} = User.set_activation(user, false)
1388 user2 = User.get_cached_by_id(user2.id)
1390 assert refresh_record(user2).following_count == 0
1391 assert user2.following_count == 0
1392 assert User.following_count(user2) == 0
1393 assert [] = User.get_friends(user2)
1396 test "hide a user's statuses from timelines and notifications" do
1397 user = insert(:user)
1398 user2 = insert(:user)
1400 {:ok, user2, user} = User.follow(user2, user)
1402 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1404 activity = Repo.preload(activity, :bookmark)
1406 [notification] = Pleroma.Notification.for_user(user2)
1407 assert notification.activity.id == activity.id
1409 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1411 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1412 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1416 {:ok, _user} = User.set_activation(user, false)
1418 assert [] == ActivityPub.fetch_public_activities(%{})
1419 assert [] == Pleroma.Notification.for_user(user2)
1422 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1428 describe "approve" do
1429 test "approves a user" do
1430 user = insert(:user, is_approved: false)
1431 refute user.is_approved
1432 {:ok, user} = User.approve(user)
1433 assert user.is_approved
1436 test "approves a list of users" do
1437 unapproved_users = [
1438 insert(:user, is_approved: false),
1439 insert(:user, is_approved: false),
1440 insert(:user, is_approved: false)
1443 {:ok, users} = User.approve(unapproved_users)
1445 assert Enum.count(users) == 3
1447 Enum.each(users, fn user ->
1448 assert user.is_approved
1452 test "it sends welcome email if it is set" do
1453 clear_config([:welcome, :email, :enabled], true)
1454 clear_config([:welcome, :email, :sender], "tester@test.me")
1456 user = insert(:user, is_approved: false)
1457 welcome_user = insert(:user, email: "tester@test.me")
1458 instance_name = Pleroma.Config.get([:instance, :name])
1462 ObanHelpers.perform_all()
1465 from: {instance_name, welcome_user.email},
1466 to: {user.name, user.email},
1467 html_body: "Welcome to #{instance_name}"
1471 test "approving an approved user does not trigger post-register actions" do
1472 clear_config([:welcome, :email, :enabled], true)
1474 user = insert(:user, is_approved: true)
1477 ObanHelpers.perform_all()
1479 assert_no_email_sent()
1483 describe "confirm" do
1484 test "confirms a user" do
1485 user = insert(:user, is_confirmed: false)
1486 refute user.is_confirmed
1487 {:ok, user} = User.confirm(user)
1488 assert user.is_confirmed
1491 test "confirms a list of users" do
1492 unconfirmed_users = [
1493 insert(:user, is_confirmed: false),
1494 insert(:user, is_confirmed: false),
1495 insert(:user, is_confirmed: false)
1498 {:ok, users} = User.confirm(unconfirmed_users)
1500 assert Enum.count(users) == 3
1502 Enum.each(users, fn user ->
1503 assert user.is_confirmed
1507 test "sends approval emails when `is_approved: false`" do
1508 admin = insert(:user, is_admin: true)
1509 user = insert(:user, is_confirmed: false, is_approved: false)
1512 ObanHelpers.perform_all()
1514 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1515 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1517 notify_email = Pleroma.Config.get([:instance, :notify_email])
1518 instance_name = Pleroma.Config.get([:instance, :name])
1520 # User approval email
1522 from: {instance_name, notify_email},
1523 to: {user.name, user.email},
1524 html_body: user_email.html_body
1529 from: {instance_name, notify_email},
1530 to: {admin.name, admin.email},
1531 html_body: admin_email.html_body
1535 test "confirming a confirmed user does not trigger post-register actions" do
1536 user = insert(:user, is_confirmed: true, is_approved: false)
1539 ObanHelpers.perform_all()
1541 assert_no_email_sent()
1545 describe "delete" do
1547 {:ok, user} = insert(:user) |> User.set_cache()
1552 setup do: clear_config([:instance, :federating])
1554 test ".delete_user_activities deletes all create activities", %{user: user} do
1555 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1557 User.delete_user_activities(user)
1559 # TODO: Test removal favorites, repeats, delete activities.
1560 refute Activity.get_by_id(activity.id)
1563 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1564 follower = insert(:user)
1565 {:ok, follower, user} = User.follow(follower, user)
1567 locked_user = insert(:user, name: "locked", is_locked: true)
1568 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1570 object = insert(:note, user: user)
1571 activity = insert(:note_activity, user: user, note: object)
1573 object_two = insert(:note, user: follower)
1574 activity_two = insert(:note_activity, user: follower, note: object_two)
1576 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1577 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1578 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1580 {:ok, job} = User.delete(user)
1581 {:ok, _user} = ObanHelpers.perform(job)
1583 follower = User.get_cached_by_id(follower.id)
1585 refute User.following?(follower, user)
1586 assert %{is_active: false} = User.get_by_id(user.id)
1588 assert [] == User.get_follow_requests(locked_user)
1592 |> Activity.Queries.by_actor()
1594 |> Enum.map(fn act -> act.data["type"] end)
1596 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1598 refute Activity.get_by_id(activity.id)
1599 refute Activity.get_by_id(like.id)
1600 refute Activity.get_by_id(like_two.id)
1601 refute Activity.get_by_id(repeat.id)
1605 test "delete/1 when confirmation is pending deletes the user" do
1606 clear_config([:instance, :account_activation_required], true)
1607 user = insert(:user, is_confirmed: false)
1609 {:ok, job} = User.delete(user)
1610 {:ok, _} = ObanHelpers.perform(job)
1612 refute User.get_cached_by_id(user.id)
1613 refute User.get_by_id(user.id)
1616 test "delete/1 when approval is pending deletes the user" do
1617 user = insert(:user, is_approved: false)
1619 {:ok, job} = User.delete(user)
1620 {:ok, _} = ObanHelpers.perform(job)
1622 refute User.get_cached_by_id(user.id)
1623 refute User.get_by_id(user.id)
1626 test "delete/1 purges a user when they wouldn't be fully deleted" do
1631 password_hash: "pdfk2$1b3n159001",
1632 keys: "RSA begin buplic key",
1633 public_key: "--PRIVATE KEYE--",
1634 avatar: %{"a" => "b"},
1636 banner: %{"a" => "b"},
1637 background: %{"a" => "b"},
1640 following_count: 9001,
1643 password_reset_pending: true,
1645 registration_reason: "ahhhhh",
1646 confirmation_token: "qqqq",
1647 domain_blocks: ["lain.com"],
1652 mastofe_settings: %{"a" => "b"},
1653 mascot: %{"a" => "b"},
1654 emoji: %{"a" => "b"},
1655 pleroma_settings_store: %{"q" => "x"},
1656 fields: [%{"gg" => "qq"}],
1657 raw_fields: [%{"gg" => "qq"}],
1658 is_discoverable: true,
1659 also_known_as: ["https://lol.olo/users/loll"]
1662 {:ok, job} = User.delete(user)
1663 {:ok, _} = ObanHelpers.perform(job)
1664 user = User.get_by_id(user.id)
1672 keys: "RSA begin buplic key",
1673 public_key: "--PRIVATE KEYE--",
1676 last_refreshed_at: nil,
1677 last_digest_emailed_at: nil,
1685 password_reset_pending: false,
1687 registration_reason: nil,
1688 confirmation_token: nil,
1692 is_moderator: false,
1694 mastofe_settings: nil,
1697 pleroma_settings_store: %{},
1700 is_discoverable: false,
1705 test "delete/1 purges a remote user" do
1709 avatar: %{"a" => "b"},
1710 banner: %{"a" => "b"},
1714 {:ok, job} = User.delete(user)
1715 {:ok, _} = ObanHelpers.perform(job)
1716 user = User.get_by_id(user.id)
1718 assert user.name == nil
1719 assert user.avatar == %{}
1720 assert user.banner == %{}
1723 describe "set_suggestion" do
1724 test "suggests a user" do
1725 user = insert(:user, is_suggested: false)
1726 refute user.is_suggested
1727 {:ok, user} = User.set_suggestion(user, true)
1728 assert user.is_suggested
1731 test "suggests a list of users" do
1732 unsuggested_users = [
1733 insert(:user, is_suggested: false),
1734 insert(:user, is_suggested: false),
1735 insert(:user, is_suggested: false)
1738 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1740 assert Enum.count(users) == 3
1742 Enum.each(users, fn user ->
1743 assert user.is_suggested
1747 test "unsuggests a user" do
1748 user = insert(:user, is_suggested: true)
1749 assert user.is_suggested
1750 {:ok, user} = User.set_suggestion(user, false)
1751 refute user.is_suggested
1755 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1756 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1759 describe "per-user rich-text filtering" do
1760 test "html_filter_policy returns default policies, when rich-text is enabled" do
1761 user = insert(:user)
1763 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1766 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1767 user = insert(:user, no_rich_text: true)
1769 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1773 describe "caching" do
1774 test "invalidate_cache works" do
1775 user = insert(:user)
1777 User.set_cache(user)
1778 User.invalidate_cache(user)
1780 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1781 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1784 test "User.delete() plugs any possible zombie objects" do
1785 user = insert(:user)
1787 {:ok, job} = User.delete(user)
1788 {:ok, _} = ObanHelpers.perform(job)
1790 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1792 assert cached_user != user
1794 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1796 assert cached_user != user
1800 describe "account_status/1" do
1801 setup do: clear_config([:instance, :account_activation_required])
1803 test "return confirmation_pending for unconfirm user" do
1804 clear_config([:instance, :account_activation_required], true)
1805 user = insert(:user, is_confirmed: false)
1806 assert User.account_status(user) == :confirmation_pending
1809 test "return active for confirmed user" do
1810 clear_config([:instance, :account_activation_required], true)
1811 user = insert(:user, is_confirmed: true)
1812 assert User.account_status(user) == :active
1815 test "return active for remote user" do
1816 user = insert(:user, local: false)
1817 assert User.account_status(user) == :active
1820 test "returns :password_reset_pending for user with reset password" do
1821 user = insert(:user, password_reset_pending: true)
1822 assert User.account_status(user) == :password_reset_pending
1825 test "returns :deactivated for deactivated user" do
1826 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1827 assert User.account_status(user) == :deactivated
1830 test "returns :approval_pending for unapproved user" do
1831 user = insert(:user, local: true, is_approved: false)
1832 assert User.account_status(user) == :approval_pending
1834 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1835 assert User.account_status(user) == :approval_pending
1839 describe "superuser?/1" do
1840 test "returns false for unprivileged users" do
1841 user = insert(:user, local: true)
1843 refute User.superuser?(user)
1846 test "returns false for remote users" do
1847 user = insert(:user, local: false)
1848 remote_admin_user = insert(:user, local: false, is_admin: true)
1850 refute User.superuser?(user)
1851 refute User.superuser?(remote_admin_user)
1854 test "returns true for local moderators" do
1855 user = insert(:user, local: true, is_moderator: true)
1857 assert User.superuser?(user)
1860 test "returns true for local admins" do
1861 user = insert(:user, local: true, is_admin: true)
1863 assert User.superuser?(user)
1867 describe "invisible?/1" do
1868 test "returns true for an invisible user" do
1869 user = insert(:user, local: true, invisible: true)
1871 assert User.invisible?(user)
1874 test "returns false for a non-invisible user" do
1875 user = insert(:user, local: true)
1877 refute User.invisible?(user)
1881 describe "visible_for/2" do
1882 test "returns true when the account is itself" do
1883 user = insert(:user, local: true)
1885 assert User.visible_for(user, user) == :visible
1888 test "returns false when the account is unconfirmed and confirmation is required" do
1889 clear_config([:instance, :account_activation_required], true)
1891 user = insert(:user, local: true, is_confirmed: false)
1892 other_user = insert(:user, local: true)
1894 refute User.visible_for(user, other_user) == :visible
1897 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1898 clear_config([:instance, :account_activation_required], true)
1900 user = insert(:user, local: false, is_confirmed: false)
1901 other_user = insert(:user, local: true)
1903 assert User.visible_for(user, other_user) == :visible
1906 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1907 clear_config([:instance, :account_activation_required], true)
1909 user = insert(:user, local: true, is_confirmed: false)
1910 other_user = insert(:user, local: true, is_admin: true)
1912 assert User.visible_for(user, other_user) == :visible
1916 describe "parse_bio/2" do
1917 test "preserves hosts in user links text" do
1918 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1919 user = insert(:user)
1920 bio = "A.k.a. @nick@domain.com"
1923 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{remote_user.ap_id}" rel="ugc">@<span>nick@domain.com</span></a></span>)
1925 assert expected_text == User.parse_bio(bio, user)
1928 test "Adds rel=me on linkbacked urls" do
1929 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1931 bio = "http://example.com/rel_me/null"
1932 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1933 assert expected_text == User.parse_bio(bio, user)
1935 bio = "http://example.com/rel_me/link"
1936 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1937 assert expected_text == User.parse_bio(bio, user)
1939 bio = "http://example.com/rel_me/anchor"
1940 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1941 assert expected_text == User.parse_bio(bio, user)
1945 test "follower count is updated when a follower is blocked" do
1946 user = insert(:user)
1947 follower = insert(:user)
1948 follower2 = insert(:user)
1949 follower3 = insert(:user)
1951 {:ok, follower, user} = User.follow(follower, user)
1952 {:ok, _follower2, _user} = User.follow(follower2, user)
1953 {:ok, _follower3, _user} = User.follow(follower3, user)
1955 {:ok, _user_relationship} = User.block(user, follower)
1956 user = refresh_record(user)
1958 assert user.follower_count == 2
1961 describe "list_inactive_users_query/1" do
1962 defp days_ago(days) do
1964 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1965 -days * 60 * 60 * 24,
1970 test "Users are inactive by default" do
1974 Enum.map(1..total, fn _ ->
1975 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1978 inactive_users_ids =
1979 Pleroma.User.list_inactive_users_query()
1980 |> Pleroma.Repo.all()
1981 |> Enum.map(& &1.id)
1983 Enum.each(users, fn user ->
1984 assert user.id in inactive_users_ids
1988 test "Only includes users who has no recent activity" do
1992 Enum.map(1..total, fn _ ->
1993 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1996 {inactive, active} = Enum.split(users, trunc(total / 2))
1998 Enum.map(active, fn user ->
1999 to = Enum.random(users -- [user])
2002 CommonAPI.post(user, %{
2003 status: "hey @#{to.nickname}"
2007 inactive_users_ids =
2008 Pleroma.User.list_inactive_users_query()
2009 |> Pleroma.Repo.all()
2010 |> Enum.map(& &1.id)
2012 Enum.each(active, fn user ->
2013 refute user.id in inactive_users_ids
2016 Enum.each(inactive, fn user ->
2017 assert user.id in inactive_users_ids
2021 test "Only includes users with no read notifications" do
2025 Enum.map(1..total, fn _ ->
2026 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2029 [sender | recipients] = users
2030 {inactive, active} = Enum.split(recipients, trunc(total / 2))
2032 Enum.each(recipients, fn to ->
2034 CommonAPI.post(sender, %{
2035 status: "hey @#{to.nickname}"
2039 CommonAPI.post(sender, %{
2040 status: "hey again @#{to.nickname}"
2044 Enum.each(active, fn user ->
2045 [n1, _n2] = Pleroma.Notification.for_user(user)
2046 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2049 inactive_users_ids =
2050 Pleroma.User.list_inactive_users_query()
2051 |> Pleroma.Repo.all()
2052 |> Enum.map(& &1.id)
2054 Enum.each(active, fn user ->
2055 refute user.id in inactive_users_ids
2058 Enum.each(inactive, fn user ->
2059 assert user.id in inactive_users_ids
2064 describe "ensure_keys_present" do
2065 test "it creates keys for a user and stores them in info" do
2066 user = insert(:user)
2067 refute is_binary(user.keys)
2068 {:ok, user} = User.ensure_keys_present(user)
2069 assert is_binary(user.keys)
2072 test "it doesn't create keys if there already are some" do
2073 user = insert(:user, keys: "xxx")
2074 {:ok, user} = User.ensure_keys_present(user)
2075 assert user.keys == "xxx"
2079 describe "get_ap_ids_by_nicknames" do
2080 test "it returns a list of AP ids for a given set of nicknames" do
2081 user = insert(:user)
2082 user_two = insert(:user)
2084 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2085 assert length(ap_ids) == 2
2086 assert user.ap_id in ap_ids
2087 assert user_two.ap_id in ap_ids
2091 describe "sync followers count" do
2093 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2094 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2095 insert(:user, local: true)
2096 insert(:user, local: false, is_active: false)
2097 {:ok, user1: user1, user2: user2}
2100 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2101 [fdb_user1] = User.external_users(limit: 1)
2103 assert fdb_user1.ap_id
2104 assert fdb_user1.ap_id == user1.ap_id
2105 assert fdb_user1.id == user1.id
2107 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2109 assert fdb_user2.ap_id
2110 assert fdb_user2.ap_id == user2.ap_id
2111 assert fdb_user2.id == user2.id
2113 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2117 describe "is_internal_user?/1" do
2118 test "non-internal user returns false" do
2119 user = insert(:user)
2120 refute User.is_internal_user?(user)
2123 test "user with no nickname returns true" do
2124 user = insert(:user, %{nickname: nil})
2125 assert User.is_internal_user?(user)
2128 test "user with internal-prefixed nickname returns true" do
2129 user = insert(:user, %{nickname: "internal.test"})
2130 assert User.is_internal_user?(user)
2134 describe "update_and_set_cache/1" do
2135 test "returns error when user is stale instead Ecto.StaleEntryError" do
2136 user = insert(:user)
2138 changeset = Ecto.Changeset.change(user, bio: "test")
2142 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2143 User.update_and_set_cache(changeset)
2146 test "performs update cache if user updated" do
2147 user = insert(:user)
2148 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2150 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2152 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2153 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2154 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2158 describe "following/followers synchronization" do
2159 setup do: clear_config([:instance, :external_user_synchronization])
2161 test "updates the counters normally on following/getting a follow when disabled" do
2162 clear_config([:instance, :external_user_synchronization], false)
2163 user = insert(:user)
2168 follower_address: "http://localhost:4001/users/masto_closed/followers",
2169 following_address: "http://localhost:4001/users/masto_closed/following",
2173 assert other_user.following_count == 0
2174 assert other_user.follower_count == 0
2176 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2178 assert user.following_count == 1
2179 assert other_user.follower_count == 1
2182 test "syncronizes the counters with the remote instance for the followed when enabled" do
2183 clear_config([:instance, :external_user_synchronization], false)
2185 user = insert(:user)
2190 follower_address: "http://localhost:4001/users/masto_closed/followers",
2191 following_address: "http://localhost:4001/users/masto_closed/following",
2195 assert other_user.following_count == 0
2196 assert other_user.follower_count == 0
2198 clear_config([:instance, :external_user_synchronization], true)
2199 {:ok, _user, other_user} = User.follow(user, other_user)
2201 assert other_user.follower_count == 437
2204 test "syncronizes the counters with the remote instance for the follower when enabled" do
2205 clear_config([:instance, :external_user_synchronization], false)
2207 user = insert(:user)
2212 follower_address: "http://localhost:4001/users/masto_closed/followers",
2213 following_address: "http://localhost:4001/users/masto_closed/following",
2217 assert other_user.following_count == 0
2218 assert other_user.follower_count == 0
2220 clear_config([:instance, :external_user_synchronization], true)
2221 {:ok, other_user, _user} = User.follow(other_user, user)
2223 assert other_user.following_count == 152
2227 describe "change_email/2" do
2229 [user: insert(:user)]
2232 test "blank email returns error if we require an email on registration", %{user: user} do
2233 orig_account_activation_required =
2234 Pleroma.Config.get([:instance, :account_activation_required])
2236 Pleroma.Config.put([:instance, :account_activation_required], true)
2240 [:instance, :account_activation_required],
2241 orig_account_activation_required
2245 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2246 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2249 test "blank email should be fine if we do not require an email on registration", %{user: user} do
2250 orig_account_activation_required =
2251 Pleroma.Config.get([:instance, :account_activation_required])
2253 Pleroma.Config.put([:instance, :account_activation_required], false)
2257 [:instance, :account_activation_required],
2258 orig_account_activation_required
2262 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2263 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2266 test "non unique email returns error", %{user: user} do
2267 %{email: email} = insert(:user)
2269 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2270 User.change_email(user, email)
2273 test "invalid email returns error", %{user: user} do
2274 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2275 User.change_email(user, "cofe")
2278 test "changes email", %{user: user} do
2279 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2282 test "adds email", %{user: user} do
2283 orig_account_activation_required =
2284 Pleroma.Config.get([:instance, :account_activation_required])
2286 Pleroma.Config.put([:instance, :account_activation_required], false)
2290 [:instance, :account_activation_required],
2291 orig_account_activation_required
2295 assert {:ok, _} = User.change_email(user, "")
2296 Pleroma.Config.put([:instance, :account_activation_required], true)
2298 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2302 describe "get_cached_by_nickname_or_id" do
2304 local_user = insert(:user)
2305 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2307 [local_user: local_user, remote_user: remote_user]
2310 setup do: clear_config([:instance, :limit_to_local_content])
2312 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2313 remote_user: remote_user
2315 clear_config([:instance, :limit_to_local_content], false)
2316 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2318 clear_config([:instance, :limit_to_local_content], true)
2319 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2321 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2322 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2325 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2326 %{remote_user: remote_user} do
2327 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2328 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2331 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2332 %{remote_user: remote_user, local_user: local_user} do
2333 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2334 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2337 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2338 %{remote_user: remote_user} do
2339 clear_config([:instance, :limit_to_local_content], true)
2340 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2343 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2344 %{local_user: local_user} do
2345 clear_config([:instance, :limit_to_local_content], false)
2346 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2348 clear_config([:instance, :limit_to_local_content], true)
2349 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2351 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2352 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2356 describe "update_email_notifications/2" do
2358 user = insert(:user, email_notifications: %{"digest" => true})
2363 test "Notifications are updated", %{user: user} do
2364 true = user.email_notifications["digest"]
2365 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2366 assert result.email_notifications["digest"] == false
2370 describe "local_nickname/1" do
2371 test "returns nickname without host" do
2372 assert User.local_nickname("@mentioned") == "mentioned"
2373 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2374 assert User.local_nickname("nickname@host.com") == "nickname"
2378 describe "full_nickname/1" do
2379 test "returns fully qualified nickname for local and remote users" do
2381 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2383 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2385 assert User.full_nickname(local_user) == "local_user@somehost.com"
2386 assert User.full_nickname(remote_user) == "remote@host.com"
2389 test "strips leading @ from mentions" do
2390 assert User.full_nickname("@mentioned") == "mentioned"
2391 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2394 test "does not modify nicknames" do
2395 assert User.full_nickname("nickname") == "nickname"
2396 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2400 test "avatar fallback" do
2401 user = insert(:user)
2402 assert User.avatar_url(user) =~ "/images/avi.png"
2404 clear_config([:assets, :default_user_avatar], "avatar.png")
2406 user = User.get_cached_by_nickname_or_id(user.nickname)
2407 assert User.avatar_url(user) =~ "avatar.png"
2409 assert User.avatar_url(user, no_default: true) == nil
2412 test "get_host/1" do
2413 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2414 assert User.get_host(user) == "lain.com"
2417 test "update_last_active_at/1" do
2418 user = insert(:user)
2419 assert is_nil(user.last_active_at)
2421 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2423 assert {:ok, user} = User.update_last_active_at(user)
2425 assert user.last_active_at >= test_started_at
2426 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2429 NaiveDateTime.utc_now()
2430 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2431 |> NaiveDateTime.truncate(:second)
2433 assert {:ok, user} =
2435 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2436 |> User.update_and_set_cache()
2438 assert user.last_active_at == last_active_at
2439 assert {:ok, user} = User.update_last_active_at(user)
2440 assert user.last_active_at >= test_started_at
2441 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2444 test "active_user_count/1" do
2446 insert(:user, %{local: false})
2447 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2448 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2449 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2450 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2451 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2453 assert User.active_user_count() == 2
2454 assert User.active_user_count(180) == 3
2455 assert User.active_user_count(365) == 4
2456 assert User.active_user_count(1000) == 5
2461 user = insert(:user)
2463 [user: user, object_id: object_id_from_created_activity(user)]
2466 test "unique pins", %{user: user, object_id: object_id} do
2467 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2468 User.add_pinned_object_id(user, object_id)
2470 assert Enum.count(pins) == 1
2472 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2473 User.add_pinned_object_id(updated_user, object_id)
2475 assert pinned_at1 == pinned_at2
2477 assert Enum.count(pins) == 1
2480 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2481 clear_config([:instance, :max_pinned_statuses], 1)
2482 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2484 object_id2 = object_id_from_created_activity(user)
2486 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2487 assert Keyword.has_key?(errors, :pinned_objects)
2490 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2491 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2493 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2494 assert after_remove.pinned_objects == %{}
2498 defp object_id_from_created_activity(user) do
2499 %{id: id} = insert(:note_activity, user: user)
2500 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)