1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.UserTest do
7 alias Pleroma.Builders.UserBuilder
10 alias Pleroma.Tests.ObanHelpers
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.CommonAPI
16 use Oban.Testing, repo: Pleroma.Repo
18 import Pleroma.Factory
19 import ExUnit.CaptureLog
20 import Swoosh.TestAssertions
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
27 setup do: clear_config([:instance, :account_activation_required])
29 describe "service actors" do
30 test "returns updated invisible actor" do
31 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
32 followers_uri = "#{uri}/followers"
41 follower_address: followers_uri
45 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
46 assert actor.invisible
49 test "returns relay user" do
50 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
51 followers_uri = "#{uri}/followers"
58 follower_address: ^followers_uri
59 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
61 assert capture_log(fn ->
62 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
63 end) =~ "Cannot create service actor:"
66 test "returns invisible actor" do
67 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
68 followers_uri = "#{uri}/followers"
69 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
72 nickname: "internal.fetch-test",
76 follower_address: ^followers_uri
79 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
80 assert user.id == user2.id
84 describe "AP ID user relationships" do
86 {:ok, user: insert(:user)}
89 test "outgoing_relationships_ap_ids/1", %{user: user} do
90 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
98 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
100 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
101 {rel_type, Enum.sort(ap_ids)}
105 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
106 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
108 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
109 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
111 assert ap_ids_by_rel[:notification_mute] ==
112 Enum.sort(User.notification_muted_users_ap_ids(user))
114 assert ap_ids_by_rel[:notification_mute] ==
115 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
117 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
119 assert ap_ids_by_rel[:reblog_mute] ==
120 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
122 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
124 assert ap_ids_by_rel[:inverse_subscription] ==
125 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
127 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
129 assert ap_ids_by_rel ==
130 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
134 describe "when tags are nil" do
135 test "tagging a user" do
136 user = insert(:user, %{tags: nil})
137 user = User.tag(user, ["cool", "dude"])
139 assert "cool" in user.tags
140 assert "dude" in user.tags
143 test "untagging a user" do
144 user = insert(:user, %{tags: nil})
145 user = User.untag(user, ["cool", "dude"])
147 assert user.tags == []
151 test "ap_id returns the activity pub id for the user" do
152 user = UserBuilder.build()
154 expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
156 assert expected_ap_id == User.ap_id(user)
159 test "ap_followers returns the followers collection for the user" do
160 user = UserBuilder.build()
162 expected_followers_collection = "#{User.ap_id(user)}/followers"
164 assert expected_followers_collection == User.ap_followers(user)
167 test "ap_following returns the following collection for the user" do
168 user = UserBuilder.build()
170 expected_followers_collection = "#{User.ap_id(user)}/following"
172 assert expected_followers_collection == User.ap_following(user)
175 test "returns all pending follow requests" do
176 unlocked = insert(:user)
177 locked = insert(:user, is_locked: true)
178 follower = insert(:user)
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, is_locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
200 assert [^pending_follower] = User.get_follow_requests(locked)
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, is_locked: true)
205 pending_follower = insert(:user, %{is_active: false})
207 CommonAPI.follow(pending_follower, locked)
209 refute pending_follower.is_active
210 assert [] = User.get_follow_requests(locked)
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, is_locked: true)
215 follower = insert(:user)
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
224 test "follow_all follows mutliple users" do
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
236 {:ok, user, followed_zero} = User.follow(user, followed_zero)
238 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
240 assert User.following?(user, followed_one)
241 assert User.following?(user, followed_two)
242 assert User.following?(user, followed_zero)
243 refute User.following?(user, not_followed)
244 refute User.following?(user, blocked)
245 refute User.following?(user, reverse_blocked)
248 test "follow_all follows mutliple users without duplicating" do
250 followed_zero = insert(:user)
251 followed_one = insert(:user)
252 followed_two = insert(:user)
254 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
255 assert length(User.following(user)) == 3
257 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
258 assert length(User.following(user)) == 4
261 test "follow takes a user and another user" do
263 followed = insert(:user)
265 {:ok, user, followed} = User.follow(user, followed)
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
270 assert followed.follower_count == 1
271 assert user.following_count == 1
273 assert User.ap_followers(followed) in User.following(user)
276 test "can't follow a deactivated users" do
278 followed = insert(:user, %{is_active: false})
280 {:error, _} = User.follow(user, followed)
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
287 {:ok, _user_relationship} = User.block(blocker, blockee)
289 {:error, _} = User.follow(blockee, blocker)
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
296 {:ok, _user_relationship} = User.block(blocker, blocked)
298 {:error, _} = User.subscribe(blocked, blocker)
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, is_locked: true)
303 followed = insert(:user, is_locked: true)
305 {:ok, follower, followed} = User.maybe_direct_follow(follower, followed)
307 refute User.following?(follower, followed)
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
313 test "unfollow with syncronizes external user" do
314 clear_config([:instance, :external_user_synchronization], true)
319 follower_address: "http://localhost:4001/users/fuser1/followers",
320 following_address: "http://localhost:4001/users/fuser1/following",
321 ap_id: "http://localhost:4001/users/fuser1"
328 ap_id: "http://localhost:4001/users/fuser2",
329 follower_address: "http://localhost:4001/users/fuser2/followers",
330 following_address: "http://localhost:4001/users/fuser2/following"
333 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
335 {:ok, user, _activity} = User.unfollow(user, followed)
337 user = User.get_cached_by_id(user.id)
339 assert User.following(user) == []
342 test "unfollow takes a user and another user" do
343 followed = insert(:user)
346 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
348 assert User.following(user) == [user.follower_address, followed.follower_address]
350 {:ok, user, _activity} = User.unfollow(user, followed)
352 assert User.following(user) == [user.follower_address]
355 test "unfollow doesn't unfollow yourself" do
358 {:error, _} = User.unfollow(user, user)
360 assert User.following(user) == [user.follower_address]
364 test "test if a user is following another user" do
365 followed = insert(:user)
367 User.follow(user, followed, :follow_accept)
369 assert User.following?(user, followed)
370 refute User.following?(followed, user)
373 test "fetches correct profile for nickname beginning with number" do
374 # Use old-style integer ID to try to reproduce the problem
375 user = insert(:user, %{id: 1080})
376 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
377 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
380 describe "user registration" do
386 password_confirmation: "test",
387 email: "email@example.com"
390 setup do: clear_config([:instance, :autofollowed_nicknames])
391 setup do: clear_config([:instance, :autofollowing_nicknames])
392 setup do: clear_config([:welcome])
393 setup do: clear_config([:instance, :account_activation_required])
395 test "it autofollows accounts that are set for it" do
397 remote_user = insert(:user, %{local: false})
399 clear_config([:instance, :autofollowed_nicknames], [
404 cng = User.register_changeset(%User{}, @full_user_data)
406 {:ok, registered_user} = User.register(cng)
408 assert User.following?(registered_user, user)
409 refute User.following?(registered_user, remote_user)
412 test "it adds automatic followers for new registered accounts" do
413 user1 = insert(:user)
414 user2 = insert(:user)
416 clear_config([:instance, :autofollowing_nicknames], [
421 cng = User.register_changeset(%User{}, @full_user_data)
423 {:ok, registered_user} = User.register(cng)
425 assert User.following?(user1, registered_user)
426 assert User.following?(user2, registered_user)
429 test "it sends a welcome message if it is set" do
430 welcome_user = insert(:user)
431 clear_config([:welcome, :direct_message, :enabled], true)
432 clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
433 clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message")
435 cng = User.register_changeset(%User{}, @full_user_data)
436 {:ok, registered_user} = User.register(cng)
437 ObanHelpers.perform_all()
439 activity = Repo.one(Pleroma.Activity)
440 assert registered_user.ap_id in activity.recipients
441 assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message"
442 assert activity.actor == welcome_user.ap_id
445 test "it sends a welcome chat message if it is set" do
446 welcome_user = insert(:user)
447 clear_config([:welcome, :chat_message, :enabled], true)
448 clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
449 clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
451 cng = User.register_changeset(%User{}, @full_user_data)
452 {:ok, registered_user} = User.register(cng)
453 ObanHelpers.perform_all()
455 activity = Repo.one(Pleroma.Activity)
456 assert registered_user.ap_id in activity.recipients
457 assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
458 assert activity.actor == welcome_user.ap_id
462 clear_config(:mrf_simple,
465 federated_timeline_removal: [],
478 Pleroma.Web.ActivityPub.MRF.SimplePolicy
482 test "it sends a welcome chat message when Simple policy applied to local instance" do
483 clear_config([:mrf_simple, :media_nsfw], ["localhost"])
485 welcome_user = insert(:user)
486 clear_config([:welcome, :chat_message, :enabled], true)
487 clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
488 clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
490 cng = User.register_changeset(%User{}, @full_user_data)
491 {:ok, registered_user} = User.register(cng)
492 ObanHelpers.perform_all()
494 activity = Repo.one(Pleroma.Activity)
495 assert registered_user.ap_id in activity.recipients
496 assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
497 assert activity.actor == welcome_user.ap_id
500 test "it sends a welcome email message if it is set" do
501 welcome_user = insert(:user)
502 clear_config([:welcome, :email, :enabled], true)
503 clear_config([:welcome, :email, :sender], welcome_user.email)
506 [:welcome, :email, :subject],
507 "Hello, welcome to cool site: <%= instance_name %>"
510 instance_name = Pleroma.Config.get([:instance, :name])
512 cng = User.register_changeset(%User{}, @full_user_data)
513 {:ok, registered_user} = User.register(cng)
514 ObanHelpers.perform_all()
517 from: {instance_name, welcome_user.email},
518 to: {registered_user.name, registered_user.email},
519 subject: "Hello, welcome to cool site: #{instance_name}",
520 html_body: "Welcome to #{instance_name}"
524 test "it sends a confirm email" do
525 clear_config([:instance, :account_activation_required], true)
527 cng = User.register_changeset(%User{}, @full_user_data)
528 {:ok, registered_user} = User.register(cng)
529 ObanHelpers.perform_all()
531 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
532 # temporary hackney fix until hackney max_connections bug is fixed
533 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
534 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
535 |> assert_email_sent()
538 test "sends a pending approval email" do
539 clear_config([:instance, :account_approval_required], true)
542 User.register_changeset(%User{}, @full_user_data)
545 ObanHelpers.perform_all()
548 from: Pleroma.Config.Helpers.sender(),
549 to: {user.name, user.email},
550 subject: "Your account is awaiting approval"
554 test "it sends a registration confirmed email if no others will be sent" do
555 clear_config([:welcome, :email, :enabled], false)
556 clear_config([:instance, :account_activation_required], false)
557 clear_config([:instance, :account_approval_required], false)
560 User.register_changeset(%User{}, @full_user_data)
562 ObanHelpers.perform_all()
564 instance_name = Pleroma.Config.get([:instance, :name])
565 sender = Pleroma.Config.get([:instance, :notify_email])
568 from: {instance_name, sender},
569 to: {user.name, user.email},
570 subject: "Account registered on #{instance_name}"
574 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
575 clear_config([:instance, :account_activation_required], true)
579 |> Enum.each(fn key ->
580 params = Map.delete(@full_user_data, key)
581 changeset = User.register_changeset(%User{}, params)
583 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
587 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
588 clear_config([:instance, :account_activation_required], false)
592 |> Enum.each(fn key ->
593 params = Map.delete(@full_user_data, key)
594 changeset = User.register_changeset(%User{}, params)
596 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
600 test "it restricts certain nicknames" do
601 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
603 assert is_bitstring(restricted_name)
607 |> Map.put(:nickname, restricted_name)
609 changeset = User.register_changeset(%User{}, params)
611 refute changeset.valid?
614 test "it blocks blacklisted email domains" do
615 clear_config([User, :email_blacklist], ["trolling.world"])
618 params = Map.put(@full_user_data, :email, "troll@trolling.world")
619 changeset = User.register_changeset(%User{}, params)
620 refute changeset.valid?
622 # Block with subdomain match
623 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
624 changeset = User.register_changeset(%User{}, params)
625 refute changeset.valid?
627 # Pass with different domains that are similar
628 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
629 changeset = User.register_changeset(%User{}, params)
630 assert changeset.valid?
632 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
633 changeset = User.register_changeset(%User{}, params)
634 assert changeset.valid?
637 test "it sets the password_hash and ap_id" do
638 changeset = User.register_changeset(%User{}, @full_user_data)
640 assert changeset.valid?
642 assert is_binary(changeset.changes[:password_hash])
643 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
645 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
648 test "it sets the 'accepts_chat_messages' set to true" do
649 changeset = User.register_changeset(%User{}, @full_user_data)
650 assert changeset.valid?
652 {:ok, user} = Repo.insert(changeset)
654 assert user.accepts_chat_messages
657 test "it creates a confirmed user" do
658 changeset = User.register_changeset(%User{}, @full_user_data)
659 assert changeset.valid?
661 {:ok, user} = Repo.insert(changeset)
663 assert user.is_confirmed
667 describe "user registration, with :account_activation_required" do
673 password_confirmation: "test",
674 email: "email@example.com"
676 setup do: clear_config([:instance, :account_activation_required], true)
678 test "it creates unconfirmed user" do
679 changeset = User.register_changeset(%User{}, @full_user_data)
680 assert changeset.valid?
682 {:ok, user} = Repo.insert(changeset)
684 refute user.is_confirmed
685 assert user.confirmation_token
688 test "it creates confirmed user if :confirmed option is given" do
689 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
690 assert changeset.valid?
692 {:ok, user} = Repo.insert(changeset)
694 assert user.is_confirmed
695 refute user.confirmation_token
699 describe "user registration, with :account_approval_required" do
705 password_confirmation: "test",
706 email: "email@example.com",
707 registration_reason: "I'm a cool guy :)"
709 setup do: clear_config([:instance, :account_approval_required], true)
711 test "it creates unapproved user" do
712 changeset = User.register_changeset(%User{}, @full_user_data)
713 assert changeset.valid?
715 {:ok, user} = Repo.insert(changeset)
717 refute user.is_approved
718 assert user.registration_reason == "I'm a cool guy :)"
721 test "it restricts length of registration reason" do
722 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
724 assert is_integer(reason_limit)
729 :registration_reason,
730 "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."
733 changeset = User.register_changeset(%User{}, params)
735 refute changeset.valid?
739 describe "get_or_fetch/1" do
740 test "gets an existing user by nickname" do
742 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
744 assert user == fetched_user
747 test "gets an existing user by ap_id" do
748 ap_id = "http://mastodon.example.org/users/admin"
754 nickname: "admin@mastodon.example.org",
758 {:ok, fetched_user} = User.get_or_fetch(ap_id)
759 freshed_user = refresh_record(user)
760 assert freshed_user == fetched_user
764 describe "fetching a user from nickname or trying to build one" do
765 test "gets an existing user" do
767 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
769 assert user == fetched_user
772 test "gets an existing user, case insensitive" do
773 user = insert(:user, nickname: "nick")
774 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
776 assert user == fetched_user
779 test "gets an existing user by fully qualified nickname" do
782 {:ok, fetched_user} =
783 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
785 assert user == fetched_user
788 test "gets an existing user by fully qualified nickname, case insensitive" do
789 user = insert(:user, nickname: "nick")
790 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
792 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
794 assert user == fetched_user
797 @tag capture_log: true
798 test "returns nil if no user could be fetched" do
799 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
800 assert fetched_user == "not found nonexistant@social.heldscal.la"
803 test "returns nil for nonexistant local user" do
804 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
805 assert fetched_user == "not found nonexistant"
808 test "updates an existing user, if stale" do
809 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
815 nickname: "admin@mastodon.example.org",
816 ap_id: "http://mastodon.example.org/users/admin",
817 last_refreshed_at: a_week_ago
820 assert orig_user.last_refreshed_at == a_week_ago
822 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
826 refute user.last_refreshed_at == orig_user.last_refreshed_at
829 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
830 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
836 nickname: "admin@mastodon.example.org",
837 ap_id: "http://mastodon.example.org/users/harinezumigari",
838 last_refreshed_at: a_week_ago
841 assert orig_user.last_refreshed_at == a_week_ago
843 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
847 refute user.id == orig_user.id
849 orig_user = User.get_by_id(orig_user.id)
851 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
854 @tag capture_log: true
855 test "it returns the old user if stale, but unfetchable" do
856 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
862 nickname: "admin@mastodon.example.org",
863 ap_id: "http://mastodon.example.org/users/raymoo",
864 last_refreshed_at: a_week_ago
867 assert orig_user.last_refreshed_at == a_week_ago
869 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
871 assert user.last_refreshed_at == orig_user.last_refreshed_at
875 test "returns an ap_id for a user" do
878 assert User.ap_id(user) ==
879 Pleroma.Web.Router.Helpers.user_feed_url(
880 Pleroma.Web.Endpoint,
886 test "returns an ap_followers link for a user" do
889 assert User.ap_followers(user) ==
890 Pleroma.Web.Router.Helpers.user_feed_url(
891 Pleroma.Web.Endpoint,
897 describe "remote user changeset" do
903 avatar: %{some: "avatar"}
905 setup do: clear_config([:instance, :user_bio_length])
906 setup do: clear_config([:instance, :user_name_length])
908 test "it confirms validity" do
909 cs = User.remote_user_changeset(@valid_remote)
913 test "it sets the follower_adress" do
914 cs = User.remote_user_changeset(@valid_remote)
915 # remote users get a fake local follower address
916 assert cs.changes.follower_address ==
917 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
920 test "it enforces the fqn format for nicknames" do
921 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
922 assert Ecto.Changeset.get_field(cs, :local) == false
923 assert cs.changes.avatar
927 test "it has required fields" do
929 |> Enum.each(fn field ->
930 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
935 test "it is invalid given a local user" do
937 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
943 describe "followers and friends" do
944 test "gets all followers for a given user" do
946 follower_one = insert(:user)
947 follower_two = insert(:user)
948 not_follower = insert(:user)
950 {:ok, follower_one, user} = User.follow(follower_one, user)
951 {:ok, follower_two, user} = User.follow(follower_two, user)
953 res = User.get_followers(user)
955 assert Enum.member?(res, follower_one)
956 assert Enum.member?(res, follower_two)
957 refute Enum.member?(res, not_follower)
960 test "gets all friends (followed users) for a given user" do
962 followed_one = insert(:user)
963 followed_two = insert(:user)
964 not_followed = insert(:user)
966 {:ok, user, followed_one} = User.follow(user, followed_one)
967 {:ok, user, followed_two} = User.follow(user, followed_two)
969 res = User.get_friends(user)
971 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
972 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
973 assert Enum.member?(res, followed_one)
974 assert Enum.member?(res, followed_two)
975 refute Enum.member?(res, not_followed)
979 describe "updating note and follower count" do
980 test "it sets the note_count property" do
983 user = User.get_cached_by_ap_id(note.data["actor"])
985 assert user.note_count == 0
987 {:ok, user} = User.update_note_count(user)
989 assert user.note_count == 1
992 test "it increases the note_count property" do
994 user = User.get_cached_by_ap_id(note.data["actor"])
996 assert user.note_count == 0
998 {:ok, user} = User.increase_note_count(user)
1000 assert user.note_count == 1
1002 {:ok, user} = User.increase_note_count(user)
1004 assert user.note_count == 2
1007 test "it decreases the note_count property" do
1008 note = insert(:note)
1009 user = User.get_cached_by_ap_id(note.data["actor"])
1011 assert user.note_count == 0
1013 {:ok, user} = User.increase_note_count(user)
1015 assert user.note_count == 1
1017 {:ok, user} = User.decrease_note_count(user)
1019 assert user.note_count == 0
1021 {:ok, user} = User.decrease_note_count(user)
1023 assert user.note_count == 0
1026 test "it sets the follower_count property" do
1027 user = insert(:user)
1028 follower = insert(:user)
1030 User.follow(follower, user)
1032 assert user.follower_count == 0
1034 {:ok, user} = User.update_follower_count(user)
1036 assert user.follower_count == 1
1041 test "it mutes people" do
1042 user = insert(:user)
1043 muted_user = insert(:user)
1045 refute User.mutes?(user, muted_user)
1046 refute User.muted_notifications?(user, muted_user)
1048 {:ok, _user_relationships} = User.mute(user, muted_user)
1050 assert User.mutes?(user, muted_user)
1051 assert User.muted_notifications?(user, muted_user)
1055 user = insert(:user)
1056 muted_user = insert(:user)
1058 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1059 assert User.mutes?(user, muted_user)
1061 worker = Pleroma.Workers.MuteExpireWorker
1062 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1069 assert :ok = perform_job(worker, args)
1071 refute User.mutes?(user, muted_user)
1072 refute User.muted_notifications?(user, muted_user)
1075 test "it unmutes users" do
1076 user = insert(:user)
1077 muted_user = insert(:user)
1079 {:ok, _user_relationships} = User.mute(user, muted_user)
1080 {:ok, _user_mute} = User.unmute(user, muted_user)
1082 refute User.mutes?(user, muted_user)
1083 refute User.muted_notifications?(user, muted_user)
1086 test "it unmutes users by id" do
1087 user = insert(:user)
1088 muted_user = insert(:user)
1090 {:ok, _user_relationships} = User.mute(user, muted_user)
1091 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1093 refute User.mutes?(user, muted_user)
1094 refute User.muted_notifications?(user, muted_user)
1097 test "it mutes user without notifications" do
1098 user = insert(:user)
1099 muted_user = insert(:user)
1101 refute User.mutes?(user, muted_user)
1102 refute User.muted_notifications?(user, muted_user)
1104 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1106 assert User.mutes?(user, muted_user)
1107 refute User.muted_notifications?(user, muted_user)
1111 describe "blocks" do
1112 test "it blocks people" do
1113 user = insert(:user)
1114 blocked_user = insert(:user)
1116 refute User.blocks?(user, blocked_user)
1118 {:ok, _user_relationship} = User.block(user, blocked_user)
1120 assert User.blocks?(user, blocked_user)
1123 test "it unblocks users" do
1124 user = insert(:user)
1125 blocked_user = insert(:user)
1127 {:ok, _user_relationship} = User.block(user, blocked_user)
1128 {:ok, _user_block} = User.unblock(user, blocked_user)
1130 refute User.blocks?(user, blocked_user)
1133 test "blocks tear down cyclical follow relationships" do
1134 blocker = insert(:user)
1135 blocked = insert(:user)
1137 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1138 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1140 assert User.following?(blocker, blocked)
1141 assert User.following?(blocked, blocker)
1143 {:ok, _user_relationship} = User.block(blocker, blocked)
1144 blocked = User.get_cached_by_id(blocked.id)
1146 assert User.blocks?(blocker, blocked)
1148 refute User.following?(blocker, blocked)
1149 refute User.following?(blocked, blocker)
1152 test "blocks tear down blocker->blocked follow relationships" do
1153 blocker = insert(:user)
1154 blocked = insert(:user)
1156 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1158 assert User.following?(blocker, blocked)
1159 refute User.following?(blocked, blocker)
1161 {:ok, _user_relationship} = User.block(blocker, blocked)
1162 blocked = User.get_cached_by_id(blocked.id)
1164 assert User.blocks?(blocker, blocked)
1166 refute User.following?(blocker, blocked)
1167 refute User.following?(blocked, blocker)
1170 test "blocks tear down blocked->blocker follow relationships" do
1171 blocker = insert(:user)
1172 blocked = insert(:user)
1174 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1176 refute User.following?(blocker, blocked)
1177 assert User.following?(blocked, blocker)
1179 {:ok, _user_relationship} = User.block(blocker, blocked)
1180 blocked = User.get_cached_by_id(blocked.id)
1182 assert User.blocks?(blocker, blocked)
1184 refute User.following?(blocker, blocked)
1185 refute User.following?(blocked, blocker)
1188 test "blocks tear down blocked->blocker subscription relationships" do
1189 blocker = insert(:user)
1190 blocked = insert(:user)
1192 {:ok, _subscription} = User.subscribe(blocked, blocker)
1194 assert User.subscribed_to?(blocked, blocker)
1195 refute User.subscribed_to?(blocker, blocked)
1197 {:ok, _user_relationship} = User.block(blocker, blocked)
1199 assert User.blocks?(blocker, blocked)
1200 refute User.subscribed_to?(blocker, blocked)
1201 refute User.subscribed_to?(blocked, blocker)
1205 describe "domain blocking" do
1206 test "blocks domains" do
1207 user = insert(:user)
1208 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1210 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1212 assert User.blocks?(user, collateral_user)
1215 test "does not block domain with same end" do
1216 user = insert(:user)
1219 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1221 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1223 refute User.blocks?(user, collateral_user)
1226 test "does not block domain with same end if wildcard added" do
1227 user = insert(:user)
1230 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1232 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1234 refute User.blocks?(user, collateral_user)
1237 test "blocks domain with wildcard for subdomain" do
1238 user = insert(:user)
1240 user_from_subdomain =
1241 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1243 user_with_two_subdomains =
1245 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1248 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1250 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1252 assert User.blocks?(user, user_from_subdomain)
1253 assert User.blocks?(user, user_with_two_subdomains)
1254 assert User.blocks?(user, user_domain)
1257 test "unblocks domains" do
1258 user = insert(:user)
1259 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1261 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1262 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1264 refute User.blocks?(user, collateral_user)
1267 test "follows take precedence over domain blocks" do
1268 user = insert(:user)
1269 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1271 {:ok, user} = User.block_domain(user, "meanies.social")
1272 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1274 refute User.blocks?(user, good_eggo)
1278 describe "get_recipients_from_activity" do
1279 test "works for announces" do
1280 actor = insert(:user)
1281 user = insert(:user, local: true)
1283 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1284 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1286 recipients = User.get_recipients_from_activity(announce)
1288 assert user in recipients
1291 test "get recipients" do
1292 actor = insert(:user)
1293 user = insert(:user, local: true)
1294 user_two = insert(:user, local: false)
1295 addressed = insert(:user, local: true)
1296 addressed_remote = insert(:user, local: false)
1299 CommonAPI.post(actor, %{
1300 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1303 assert Enum.map([actor, addressed], & &1.ap_id) --
1304 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1306 {:ok, user, actor} = User.follow(user, actor)
1307 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1308 recipients = User.get_recipients_from_activity(activity)
1309 assert length(recipients) == 3
1310 assert user in recipients
1311 assert addressed in recipients
1314 test "has following" do
1315 actor = insert(:user)
1316 user = insert(:user)
1317 user_two = insert(:user)
1318 addressed = insert(:user, local: true)
1321 CommonAPI.post(actor, %{
1322 status: "hey @#{addressed.nickname}"
1325 assert Enum.map([actor, addressed], & &1.ap_id) --
1326 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1328 {:ok, _actor, _user} = User.follow(actor, user)
1329 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1330 recipients = User.get_recipients_from_activity(activity)
1331 assert length(recipients) == 2
1332 assert addressed in recipients
1336 describe ".set_activation" do
1337 test "can de-activate then re-activate a user" do
1338 user = insert(:user)
1339 assert user.is_active
1340 {:ok, user} = User.set_activation(user, false)
1341 refute user.is_active
1342 {:ok, user} = User.set_activation(user, true)
1343 assert user.is_active
1346 test "hide a user from followers" do
1347 user = insert(:user)
1348 user2 = insert(:user)
1350 {:ok, user, user2} = User.follow(user, user2)
1351 {:ok, _user} = User.set_activation(user, false)
1353 user2 = User.get_cached_by_id(user2.id)
1355 assert user2.follower_count == 0
1356 assert [] = User.get_followers(user2)
1359 test "hide a user from friends" do
1360 user = insert(:user)
1361 user2 = insert(:user)
1363 {:ok, user2, user} = User.follow(user2, user)
1364 assert user2.following_count == 1
1365 assert User.following_count(user2) == 1
1367 {:ok, _user} = User.set_activation(user, false)
1369 user2 = User.get_cached_by_id(user2.id)
1371 assert refresh_record(user2).following_count == 0
1372 assert user2.following_count == 0
1373 assert User.following_count(user2) == 0
1374 assert [] = User.get_friends(user2)
1377 test "hide a user's statuses from timelines and notifications" do
1378 user = insert(:user)
1379 user2 = insert(:user)
1381 {:ok, user2, user} = User.follow(user2, user)
1383 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1385 activity = Repo.preload(activity, :bookmark)
1387 [notification] = Pleroma.Notification.for_user(user2)
1388 assert notification.activity.id == activity.id
1390 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1392 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1393 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1397 {:ok, _user} = User.set_activation(user, false)
1399 assert [] == ActivityPub.fetch_public_activities(%{})
1400 assert [] == Pleroma.Notification.for_user(user2)
1403 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1409 describe "approve" do
1410 test "approves a user" do
1411 user = insert(:user, is_approved: false)
1412 refute user.is_approved
1413 {:ok, user} = User.approve(user)
1414 assert user.is_approved
1417 test "approves a list of users" do
1418 unapproved_users = [
1419 insert(:user, is_approved: false),
1420 insert(:user, is_approved: false),
1421 insert(:user, is_approved: false)
1424 {:ok, users} = User.approve(unapproved_users)
1426 assert Enum.count(users) == 3
1428 Enum.each(users, fn user ->
1429 assert user.is_approved
1433 test "it sends welcome email if it is set" do
1434 clear_config([:welcome, :email, :enabled], true)
1435 clear_config([:welcome, :email, :sender], "tester@test.me")
1437 user = insert(:user, is_approved: false)
1438 welcome_user = insert(:user, email: "tester@test.me")
1439 instance_name = Pleroma.Config.get([:instance, :name])
1443 ObanHelpers.perform_all()
1446 from: {instance_name, welcome_user.email},
1447 to: {user.name, user.email},
1448 html_body: "Welcome to #{instance_name}"
1452 test "approving an approved user does not trigger post-register actions" do
1453 clear_config([:welcome, :email, :enabled], true)
1455 user = insert(:user, is_approved: true)
1458 ObanHelpers.perform_all()
1460 assert_no_email_sent()
1464 describe "confirm" do
1465 test "confirms a user" do
1466 user = insert(:user, is_confirmed: false)
1467 refute user.is_confirmed
1468 {:ok, user} = User.confirm(user)
1469 assert user.is_confirmed
1472 test "confirms a list of users" do
1473 unconfirmed_users = [
1474 insert(:user, is_confirmed: false),
1475 insert(:user, is_confirmed: false),
1476 insert(:user, is_confirmed: false)
1479 {:ok, users} = User.confirm(unconfirmed_users)
1481 assert Enum.count(users) == 3
1483 Enum.each(users, fn user ->
1484 assert user.is_confirmed
1488 test "sends approval emails when `is_approved: false`" do
1489 admin = insert(:user, is_admin: true)
1490 user = insert(:user, is_confirmed: false, is_approved: false)
1493 ObanHelpers.perform_all()
1495 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1496 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1498 notify_email = Pleroma.Config.get([:instance, :notify_email])
1499 instance_name = Pleroma.Config.get([:instance, :name])
1501 # User approval email
1503 from: {instance_name, notify_email},
1504 to: {user.name, user.email},
1505 html_body: user_email.html_body
1510 from: {instance_name, notify_email},
1511 to: {admin.name, admin.email},
1512 html_body: admin_email.html_body
1516 test "confirming a confirmed user does not trigger post-register actions" do
1517 user = insert(:user, is_confirmed: true, is_approved: false)
1520 ObanHelpers.perform_all()
1522 assert_no_email_sent()
1526 describe "delete" do
1528 {:ok, user} = insert(:user) |> User.set_cache()
1533 setup do: clear_config([:instance, :federating])
1535 test ".delete_user_activities deletes all create activities", %{user: user} do
1536 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1538 User.delete_user_activities(user)
1540 # TODO: Test removal favorites, repeats, delete activities.
1541 refute Activity.get_by_id(activity.id)
1544 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1545 follower = insert(:user)
1546 {:ok, follower, user} = User.follow(follower, user)
1548 locked_user = insert(:user, name: "locked", is_locked: true)
1549 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1551 object = insert(:note, user: user)
1552 activity = insert(:note_activity, user: user, note: object)
1554 object_two = insert(:note, user: follower)
1555 activity_two = insert(:note_activity, user: follower, note: object_two)
1557 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1558 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1559 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1561 {:ok, job} = User.delete(user)
1562 {:ok, _user} = ObanHelpers.perform(job)
1564 follower = User.get_cached_by_id(follower.id)
1566 refute User.following?(follower, user)
1567 assert %{is_active: false} = User.get_by_id(user.id)
1569 assert [] == User.get_follow_requests(locked_user)
1573 |> Activity.Queries.by_actor()
1575 |> Enum.map(fn act -> act.data["type"] end)
1577 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1579 refute Activity.get_by_id(activity.id)
1580 refute Activity.get_by_id(like.id)
1581 refute Activity.get_by_id(like_two.id)
1582 refute Activity.get_by_id(repeat.id)
1586 test "delete/1 when confirmation is pending deletes the user" do
1587 clear_config([:instance, :account_activation_required], true)
1588 user = insert(:user, is_confirmed: false)
1590 {:ok, job} = User.delete(user)
1591 {:ok, _} = ObanHelpers.perform(job)
1593 refute User.get_cached_by_id(user.id)
1594 refute User.get_by_id(user.id)
1597 test "delete/1 when approval is pending deletes the user" do
1598 user = insert(:user, is_approved: false)
1600 {:ok, job} = User.delete(user)
1601 {:ok, _} = ObanHelpers.perform(job)
1603 refute User.get_cached_by_id(user.id)
1604 refute User.get_by_id(user.id)
1607 test "delete/1 purges a user when they wouldn't be fully deleted" do
1612 password_hash: "pdfk2$1b3n159001",
1613 keys: "RSA begin buplic key",
1614 public_key: "--PRIVATE KEYE--",
1615 avatar: %{"a" => "b"},
1617 banner: %{"a" => "b"},
1618 background: %{"a" => "b"},
1621 following_count: 9001,
1623 is_confirmed: false,
1624 password_reset_pending: true,
1626 registration_reason: "ahhhhh",
1627 confirmation_token: "qqqq",
1628 domain_blocks: ["lain.com"],
1633 mastofe_settings: %{"a" => "b"},
1634 mascot: %{"a" => "b"},
1635 emoji: %{"a" => "b"},
1636 pleroma_settings_store: %{"q" => "x"},
1637 fields: [%{"gg" => "qq"}],
1638 raw_fields: [%{"gg" => "qq"}],
1639 is_discoverable: true,
1640 also_known_as: ["https://lol.olo/users/loll"]
1643 {:ok, job} = User.delete(user)
1644 {:ok, _} = ObanHelpers.perform(job)
1645 user = User.get_by_id(user.id)
1657 last_refreshed_at: nil,
1658 last_digest_emailed_at: nil,
1666 password_reset_pending: false,
1668 registration_reason: nil,
1669 confirmation_token: nil,
1673 is_moderator: false,
1675 mastofe_settings: nil,
1678 pleroma_settings_store: %{},
1681 is_discoverable: false,
1686 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1687 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1690 describe "per-user rich-text filtering" do
1691 test "html_filter_policy returns default policies, when rich-text is enabled" do
1692 user = insert(:user)
1694 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1697 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1698 user = insert(:user, no_rich_text: true)
1700 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1704 describe "caching" do
1705 test "invalidate_cache works" do
1706 user = insert(:user)
1708 User.set_cache(user)
1709 User.invalidate_cache(user)
1711 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1712 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1715 test "User.delete() plugs any possible zombie objects" do
1716 user = insert(:user)
1718 {:ok, job} = User.delete(user)
1719 {:ok, _} = ObanHelpers.perform(job)
1721 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1723 assert cached_user != user
1725 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1727 assert cached_user != user
1731 describe "account_status/1" do
1732 setup do: clear_config([:instance, :account_activation_required])
1734 test "return confirmation_pending for unconfirm user" do
1735 clear_config([:instance, :account_activation_required], true)
1736 user = insert(:user, is_confirmed: false)
1737 assert User.account_status(user) == :confirmation_pending
1740 test "return active for confirmed user" do
1741 clear_config([:instance, :account_activation_required], true)
1742 user = insert(:user, is_confirmed: true)
1743 assert User.account_status(user) == :active
1746 test "return active for remote user" do
1747 user = insert(:user, local: false)
1748 assert User.account_status(user) == :active
1751 test "returns :password_reset_pending for user with reset password" do
1752 user = insert(:user, password_reset_pending: true)
1753 assert User.account_status(user) == :password_reset_pending
1756 test "returns :deactivated for deactivated user" do
1757 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1758 assert User.account_status(user) == :deactivated
1761 test "returns :approval_pending for unapproved user" do
1762 user = insert(:user, local: true, is_approved: false)
1763 assert User.account_status(user) == :approval_pending
1765 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1766 assert User.account_status(user) == :approval_pending
1770 describe "superuser?/1" do
1771 test "returns false for unprivileged users" do
1772 user = insert(:user, local: true)
1774 refute User.superuser?(user)
1777 test "returns false for remote users" do
1778 user = insert(:user, local: false)
1779 remote_admin_user = insert(:user, local: false, is_admin: true)
1781 refute User.superuser?(user)
1782 refute User.superuser?(remote_admin_user)
1785 test "returns true for local moderators" do
1786 user = insert(:user, local: true, is_moderator: true)
1788 assert User.superuser?(user)
1791 test "returns true for local admins" do
1792 user = insert(:user, local: true, is_admin: true)
1794 assert User.superuser?(user)
1798 describe "invisible?/1" do
1799 test "returns true for an invisible user" do
1800 user = insert(:user, local: true, invisible: true)
1802 assert User.invisible?(user)
1805 test "returns false for a non-invisible user" do
1806 user = insert(:user, local: true)
1808 refute User.invisible?(user)
1812 describe "visible_for/2" do
1813 test "returns true when the account is itself" do
1814 user = insert(:user, local: true)
1816 assert User.visible_for(user, user) == :visible
1819 test "returns false when the account is unconfirmed and confirmation is required" do
1820 clear_config([:instance, :account_activation_required], true)
1822 user = insert(:user, local: true, is_confirmed: false)
1823 other_user = insert(:user, local: true)
1825 refute User.visible_for(user, other_user) == :visible
1828 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1829 clear_config([:instance, :account_activation_required], true)
1831 user = insert(:user, local: false, is_confirmed: false)
1832 other_user = insert(:user, local: true)
1834 assert User.visible_for(user, other_user) == :visible
1837 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1838 clear_config([:instance, :account_activation_required], true)
1840 user = insert(:user, local: true, is_confirmed: false)
1841 other_user = insert(:user, local: true, is_admin: true)
1843 assert User.visible_for(user, other_user) == :visible
1847 describe "parse_bio/2" do
1848 test "preserves hosts in user links text" do
1849 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1850 user = insert(:user)
1851 bio = "A.k.a. @nick@domain.com"
1854 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1856 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1858 assert expected_text == User.parse_bio(bio, user)
1861 test "Adds rel=me on linkbacked urls" do
1862 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1864 bio = "http://example.com/rel_me/null"
1865 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1866 assert expected_text == User.parse_bio(bio, user)
1868 bio = "http://example.com/rel_me/link"
1869 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1870 assert expected_text == User.parse_bio(bio, user)
1872 bio = "http://example.com/rel_me/anchor"
1873 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1874 assert expected_text == User.parse_bio(bio, user)
1878 test "follower count is updated when a follower is blocked" do
1879 user = insert(:user)
1880 follower = insert(:user)
1881 follower2 = insert(:user)
1882 follower3 = insert(:user)
1884 {:ok, follower, user} = User.follow(follower, user)
1885 {:ok, _follower2, _user} = User.follow(follower2, user)
1886 {:ok, _follower3, _user} = User.follow(follower3, user)
1888 {:ok, _user_relationship} = User.block(user, follower)
1889 user = refresh_record(user)
1891 assert user.follower_count == 2
1894 describe "list_inactive_users_query/1" do
1895 defp days_ago(days) do
1897 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1898 -days * 60 * 60 * 24,
1903 test "Users are inactive by default" do
1907 Enum.map(1..total, fn _ ->
1908 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1911 inactive_users_ids =
1912 Pleroma.User.list_inactive_users_query()
1913 |> Pleroma.Repo.all()
1914 |> Enum.map(& &1.id)
1916 Enum.each(users, fn user ->
1917 assert user.id in inactive_users_ids
1921 test "Only includes users who has no recent activity" do
1925 Enum.map(1..total, fn _ ->
1926 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1929 {inactive, active} = Enum.split(users, trunc(total / 2))
1931 Enum.map(active, fn user ->
1932 to = Enum.random(users -- [user])
1935 CommonAPI.post(user, %{
1936 status: "hey @#{to.nickname}"
1940 inactive_users_ids =
1941 Pleroma.User.list_inactive_users_query()
1942 |> Pleroma.Repo.all()
1943 |> Enum.map(& &1.id)
1945 Enum.each(active, fn user ->
1946 refute user.id in inactive_users_ids
1949 Enum.each(inactive, fn user ->
1950 assert user.id in inactive_users_ids
1954 test "Only includes users with no read notifications" do
1958 Enum.map(1..total, fn _ ->
1959 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
1962 [sender | recipients] = users
1963 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1965 Enum.each(recipients, fn to ->
1967 CommonAPI.post(sender, %{
1968 status: "hey @#{to.nickname}"
1972 CommonAPI.post(sender, %{
1973 status: "hey again @#{to.nickname}"
1977 Enum.each(active, fn user ->
1978 [n1, _n2] = Pleroma.Notification.for_user(user)
1979 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1982 inactive_users_ids =
1983 Pleroma.User.list_inactive_users_query()
1984 |> Pleroma.Repo.all()
1985 |> Enum.map(& &1.id)
1987 Enum.each(active, fn user ->
1988 refute user.id in inactive_users_ids
1991 Enum.each(inactive, fn user ->
1992 assert user.id in inactive_users_ids
1997 describe "ensure_keys_present" do
1998 test "it creates keys for a user and stores them in info" do
1999 user = insert(:user)
2000 refute is_binary(user.keys)
2001 {:ok, user} = User.ensure_keys_present(user)
2002 assert is_binary(user.keys)
2005 test "it doesn't create keys if there already are some" do
2006 user = insert(:user, keys: "xxx")
2007 {:ok, user} = User.ensure_keys_present(user)
2008 assert user.keys == "xxx"
2012 describe "get_ap_ids_by_nicknames" do
2013 test "it returns a list of AP ids for a given set of nicknames" do
2014 user = insert(:user)
2015 user_two = insert(:user)
2017 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2018 assert length(ap_ids) == 2
2019 assert user.ap_id in ap_ids
2020 assert user_two.ap_id in ap_ids
2024 describe "sync followers count" do
2026 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2027 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2028 insert(:user, local: true)
2029 insert(:user, local: false, is_active: false)
2030 {:ok, user1: user1, user2: user2}
2033 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2034 [fdb_user1] = User.external_users(limit: 1)
2036 assert fdb_user1.ap_id
2037 assert fdb_user1.ap_id == user1.ap_id
2038 assert fdb_user1.id == user1.id
2040 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2042 assert fdb_user2.ap_id
2043 assert fdb_user2.ap_id == user2.ap_id
2044 assert fdb_user2.id == user2.id
2046 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2050 describe "is_internal_user?/1" do
2051 test "non-internal user returns false" do
2052 user = insert(:user)
2053 refute User.is_internal_user?(user)
2056 test "user with no nickname returns true" do
2057 user = insert(:user, %{nickname: nil})
2058 assert User.is_internal_user?(user)
2061 test "user with internal-prefixed nickname returns true" do
2062 user = insert(:user, %{nickname: "internal.test"})
2063 assert User.is_internal_user?(user)
2067 describe "update_and_set_cache/1" do
2068 test "returns error when user is stale instead Ecto.StaleEntryError" do
2069 user = insert(:user)
2071 changeset = Ecto.Changeset.change(user, bio: "test")
2075 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2076 User.update_and_set_cache(changeset)
2079 test "performs update cache if user updated" do
2080 user = insert(:user)
2081 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2083 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2085 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2086 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2087 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2091 describe "following/followers synchronization" do
2092 setup do: clear_config([:instance, :external_user_synchronization])
2094 test "updates the counters normally on following/getting a follow when disabled" do
2095 clear_config([:instance, :external_user_synchronization], false)
2096 user = insert(:user)
2101 follower_address: "http://localhost:4001/users/masto_closed/followers",
2102 following_address: "http://localhost:4001/users/masto_closed/following",
2106 assert other_user.following_count == 0
2107 assert other_user.follower_count == 0
2109 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2111 assert user.following_count == 1
2112 assert other_user.follower_count == 1
2115 test "syncronizes the counters with the remote instance for the followed when enabled" do
2116 clear_config([:instance, :external_user_synchronization], false)
2118 user = insert(:user)
2123 follower_address: "http://localhost:4001/users/masto_closed/followers",
2124 following_address: "http://localhost:4001/users/masto_closed/following",
2128 assert other_user.following_count == 0
2129 assert other_user.follower_count == 0
2131 clear_config([:instance, :external_user_synchronization], true)
2132 {:ok, _user, other_user} = User.follow(user, other_user)
2134 assert other_user.follower_count == 437
2137 test "syncronizes the counters with the remote instance for the follower when enabled" do
2138 clear_config([:instance, :external_user_synchronization], false)
2140 user = insert(:user)
2145 follower_address: "http://localhost:4001/users/masto_closed/followers",
2146 following_address: "http://localhost:4001/users/masto_closed/following",
2150 assert other_user.following_count == 0
2151 assert other_user.follower_count == 0
2153 clear_config([:instance, :external_user_synchronization], true)
2154 {:ok, other_user, _user} = User.follow(other_user, user)
2156 assert other_user.following_count == 152
2160 describe "change_email/2" do
2162 [user: insert(:user)]
2165 test "blank email returns error", %{user: user} do
2166 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2167 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2170 test "non unique email returns error", %{user: user} do
2171 %{email: email} = insert(:user)
2173 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2174 User.change_email(user, email)
2177 test "invalid email returns error", %{user: user} do
2178 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2179 User.change_email(user, "cofe")
2182 test "changes email", %{user: user} do
2183 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2187 describe "get_cached_by_nickname_or_id" do
2189 local_user = insert(:user)
2190 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2192 [local_user: local_user, remote_user: remote_user]
2195 setup do: clear_config([:instance, :limit_to_local_content])
2197 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2198 remote_user: remote_user
2200 clear_config([:instance, :limit_to_local_content], false)
2201 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2203 clear_config([:instance, :limit_to_local_content], true)
2204 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2206 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2207 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2210 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2211 %{remote_user: remote_user} do
2212 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2213 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2216 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2217 %{remote_user: remote_user, local_user: local_user} do
2218 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2219 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2222 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2223 %{remote_user: remote_user} do
2224 clear_config([:instance, :limit_to_local_content], true)
2225 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2228 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2229 %{local_user: local_user} do
2230 clear_config([:instance, :limit_to_local_content], false)
2231 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2233 clear_config([:instance, :limit_to_local_content], true)
2234 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2236 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2237 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2241 describe "update_email_notifications/2" do
2243 user = insert(:user, email_notifications: %{"digest" => true})
2248 test "Notifications are updated", %{user: user} do
2249 true = user.email_notifications["digest"]
2250 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2251 assert result.email_notifications["digest"] == false
2255 describe "local_nickname/1" do
2256 test "returns nickname without host" do
2257 assert User.local_nickname("@mentioned") == "mentioned"
2258 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2259 assert User.local_nickname("nickname@host.com") == "nickname"
2263 describe "full_nickname/1" do
2264 test "returns fully qualified nickname for local and remote users" do
2266 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2268 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2270 assert User.full_nickname(local_user) == "local_user@somehost.com"
2271 assert User.full_nickname(remote_user) == "remote@host.com"
2274 test "strips leading @ from mentions" do
2275 assert User.full_nickname("@mentioned") == "mentioned"
2276 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2279 test "does not modify nicknames" do
2280 assert User.full_nickname("nickname") == "nickname"
2281 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2285 test "avatar fallback" do
2286 user = insert(:user)
2287 assert User.avatar_url(user) =~ "/images/avi.png"
2289 clear_config([:assets, :default_user_avatar], "avatar.png")
2291 user = User.get_cached_by_nickname_or_id(user.nickname)
2292 assert User.avatar_url(user) =~ "avatar.png"
2294 assert User.avatar_url(user, no_default: true) == nil
2297 test "get_host/1" do
2298 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2299 assert User.get_host(user) == "lain.com"
2302 test "update_last_active_at/1" do
2303 user = insert(:user)
2304 assert is_nil(user.last_active_at)
2306 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2308 assert {:ok, user} = User.update_last_active_at(user)
2310 assert user.last_active_at >= test_started_at
2311 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2314 NaiveDateTime.utc_now()
2315 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2316 |> NaiveDateTime.truncate(:second)
2318 assert {:ok, user} =
2320 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2321 |> User.update_and_set_cache()
2323 assert user.last_active_at == last_active_at
2324 assert {:ok, user} = User.update_last_active_at(user)
2325 assert user.last_active_at >= test_started_at
2326 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2329 test "active_user_count/1" do
2331 insert(:user, %{local: false})
2332 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -5)})
2333 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -3)})
2334 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2336 assert User.active_user_count() == 2
2337 assert User.active_user_count(6) == 3
2338 assert User.active_user_count(1) == 1