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, is_locked: true)
178 follower = insert(:user)
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, is_locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
200 assert [^pending_follower] = User.get_follow_requests(locked)
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, is_locked: true)
205 pending_follower = insert(:user, %{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, is_locked: true)
215 follower = insert(:user)
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
224 test "follow_all follows mutliple users" do
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
236 {:ok, user} = 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, is_locked: true)
303 followed = insert(:user, is_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))
881 test "it is invalid given a local user" do
883 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
889 describe "followers and friends" do
890 test "gets all followers for a given user" do
892 follower_one = insert(:user)
893 follower_two = insert(:user)
894 not_follower = insert(:user)
896 {:ok, follower_one} = User.follow(follower_one, user)
897 {:ok, follower_two} = User.follow(follower_two, user)
899 res = User.get_followers(user)
901 assert Enum.member?(res, follower_one)
902 assert Enum.member?(res, follower_two)
903 refute Enum.member?(res, not_follower)
906 test "gets all friends (followed users) for a given user" do
908 followed_one = insert(:user)
909 followed_two = insert(:user)
910 not_followed = insert(:user)
912 {:ok, user} = User.follow(user, followed_one)
913 {:ok, user} = User.follow(user, followed_two)
915 res = User.get_friends(user)
917 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
918 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
919 assert Enum.member?(res, followed_one)
920 assert Enum.member?(res, followed_two)
921 refute Enum.member?(res, not_followed)
925 describe "updating note and follower count" do
926 test "it sets the note_count property" do
929 user = User.get_cached_by_ap_id(note.data["actor"])
931 assert user.note_count == 0
933 {:ok, user} = User.update_note_count(user)
935 assert user.note_count == 1
938 test "it increases the note_count property" do
940 user = User.get_cached_by_ap_id(note.data["actor"])
942 assert user.note_count == 0
944 {:ok, user} = User.increase_note_count(user)
946 assert user.note_count == 1
948 {:ok, user} = User.increase_note_count(user)
950 assert user.note_count == 2
953 test "it decreases the note_count property" do
955 user = User.get_cached_by_ap_id(note.data["actor"])
957 assert user.note_count == 0
959 {:ok, user} = User.increase_note_count(user)
961 assert user.note_count == 1
963 {:ok, user} = User.decrease_note_count(user)
965 assert user.note_count == 0
967 {:ok, user} = User.decrease_note_count(user)
969 assert user.note_count == 0
972 test "it sets the follower_count property" do
974 follower = insert(:user)
976 User.follow(follower, user)
978 assert user.follower_count == 0
980 {:ok, user} = User.update_follower_count(user)
982 assert user.follower_count == 1
987 test "it mutes people" do
989 muted_user = insert(:user)
991 refute User.mutes?(user, muted_user)
992 refute User.muted_notifications?(user, muted_user)
994 {:ok, _user_relationships} = User.mute(user, muted_user)
996 assert User.mutes?(user, muted_user)
997 assert User.muted_notifications?(user, muted_user)
1000 test "it unmutes users" do
1001 user = insert(:user)
1002 muted_user = insert(:user)
1004 {:ok, _user_relationships} = User.mute(user, muted_user)
1005 {:ok, _user_mute} = User.unmute(user, muted_user)
1007 refute User.mutes?(user, muted_user)
1008 refute User.muted_notifications?(user, muted_user)
1011 test "it mutes user without notifications" do
1012 user = insert(:user)
1013 muted_user = insert(:user)
1015 refute User.mutes?(user, muted_user)
1016 refute User.muted_notifications?(user, muted_user)
1018 {:ok, _user_relationships} = User.mute(user, muted_user, false)
1020 assert User.mutes?(user, muted_user)
1021 refute User.muted_notifications?(user, muted_user)
1025 describe "blocks" do
1026 test "it blocks people" do
1027 user = insert(:user)
1028 blocked_user = insert(:user)
1030 refute User.blocks?(user, blocked_user)
1032 {:ok, _user_relationship} = User.block(user, blocked_user)
1034 assert User.blocks?(user, blocked_user)
1037 test "it unblocks users" do
1038 user = insert(:user)
1039 blocked_user = insert(:user)
1041 {:ok, _user_relationship} = User.block(user, blocked_user)
1042 {:ok, _user_block} = User.unblock(user, blocked_user)
1044 refute User.blocks?(user, blocked_user)
1047 test "blocks tear down cyclical follow relationships" do
1048 blocker = insert(:user)
1049 blocked = insert(:user)
1051 {:ok, blocker} = User.follow(blocker, blocked)
1052 {:ok, blocked} = User.follow(blocked, blocker)
1054 assert User.following?(blocker, blocked)
1055 assert User.following?(blocked, blocker)
1057 {:ok, _user_relationship} = User.block(blocker, blocked)
1058 blocked = User.get_cached_by_id(blocked.id)
1060 assert User.blocks?(blocker, blocked)
1062 refute User.following?(blocker, blocked)
1063 refute User.following?(blocked, blocker)
1066 test "blocks tear down blocker->blocked follow relationships" do
1067 blocker = insert(:user)
1068 blocked = insert(:user)
1070 {:ok, blocker} = User.follow(blocker, blocked)
1072 assert User.following?(blocker, blocked)
1073 refute User.following?(blocked, blocker)
1075 {:ok, _user_relationship} = User.block(blocker, blocked)
1076 blocked = User.get_cached_by_id(blocked.id)
1078 assert User.blocks?(blocker, blocked)
1080 refute User.following?(blocker, blocked)
1081 refute User.following?(blocked, blocker)
1084 test "blocks tear down blocked->blocker follow relationships" do
1085 blocker = insert(:user)
1086 blocked = insert(:user)
1088 {:ok, blocked} = User.follow(blocked, blocker)
1090 refute User.following?(blocker, blocked)
1091 assert User.following?(blocked, blocker)
1093 {:ok, _user_relationship} = User.block(blocker, blocked)
1094 blocked = User.get_cached_by_id(blocked.id)
1096 assert User.blocks?(blocker, blocked)
1098 refute User.following?(blocker, blocked)
1099 refute User.following?(blocked, blocker)
1102 test "blocks tear down blocked->blocker subscription relationships" do
1103 blocker = insert(:user)
1104 blocked = insert(:user)
1106 {:ok, _subscription} = User.subscribe(blocked, blocker)
1108 assert User.subscribed_to?(blocked, blocker)
1109 refute User.subscribed_to?(blocker, blocked)
1111 {:ok, _user_relationship} = User.block(blocker, blocked)
1113 assert User.blocks?(blocker, blocked)
1114 refute User.subscribed_to?(blocker, blocked)
1115 refute User.subscribed_to?(blocked, blocker)
1119 describe "domain blocking" do
1120 test "blocks domains" do
1121 user = insert(:user)
1122 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1124 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1126 assert User.blocks?(user, collateral_user)
1129 test "does not block domain with same end" do
1130 user = insert(:user)
1133 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1135 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1137 refute User.blocks?(user, collateral_user)
1140 test "does not block domain with same end if wildcard added" do
1141 user = insert(:user)
1144 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1146 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1148 refute User.blocks?(user, collateral_user)
1151 test "blocks domain with wildcard for subdomain" do
1152 user = insert(:user)
1154 user_from_subdomain =
1155 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1157 user_with_two_subdomains =
1159 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1162 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1164 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1166 assert User.blocks?(user, user_from_subdomain)
1167 assert User.blocks?(user, user_with_two_subdomains)
1168 assert User.blocks?(user, user_domain)
1171 test "unblocks domains" do
1172 user = insert(:user)
1173 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1175 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1176 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1178 refute User.blocks?(user, collateral_user)
1181 test "follows take precedence over domain blocks" do
1182 user = insert(:user)
1183 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1185 {:ok, user} = User.block_domain(user, "meanies.social")
1186 {:ok, user} = User.follow(user, good_eggo)
1188 refute User.blocks?(user, good_eggo)
1192 describe "get_recipients_from_activity" do
1193 test "works for announces" do
1194 actor = insert(:user)
1195 user = insert(:user, local: true)
1197 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1198 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1200 recipients = User.get_recipients_from_activity(announce)
1202 assert user in recipients
1205 test "get recipients" do
1206 actor = insert(:user)
1207 user = insert(:user, local: true)
1208 user_two = insert(:user, local: false)
1209 addressed = insert(:user, local: true)
1210 addressed_remote = insert(:user, local: false)
1213 CommonAPI.post(actor, %{
1214 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1217 assert Enum.map([actor, addressed], & &1.ap_id) --
1218 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1220 {:ok, user} = User.follow(user, actor)
1221 {:ok, _user_two} = User.follow(user_two, actor)
1222 recipients = User.get_recipients_from_activity(activity)
1223 assert length(recipients) == 3
1224 assert user in recipients
1225 assert addressed in recipients
1228 test "has following" do
1229 actor = insert(:user)
1230 user = insert(:user)
1231 user_two = insert(:user)
1232 addressed = insert(:user, local: true)
1235 CommonAPI.post(actor, %{
1236 status: "hey @#{addressed.nickname}"
1239 assert Enum.map([actor, addressed], & &1.ap_id) --
1240 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1242 {:ok, _actor} = User.follow(actor, user)
1243 {:ok, _actor} = User.follow(actor, user_two)
1244 recipients = User.get_recipients_from_activity(activity)
1245 assert length(recipients) == 2
1246 assert addressed in recipients
1250 describe ".deactivate" do
1251 test "can de-activate then re-activate a user" do
1252 user = insert(:user)
1253 assert false == user.deactivated
1254 {:ok, user} = User.deactivate(user)
1255 assert true == user.deactivated
1256 {:ok, user} = User.deactivate(user, false)
1257 assert false == user.deactivated
1260 test "hide a user from followers" do
1261 user = insert(:user)
1262 user2 = insert(:user)
1264 {:ok, user} = User.follow(user, user2)
1265 {:ok, _user} = User.deactivate(user)
1267 user2 = User.get_cached_by_id(user2.id)
1269 assert user2.follower_count == 0
1270 assert [] = User.get_followers(user2)
1273 test "hide a user from friends" do
1274 user = insert(:user)
1275 user2 = insert(:user)
1277 {:ok, user2} = User.follow(user2, user)
1278 assert user2.following_count == 1
1279 assert User.following_count(user2) == 1
1281 {:ok, _user} = User.deactivate(user)
1283 user2 = User.get_cached_by_id(user2.id)
1285 assert refresh_record(user2).following_count == 0
1286 assert user2.following_count == 0
1287 assert User.following_count(user2) == 0
1288 assert [] = User.get_friends(user2)
1291 test "hide a user's statuses from timelines and notifications" do
1292 user = insert(:user)
1293 user2 = insert(:user)
1295 {:ok, user2} = User.follow(user2, user)
1297 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1299 activity = Repo.preload(activity, :bookmark)
1301 [notification] = Pleroma.Notification.for_user(user2)
1302 assert notification.activity.id == activity.id
1304 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1306 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1307 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1311 {:ok, _user} = User.deactivate(user)
1313 assert [] == ActivityPub.fetch_public_activities(%{})
1314 assert [] == Pleroma.Notification.for_user(user2)
1317 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1323 describe "approve" do
1324 test "approves a user" do
1325 user = insert(:user, approval_pending: true)
1326 assert true == user.approval_pending
1327 {:ok, user} = User.approve(user)
1328 assert false == user.approval_pending
1331 test "approves a list of users" do
1332 unapproved_users = [
1333 insert(:user, approval_pending: true),
1334 insert(:user, approval_pending: true),
1335 insert(:user, approval_pending: true)
1338 {:ok, users} = User.approve(unapproved_users)
1340 assert Enum.count(users) == 3
1342 Enum.each(users, fn user ->
1343 assert false == user.approval_pending
1348 describe "delete" do
1350 {:ok, user} = insert(:user) |> User.set_cache()
1355 setup do: clear_config([:instance, :federating])
1357 test ".delete_user_activities deletes all create activities", %{user: user} do
1358 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1360 User.delete_user_activities(user)
1362 # TODO: Test removal favorites, repeats, delete activities.
1363 refute Activity.get_by_id(activity.id)
1366 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1367 follower = insert(:user)
1368 {:ok, follower} = User.follow(follower, user)
1370 locked_user = insert(:user, name: "locked", is_locked: true)
1371 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1373 object = insert(:note, user: user)
1374 activity = insert(:note_activity, user: user, note: object)
1376 object_two = insert(:note, user: follower)
1377 activity_two = insert(:note_activity, user: follower, note: object_two)
1379 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1380 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1381 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1383 {:ok, job} = User.delete(user)
1384 {:ok, _user} = ObanHelpers.perform(job)
1386 follower = User.get_cached_by_id(follower.id)
1388 refute User.following?(follower, user)
1389 assert %{deactivated: true} = User.get_by_id(user.id)
1391 assert [] == User.get_follow_requests(locked_user)
1395 |> Activity.Queries.by_actor()
1397 |> Enum.map(fn act -> act.data["type"] end)
1399 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1401 refute Activity.get_by_id(activity.id)
1402 refute Activity.get_by_id(like.id)
1403 refute Activity.get_by_id(like_two.id)
1404 refute Activity.get_by_id(repeat.id)
1408 describe "delete/1 when confirmation is pending" do
1410 user = insert(:user, confirmation_pending: true)
1414 test "deletes user from database when activation required", %{user: user} do
1415 clear_config([:instance, :account_activation_required], true)
1417 {:ok, job} = User.delete(user)
1418 {:ok, _} = ObanHelpers.perform(job)
1420 refute User.get_cached_by_id(user.id)
1421 refute User.get_by_id(user.id)
1424 test "deactivates user when activation is not required", %{user: user} do
1425 clear_config([:instance, :account_activation_required], false)
1427 {:ok, job} = User.delete(user)
1428 {:ok, _} = ObanHelpers.perform(job)
1430 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1431 assert %{deactivated: true} = User.get_by_id(user.id)
1435 test "delete/1 when approval is pending deletes the user" do
1436 user = insert(:user, approval_pending: true)
1438 {:ok, job} = User.delete(user)
1439 {:ok, _} = ObanHelpers.perform(job)
1441 refute User.get_cached_by_id(user.id)
1442 refute User.get_by_id(user.id)
1445 test "delete/1 purges a user when they wouldn't be fully deleted" do
1450 password_hash: "pdfk2$1b3n159001",
1451 keys: "RSA begin buplic key",
1452 public_key: "--PRIVATE KEYE--",
1453 avatar: %{"a" => "b"},
1455 banner: %{"a" => "b"},
1456 background: %{"a" => "b"},
1459 following_count: 9001,
1461 confirmation_pending: true,
1462 password_reset_pending: true,
1463 approval_pending: true,
1464 registration_reason: "ahhhhh",
1465 confirmation_token: "qqqq",
1466 domain_blocks: ["lain.com"],
1471 mastofe_settings: %{"a" => "b"},
1472 mascot: %{"a" => "b"},
1473 emoji: %{"a" => "b"},
1474 pleroma_settings_store: %{"q" => "x"},
1475 fields: [%{"gg" => "qq"}],
1476 raw_fields: [%{"gg" => "qq"}],
1478 also_known_as: ["https://lol.olo/users/loll"]
1481 {:ok, job} = User.delete(user)
1482 {:ok, _} = ObanHelpers.perform(job)
1483 user = User.get_by_id(user.id)
1495 last_refreshed_at: nil,
1496 last_digest_emailed_at: nil,
1503 confirmation_pending: false,
1504 password_reset_pending: false,
1505 approval_pending: false,
1506 registration_reason: nil,
1507 confirmation_token: nil,
1511 is_moderator: false,
1513 mastofe_settings: nil,
1516 pleroma_settings_store: %{},
1519 discoverable: false,
1524 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1525 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1528 describe "per-user rich-text filtering" do
1529 test "html_filter_policy returns default policies, when rich-text is enabled" do
1530 user = insert(:user)
1532 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1535 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1536 user = insert(:user, no_rich_text: true)
1538 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1542 describe "caching" do
1543 test "invalidate_cache works" do
1544 user = insert(:user)
1546 User.set_cache(user)
1547 User.invalidate_cache(user)
1549 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1550 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1553 test "User.delete() plugs any possible zombie objects" do
1554 user = insert(:user)
1556 {:ok, job} = User.delete(user)
1557 {:ok, _} = ObanHelpers.perform(job)
1559 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1561 assert cached_user != user
1563 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1565 assert cached_user != user
1569 describe "account_status/1" do
1570 setup do: clear_config([:instance, :account_activation_required])
1572 test "return confirmation_pending for unconfirm user" do
1573 Pleroma.Config.put([:instance, :account_activation_required], true)
1574 user = insert(:user, confirmation_pending: true)
1575 assert User.account_status(user) == :confirmation_pending
1578 test "return active for confirmed user" do
1579 Pleroma.Config.put([:instance, :account_activation_required], true)
1580 user = insert(:user, confirmation_pending: false)
1581 assert User.account_status(user) == :active
1584 test "return active for remote user" do
1585 user = insert(:user, local: false)
1586 assert User.account_status(user) == :active
1589 test "returns :password_reset_pending for user with reset password" do
1590 user = insert(:user, password_reset_pending: true)
1591 assert User.account_status(user) == :password_reset_pending
1594 test "returns :deactivated for deactivated user" do
1595 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1596 assert User.account_status(user) == :deactivated
1599 test "returns :approval_pending for unapproved user" do
1600 user = insert(:user, local: true, approval_pending: true)
1601 assert User.account_status(user) == :approval_pending
1603 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1604 assert User.account_status(user) == :approval_pending
1608 describe "superuser?/1" do
1609 test "returns false for unprivileged users" do
1610 user = insert(:user, local: true)
1612 refute User.superuser?(user)
1615 test "returns false for remote users" do
1616 user = insert(:user, local: false)
1617 remote_admin_user = insert(:user, local: false, is_admin: true)
1619 refute User.superuser?(user)
1620 refute User.superuser?(remote_admin_user)
1623 test "returns true for local moderators" do
1624 user = insert(:user, local: true, is_moderator: true)
1626 assert User.superuser?(user)
1629 test "returns true for local admins" do
1630 user = insert(:user, local: true, is_admin: true)
1632 assert User.superuser?(user)
1636 describe "invisible?/1" do
1637 test "returns true for an invisible user" do
1638 user = insert(:user, local: true, invisible: true)
1640 assert User.invisible?(user)
1643 test "returns false for a non-invisible user" do
1644 user = insert(:user, local: true)
1646 refute User.invisible?(user)
1650 describe "visible_for/2" do
1651 test "returns true when the account is itself" do
1652 user = insert(:user, local: true)
1654 assert User.visible_for(user, user) == :visible
1657 test "returns false when the account is unconfirmed and confirmation is required" do
1658 Pleroma.Config.put([:instance, :account_activation_required], true)
1660 user = insert(:user, local: true, confirmation_pending: true)
1661 other_user = insert(:user, local: true)
1663 refute User.visible_for(user, other_user) == :visible
1666 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1667 Pleroma.Config.put([:instance, :account_activation_required], true)
1669 user = insert(:user, local: false, confirmation_pending: true)
1670 other_user = insert(:user, local: true)
1672 assert User.visible_for(user, other_user) == :visible
1675 test "returns true when the account is unconfirmed and confirmation is not required" do
1676 user = insert(:user, local: true, confirmation_pending: true)
1677 other_user = insert(:user, local: true)
1679 assert User.visible_for(user, other_user) == :visible
1682 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1683 Pleroma.Config.put([:instance, :account_activation_required], true)
1685 user = insert(:user, local: true, confirmation_pending: true)
1686 other_user = insert(:user, local: true, is_admin: true)
1688 assert User.visible_for(user, other_user) == :visible
1692 describe "parse_bio/2" do
1693 test "preserves hosts in user links text" do
1694 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1695 user = insert(:user)
1696 bio = "A.k.a. @nick@domain.com"
1699 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1701 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1703 assert expected_text == User.parse_bio(bio, user)
1706 test "Adds rel=me on linkbacked urls" do
1707 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1709 bio = "http://example.com/rel_me/null"
1710 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1711 assert expected_text == User.parse_bio(bio, user)
1713 bio = "http://example.com/rel_me/link"
1714 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1715 assert expected_text == User.parse_bio(bio, user)
1717 bio = "http://example.com/rel_me/anchor"
1718 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1719 assert expected_text == User.parse_bio(bio, user)
1723 test "follower count is updated when a follower is blocked" do
1724 user = insert(:user)
1725 follower = insert(:user)
1726 follower2 = insert(:user)
1727 follower3 = insert(:user)
1729 {:ok, follower} = User.follow(follower, user)
1730 {:ok, _follower2} = User.follow(follower2, user)
1731 {:ok, _follower3} = User.follow(follower3, user)
1733 {:ok, _user_relationship} = User.block(user, follower)
1734 user = refresh_record(user)
1736 assert user.follower_count == 2
1739 describe "list_inactive_users_query/1" do
1740 defp days_ago(days) do
1742 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1743 -days * 60 * 60 * 24,
1748 test "Users are inactive by default" do
1752 Enum.map(1..total, fn _ ->
1753 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1756 inactive_users_ids =
1757 Pleroma.User.list_inactive_users_query()
1758 |> Pleroma.Repo.all()
1759 |> Enum.map(& &1.id)
1761 Enum.each(users, fn user ->
1762 assert user.id in inactive_users_ids
1766 test "Only includes users who has no recent activity" do
1770 Enum.map(1..total, fn _ ->
1771 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1774 {inactive, active} = Enum.split(users, trunc(total / 2))
1776 Enum.map(active, fn user ->
1777 to = Enum.random(users -- [user])
1780 CommonAPI.post(user, %{
1781 status: "hey @#{to.nickname}"
1785 inactive_users_ids =
1786 Pleroma.User.list_inactive_users_query()
1787 |> Pleroma.Repo.all()
1788 |> Enum.map(& &1.id)
1790 Enum.each(active, fn user ->
1791 refute user.id in inactive_users_ids
1794 Enum.each(inactive, fn user ->
1795 assert user.id in inactive_users_ids
1799 test "Only includes users with no read notifications" do
1803 Enum.map(1..total, fn _ ->
1804 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1807 [sender | recipients] = users
1808 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1810 Enum.each(recipients, fn to ->
1812 CommonAPI.post(sender, %{
1813 status: "hey @#{to.nickname}"
1817 CommonAPI.post(sender, %{
1818 status: "hey again @#{to.nickname}"
1822 Enum.each(active, fn user ->
1823 [n1, _n2] = Pleroma.Notification.for_user(user)
1824 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1827 inactive_users_ids =
1828 Pleroma.User.list_inactive_users_query()
1829 |> Pleroma.Repo.all()
1830 |> Enum.map(& &1.id)
1832 Enum.each(active, fn user ->
1833 refute user.id in inactive_users_ids
1836 Enum.each(inactive, fn user ->
1837 assert user.id in inactive_users_ids
1842 describe "toggle_confirmation/1" do
1843 test "if user is confirmed" do
1844 user = insert(:user, confirmation_pending: false)
1845 {:ok, user} = User.toggle_confirmation(user)
1847 assert user.confirmation_pending
1848 assert user.confirmation_token
1851 test "if user is unconfirmed" do
1852 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1853 {:ok, user} = User.toggle_confirmation(user)
1855 refute user.confirmation_pending
1856 refute user.confirmation_token
1860 describe "ensure_keys_present" do
1861 test "it creates keys for a user and stores them in info" do
1862 user = insert(:user)
1863 refute is_binary(user.keys)
1864 {:ok, user} = User.ensure_keys_present(user)
1865 assert is_binary(user.keys)
1868 test "it doesn't create keys if there already are some" do
1869 user = insert(:user, keys: "xxx")
1870 {:ok, user} = User.ensure_keys_present(user)
1871 assert user.keys == "xxx"
1875 describe "get_ap_ids_by_nicknames" do
1876 test "it returns a list of AP ids for a given set of nicknames" do
1877 user = insert(:user)
1878 user_two = insert(:user)
1880 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1881 assert length(ap_ids) == 2
1882 assert user.ap_id in ap_ids
1883 assert user_two.ap_id in ap_ids
1887 describe "sync followers count" do
1889 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1890 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1891 insert(:user, local: true)
1892 insert(:user, local: false, deactivated: true)
1893 {:ok, user1: user1, user2: user2}
1896 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1897 [fdb_user1] = User.external_users(limit: 1)
1899 assert fdb_user1.ap_id
1900 assert fdb_user1.ap_id == user1.ap_id
1901 assert fdb_user1.id == user1.id
1903 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1905 assert fdb_user2.ap_id
1906 assert fdb_user2.ap_id == user2.ap_id
1907 assert fdb_user2.id == user2.id
1909 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1913 describe "is_internal_user?/1" do
1914 test "non-internal user returns false" do
1915 user = insert(:user)
1916 refute User.is_internal_user?(user)
1919 test "user with no nickname returns true" do
1920 user = insert(:user, %{nickname: nil})
1921 assert User.is_internal_user?(user)
1924 test "user with internal-prefixed nickname returns true" do
1925 user = insert(:user, %{nickname: "internal.test"})
1926 assert User.is_internal_user?(user)
1930 describe "update_and_set_cache/1" do
1931 test "returns error when user is stale instead Ecto.StaleEntryError" do
1932 user = insert(:user)
1934 changeset = Ecto.Changeset.change(user, bio: "test")
1938 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1939 User.update_and_set_cache(changeset)
1942 test "performs update cache if user updated" do
1943 user = insert(:user)
1944 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1946 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1948 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1949 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1950 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1954 describe "following/followers synchronization" do
1955 setup do: clear_config([:instance, :external_user_synchronization])
1957 test "updates the counters normally on following/getting a follow when disabled" do
1958 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1959 user = insert(:user)
1964 follower_address: "http://localhost:4001/users/masto_closed/followers",
1965 following_address: "http://localhost:4001/users/masto_closed/following",
1969 assert other_user.following_count == 0
1970 assert other_user.follower_count == 0
1972 {:ok, user} = Pleroma.User.follow(user, other_user)
1973 other_user = Pleroma.User.get_by_id(other_user.id)
1975 assert user.following_count == 1
1976 assert other_user.follower_count == 1
1979 test "syncronizes the counters with the remote instance for the followed when enabled" do
1980 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1982 user = insert(:user)
1987 follower_address: "http://localhost:4001/users/masto_closed/followers",
1988 following_address: "http://localhost:4001/users/masto_closed/following",
1992 assert other_user.following_count == 0
1993 assert other_user.follower_count == 0
1995 Pleroma.Config.put([:instance, :external_user_synchronization], true)
1996 {:ok, _user} = User.follow(user, other_user)
1997 other_user = User.get_by_id(other_user.id)
1999 assert other_user.follower_count == 437
2002 test "syncronizes the counters with the remote instance for the follower when enabled" do
2003 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2005 user = insert(:user)
2010 follower_address: "http://localhost:4001/users/masto_closed/followers",
2011 following_address: "http://localhost:4001/users/masto_closed/following",
2015 assert other_user.following_count == 0
2016 assert other_user.follower_count == 0
2018 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2019 {:ok, other_user} = User.follow(other_user, user)
2021 assert other_user.following_count == 152
2025 describe "change_email/2" do
2027 [user: insert(:user)]
2030 test "blank email returns error", %{user: user} do
2031 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2032 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2035 test "non unique email returns error", %{user: user} do
2036 %{email: email} = insert(:user)
2038 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2039 User.change_email(user, email)
2042 test "invalid email returns error", %{user: user} do
2043 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2044 User.change_email(user, "cofe")
2047 test "changes email", %{user: user} do
2048 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2052 describe "get_cached_by_nickname_or_id" do
2054 local_user = insert(:user)
2055 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2057 [local_user: local_user, remote_user: remote_user]
2060 setup do: clear_config([:instance, :limit_to_local_content])
2062 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2063 remote_user: remote_user
2065 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2066 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2068 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2069 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2071 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2072 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2075 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2076 %{remote_user: remote_user} do
2077 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2078 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2081 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2082 %{remote_user: remote_user, local_user: local_user} do
2083 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2084 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2087 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2088 %{remote_user: remote_user} do
2089 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2090 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2093 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2094 %{local_user: local_user} do
2095 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2096 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2098 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2099 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2101 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2102 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2106 describe "update_email_notifications/2" do
2108 user = insert(:user, email_notifications: %{"digest" => true})
2113 test "Notifications are updated", %{user: user} do
2114 true = user.email_notifications["digest"]
2115 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2116 assert result.email_notifications["digest"] == false
2120 test "avatar fallback" do
2121 user = insert(:user)
2122 assert User.avatar_url(user) =~ "/images/avi.png"
2124 clear_config([:assets, :default_user_avatar], "avatar.png")
2126 user = User.get_cached_by_nickname_or_id(user.nickname)
2127 assert User.avatar_url(user) =~ "avatar.png"
2129 assert User.avatar_url(user, no_default: true) == nil