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 "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
521 Pleroma.Config.put([:instance, :account_activation_required], true)
525 |> Enum.each(fn key ->
526 params = Map.delete(@full_user_data, key)
527 changeset = User.register_changeset(%User{}, params)
529 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
533 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
534 Pleroma.Config.put([:instance, :account_activation_required], false)
538 |> Enum.each(fn key ->
539 params = Map.delete(@full_user_data, key)
540 changeset = User.register_changeset(%User{}, params)
542 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
546 test "it restricts certain nicknames" do
547 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
549 assert is_bitstring(restricted_name)
553 |> Map.put(:nickname, restricted_name)
555 changeset = User.register_changeset(%User{}, params)
557 refute changeset.valid?
560 test "it blocks blacklisted email domains" do
561 clear_config([User, :email_blacklist], ["trolling.world"])
564 params = Map.put(@full_user_data, :email, "troll@trolling.world")
565 changeset = User.register_changeset(%User{}, params)
566 refute changeset.valid?
568 # Block with subdomain match
569 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
570 changeset = User.register_changeset(%User{}, params)
571 refute changeset.valid?
573 # Pass with different domains that are similar
574 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
575 changeset = User.register_changeset(%User{}, params)
576 assert changeset.valid?
578 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
579 changeset = User.register_changeset(%User{}, params)
580 assert changeset.valid?
583 test "it sets the password_hash and ap_id" do
584 changeset = User.register_changeset(%User{}, @full_user_data)
586 assert changeset.valid?
588 assert is_binary(changeset.changes[:password_hash])
589 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
591 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
594 test "it sets the 'accepts_chat_messages' set to true" do
595 changeset = User.register_changeset(%User{}, @full_user_data)
596 assert changeset.valid?
598 {:ok, user} = Repo.insert(changeset)
600 assert user.accepts_chat_messages
603 test "it creates a confirmed user" do
604 changeset = User.register_changeset(%User{}, @full_user_data)
605 assert changeset.valid?
607 {:ok, user} = Repo.insert(changeset)
609 refute user.confirmation_pending
613 describe "user registration, with :account_activation_required" do
619 password_confirmation: "test",
620 email: "email@example.com"
622 setup do: clear_config([:instance, :account_activation_required], true)
624 test "it creates unconfirmed user" do
625 changeset = User.register_changeset(%User{}, @full_user_data)
626 assert changeset.valid?
628 {:ok, user} = Repo.insert(changeset)
630 assert user.confirmation_pending
631 assert user.confirmation_token
634 test "it creates confirmed user if :confirmed option is given" do
635 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
636 assert changeset.valid?
638 {:ok, user} = Repo.insert(changeset)
640 refute user.confirmation_pending
641 refute user.confirmation_token
645 describe "user registration, with :account_approval_required" do
651 password_confirmation: "test",
652 email: "email@example.com",
653 registration_reason: "I'm a cool guy :)"
655 setup do: clear_config([:instance, :account_approval_required], true)
657 test "it creates unapproved user" do
658 changeset = User.register_changeset(%User{}, @full_user_data)
659 assert changeset.valid?
661 {:ok, user} = Repo.insert(changeset)
663 assert user.approval_pending
664 assert user.registration_reason == "I'm a cool guy :)"
667 test "it restricts length of registration reason" do
668 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
670 assert is_integer(reason_limit)
675 :registration_reason,
676 "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."
679 changeset = User.register_changeset(%User{}, params)
681 refute changeset.valid?
685 describe "get_or_fetch/1" do
686 test "gets an existing user by nickname" do
688 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
690 assert user == fetched_user
693 test "gets an existing user by ap_id" do
694 ap_id = "http://mastodon.example.org/users/admin"
700 nickname: "admin@mastodon.example.org",
704 {:ok, fetched_user} = User.get_or_fetch(ap_id)
705 freshed_user = refresh_record(user)
706 assert freshed_user == fetched_user
710 describe "fetching a user from nickname or trying to build one" do
711 test "gets an existing user" do
713 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
715 assert user == fetched_user
718 test "gets an existing user, case insensitive" do
719 user = insert(:user, nickname: "nick")
720 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
722 assert user == fetched_user
725 test "gets an existing user by fully qualified nickname" do
728 {:ok, fetched_user} =
729 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
731 assert user == fetched_user
734 test "gets an existing user by fully qualified nickname, case insensitive" do
735 user = insert(:user, nickname: "nick")
736 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
738 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
740 assert user == fetched_user
743 @tag capture_log: true
744 test "returns nil if no user could be fetched" do
745 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
746 assert fetched_user == "not found nonexistant@social.heldscal.la"
749 test "returns nil for nonexistant local user" do
750 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
751 assert fetched_user == "not found nonexistant"
754 test "updates an existing user, if stale" do
755 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
761 nickname: "admin@mastodon.example.org",
762 ap_id: "http://mastodon.example.org/users/admin",
763 last_refreshed_at: a_week_ago
766 assert orig_user.last_refreshed_at == a_week_ago
768 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
772 refute user.last_refreshed_at == orig_user.last_refreshed_at
775 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
776 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
782 nickname: "admin@mastodon.example.org",
783 ap_id: "http://mastodon.example.org/users/harinezumigari",
784 last_refreshed_at: a_week_ago
787 assert orig_user.last_refreshed_at == a_week_ago
789 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
793 refute user.id == orig_user.id
795 orig_user = User.get_by_id(orig_user.id)
797 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
800 @tag capture_log: true
801 test "it returns the old user if stale, but unfetchable" do
802 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
808 nickname: "admin@mastodon.example.org",
809 ap_id: "http://mastodon.example.org/users/raymoo",
810 last_refreshed_at: a_week_ago
813 assert orig_user.last_refreshed_at == a_week_ago
815 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
817 assert user.last_refreshed_at == orig_user.last_refreshed_at
821 test "returns an ap_id for a user" do
824 assert User.ap_id(user) ==
825 Pleroma.Web.Router.Helpers.user_feed_url(
826 Pleroma.Web.Endpoint,
832 test "returns an ap_followers link for a user" do
835 assert User.ap_followers(user) ==
836 Pleroma.Web.Router.Helpers.user_feed_url(
837 Pleroma.Web.Endpoint,
843 describe "remote user changeset" do
849 avatar: %{some: "avatar"}
851 setup do: clear_config([:instance, :user_bio_length])
852 setup do: clear_config([:instance, :user_name_length])
854 test "it confirms validity" do
855 cs = User.remote_user_changeset(@valid_remote)
859 test "it sets the follower_adress" do
860 cs = User.remote_user_changeset(@valid_remote)
861 # remote users get a fake local follower address
862 assert cs.changes.follower_address ==
863 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
866 test "it enforces the fqn format for nicknames" do
867 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
868 assert Ecto.Changeset.get_field(cs, :local) == false
869 assert cs.changes.avatar
873 test "it has required fields" do
875 |> Enum.each(fn field ->
876 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
882 describe "followers and friends" do
883 test "gets all followers for a given user" do
885 follower_one = insert(:user)
886 follower_two = insert(:user)
887 not_follower = insert(:user)
889 {:ok, follower_one} = User.follow(follower_one, user)
890 {:ok, follower_two} = User.follow(follower_two, user)
892 res = User.get_followers(user)
894 assert Enum.member?(res, follower_one)
895 assert Enum.member?(res, follower_two)
896 refute Enum.member?(res, not_follower)
899 test "gets all friends (followed users) for a given user" do
901 followed_one = insert(:user)
902 followed_two = insert(:user)
903 not_followed = insert(:user)
905 {:ok, user} = User.follow(user, followed_one)
906 {:ok, user} = User.follow(user, followed_two)
908 res = User.get_friends(user)
910 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
911 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
912 assert Enum.member?(res, followed_one)
913 assert Enum.member?(res, followed_two)
914 refute Enum.member?(res, not_followed)
918 describe "updating note and follower count" do
919 test "it sets the note_count property" do
922 user = User.get_cached_by_ap_id(note.data["actor"])
924 assert user.note_count == 0
926 {:ok, user} = User.update_note_count(user)
928 assert user.note_count == 1
931 test "it increases the note_count property" do
933 user = User.get_cached_by_ap_id(note.data["actor"])
935 assert user.note_count == 0
937 {:ok, user} = User.increase_note_count(user)
939 assert user.note_count == 1
941 {:ok, user} = User.increase_note_count(user)
943 assert user.note_count == 2
946 test "it decreases the note_count property" do
948 user = User.get_cached_by_ap_id(note.data["actor"])
950 assert user.note_count == 0
952 {:ok, user} = User.increase_note_count(user)
954 assert user.note_count == 1
956 {:ok, user} = User.decrease_note_count(user)
958 assert user.note_count == 0
960 {:ok, user} = User.decrease_note_count(user)
962 assert user.note_count == 0
965 test "it sets the follower_count property" do
967 follower = insert(:user)
969 User.follow(follower, user)
971 assert user.follower_count == 0
973 {:ok, user} = User.update_follower_count(user)
975 assert user.follower_count == 1
979 describe "follow_import" do
980 test "it imports user followings from list" do
981 [user1, user2, user3] = insert_list(3, :user)
988 {:ok, job} = User.follow_import(user1, identifiers)
990 assert {:ok, result} = ObanHelpers.perform(job)
991 assert is_list(result)
992 assert result == [user2, user3]
997 test "it mutes people" do
999 muted_user = insert(:user)
1001 refute User.mutes?(user, muted_user)
1002 refute User.muted_notifications?(user, muted_user)
1004 {:ok, _user_relationships} = User.mute(user, muted_user)
1006 assert User.mutes?(user, muted_user)
1007 assert User.muted_notifications?(user, muted_user)
1010 test "it unmutes users" do
1011 user = insert(:user)
1012 muted_user = insert(:user)
1014 {:ok, _user_relationships} = User.mute(user, muted_user)
1015 {:ok, _user_mute} = User.unmute(user, muted_user)
1017 refute User.mutes?(user, muted_user)
1018 refute User.muted_notifications?(user, muted_user)
1021 test "it mutes user without notifications" do
1022 user = insert(:user)
1023 muted_user = insert(:user)
1025 refute User.mutes?(user, muted_user)
1026 refute User.muted_notifications?(user, muted_user)
1028 {:ok, _user_relationships} = User.mute(user, muted_user, false)
1030 assert User.mutes?(user, muted_user)
1031 refute User.muted_notifications?(user, muted_user)
1035 describe "blocks" do
1036 test "it blocks people" do
1037 user = insert(:user)
1038 blocked_user = insert(:user)
1040 refute User.blocks?(user, blocked_user)
1042 {:ok, _user_relationship} = User.block(user, blocked_user)
1044 assert User.blocks?(user, blocked_user)
1047 test "it unblocks users" do
1048 user = insert(:user)
1049 blocked_user = insert(:user)
1051 {:ok, _user_relationship} = User.block(user, blocked_user)
1052 {:ok, _user_block} = User.unblock(user, blocked_user)
1054 refute User.blocks?(user, blocked_user)
1057 test "blocks tear down cyclical follow relationships" do
1058 blocker = insert(:user)
1059 blocked = insert(:user)
1061 {:ok, blocker} = User.follow(blocker, blocked)
1062 {:ok, blocked} = User.follow(blocked, blocker)
1064 assert User.following?(blocker, blocked)
1065 assert User.following?(blocked, blocker)
1067 {:ok, _user_relationship} = User.block(blocker, blocked)
1068 blocked = User.get_cached_by_id(blocked.id)
1070 assert User.blocks?(blocker, blocked)
1072 refute User.following?(blocker, blocked)
1073 refute User.following?(blocked, blocker)
1076 test "blocks tear down blocker->blocked follow relationships" do
1077 blocker = insert(:user)
1078 blocked = insert(:user)
1080 {:ok, blocker} = User.follow(blocker, blocked)
1082 assert User.following?(blocker, blocked)
1083 refute User.following?(blocked, blocker)
1085 {:ok, _user_relationship} = User.block(blocker, blocked)
1086 blocked = User.get_cached_by_id(blocked.id)
1088 assert User.blocks?(blocker, blocked)
1090 refute User.following?(blocker, blocked)
1091 refute User.following?(blocked, blocker)
1094 test "blocks tear down blocked->blocker follow relationships" do
1095 blocker = insert(:user)
1096 blocked = insert(:user)
1098 {:ok, blocked} = User.follow(blocked, blocker)
1100 refute User.following?(blocker, blocked)
1101 assert User.following?(blocked, blocker)
1103 {:ok, _user_relationship} = User.block(blocker, blocked)
1104 blocked = User.get_cached_by_id(blocked.id)
1106 assert User.blocks?(blocker, blocked)
1108 refute User.following?(blocker, blocked)
1109 refute User.following?(blocked, blocker)
1112 test "blocks tear down blocked->blocker subscription relationships" do
1113 blocker = insert(:user)
1114 blocked = insert(:user)
1116 {:ok, _subscription} = User.subscribe(blocked, blocker)
1118 assert User.subscribed_to?(blocked, blocker)
1119 refute User.subscribed_to?(blocker, blocked)
1121 {:ok, _user_relationship} = User.block(blocker, blocked)
1123 assert User.blocks?(blocker, blocked)
1124 refute User.subscribed_to?(blocker, blocked)
1125 refute User.subscribed_to?(blocked, blocker)
1129 describe "domain blocking" do
1130 test "blocks domains" do
1131 user = insert(:user)
1132 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1134 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1136 assert User.blocks?(user, collateral_user)
1139 test "does not block domain with same end" do
1140 user = insert(:user)
1143 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1145 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1147 refute User.blocks?(user, collateral_user)
1150 test "does not block domain with same end if wildcard added" do
1151 user = insert(:user)
1154 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1156 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1158 refute User.blocks?(user, collateral_user)
1161 test "blocks domain with wildcard for subdomain" do
1162 user = insert(:user)
1164 user_from_subdomain =
1165 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1167 user_with_two_subdomains =
1169 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1172 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1174 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1176 assert User.blocks?(user, user_from_subdomain)
1177 assert User.blocks?(user, user_with_two_subdomains)
1178 assert User.blocks?(user, user_domain)
1181 test "unblocks domains" do
1182 user = insert(:user)
1183 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1185 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1186 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1188 refute User.blocks?(user, collateral_user)
1191 test "follows take precedence over domain blocks" do
1192 user = insert(:user)
1193 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1195 {:ok, user} = User.block_domain(user, "meanies.social")
1196 {:ok, user} = User.follow(user, good_eggo)
1198 refute User.blocks?(user, good_eggo)
1202 describe "blocks_import" do
1203 test "it imports user blocks from list" do
1204 [user1, user2, user3] = insert_list(3, :user)
1211 {:ok, job} = User.blocks_import(user1, identifiers)
1213 assert {:ok, result} = ObanHelpers.perform(job)
1214 assert is_list(result)
1215 assert result == [user2, user3]
1219 describe "get_recipients_from_activity" do
1220 test "works for announces" do
1221 actor = insert(:user)
1222 user = insert(:user, local: true)
1224 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1225 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1227 recipients = User.get_recipients_from_activity(announce)
1229 assert user in recipients
1232 test "get recipients" do
1233 actor = insert(:user)
1234 user = insert(:user, local: true)
1235 user_two = insert(:user, local: false)
1236 addressed = insert(:user, local: true)
1237 addressed_remote = insert(:user, local: false)
1240 CommonAPI.post(actor, %{
1241 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1244 assert Enum.map([actor, addressed], & &1.ap_id) --
1245 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1247 {:ok, user} = User.follow(user, actor)
1248 {:ok, _user_two} = User.follow(user_two, actor)
1249 recipients = User.get_recipients_from_activity(activity)
1250 assert length(recipients) == 3
1251 assert user in recipients
1252 assert addressed in recipients
1255 test "has following" do
1256 actor = insert(:user)
1257 user = insert(:user)
1258 user_two = insert(:user)
1259 addressed = insert(:user, local: true)
1262 CommonAPI.post(actor, %{
1263 status: "hey @#{addressed.nickname}"
1266 assert Enum.map([actor, addressed], & &1.ap_id) --
1267 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1269 {:ok, _actor} = User.follow(actor, user)
1270 {:ok, _actor} = User.follow(actor, user_two)
1271 recipients = User.get_recipients_from_activity(activity)
1272 assert length(recipients) == 2
1273 assert addressed in recipients
1277 describe ".deactivate" do
1278 test "can de-activate then re-activate a user" do
1279 user = insert(:user)
1280 assert false == user.deactivated
1281 {:ok, user} = User.deactivate(user)
1282 assert true == user.deactivated
1283 {:ok, user} = User.deactivate(user, false)
1284 assert false == user.deactivated
1287 test "hide a user from followers" do
1288 user = insert(:user)
1289 user2 = insert(:user)
1291 {:ok, user} = User.follow(user, user2)
1292 {:ok, _user} = User.deactivate(user)
1294 user2 = User.get_cached_by_id(user2.id)
1296 assert user2.follower_count == 0
1297 assert [] = User.get_followers(user2)
1300 test "hide a user from friends" do
1301 user = insert(:user)
1302 user2 = insert(:user)
1304 {:ok, user2} = User.follow(user2, user)
1305 assert user2.following_count == 1
1306 assert User.following_count(user2) == 1
1308 {:ok, _user} = User.deactivate(user)
1310 user2 = User.get_cached_by_id(user2.id)
1312 assert refresh_record(user2).following_count == 0
1313 assert user2.following_count == 0
1314 assert User.following_count(user2) == 0
1315 assert [] = User.get_friends(user2)
1318 test "hide a user's statuses from timelines and notifications" do
1319 user = insert(:user)
1320 user2 = insert(:user)
1322 {:ok, user2} = User.follow(user2, user)
1324 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1326 activity = Repo.preload(activity, :bookmark)
1328 [notification] = Pleroma.Notification.for_user(user2)
1329 assert notification.activity.id == activity.id
1331 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1333 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1334 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1338 {:ok, _user} = User.deactivate(user)
1340 assert [] == ActivityPub.fetch_public_activities(%{})
1341 assert [] == Pleroma.Notification.for_user(user2)
1344 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1350 describe "approve" do
1351 test "approves a user" do
1352 user = insert(:user, approval_pending: true)
1353 assert true == user.approval_pending
1354 {:ok, user} = User.approve(user)
1355 assert false == user.approval_pending
1358 test "approves a list of users" do
1359 unapproved_users = [
1360 insert(:user, approval_pending: true),
1361 insert(:user, approval_pending: true),
1362 insert(:user, approval_pending: true)
1365 {:ok, users} = User.approve(unapproved_users)
1367 assert Enum.count(users) == 3
1369 Enum.each(users, fn user ->
1370 assert false == user.approval_pending
1375 describe "delete" do
1377 {:ok, user} = insert(:user) |> User.set_cache()
1382 setup do: clear_config([:instance, :federating])
1384 test ".delete_user_activities deletes all create activities", %{user: user} do
1385 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1387 User.delete_user_activities(user)
1389 # TODO: Test removal favorites, repeats, delete activities.
1390 refute Activity.get_by_id(activity.id)
1393 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1394 follower = insert(:user)
1395 {:ok, follower} = User.follow(follower, user)
1397 locked_user = insert(:user, name: "locked", locked: true)
1398 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1400 object = insert(:note, user: user)
1401 activity = insert(:note_activity, user: user, note: object)
1403 object_two = insert(:note, user: follower)
1404 activity_two = insert(:note_activity, user: follower, note: object_two)
1406 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1407 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1408 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1410 {:ok, job} = User.delete(user)
1411 {:ok, _user} = ObanHelpers.perform(job)
1413 follower = User.get_cached_by_id(follower.id)
1415 refute User.following?(follower, user)
1416 assert %{deactivated: true} = User.get_by_id(user.id)
1418 assert [] == User.get_follow_requests(locked_user)
1422 |> Activity.Queries.by_actor()
1424 |> Enum.map(fn act -> act.data["type"] end)
1426 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1428 refute Activity.get_by_id(activity.id)
1429 refute Activity.get_by_id(like.id)
1430 refute Activity.get_by_id(like_two.id)
1431 refute Activity.get_by_id(repeat.id)
1435 describe "delete/1 when confirmation is pending" do
1437 user = insert(:user, confirmation_pending: true)
1441 test "deletes user from database when activation required", %{user: user} do
1442 clear_config([:instance, :account_activation_required], true)
1444 {:ok, job} = User.delete(user)
1445 {:ok, _} = ObanHelpers.perform(job)
1447 refute User.get_cached_by_id(user.id)
1448 refute User.get_by_id(user.id)
1451 test "deactivates user when activation is not required", %{user: user} do
1452 clear_config([:instance, :account_activation_required], false)
1454 {:ok, job} = User.delete(user)
1455 {:ok, _} = ObanHelpers.perform(job)
1457 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1458 assert %{deactivated: true} = User.get_by_id(user.id)
1462 test "delete/1 when approval is pending deletes the user" do
1463 user = insert(:user, approval_pending: true)
1465 {:ok, job} = User.delete(user)
1466 {:ok, _} = ObanHelpers.perform(job)
1468 refute User.get_cached_by_id(user.id)
1469 refute User.get_by_id(user.id)
1472 test "delete/1 purges a user when they wouldn't be fully deleted" do
1477 password_hash: "pdfk2$1b3n159001",
1478 keys: "RSA begin buplic key",
1479 public_key: "--PRIVATE KEYE--",
1480 avatar: %{"a" => "b"},
1482 banner: %{"a" => "b"},
1483 background: %{"a" => "b"},
1486 following_count: 9001,
1488 confirmation_pending: true,
1489 password_reset_pending: true,
1490 approval_pending: true,
1491 registration_reason: "ahhhhh",
1492 confirmation_token: "qqqq",
1493 domain_blocks: ["lain.com"],
1498 mastofe_settings: %{"a" => "b"},
1499 mascot: %{"a" => "b"},
1500 emoji: %{"a" => "b"},
1501 pleroma_settings_store: %{"q" => "x"},
1502 fields: [%{"gg" => "qq"}],
1503 raw_fields: [%{"gg" => "qq"}],
1505 also_known_as: ["https://lol.olo/users/loll"]
1508 {:ok, job} = User.delete(user)
1509 {:ok, _} = ObanHelpers.perform(job)
1510 user = User.get_by_id(user.id)
1522 last_refreshed_at: nil,
1523 last_digest_emailed_at: nil,
1530 confirmation_pending: false,
1531 password_reset_pending: false,
1532 approval_pending: false,
1533 registration_reason: nil,
1534 confirmation_token: nil,
1538 is_moderator: false,
1540 mastofe_settings: nil,
1543 pleroma_settings_store: %{},
1546 discoverable: false,
1551 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1552 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1555 describe "per-user rich-text filtering" do
1556 test "html_filter_policy returns default policies, when rich-text is enabled" do
1557 user = insert(:user)
1559 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1562 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1563 user = insert(:user, no_rich_text: true)
1565 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1569 describe "caching" do
1570 test "invalidate_cache works" do
1571 user = insert(:user)
1573 User.set_cache(user)
1574 User.invalidate_cache(user)
1576 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1577 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1580 test "User.delete() plugs any possible zombie objects" do
1581 user = insert(:user)
1583 {:ok, job} = User.delete(user)
1584 {:ok, _} = ObanHelpers.perform(job)
1586 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1588 assert cached_user != user
1590 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1592 assert cached_user != user
1596 describe "account_status/1" do
1597 setup do: clear_config([:instance, :account_activation_required])
1599 test "return confirmation_pending for unconfirm user" do
1600 Pleroma.Config.put([:instance, :account_activation_required], true)
1601 user = insert(:user, confirmation_pending: true)
1602 assert User.account_status(user) == :confirmation_pending
1605 test "return active for confirmed user" do
1606 Pleroma.Config.put([:instance, :account_activation_required], true)
1607 user = insert(:user, confirmation_pending: false)
1608 assert User.account_status(user) == :active
1611 test "return active for remote user" do
1612 user = insert(:user, local: false)
1613 assert User.account_status(user) == :active
1616 test "returns :password_reset_pending for user with reset password" do
1617 user = insert(:user, password_reset_pending: true)
1618 assert User.account_status(user) == :password_reset_pending
1621 test "returns :deactivated for deactivated user" do
1622 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1623 assert User.account_status(user) == :deactivated
1626 test "returns :approval_pending for unapproved user" do
1627 user = insert(:user, local: true, approval_pending: true)
1628 assert User.account_status(user) == :approval_pending
1630 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1631 assert User.account_status(user) == :approval_pending
1635 describe "superuser?/1" do
1636 test "returns false for unprivileged users" do
1637 user = insert(:user, local: true)
1639 refute User.superuser?(user)
1642 test "returns false for remote users" do
1643 user = insert(:user, local: false)
1644 remote_admin_user = insert(:user, local: false, is_admin: true)
1646 refute User.superuser?(user)
1647 refute User.superuser?(remote_admin_user)
1650 test "returns true for local moderators" do
1651 user = insert(:user, local: true, is_moderator: true)
1653 assert User.superuser?(user)
1656 test "returns true for local admins" do
1657 user = insert(:user, local: true, is_admin: true)
1659 assert User.superuser?(user)
1663 describe "invisible?/1" do
1664 test "returns true for an invisible user" do
1665 user = insert(:user, local: true, invisible: true)
1667 assert User.invisible?(user)
1670 test "returns false for a non-invisible user" do
1671 user = insert(:user, local: true)
1673 refute User.invisible?(user)
1677 describe "visible_for/2" do
1678 test "returns true when the account is itself" do
1679 user = insert(:user, local: true)
1681 assert User.visible_for(user, user) == :visible
1684 test "returns false when the account is unauthenticated and auth is required" do
1685 Pleroma.Config.put([:instance, :account_activation_required], true)
1687 user = insert(:user, local: true, confirmation_pending: true)
1688 other_user = insert(:user, local: true)
1690 refute User.visible_for(user, other_user) == :visible
1693 test "returns true when the account is unauthenticated and auth is not required" do
1694 user = insert(:user, local: true, confirmation_pending: true)
1695 other_user = insert(:user, local: true)
1697 assert User.visible_for(user, other_user) == :visible
1700 test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do
1701 Pleroma.Config.put([:instance, :account_activation_required], true)
1703 user = insert(:user, local: true, confirmation_pending: true)
1704 other_user = insert(:user, local: true, is_admin: true)
1706 assert User.visible_for(user, other_user) == :visible
1710 describe "parse_bio/2" do
1711 test "preserves hosts in user links text" do
1712 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1713 user = insert(:user)
1714 bio = "A.k.a. @nick@domain.com"
1717 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1719 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1721 assert expected_text == User.parse_bio(bio, user)
1724 test "Adds rel=me on linkbacked urls" do
1725 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1727 bio = "http://example.com/rel_me/null"
1728 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1729 assert expected_text == User.parse_bio(bio, user)
1731 bio = "http://example.com/rel_me/link"
1732 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1733 assert expected_text == User.parse_bio(bio, user)
1735 bio = "http://example.com/rel_me/anchor"
1736 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1737 assert expected_text == User.parse_bio(bio, user)
1741 test "follower count is updated when a follower is blocked" do
1742 user = insert(:user)
1743 follower = insert(:user)
1744 follower2 = insert(:user)
1745 follower3 = insert(:user)
1747 {:ok, follower} = User.follow(follower, user)
1748 {:ok, _follower2} = User.follow(follower2, user)
1749 {:ok, _follower3} = User.follow(follower3, user)
1751 {:ok, _user_relationship} = User.block(user, follower)
1752 user = refresh_record(user)
1754 assert user.follower_count == 2
1757 describe "list_inactive_users_query/1" do
1758 defp days_ago(days) do
1760 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1761 -days * 60 * 60 * 24,
1766 test "Users are inactive by default" do
1770 Enum.map(1..total, fn _ ->
1771 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1774 inactive_users_ids =
1775 Pleroma.User.list_inactive_users_query()
1776 |> Pleroma.Repo.all()
1777 |> Enum.map(& &1.id)
1779 Enum.each(users, fn user ->
1780 assert user.id in inactive_users_ids
1784 test "Only includes users who has no recent activity" do
1788 Enum.map(1..total, fn _ ->
1789 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1792 {inactive, active} = Enum.split(users, trunc(total / 2))
1794 Enum.map(active, fn user ->
1795 to = Enum.random(users -- [user])
1798 CommonAPI.post(user, %{
1799 status: "hey @#{to.nickname}"
1803 inactive_users_ids =
1804 Pleroma.User.list_inactive_users_query()
1805 |> Pleroma.Repo.all()
1806 |> Enum.map(& &1.id)
1808 Enum.each(active, fn user ->
1809 refute user.id in inactive_users_ids
1812 Enum.each(inactive, fn user ->
1813 assert user.id in inactive_users_ids
1817 test "Only includes users with no read notifications" do
1821 Enum.map(1..total, fn _ ->
1822 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1825 [sender | recipients] = users
1826 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1828 Enum.each(recipients, fn to ->
1830 CommonAPI.post(sender, %{
1831 status: "hey @#{to.nickname}"
1835 CommonAPI.post(sender, %{
1836 status: "hey again @#{to.nickname}"
1840 Enum.each(active, fn user ->
1841 [n1, _n2] = Pleroma.Notification.for_user(user)
1842 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1845 inactive_users_ids =
1846 Pleroma.User.list_inactive_users_query()
1847 |> Pleroma.Repo.all()
1848 |> Enum.map(& &1.id)
1850 Enum.each(active, fn user ->
1851 refute user.id in inactive_users_ids
1854 Enum.each(inactive, fn user ->
1855 assert user.id in inactive_users_ids
1860 describe "toggle_confirmation/1" do
1861 test "if user is confirmed" do
1862 user = insert(:user, confirmation_pending: false)
1863 {:ok, user} = User.toggle_confirmation(user)
1865 assert user.confirmation_pending
1866 assert user.confirmation_token
1869 test "if user is unconfirmed" do
1870 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1871 {:ok, user} = User.toggle_confirmation(user)
1873 refute user.confirmation_pending
1874 refute user.confirmation_token
1878 describe "ensure_keys_present" do
1879 test "it creates keys for a user and stores them in info" do
1880 user = insert(:user)
1881 refute is_binary(user.keys)
1882 {:ok, user} = User.ensure_keys_present(user)
1883 assert is_binary(user.keys)
1886 test "it doesn't create keys if there already are some" do
1887 user = insert(:user, keys: "xxx")
1888 {:ok, user} = User.ensure_keys_present(user)
1889 assert user.keys == "xxx"
1893 describe "get_ap_ids_by_nicknames" do
1894 test "it returns a list of AP ids for a given set of nicknames" do
1895 user = insert(:user)
1896 user_two = insert(:user)
1898 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1899 assert length(ap_ids) == 2
1900 assert user.ap_id in ap_ids
1901 assert user_two.ap_id in ap_ids
1905 describe "sync followers count" do
1907 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1908 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1909 insert(:user, local: true)
1910 insert(:user, local: false, deactivated: true)
1911 {:ok, user1: user1, user2: user2}
1914 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1915 [fdb_user1] = User.external_users(limit: 1)
1917 assert fdb_user1.ap_id
1918 assert fdb_user1.ap_id == user1.ap_id
1919 assert fdb_user1.id == user1.id
1921 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1923 assert fdb_user2.ap_id
1924 assert fdb_user2.ap_id == user2.ap_id
1925 assert fdb_user2.id == user2.id
1927 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1931 describe "is_internal_user?/1" do
1932 test "non-internal user returns false" do
1933 user = insert(:user)
1934 refute User.is_internal_user?(user)
1937 test "user with no nickname returns true" do
1938 user = insert(:user, %{nickname: nil})
1939 assert User.is_internal_user?(user)
1942 test "user with internal-prefixed nickname returns true" do
1943 user = insert(:user, %{nickname: "internal.test"})
1944 assert User.is_internal_user?(user)
1948 describe "update_and_set_cache/1" do
1949 test "returns error when user is stale instead Ecto.StaleEntryError" do
1950 user = insert(:user)
1952 changeset = Ecto.Changeset.change(user, bio: "test")
1956 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1957 User.update_and_set_cache(changeset)
1960 test "performs update cache if user updated" do
1961 user = insert(:user)
1962 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1964 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1966 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1967 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1968 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1972 describe "following/followers synchronization" do
1973 setup do: clear_config([:instance, :external_user_synchronization])
1975 test "updates the counters normally on following/getting a follow when disabled" do
1976 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1977 user = insert(:user)
1982 follower_address: "http://localhost:4001/users/masto_closed/followers",
1983 following_address: "http://localhost:4001/users/masto_closed/following",
1987 assert other_user.following_count == 0
1988 assert other_user.follower_count == 0
1990 {:ok, user} = Pleroma.User.follow(user, other_user)
1991 other_user = Pleroma.User.get_by_id(other_user.id)
1993 assert user.following_count == 1
1994 assert other_user.follower_count == 1
1997 test "syncronizes the counters with the remote instance for the followed when enabled" do
1998 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2000 user = insert(:user)
2005 follower_address: "http://localhost:4001/users/masto_closed/followers",
2006 following_address: "http://localhost:4001/users/masto_closed/following",
2010 assert other_user.following_count == 0
2011 assert other_user.follower_count == 0
2013 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2014 {:ok, _user} = User.follow(user, other_user)
2015 other_user = User.get_by_id(other_user.id)
2017 assert other_user.follower_count == 437
2020 test "syncronizes the counters with the remote instance for the follower when enabled" do
2021 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2023 user = insert(:user)
2028 follower_address: "http://localhost:4001/users/masto_closed/followers",
2029 following_address: "http://localhost:4001/users/masto_closed/following",
2033 assert other_user.following_count == 0
2034 assert other_user.follower_count == 0
2036 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2037 {:ok, other_user} = User.follow(other_user, user)
2039 assert other_user.following_count == 152
2043 describe "change_email/2" do
2045 [user: insert(:user)]
2048 test "blank email returns error", %{user: user} do
2049 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2050 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2053 test "non unique email returns error", %{user: user} do
2054 %{email: email} = insert(:user)
2056 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2057 User.change_email(user, email)
2060 test "invalid email returns error", %{user: user} do
2061 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2062 User.change_email(user, "cofe")
2065 test "changes email", %{user: user} do
2066 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2070 describe "get_cached_by_nickname_or_id" do
2072 local_user = insert(:user)
2073 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2075 [local_user: local_user, remote_user: remote_user]
2078 setup do: clear_config([:instance, :limit_to_local_content])
2080 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2081 remote_user: remote_user
2083 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2084 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2086 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2087 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2089 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2090 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2093 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2094 %{remote_user: remote_user} do
2095 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2096 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2099 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2100 %{remote_user: remote_user, local_user: local_user} do
2101 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2102 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2105 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2106 %{remote_user: remote_user} do
2107 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2108 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2111 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2112 %{local_user: local_user} do
2113 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2114 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2116 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2117 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2119 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2120 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2124 describe "update_email_notifications/2" do
2126 user = insert(:user, email_notifications: %{"digest" => true})
2131 test "Notifications are updated", %{user: user} do
2132 true = user.email_notifications["digest"]
2133 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2134 assert result.email_notifications["digest"] == false
2138 test "avatar fallback" do
2139 user = insert(:user)
2140 assert User.avatar_url(user) =~ "/images/avi.png"
2142 clear_config([:assets, :default_user_avatar], "avatar.png")
2144 user = User.get_cached_by_nickname_or_id(user.nickname)
2145 assert User.avatar_url(user) =~ "avatar.png"
2147 assert User.avatar_url(user, no_default: true) == nil