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
1357 describe "delete" do
1359 {:ok, user} = insert(:user) |> User.set_cache()
1364 setup do: clear_config([:instance, :federating])
1366 test ".delete_user_activities deletes all create activities", %{user: user} do
1367 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1369 User.delete_user_activities(user)
1371 # TODO: Test removal favorites, repeats, delete activities.
1372 refute Activity.get_by_id(activity.id)
1375 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1376 follower = insert(:user)
1377 {:ok, follower} = User.follow(follower, user)
1379 locked_user = insert(:user, name: "locked", locked: true)
1380 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1382 object = insert(:note, user: user)
1383 activity = insert(:note_activity, user: user, note: object)
1385 object_two = insert(:note, user: follower)
1386 activity_two = insert(:note_activity, user: follower, note: object_two)
1388 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1389 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1390 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1392 {:ok, job} = User.delete(user)
1393 {:ok, _user} = ObanHelpers.perform(job)
1395 follower = User.get_cached_by_id(follower.id)
1397 refute User.following?(follower, user)
1398 assert %{deactivated: true} = User.get_by_id(user.id)
1400 assert [] == User.get_follow_requests(locked_user)
1404 |> Activity.Queries.by_actor()
1406 |> Enum.map(fn act -> act.data["type"] end)
1408 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1410 refute Activity.get_by_id(activity.id)
1411 refute Activity.get_by_id(like.id)
1412 refute Activity.get_by_id(like_two.id)
1413 refute Activity.get_by_id(repeat.id)
1417 describe "delete/1 when confirmation is pending" do
1419 user = insert(:user, confirmation_pending: true)
1423 test "deletes user from database when activation required", %{user: user} do
1424 clear_config([:instance, :account_activation_required], true)
1426 {:ok, job} = User.delete(user)
1427 {:ok, _} = ObanHelpers.perform(job)
1429 refute User.get_cached_by_id(user.id)
1430 refute User.get_by_id(user.id)
1433 test "deactivates user when activation is not required", %{user: user} do
1434 clear_config([:instance, :account_activation_required], false)
1436 {:ok, job} = User.delete(user)
1437 {:ok, _} = ObanHelpers.perform(job)
1439 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1440 assert %{deactivated: true} = User.get_by_id(user.id)
1444 test "delete/1 when approval is pending deletes the user" do
1445 user = insert(:user, approval_pending: true)
1447 {:ok, job} = User.delete(user)
1448 {:ok, _} = ObanHelpers.perform(job)
1450 refute User.get_cached_by_id(user.id)
1451 refute User.get_by_id(user.id)
1454 test "delete/1 purges a user when they wouldn't be fully deleted" do
1459 password_hash: "pdfk2$1b3n159001",
1460 keys: "RSA begin buplic key",
1461 public_key: "--PRIVATE KEYE--",
1462 avatar: %{"a" => "b"},
1464 banner: %{"a" => "b"},
1465 background: %{"a" => "b"},
1468 following_count: 9001,
1470 confirmation_pending: true,
1471 password_reset_pending: true,
1472 approval_pending: true,
1473 registration_reason: "ahhhhh",
1474 confirmation_token: "qqqq",
1475 domain_blocks: ["lain.com"],
1480 mastofe_settings: %{"a" => "b"},
1481 mascot: %{"a" => "b"},
1482 emoji: %{"a" => "b"},
1483 pleroma_settings_store: %{"q" => "x"},
1484 fields: [%{"gg" => "qq"}],
1485 raw_fields: [%{"gg" => "qq"}],
1487 also_known_as: ["https://lol.olo/users/loll"]
1490 {:ok, job} = User.delete(user)
1491 {:ok, _} = ObanHelpers.perform(job)
1492 user = User.get_by_id(user.id)
1504 last_refreshed_at: nil,
1505 last_digest_emailed_at: nil,
1512 confirmation_pending: false,
1513 password_reset_pending: false,
1514 approval_pending: false,
1515 registration_reason: nil,
1516 confirmation_token: nil,
1520 is_moderator: false,
1522 mastofe_settings: nil,
1525 pleroma_settings_store: %{},
1528 discoverable: false,
1533 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1534 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1537 describe "per-user rich-text filtering" do
1538 test "html_filter_policy returns default policies, when rich-text is enabled" do
1539 user = insert(:user)
1541 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1544 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1545 user = insert(:user, no_rich_text: true)
1547 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1551 describe "caching" do
1552 test "invalidate_cache works" do
1553 user = insert(:user)
1555 User.set_cache(user)
1556 User.invalidate_cache(user)
1558 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1559 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1562 test "User.delete() plugs any possible zombie objects" do
1563 user = insert(:user)
1565 {:ok, job} = User.delete(user)
1566 {:ok, _} = ObanHelpers.perform(job)
1568 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1570 assert cached_user != user
1572 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1574 assert cached_user != user
1578 describe "account_status/1" do
1579 setup do: clear_config([:instance, :account_activation_required])
1581 test "return confirmation_pending for unconfirm user" do
1582 Pleroma.Config.put([:instance, :account_activation_required], true)
1583 user = insert(:user, confirmation_pending: true)
1584 assert User.account_status(user) == :confirmation_pending
1587 test "return active for confirmed user" do
1588 Pleroma.Config.put([:instance, :account_activation_required], true)
1589 user = insert(:user, confirmation_pending: false)
1590 assert User.account_status(user) == :active
1593 test "return active for remote user" do
1594 user = insert(:user, local: false)
1595 assert User.account_status(user) == :active
1598 test "returns :password_reset_pending for user with reset password" do
1599 user = insert(:user, password_reset_pending: true)
1600 assert User.account_status(user) == :password_reset_pending
1603 test "returns :deactivated for deactivated user" do
1604 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1605 assert User.account_status(user) == :deactivated
1608 test "returns :approval_pending for unapproved user" do
1609 user = insert(:user, local: true, approval_pending: true)
1610 assert User.account_status(user) == :approval_pending
1612 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1613 assert User.account_status(user) == :approval_pending
1617 describe "superuser?/1" do
1618 test "returns false for unprivileged users" do
1619 user = insert(:user, local: true)
1621 refute User.superuser?(user)
1624 test "returns false for remote users" do
1625 user = insert(:user, local: false)
1626 remote_admin_user = insert(:user, local: false, is_admin: true)
1628 refute User.superuser?(user)
1629 refute User.superuser?(remote_admin_user)
1632 test "returns true for local moderators" do
1633 user = insert(:user, local: true, is_moderator: true)
1635 assert User.superuser?(user)
1638 test "returns true for local admins" do
1639 user = insert(:user, local: true, is_admin: true)
1641 assert User.superuser?(user)
1645 describe "invisible?/1" do
1646 test "returns true for an invisible user" do
1647 user = insert(:user, local: true, invisible: true)
1649 assert User.invisible?(user)
1652 test "returns false for a non-invisible user" do
1653 user = insert(:user, local: true)
1655 refute User.invisible?(user)
1659 describe "visible_for/2" do
1660 test "returns true when the account is itself" do
1661 user = insert(:user, local: true)
1663 assert User.visible_for(user, user) == :visible
1666 test "returns false when the account is unconfirmed and confirmation is required" do
1667 Pleroma.Config.put([:instance, :account_activation_required], true)
1669 user = insert(:user, local: true, confirmation_pending: true)
1670 other_user = insert(:user, local: true)
1672 refute User.visible_for(user, other_user) == :visible
1675 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1676 Pleroma.Config.put([:instance, :account_activation_required], true)
1678 user = insert(:user, local: false, confirmation_pending: true)
1679 other_user = insert(:user, local: true)
1681 assert User.visible_for(user, other_user) == :visible
1684 test "returns true when the account is unconfirmed and confirmation is not required" do
1685 user = insert(:user, local: true, confirmation_pending: true)
1686 other_user = insert(:user, local: true)
1688 assert User.visible_for(user, other_user) == :visible
1691 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1692 Pleroma.Config.put([:instance, :account_activation_required], true)
1694 user = insert(:user, local: true, confirmation_pending: true)
1695 other_user = insert(:user, local: true, is_admin: true)
1697 assert User.visible_for(user, other_user) == :visible
1701 describe "parse_bio/2" do
1702 test "preserves hosts in user links text" do
1703 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1704 user = insert(:user)
1705 bio = "A.k.a. @nick@domain.com"
1708 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1710 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1712 assert expected_text == User.parse_bio(bio, user)
1715 test "Adds rel=me on linkbacked urls" do
1716 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1718 bio = "http://example.com/rel_me/null"
1719 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1720 assert expected_text == User.parse_bio(bio, user)
1722 bio = "http://example.com/rel_me/link"
1723 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1724 assert expected_text == User.parse_bio(bio, user)
1726 bio = "http://example.com/rel_me/anchor"
1727 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1728 assert expected_text == User.parse_bio(bio, user)
1732 test "follower count is updated when a follower is blocked" do
1733 user = insert(:user)
1734 follower = insert(:user)
1735 follower2 = insert(:user)
1736 follower3 = insert(:user)
1738 {:ok, follower} = User.follow(follower, user)
1739 {:ok, _follower2} = User.follow(follower2, user)
1740 {:ok, _follower3} = User.follow(follower3, user)
1742 {:ok, _user_relationship} = User.block(user, follower)
1743 user = refresh_record(user)
1745 assert user.follower_count == 2
1748 describe "list_inactive_users_query/1" do
1749 defp days_ago(days) do
1751 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1752 -days * 60 * 60 * 24,
1757 test "Users are inactive by default" do
1761 Enum.map(1..total, fn _ ->
1762 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1765 inactive_users_ids =
1766 Pleroma.User.list_inactive_users_query()
1767 |> Pleroma.Repo.all()
1768 |> Enum.map(& &1.id)
1770 Enum.each(users, fn user ->
1771 assert user.id in inactive_users_ids
1775 test "Only includes users who has no recent activity" do
1779 Enum.map(1..total, fn _ ->
1780 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1783 {inactive, active} = Enum.split(users, trunc(total / 2))
1785 Enum.map(active, fn user ->
1786 to = Enum.random(users -- [user])
1789 CommonAPI.post(user, %{
1790 status: "hey @#{to.nickname}"
1794 inactive_users_ids =
1795 Pleroma.User.list_inactive_users_query()
1796 |> Pleroma.Repo.all()
1797 |> Enum.map(& &1.id)
1799 Enum.each(active, fn user ->
1800 refute user.id in inactive_users_ids
1803 Enum.each(inactive, fn user ->
1804 assert user.id in inactive_users_ids
1808 test "Only includes users with no read notifications" do
1812 Enum.map(1..total, fn _ ->
1813 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1816 [sender | recipients] = users
1817 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1819 Enum.each(recipients, fn to ->
1821 CommonAPI.post(sender, %{
1822 status: "hey @#{to.nickname}"
1826 CommonAPI.post(sender, %{
1827 status: "hey again @#{to.nickname}"
1831 Enum.each(active, fn user ->
1832 [n1, _n2] = Pleroma.Notification.for_user(user)
1833 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1836 inactive_users_ids =
1837 Pleroma.User.list_inactive_users_query()
1838 |> Pleroma.Repo.all()
1839 |> Enum.map(& &1.id)
1841 Enum.each(active, fn user ->
1842 refute user.id in inactive_users_ids
1845 Enum.each(inactive, fn user ->
1846 assert user.id in inactive_users_ids
1851 describe "toggle_confirmation/1" do
1852 test "if user is confirmed" do
1853 user = insert(:user, confirmation_pending: false)
1854 {:ok, user} = User.toggle_confirmation(user)
1856 assert user.confirmation_pending
1857 assert user.confirmation_token
1860 test "if user is unconfirmed" do
1861 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1862 {:ok, user} = User.toggle_confirmation(user)
1864 refute user.confirmation_pending
1865 refute user.confirmation_token
1869 describe "ensure_keys_present" do
1870 test "it creates keys for a user and stores them in info" do
1871 user = insert(:user)
1872 refute is_binary(user.keys)
1873 {:ok, user} = User.ensure_keys_present(user)
1874 assert is_binary(user.keys)
1877 test "it doesn't create keys if there already are some" do
1878 user = insert(:user, keys: "xxx")
1879 {:ok, user} = User.ensure_keys_present(user)
1880 assert user.keys == "xxx"
1884 describe "get_ap_ids_by_nicknames" do
1885 test "it returns a list of AP ids for a given set of nicknames" do
1886 user = insert(:user)
1887 user_two = insert(:user)
1889 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1890 assert length(ap_ids) == 2
1891 assert user.ap_id in ap_ids
1892 assert user_two.ap_id in ap_ids
1896 describe "sync followers count" do
1898 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1899 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1900 insert(:user, local: true)
1901 insert(:user, local: false, deactivated: true)
1902 {:ok, user1: user1, user2: user2}
1905 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1906 [fdb_user1] = User.external_users(limit: 1)
1908 assert fdb_user1.ap_id
1909 assert fdb_user1.ap_id == user1.ap_id
1910 assert fdb_user1.id == user1.id
1912 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1914 assert fdb_user2.ap_id
1915 assert fdb_user2.ap_id == user2.ap_id
1916 assert fdb_user2.id == user2.id
1918 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1922 describe "is_internal_user?/1" do
1923 test "non-internal user returns false" do
1924 user = insert(:user)
1925 refute User.is_internal_user?(user)
1928 test "user with no nickname returns true" do
1929 user = insert(:user, %{nickname: nil})
1930 assert User.is_internal_user?(user)
1933 test "user with internal-prefixed nickname returns true" do
1934 user = insert(:user, %{nickname: "internal.test"})
1935 assert User.is_internal_user?(user)
1939 describe "update_and_set_cache/1" do
1940 test "returns error when user is stale instead Ecto.StaleEntryError" do
1941 user = insert(:user)
1943 changeset = Ecto.Changeset.change(user, bio: "test")
1947 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1948 User.update_and_set_cache(changeset)
1951 test "performs update cache if user updated" do
1952 user = insert(:user)
1953 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1955 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1957 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1958 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1959 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1963 describe "following/followers synchronization" do
1964 setup do: clear_config([:instance, :external_user_synchronization])
1966 test "updates the counters normally on following/getting a follow when disabled" do
1967 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1968 user = insert(:user)
1973 follower_address: "http://localhost:4001/users/masto_closed/followers",
1974 following_address: "http://localhost:4001/users/masto_closed/following",
1978 assert other_user.following_count == 0
1979 assert other_user.follower_count == 0
1981 {:ok, user} = Pleroma.User.follow(user, other_user)
1982 other_user = Pleroma.User.get_by_id(other_user.id)
1984 assert user.following_count == 1
1985 assert other_user.follower_count == 1
1988 test "syncronizes the counters with the remote instance for the followed when enabled" do
1989 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1991 user = insert(:user)
1996 follower_address: "http://localhost:4001/users/masto_closed/followers",
1997 following_address: "http://localhost:4001/users/masto_closed/following",
2001 assert other_user.following_count == 0
2002 assert other_user.follower_count == 0
2004 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2005 {:ok, _user} = User.follow(user, other_user)
2006 other_user = User.get_by_id(other_user.id)
2008 assert other_user.follower_count == 437
2011 test "syncronizes the counters with the remote instance for the follower when enabled" do
2012 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2014 user = insert(:user)
2019 follower_address: "http://localhost:4001/users/masto_closed/followers",
2020 following_address: "http://localhost:4001/users/masto_closed/following",
2024 assert other_user.following_count == 0
2025 assert other_user.follower_count == 0
2027 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2028 {:ok, other_user} = User.follow(other_user, user)
2030 assert other_user.following_count == 152
2034 describe "change_email/2" do
2036 [user: insert(:user)]
2039 test "blank email returns error", %{user: user} do
2040 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2041 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2044 test "non unique email returns error", %{user: user} do
2045 %{email: email} = insert(:user)
2047 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2048 User.change_email(user, email)
2051 test "invalid email returns error", %{user: user} do
2052 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2053 User.change_email(user, "cofe")
2056 test "changes email", %{user: user} do
2057 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2061 describe "get_cached_by_nickname_or_id" do
2063 local_user = insert(:user)
2064 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2066 [local_user: local_user, remote_user: remote_user]
2069 setup do: clear_config([:instance, :limit_to_local_content])
2071 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2072 remote_user: remote_user
2074 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2075 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2077 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2078 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2080 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2081 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2084 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2085 %{remote_user: remote_user} do
2086 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2087 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2090 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2091 %{remote_user: remote_user, local_user: local_user} do
2092 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2093 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2096 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2097 %{remote_user: remote_user} do
2098 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2099 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2102 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2103 %{local_user: local_user} do
2104 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2105 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2107 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2108 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2110 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2111 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2115 describe "update_email_notifications/2" do
2117 user = insert(:user, email_notifications: %{"digest" => true})
2122 test "Notifications are updated", %{user: user} do
2123 true = user.email_notifications["digest"]
2124 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2125 assert result.email_notifications["digest"] == false
2129 test "avatar fallback" do
2130 user = insert(:user)
2131 assert User.avatar_url(user) =~ "/images/avi.png"
2133 clear_config([:assets, :default_user_avatar], "avatar.png")
2135 user = User.get_cached_by_nickname_or_id(user.nickname)
2136 assert User.avatar_url(user) =~ "avatar.png"
2138 assert User.avatar_url(user, no_default: true) == nil