1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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, 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, 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, locked: true)
205 pending_follower = insert(:user, %{deactivated: true})
207 CommonAPI.follow(pending_follower, locked)
209 assert true == pending_follower.deactivated
210 assert [] = User.get_follow_requests(locked)
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, 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} = 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} = User.follow(user, followed)
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
270 assert followed.follower_count == 1
271 assert user.following_count == 1
273 assert User.ap_followers(followed) in User.following(user)
276 test "can't follow a deactivated users" do
278 followed = insert(:user, %{deactivated: true})
280 {:error, _} = User.follow(user, followed)
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
287 {:ok, _user_relationship} = User.block(blocker, blockee)
289 {:error, _} = User.follow(blockee, blocker)
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
296 {:ok, _user_relationship} = User.block(blocker, blocked)
298 {:error, _} = User.subscribe(blocked, blocker)
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, locked: true)
303 followed = insert(:user, locked: true)
305 {:ok, follower} = User.maybe_direct_follow(follower, followed)
307 refute User.following?(follower, followed)
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
313 test "unfollow with syncronizes external user" do
314 Pleroma.Config.put([:instance, :external_user_synchronization], true)
319 follower_address: "http://localhost:4001/users/fuser1/followers",
320 following_address: "http://localhost:4001/users/fuser1/following",
321 ap_id: "http://localhost:4001/users/fuser1"
328 ap_id: "http://localhost:4001/users/fuser2",
329 follower_address: "http://localhost:4001/users/fuser2/followers",
330 following_address: "http://localhost:4001/users/fuser2/following"
333 {:ok, user} = 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} = 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([:welcome])
392 setup do: clear_config([:instance, :account_activation_required])
394 test "it autofollows accounts that are set for it" do
396 remote_user = insert(:user, %{local: false})
398 Pleroma.Config.put([:instance, :autofollowed_nicknames], [
403 cng = User.register_changeset(%User{}, @full_user_data)
405 {:ok, registered_user} = User.register(cng)
407 assert User.following?(registered_user, user)
408 refute User.following?(registered_user, remote_user)
411 test "it sends a welcome message if it is set" do
412 welcome_user = insert(:user)
413 Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
414 Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
415 Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message")
417 cng = User.register_changeset(%User{}, @full_user_data)
418 {:ok, registered_user} = User.register(cng)
419 ObanHelpers.perform_all()
421 activity = Repo.one(Pleroma.Activity)
422 assert registered_user.ap_id in activity.recipients
423 assert Object.normalize(activity).data["content"] =~ "direct message"
424 assert activity.actor == welcome_user.ap_id
427 test "it sends a welcome chat message if it is set" do
428 welcome_user = insert(:user)
429 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
430 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
431 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
433 cng = User.register_changeset(%User{}, @full_user_data)
434 {:ok, registered_user} = User.register(cng)
435 ObanHelpers.perform_all()
437 activity = Repo.one(Pleroma.Activity)
438 assert registered_user.ap_id in activity.recipients
439 assert Object.normalize(activity).data["content"] =~ "chat message"
440 assert activity.actor == welcome_user.ap_id
444 clear_config(:mrf_simple,
447 federated_timeline_removal: [],
460 Pleroma.Web.ActivityPub.MRF.SimplePolicy
464 test "it sends a welcome chat message when Simple policy applied to local instance" do
465 Pleroma.Config.put([:mrf_simple, :media_nsfw], ["localhost"])
467 welcome_user = insert(:user)
468 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
469 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
470 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
472 cng = User.register_changeset(%User{}, @full_user_data)
473 {:ok, registered_user} = User.register(cng)
474 ObanHelpers.perform_all()
476 activity = Repo.one(Pleroma.Activity)
477 assert registered_user.ap_id in activity.recipients
478 assert Object.normalize(activity).data["content"] =~ "chat message"
479 assert activity.actor == welcome_user.ap_id
482 test "it sends a welcome email message if it is set" do
483 welcome_user = insert(:user)
484 Pleroma.Config.put([:welcome, :email, :enabled], true)
485 Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
488 [:welcome, :email, :subject],
489 "Hello, welcome to cool site: <%= instance_name %>"
492 instance_name = Pleroma.Config.get([:instance, :name])
494 cng = User.register_changeset(%User{}, @full_user_data)
495 {:ok, registered_user} = User.register(cng)
496 ObanHelpers.perform_all()
499 from: {instance_name, welcome_user.email},
500 to: {registered_user.name, registered_user.email},
501 subject: "Hello, welcome to cool site: #{instance_name}",
502 html_body: "Welcome to #{instance_name}"
506 test "it sends a confirm email" do
507 Pleroma.Config.put([:instance, :account_activation_required], true)
509 cng = User.register_changeset(%User{}, @full_user_data)
510 {:ok, registered_user} = User.register(cng)
511 ObanHelpers.perform_all()
513 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
514 # temporary hackney fix until hackney max_connections bug is fixed
515 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
516 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
517 |> assert_email_sent()
520 test "sends a pending approval email" do
521 clear_config([:instance, :account_approval_required], true)
524 User.register_changeset(%User{}, @full_user_data)
527 ObanHelpers.perform_all()
530 from: Pleroma.Config.Helpers.sender(),
531 to: {user.name, user.email},
532 subject: "Your account is awaiting approval"
536 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
537 Pleroma.Config.put([:instance, :account_activation_required], true)
541 |> Enum.each(fn key ->
542 params = Map.delete(@full_user_data, key)
543 changeset = User.register_changeset(%User{}, params)
545 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
549 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
550 Pleroma.Config.put([:instance, :account_activation_required], false)
554 |> Enum.each(fn key ->
555 params = Map.delete(@full_user_data, key)
556 changeset = User.register_changeset(%User{}, params)
558 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
562 test "it restricts certain nicknames" do
563 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
565 assert is_bitstring(restricted_name)
569 |> Map.put(:nickname, restricted_name)
571 changeset = User.register_changeset(%User{}, params)
573 refute changeset.valid?
576 test "it blocks blacklisted email domains" do
577 clear_config([User, :email_blacklist], ["trolling.world"])
580 params = Map.put(@full_user_data, :email, "troll@trolling.world")
581 changeset = User.register_changeset(%User{}, params)
582 refute changeset.valid?
584 # Block with subdomain match
585 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
586 changeset = User.register_changeset(%User{}, params)
587 refute changeset.valid?
589 # Pass with different domains that are similar
590 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
591 changeset = User.register_changeset(%User{}, params)
592 assert changeset.valid?
594 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
595 changeset = User.register_changeset(%User{}, params)
596 assert changeset.valid?
599 test "it sets the password_hash and ap_id" do
600 changeset = User.register_changeset(%User{}, @full_user_data)
602 assert changeset.valid?
604 assert is_binary(changeset.changes[:password_hash])
605 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
607 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
610 test "it sets the 'accepts_chat_messages' set to true" do
611 changeset = User.register_changeset(%User{}, @full_user_data)
612 assert changeset.valid?
614 {:ok, user} = Repo.insert(changeset)
616 assert user.accepts_chat_messages
619 test "it creates a confirmed user" do
620 changeset = User.register_changeset(%User{}, @full_user_data)
621 assert changeset.valid?
623 {:ok, user} = Repo.insert(changeset)
625 refute user.confirmation_pending
629 describe "user registration, with :account_activation_required" do
635 password_confirmation: "test",
636 email: "email@example.com"
638 setup do: clear_config([:instance, :account_activation_required], true)
640 test "it creates unconfirmed user" do
641 changeset = User.register_changeset(%User{}, @full_user_data)
642 assert changeset.valid?
644 {:ok, user} = Repo.insert(changeset)
646 assert user.confirmation_pending
647 assert user.confirmation_token
650 test "it creates confirmed user if :confirmed option is given" do
651 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
652 assert changeset.valid?
654 {:ok, user} = Repo.insert(changeset)
656 refute user.confirmation_pending
657 refute user.confirmation_token
661 describe "user registration, with :account_approval_required" do
667 password_confirmation: "test",
668 email: "email@example.com",
669 registration_reason: "I'm a cool guy :)"
671 setup do: clear_config([:instance, :account_approval_required], true)
673 test "it creates unapproved user" do
674 changeset = User.register_changeset(%User{}, @full_user_data)
675 assert changeset.valid?
677 {:ok, user} = Repo.insert(changeset)
679 assert user.approval_pending
680 assert user.registration_reason == "I'm a cool guy :)"
683 test "it restricts length of registration reason" do
684 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
686 assert is_integer(reason_limit)
691 :registration_reason,
692 "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."
695 changeset = User.register_changeset(%User{}, params)
697 refute changeset.valid?
701 describe "get_or_fetch/1" do
702 test "gets an existing user by nickname" do
704 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
706 assert user == fetched_user
709 test "gets an existing user by ap_id" do
710 ap_id = "http://mastodon.example.org/users/admin"
716 nickname: "admin@mastodon.example.org",
720 {:ok, fetched_user} = User.get_or_fetch(ap_id)
721 freshed_user = refresh_record(user)
722 assert freshed_user == fetched_user
726 describe "fetching a user from nickname or trying to build one" do
727 test "gets an existing user" do
729 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
731 assert user == fetched_user
734 test "gets an existing user, case insensitive" do
735 user = insert(:user, nickname: "nick")
736 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
738 assert user == fetched_user
741 test "gets an existing user by fully qualified nickname" do
744 {:ok, fetched_user} =
745 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
747 assert user == fetched_user
750 test "gets an existing user by fully qualified nickname, case insensitive" do
751 user = insert(:user, nickname: "nick")
752 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
754 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
756 assert user == fetched_user
759 @tag capture_log: true
760 test "returns nil if no user could be fetched" do
761 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
762 assert fetched_user == "not found nonexistant@social.heldscal.la"
765 test "returns nil for nonexistant local user" do
766 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
767 assert fetched_user == "not found nonexistant"
770 test "updates an existing user, if stale" do
771 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
777 nickname: "admin@mastodon.example.org",
778 ap_id: "http://mastodon.example.org/users/admin",
779 last_refreshed_at: a_week_ago
782 assert orig_user.last_refreshed_at == a_week_ago
784 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
788 refute user.last_refreshed_at == orig_user.last_refreshed_at
791 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
792 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
798 nickname: "admin@mastodon.example.org",
799 ap_id: "http://mastodon.example.org/users/harinezumigari",
800 last_refreshed_at: a_week_ago
803 assert orig_user.last_refreshed_at == a_week_ago
805 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
809 refute user.id == orig_user.id
811 orig_user = User.get_by_id(orig_user.id)
813 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
816 @tag capture_log: true
817 test "it returns the old user if stale, but unfetchable" do
818 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
824 nickname: "admin@mastodon.example.org",
825 ap_id: "http://mastodon.example.org/users/raymoo",
826 last_refreshed_at: a_week_ago
829 assert orig_user.last_refreshed_at == a_week_ago
831 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
833 assert user.last_refreshed_at == orig_user.last_refreshed_at
837 test "returns an ap_id for a user" do
840 assert User.ap_id(user) ==
841 Pleroma.Web.Router.Helpers.user_feed_url(
842 Pleroma.Web.Endpoint,
848 test "returns an ap_followers link for a user" do
851 assert User.ap_followers(user) ==
852 Pleroma.Web.Router.Helpers.user_feed_url(
853 Pleroma.Web.Endpoint,
859 describe "remote user changeset" do
865 avatar: %{some: "avatar"}
867 setup do: clear_config([:instance, :user_bio_length])
868 setup do: clear_config([:instance, :user_name_length])
870 test "it confirms validity" do
871 cs = User.remote_user_changeset(@valid_remote)
875 test "it sets the follower_adress" do
876 cs = User.remote_user_changeset(@valid_remote)
877 # remote users get a fake local follower address
878 assert cs.changes.follower_address ==
879 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
882 test "it enforces the fqn format for nicknames" do
883 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
884 assert Ecto.Changeset.get_field(cs, :local) == false
885 assert cs.changes.avatar
889 test "it has required fields" do
891 |> Enum.each(fn field ->
892 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
898 describe "followers and friends" do
899 test "gets all followers for a given user" do
901 follower_one = insert(:user)
902 follower_two = insert(:user)
903 not_follower = insert(:user)
905 {:ok, follower_one} = User.follow(follower_one, user)
906 {:ok, follower_two} = User.follow(follower_two, user)
908 res = User.get_followers(user)
910 assert Enum.member?(res, follower_one)
911 assert Enum.member?(res, follower_two)
912 refute Enum.member?(res, not_follower)
915 test "gets all friends (followed users) for a given user" do
917 followed_one = insert(:user)
918 followed_two = insert(:user)
919 not_followed = insert(:user)
921 {:ok, user} = User.follow(user, followed_one)
922 {:ok, user} = User.follow(user, followed_two)
924 res = User.get_friends(user)
926 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
927 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
928 assert Enum.member?(res, followed_one)
929 assert Enum.member?(res, followed_two)
930 refute Enum.member?(res, not_followed)
934 describe "updating note and follower count" do
935 test "it sets the note_count property" do
938 user = User.get_cached_by_ap_id(note.data["actor"])
940 assert user.note_count == 0
942 {:ok, user} = User.update_note_count(user)
944 assert user.note_count == 1
947 test "it increases the note_count property" do
949 user = User.get_cached_by_ap_id(note.data["actor"])
951 assert user.note_count == 0
953 {:ok, user} = User.increase_note_count(user)
955 assert user.note_count == 1
957 {:ok, user} = User.increase_note_count(user)
959 assert user.note_count == 2
962 test "it decreases the note_count property" do
964 user = User.get_cached_by_ap_id(note.data["actor"])
966 assert user.note_count == 0
968 {:ok, user} = User.increase_note_count(user)
970 assert user.note_count == 1
972 {:ok, user} = User.decrease_note_count(user)
974 assert user.note_count == 0
976 {:ok, user} = User.decrease_note_count(user)
978 assert user.note_count == 0
981 test "it sets the follower_count property" do
983 follower = insert(:user)
985 User.follow(follower, user)
987 assert user.follower_count == 0
989 {:ok, user} = User.update_follower_count(user)
991 assert user.follower_count == 1
996 test "it mutes people" do
998 muted_user = insert(:user)
1000 refute User.mutes?(user, muted_user)
1001 refute User.muted_notifications?(user, muted_user)
1003 {:ok, _user_relationships} = User.mute(user, muted_user)
1005 assert User.mutes?(user, muted_user)
1006 assert User.muted_notifications?(user, muted_user)
1009 test "it unmutes users" do
1010 user = insert(:user)
1011 muted_user = insert(:user)
1013 {:ok, _user_relationships} = User.mute(user, muted_user)
1014 {:ok, _user_mute} = User.unmute(user, muted_user)
1016 refute User.mutes?(user, muted_user)
1017 refute User.muted_notifications?(user, muted_user)
1020 test "it mutes user without notifications" do
1021 user = insert(:user)
1022 muted_user = insert(:user)
1024 refute User.mutes?(user, muted_user)
1025 refute User.muted_notifications?(user, muted_user)
1027 {:ok, _user_relationships} = User.mute(user, muted_user, false)
1029 assert User.mutes?(user, muted_user)
1030 refute User.muted_notifications?(user, muted_user)
1034 describe "blocks" do
1035 test "it blocks people" do
1036 user = insert(:user)
1037 blocked_user = insert(:user)
1039 refute User.blocks?(user, blocked_user)
1041 {:ok, _user_relationship} = User.block(user, blocked_user)
1043 assert User.blocks?(user, blocked_user)
1046 test "it unblocks users" do
1047 user = insert(:user)
1048 blocked_user = insert(:user)
1050 {:ok, _user_relationship} = User.block(user, blocked_user)
1051 {:ok, _user_block} = User.unblock(user, blocked_user)
1053 refute User.blocks?(user, blocked_user)
1056 test "blocks tear down cyclical follow relationships" do
1057 blocker = insert(:user)
1058 blocked = insert(:user)
1060 {:ok, blocker} = User.follow(blocker, blocked)
1061 {:ok, blocked} = User.follow(blocked, blocker)
1063 assert User.following?(blocker, blocked)
1064 assert User.following?(blocked, blocker)
1066 {:ok, _user_relationship} = User.block(blocker, blocked)
1067 blocked = User.get_cached_by_id(blocked.id)
1069 assert User.blocks?(blocker, blocked)
1071 refute User.following?(blocker, blocked)
1072 refute User.following?(blocked, blocker)
1075 test "blocks tear down blocker->blocked follow relationships" do
1076 blocker = insert(:user)
1077 blocked = insert(:user)
1079 {:ok, blocker} = User.follow(blocker, blocked)
1081 assert User.following?(blocker, blocked)
1082 refute User.following?(blocked, blocker)
1084 {:ok, _user_relationship} = User.block(blocker, blocked)
1085 blocked = User.get_cached_by_id(blocked.id)
1087 assert User.blocks?(blocker, blocked)
1089 refute User.following?(blocker, blocked)
1090 refute User.following?(blocked, blocker)
1093 test "blocks tear down blocked->blocker follow relationships" do
1094 blocker = insert(:user)
1095 blocked = insert(:user)
1097 {:ok, blocked} = User.follow(blocked, blocker)
1099 refute User.following?(blocker, blocked)
1100 assert User.following?(blocked, blocker)
1102 {:ok, _user_relationship} = User.block(blocker, blocked)
1103 blocked = User.get_cached_by_id(blocked.id)
1105 assert User.blocks?(blocker, blocked)
1107 refute User.following?(blocker, blocked)
1108 refute User.following?(blocked, blocker)
1111 test "blocks tear down blocked->blocker subscription relationships" do
1112 blocker = insert(:user)
1113 blocked = insert(:user)
1115 {:ok, _subscription} = User.subscribe(blocked, blocker)
1117 assert User.subscribed_to?(blocked, blocker)
1118 refute User.subscribed_to?(blocker, blocked)
1120 {:ok, _user_relationship} = User.block(blocker, blocked)
1122 assert User.blocks?(blocker, blocked)
1123 refute User.subscribed_to?(blocker, blocked)
1124 refute User.subscribed_to?(blocked, blocker)
1128 describe "domain blocking" do
1129 test "blocks domains" do
1130 user = insert(:user)
1131 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1133 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1135 assert User.blocks?(user, collateral_user)
1138 test "does not block domain with same end" do
1139 user = insert(:user)
1142 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1144 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1146 refute User.blocks?(user, collateral_user)
1149 test "does not block domain with same end if wildcard added" do
1150 user = insert(:user)
1153 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1155 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1157 refute User.blocks?(user, collateral_user)
1160 test "blocks domain with wildcard for subdomain" do
1161 user = insert(:user)
1163 user_from_subdomain =
1164 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1166 user_with_two_subdomains =
1168 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1171 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1173 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1175 assert User.blocks?(user, user_from_subdomain)
1176 assert User.blocks?(user, user_with_two_subdomains)
1177 assert User.blocks?(user, user_domain)
1180 test "unblocks domains" do
1181 user = insert(:user)
1182 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1184 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1185 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1187 refute User.blocks?(user, collateral_user)
1190 test "follows take precedence over domain blocks" do
1191 user = insert(:user)
1192 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1194 {:ok, user} = User.block_domain(user, "meanies.social")
1195 {:ok, user} = User.follow(user, good_eggo)
1197 refute User.blocks?(user, good_eggo)
1201 describe "get_recipients_from_activity" do
1202 test "works for announces" do
1203 actor = insert(:user)
1204 user = insert(:user, local: true)
1206 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1207 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1209 recipients = User.get_recipients_from_activity(announce)
1211 assert user in recipients
1214 test "get recipients" do
1215 actor = insert(:user)
1216 user = insert(:user, local: true)
1217 user_two = insert(:user, local: false)
1218 addressed = insert(:user, local: true)
1219 addressed_remote = insert(:user, local: false)
1222 CommonAPI.post(actor, %{
1223 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1226 assert Enum.map([actor, addressed], & &1.ap_id) --
1227 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1229 {:ok, user} = User.follow(user, actor)
1230 {:ok, _user_two} = User.follow(user_two, actor)
1231 recipients = User.get_recipients_from_activity(activity)
1232 assert length(recipients) == 3
1233 assert user in recipients
1234 assert addressed in recipients
1237 test "has following" do
1238 actor = insert(:user)
1239 user = insert(:user)
1240 user_two = insert(:user)
1241 addressed = insert(:user, local: true)
1244 CommonAPI.post(actor, %{
1245 status: "hey @#{addressed.nickname}"
1248 assert Enum.map([actor, addressed], & &1.ap_id) --
1249 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1251 {:ok, _actor} = User.follow(actor, user)
1252 {:ok, _actor} = User.follow(actor, user_two)
1253 recipients = User.get_recipients_from_activity(activity)
1254 assert length(recipients) == 2
1255 assert addressed in recipients
1259 describe ".deactivate" do
1260 test "can de-activate then re-activate a user" do
1261 user = insert(:user)
1262 assert false == user.deactivated
1263 {:ok, user} = User.deactivate(user)
1264 assert true == user.deactivated
1265 {:ok, user} = User.deactivate(user, false)
1266 assert false == user.deactivated
1269 test "hide a user from followers" do
1270 user = insert(:user)
1271 user2 = insert(:user)
1273 {:ok, user} = User.follow(user, user2)
1274 {:ok, _user} = User.deactivate(user)
1276 user2 = User.get_cached_by_id(user2.id)
1278 assert user2.follower_count == 0
1279 assert [] = User.get_followers(user2)
1282 test "hide a user from friends" do
1283 user = insert(:user)
1284 user2 = insert(:user)
1286 {:ok, user2} = User.follow(user2, user)
1287 assert user2.following_count == 1
1288 assert User.following_count(user2) == 1
1290 {:ok, _user} = User.deactivate(user)
1292 user2 = User.get_cached_by_id(user2.id)
1294 assert refresh_record(user2).following_count == 0
1295 assert user2.following_count == 0
1296 assert User.following_count(user2) == 0
1297 assert [] = User.get_friends(user2)
1300 test "hide a user's statuses from timelines and notifications" do
1301 user = insert(:user)
1302 user2 = insert(:user)
1304 {:ok, user2} = User.follow(user2, user)
1306 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1308 activity = Repo.preload(activity, :bookmark)
1310 [notification] = Pleroma.Notification.for_user(user2)
1311 assert notification.activity.id == activity.id
1313 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1315 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1316 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1320 {:ok, _user} = User.deactivate(user)
1322 assert [] == ActivityPub.fetch_public_activities(%{})
1323 assert [] == Pleroma.Notification.for_user(user2)
1326 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1332 describe "approve" do
1333 test "approves a user" do
1334 user = insert(:user, approval_pending: true)
1335 assert true == user.approval_pending
1336 {:ok, user} = User.approve(user)
1337 assert false == user.approval_pending
1340 test "approves a list of users" do
1341 unapproved_users = [
1342 insert(:user, approval_pending: true),
1343 insert(:user, approval_pending: true),
1344 insert(:user, approval_pending: true)
1347 {:ok, users} = User.approve(unapproved_users)
1349 assert Enum.count(users) == 3
1351 Enum.each(users, fn user ->
1352 assert false == user.approval_pending
1356 test "it sends welcome email if it is set" do
1357 clear_config([:welcome, :email, :enabled], true)
1358 clear_config([:welcome, :email, :sender], "tester@test.me")
1360 user = insert(:user, approval_pending: true)
1361 welcome_user = insert(:user, email: "tester@test.me")
1362 instance_name = Pleroma.Config.get([:instance, :name])
1366 ObanHelpers.perform_all()
1369 from: {instance_name, welcome_user.email},
1370 to: {user.name, user.email},
1371 html_body: "Welcome to #{instance_name}"
1375 test "approving an approved user does not trigger post-register actions" do
1376 clear_config([:welcome, :email, :enabled], true)
1378 user = insert(:user, approval_pending: false)
1381 ObanHelpers.perform_all()
1383 assert_no_email_sent()
1387 describe "confirm" do
1388 test "confirms a user" do
1389 user = insert(:user, confirmation_pending: true)
1390 assert true == user.confirmation_pending
1391 {:ok, user} = User.confirm(user)
1392 assert false == user.confirmation_pending
1395 test "confirms a list of users" do
1396 unconfirmed_users = [
1397 insert(:user, confirmation_pending: true),
1398 insert(:user, confirmation_pending: true),
1399 insert(:user, confirmation_pending: true)
1402 {:ok, users} = User.confirm(unconfirmed_users)
1404 assert Enum.count(users) == 3
1406 Enum.each(users, fn user ->
1407 assert false == user.confirmation_pending
1411 test "sends approval emails when `approval_pending: true`" do
1412 admin = insert(:user, is_admin: true)
1413 user = insert(:user, confirmation_pending: true, approval_pending: true)
1416 ObanHelpers.perform_all()
1418 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1419 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1421 notify_email = Pleroma.Config.get([:instance, :notify_email])
1422 instance_name = Pleroma.Config.get([:instance, :name])
1424 # User approval email
1426 from: {instance_name, notify_email},
1427 to: {user.name, user.email},
1428 html_body: user_email.html_body
1433 from: {instance_name, notify_email},
1434 to: {admin.name, admin.email},
1435 html_body: admin_email.html_body
1439 test "confirming a confirmed user does not trigger post-register actions" do
1440 user = insert(:user, confirmation_pending: false, approval_pending: true)
1443 ObanHelpers.perform_all()
1445 assert_no_email_sent()
1449 describe "delete" do
1451 {:ok, user} = insert(:user) |> User.set_cache()
1456 setup do: clear_config([:instance, :federating])
1458 test ".delete_user_activities deletes all create activities", %{user: user} do
1459 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1461 User.delete_user_activities(user)
1463 # TODO: Test removal favorites, repeats, delete activities.
1464 refute Activity.get_by_id(activity.id)
1467 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1468 follower = insert(:user)
1469 {:ok, follower} = User.follow(follower, user)
1471 locked_user = insert(:user, name: "locked", locked: true)
1472 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1474 object = insert(:note, user: user)
1475 activity = insert(:note_activity, user: user, note: object)
1477 object_two = insert(:note, user: follower)
1478 activity_two = insert(:note_activity, user: follower, note: object_two)
1480 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1481 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1482 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1484 {:ok, job} = User.delete(user)
1485 {:ok, _user} = ObanHelpers.perform(job)
1487 follower = User.get_cached_by_id(follower.id)
1489 refute User.following?(follower, user)
1490 assert %{deactivated: true} = User.get_by_id(user.id)
1492 assert [] == User.get_follow_requests(locked_user)
1496 |> Activity.Queries.by_actor()
1498 |> Enum.map(fn act -> act.data["type"] end)
1500 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1502 refute Activity.get_by_id(activity.id)
1503 refute Activity.get_by_id(like.id)
1504 refute Activity.get_by_id(like_two.id)
1505 refute Activity.get_by_id(repeat.id)
1509 describe "delete/1 when confirmation is pending" do
1511 user = insert(:user, confirmation_pending: true)
1515 test "deletes user from database when activation required", %{user: user} do
1516 clear_config([:instance, :account_activation_required], true)
1518 {:ok, job} = User.delete(user)
1519 {:ok, _} = ObanHelpers.perform(job)
1521 refute User.get_cached_by_id(user.id)
1522 refute User.get_by_id(user.id)
1525 test "deactivates user when activation is not required", %{user: user} do
1526 clear_config([:instance, :account_activation_required], false)
1528 {:ok, job} = User.delete(user)
1529 {:ok, _} = ObanHelpers.perform(job)
1531 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1532 assert %{deactivated: true} = User.get_by_id(user.id)
1536 test "delete/1 when approval is pending deletes the user" do
1537 user = insert(:user, approval_pending: true)
1539 {:ok, job} = User.delete(user)
1540 {:ok, _} = ObanHelpers.perform(job)
1542 refute User.get_cached_by_id(user.id)
1543 refute User.get_by_id(user.id)
1546 test "delete/1 purges a user when they wouldn't be fully deleted" do
1551 password_hash: "pdfk2$1b3n159001",
1552 keys: "RSA begin buplic key",
1553 public_key: "--PRIVATE KEYE--",
1554 avatar: %{"a" => "b"},
1556 banner: %{"a" => "b"},
1557 background: %{"a" => "b"},
1560 following_count: 9001,
1562 confirmation_pending: true,
1563 password_reset_pending: true,
1564 approval_pending: true,
1565 registration_reason: "ahhhhh",
1566 confirmation_token: "qqqq",
1567 domain_blocks: ["lain.com"],
1572 mastofe_settings: %{"a" => "b"},
1573 mascot: %{"a" => "b"},
1574 emoji: %{"a" => "b"},
1575 pleroma_settings_store: %{"q" => "x"},
1576 fields: [%{"gg" => "qq"}],
1577 raw_fields: [%{"gg" => "qq"}],
1579 also_known_as: ["https://lol.olo/users/loll"]
1582 {:ok, job} = User.delete(user)
1583 {:ok, _} = ObanHelpers.perform(job)
1584 user = User.get_by_id(user.id)
1596 last_refreshed_at: nil,
1597 last_digest_emailed_at: nil,
1604 confirmation_pending: false,
1605 password_reset_pending: false,
1606 approval_pending: false,
1607 registration_reason: nil,
1608 confirmation_token: nil,
1612 is_moderator: false,
1614 mastofe_settings: nil,
1617 pleroma_settings_store: %{},
1620 discoverable: false,
1625 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1626 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1629 describe "per-user rich-text filtering" do
1630 test "html_filter_policy returns default policies, when rich-text is enabled" do
1631 user = insert(:user)
1633 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1636 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1637 user = insert(:user, no_rich_text: true)
1639 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1643 describe "caching" do
1644 test "invalidate_cache works" do
1645 user = insert(:user)
1647 User.set_cache(user)
1648 User.invalidate_cache(user)
1650 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1651 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1654 test "User.delete() plugs any possible zombie objects" do
1655 user = insert(:user)
1657 {:ok, job} = User.delete(user)
1658 {:ok, _} = ObanHelpers.perform(job)
1660 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1662 assert cached_user != user
1664 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1666 assert cached_user != user
1670 describe "account_status/1" do
1671 setup do: clear_config([:instance, :account_activation_required])
1673 test "return confirmation_pending for unconfirm user" do
1674 Pleroma.Config.put([:instance, :account_activation_required], true)
1675 user = insert(:user, confirmation_pending: true)
1676 assert User.account_status(user) == :confirmation_pending
1679 test "return active for confirmed user" do
1680 Pleroma.Config.put([:instance, :account_activation_required], true)
1681 user = insert(:user, confirmation_pending: false)
1682 assert User.account_status(user) == :active
1685 test "return active for remote user" do
1686 user = insert(:user, local: false)
1687 assert User.account_status(user) == :active
1690 test "returns :password_reset_pending for user with reset password" do
1691 user = insert(:user, password_reset_pending: true)
1692 assert User.account_status(user) == :password_reset_pending
1695 test "returns :deactivated for deactivated user" do
1696 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1697 assert User.account_status(user) == :deactivated
1700 test "returns :approval_pending for unapproved user" do
1701 user = insert(:user, local: true, approval_pending: true)
1702 assert User.account_status(user) == :approval_pending
1704 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1705 assert User.account_status(user) == :approval_pending
1709 describe "superuser?/1" do
1710 test "returns false for unprivileged users" do
1711 user = insert(:user, local: true)
1713 refute User.superuser?(user)
1716 test "returns false for remote users" do
1717 user = insert(:user, local: false)
1718 remote_admin_user = insert(:user, local: false, is_admin: true)
1720 refute User.superuser?(user)
1721 refute User.superuser?(remote_admin_user)
1724 test "returns true for local moderators" do
1725 user = insert(:user, local: true, is_moderator: true)
1727 assert User.superuser?(user)
1730 test "returns true for local admins" do
1731 user = insert(:user, local: true, is_admin: true)
1733 assert User.superuser?(user)
1737 describe "invisible?/1" do
1738 test "returns true for an invisible user" do
1739 user = insert(:user, local: true, invisible: true)
1741 assert User.invisible?(user)
1744 test "returns false for a non-invisible user" do
1745 user = insert(:user, local: true)
1747 refute User.invisible?(user)
1751 describe "visible_for/2" do
1752 test "returns true when the account is itself" do
1753 user = insert(:user, local: true)
1755 assert User.visible_for(user, user) == :visible
1758 test "returns false when the account is unconfirmed and confirmation is required" do
1759 Pleroma.Config.put([:instance, :account_activation_required], true)
1761 user = insert(:user, local: true, confirmation_pending: true)
1762 other_user = insert(:user, local: true)
1764 refute User.visible_for(user, other_user) == :visible
1767 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1768 Pleroma.Config.put([:instance, :account_activation_required], true)
1770 user = insert(:user, local: false, confirmation_pending: true)
1771 other_user = insert(:user, local: true)
1773 assert User.visible_for(user, other_user) == :visible
1776 test "returns true when the account is unconfirmed and confirmation is not required" do
1777 user = insert(:user, local: true, confirmation_pending: true)
1778 other_user = insert(:user, local: true)
1780 assert User.visible_for(user, other_user) == :visible
1783 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1784 Pleroma.Config.put([:instance, :account_activation_required], true)
1786 user = insert(:user, local: true, confirmation_pending: true)
1787 other_user = insert(:user, local: true, is_admin: true)
1789 assert User.visible_for(user, other_user) == :visible
1793 describe "parse_bio/2" do
1794 test "preserves hosts in user links text" do
1795 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1796 user = insert(:user)
1797 bio = "A.k.a. @nick@domain.com"
1800 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1802 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1804 assert expected_text == User.parse_bio(bio, user)
1807 test "Adds rel=me on linkbacked urls" do
1808 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1810 bio = "http://example.com/rel_me/null"
1811 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1812 assert expected_text == User.parse_bio(bio, user)
1814 bio = "http://example.com/rel_me/link"
1815 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1816 assert expected_text == User.parse_bio(bio, user)
1818 bio = "http://example.com/rel_me/anchor"
1819 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1820 assert expected_text == User.parse_bio(bio, user)
1824 test "follower count is updated when a follower is blocked" do
1825 user = insert(:user)
1826 follower = insert(:user)
1827 follower2 = insert(:user)
1828 follower3 = insert(:user)
1830 {:ok, follower} = User.follow(follower, user)
1831 {:ok, _follower2} = User.follow(follower2, user)
1832 {:ok, _follower3} = User.follow(follower3, user)
1834 {:ok, _user_relationship} = User.block(user, follower)
1835 user = refresh_record(user)
1837 assert user.follower_count == 2
1840 describe "list_inactive_users_query/1" do
1841 defp days_ago(days) do
1843 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1844 -days * 60 * 60 * 24,
1849 test "Users are inactive by default" do
1853 Enum.map(1..total, fn _ ->
1854 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1857 inactive_users_ids =
1858 Pleroma.User.list_inactive_users_query()
1859 |> Pleroma.Repo.all()
1860 |> Enum.map(& &1.id)
1862 Enum.each(users, fn user ->
1863 assert user.id in inactive_users_ids
1867 test "Only includes users who has no recent activity" do
1871 Enum.map(1..total, fn _ ->
1872 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1875 {inactive, active} = Enum.split(users, trunc(total / 2))
1877 Enum.map(active, fn user ->
1878 to = Enum.random(users -- [user])
1881 CommonAPI.post(user, %{
1882 status: "hey @#{to.nickname}"
1886 inactive_users_ids =
1887 Pleroma.User.list_inactive_users_query()
1888 |> Pleroma.Repo.all()
1889 |> Enum.map(& &1.id)
1891 Enum.each(active, fn user ->
1892 refute user.id in inactive_users_ids
1895 Enum.each(inactive, fn user ->
1896 assert user.id in inactive_users_ids
1900 test "Only includes users with no read notifications" do
1904 Enum.map(1..total, fn _ ->
1905 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1908 [sender | recipients] = users
1909 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1911 Enum.each(recipients, fn to ->
1913 CommonAPI.post(sender, %{
1914 status: "hey @#{to.nickname}"
1918 CommonAPI.post(sender, %{
1919 status: "hey again @#{to.nickname}"
1923 Enum.each(active, fn user ->
1924 [n1, _n2] = Pleroma.Notification.for_user(user)
1925 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1928 inactive_users_ids =
1929 Pleroma.User.list_inactive_users_query()
1930 |> Pleroma.Repo.all()
1931 |> Enum.map(& &1.id)
1933 Enum.each(active, fn user ->
1934 refute user.id in inactive_users_ids
1937 Enum.each(inactive, fn user ->
1938 assert user.id in inactive_users_ids
1943 describe "toggle_confirmation/1" do
1944 test "if user is confirmed" do
1945 user = insert(:user, confirmation_pending: false)
1946 {:ok, user} = User.toggle_confirmation(user)
1948 assert user.confirmation_pending
1949 assert user.confirmation_token
1952 test "if user is unconfirmed" do
1953 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1954 {:ok, user} = User.toggle_confirmation(user)
1956 refute user.confirmation_pending
1957 refute user.confirmation_token
1961 describe "ensure_keys_present" do
1962 test "it creates keys for a user and stores them in info" do
1963 user = insert(:user)
1964 refute is_binary(user.keys)
1965 {:ok, user} = User.ensure_keys_present(user)
1966 assert is_binary(user.keys)
1969 test "it doesn't create keys if there already are some" do
1970 user = insert(:user, keys: "xxx")
1971 {:ok, user} = User.ensure_keys_present(user)
1972 assert user.keys == "xxx"
1976 describe "get_ap_ids_by_nicknames" do
1977 test "it returns a list of AP ids for a given set of nicknames" do
1978 user = insert(:user)
1979 user_two = insert(:user)
1981 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1982 assert length(ap_ids) == 2
1983 assert user.ap_id in ap_ids
1984 assert user_two.ap_id in ap_ids
1988 describe "sync followers count" do
1990 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1991 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1992 insert(:user, local: true)
1993 insert(:user, local: false, deactivated: true)
1994 {:ok, user1: user1, user2: user2}
1997 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1998 [fdb_user1] = User.external_users(limit: 1)
2000 assert fdb_user1.ap_id
2001 assert fdb_user1.ap_id == user1.ap_id
2002 assert fdb_user1.id == user1.id
2004 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2006 assert fdb_user2.ap_id
2007 assert fdb_user2.ap_id == user2.ap_id
2008 assert fdb_user2.id == user2.id
2010 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2014 describe "is_internal_user?/1" do
2015 test "non-internal user returns false" do
2016 user = insert(:user)
2017 refute User.is_internal_user?(user)
2020 test "user with no nickname returns true" do
2021 user = insert(:user, %{nickname: nil})
2022 assert User.is_internal_user?(user)
2025 test "user with internal-prefixed nickname returns true" do
2026 user = insert(:user, %{nickname: "internal.test"})
2027 assert User.is_internal_user?(user)
2031 describe "update_and_set_cache/1" do
2032 test "returns error when user is stale instead Ecto.StaleEntryError" do
2033 user = insert(:user)
2035 changeset = Ecto.Changeset.change(user, bio: "test")
2039 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2040 User.update_and_set_cache(changeset)
2043 test "performs update cache if user updated" do
2044 user = insert(:user)
2045 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2047 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2049 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2050 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2051 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2055 describe "following/followers synchronization" do
2056 setup do: clear_config([:instance, :external_user_synchronization])
2058 test "updates the counters normally on following/getting a follow when disabled" do
2059 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2060 user = insert(:user)
2065 follower_address: "http://localhost:4001/users/masto_closed/followers",
2066 following_address: "http://localhost:4001/users/masto_closed/following",
2070 assert other_user.following_count == 0
2071 assert other_user.follower_count == 0
2073 {:ok, user} = Pleroma.User.follow(user, other_user)
2074 other_user = Pleroma.User.get_by_id(other_user.id)
2076 assert user.following_count == 1
2077 assert other_user.follower_count == 1
2080 test "syncronizes the counters with the remote instance for the followed when enabled" do
2081 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2083 user = insert(:user)
2088 follower_address: "http://localhost:4001/users/masto_closed/followers",
2089 following_address: "http://localhost:4001/users/masto_closed/following",
2093 assert other_user.following_count == 0
2094 assert other_user.follower_count == 0
2096 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2097 {:ok, _user} = User.follow(user, other_user)
2098 other_user = User.get_by_id(other_user.id)
2100 assert other_user.follower_count == 437
2103 test "syncronizes the counters with the remote instance for the follower when enabled" do
2104 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2106 user = insert(:user)
2111 follower_address: "http://localhost:4001/users/masto_closed/followers",
2112 following_address: "http://localhost:4001/users/masto_closed/following",
2116 assert other_user.following_count == 0
2117 assert other_user.follower_count == 0
2119 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2120 {:ok, other_user} = User.follow(other_user, user)
2122 assert other_user.following_count == 152
2126 describe "change_email/2" do
2128 [user: insert(:user)]
2131 test "blank email returns error", %{user: user} do
2132 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2133 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2136 test "non unique email returns error", %{user: user} do
2137 %{email: email} = insert(:user)
2139 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2140 User.change_email(user, email)
2143 test "invalid email returns error", %{user: user} do
2144 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2145 User.change_email(user, "cofe")
2148 test "changes email", %{user: user} do
2149 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2153 describe "get_cached_by_nickname_or_id" do
2155 local_user = insert(:user)
2156 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2158 [local_user: local_user, remote_user: remote_user]
2161 setup do: clear_config([:instance, :limit_to_local_content])
2163 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2164 remote_user: remote_user
2166 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2167 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2169 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2170 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2172 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2173 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2176 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2177 %{remote_user: remote_user} do
2178 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2179 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2182 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2183 %{remote_user: remote_user, local_user: local_user} do
2184 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2185 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2188 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2189 %{remote_user: remote_user} do
2190 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2191 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2194 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2195 %{local_user: local_user} do
2196 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2197 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2199 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2200 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2202 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2203 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2207 describe "update_email_notifications/2" do
2209 user = insert(:user, email_notifications: %{"digest" => true})
2214 test "Notifications are updated", %{user: user} do
2215 true = user.email_notifications["digest"]
2216 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2217 assert result.email_notifications["digest"] == false
2221 test "avatar fallback" do
2222 user = insert(:user)
2223 assert User.avatar_url(user) =~ "/images/avi.png"
2225 clear_config([:assets, :default_user_avatar], "avatar.png")
2227 user = User.get_cached_by_nickname_or_id(user.nickname)
2228 assert User.avatar_url(user) =~ "avatar.png"
2230 assert User.avatar_url(user, no_default: true) == nil