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()
512 assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
515 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
516 Pleroma.Config.put([:instance, :account_activation_required], true)
520 |> Enum.each(fn key ->
521 params = Map.delete(@full_user_data, key)
522 changeset = User.register_changeset(%User{}, params)
524 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
528 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
529 Pleroma.Config.put([:instance, :account_activation_required], false)
533 |> Enum.each(fn key ->
534 params = Map.delete(@full_user_data, key)
535 changeset = User.register_changeset(%User{}, params)
537 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
541 test "it restricts certain nicknames" do
542 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
544 assert is_bitstring(restricted_name)
548 |> Map.put(:nickname, restricted_name)
550 changeset = User.register_changeset(%User{}, params)
552 refute changeset.valid?
555 test "it blocks blacklisted email domains" do
556 clear_config([User, :email_blacklist], ["trolling.world"])
559 params = Map.put(@full_user_data, :email, "troll@trolling.world")
560 changeset = User.register_changeset(%User{}, params)
561 refute changeset.valid?
563 # Block with subdomain match
564 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
565 changeset = User.register_changeset(%User{}, params)
566 refute changeset.valid?
568 # Pass with different domains that are similar
569 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
570 changeset = User.register_changeset(%User{}, params)
571 assert changeset.valid?
573 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
574 changeset = User.register_changeset(%User{}, params)
575 assert changeset.valid?
578 test "it sets the password_hash and ap_id" do
579 changeset = User.register_changeset(%User{}, @full_user_data)
581 assert changeset.valid?
583 assert is_binary(changeset.changes[:password_hash])
584 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
586 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
589 test "it sets the 'accepts_chat_messages' set to true" do
590 changeset = User.register_changeset(%User{}, @full_user_data)
591 assert changeset.valid?
593 {:ok, user} = Repo.insert(changeset)
595 assert user.accepts_chat_messages
598 test "it creates a confirmed user" do
599 changeset = User.register_changeset(%User{}, @full_user_data)
600 assert changeset.valid?
602 {:ok, user} = Repo.insert(changeset)
604 refute user.confirmation_pending
608 describe "user registration, with :account_activation_required" do
614 password_confirmation: "test",
615 email: "email@example.com"
617 setup do: clear_config([:instance, :account_activation_required], true)
619 test "it creates unconfirmed user" do
620 changeset = User.register_changeset(%User{}, @full_user_data)
621 assert changeset.valid?
623 {:ok, user} = Repo.insert(changeset)
625 assert user.confirmation_pending
626 assert user.confirmation_token
629 test "it creates confirmed user if :confirmed option is given" do
630 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
631 assert changeset.valid?
633 {:ok, user} = Repo.insert(changeset)
635 refute user.confirmation_pending
636 refute user.confirmation_token
640 describe "user registration, with :account_approval_required" do
646 password_confirmation: "test",
647 email: "email@example.com",
648 registration_reason: "I'm a cool guy :)"
650 setup do: clear_config([:instance, :account_approval_required], true)
652 test "it creates unapproved user" do
653 changeset = User.register_changeset(%User{}, @full_user_data)
654 assert changeset.valid?
656 {:ok, user} = Repo.insert(changeset)
658 assert user.approval_pending
659 assert user.registration_reason == "I'm a cool guy :)"
662 test "it restricts length of registration reason" do
663 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
665 assert is_integer(reason_limit)
670 :registration_reason,
671 "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."
674 changeset = User.register_changeset(%User{}, params)
676 refute changeset.valid?
680 describe "get_or_fetch/1" do
681 test "gets an existing user by nickname" do
683 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
685 assert user == fetched_user
688 test "gets an existing user by ap_id" do
689 ap_id = "http://mastodon.example.org/users/admin"
695 nickname: "admin@mastodon.example.org",
699 {:ok, fetched_user} = User.get_or_fetch(ap_id)
700 freshed_user = refresh_record(user)
701 assert freshed_user == fetched_user
705 describe "fetching a user from nickname or trying to build one" do
706 test "gets an existing user" do
708 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
710 assert user == fetched_user
713 test "gets an existing user, case insensitive" do
714 user = insert(:user, nickname: "nick")
715 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
717 assert user == fetched_user
720 test "gets an existing user by fully qualified nickname" do
723 {:ok, fetched_user} =
724 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
726 assert user == fetched_user
729 test "gets an existing user by fully qualified nickname, case insensitive" do
730 user = insert(:user, nickname: "nick")
731 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
733 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
735 assert user == fetched_user
738 @tag capture_log: true
739 test "returns nil if no user could be fetched" do
740 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
741 assert fetched_user == "not found nonexistant@social.heldscal.la"
744 test "returns nil for nonexistant local user" do
745 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
746 assert fetched_user == "not found nonexistant"
749 test "updates an existing user, if stale" do
750 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
756 nickname: "admin@mastodon.example.org",
757 ap_id: "http://mastodon.example.org/users/admin",
758 last_refreshed_at: a_week_ago
761 assert orig_user.last_refreshed_at == a_week_ago
763 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
767 refute user.last_refreshed_at == orig_user.last_refreshed_at
770 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
771 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
777 nickname: "admin@mastodon.example.org",
778 ap_id: "http://mastodon.example.org/users/harinezumigari",
779 last_refreshed_at: a_week_ago
782 assert orig_user.last_refreshed_at == a_week_ago
784 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
788 refute user.id == orig_user.id
790 orig_user = User.get_by_id(orig_user.id)
792 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
795 @tag capture_log: true
796 test "it returns the old user if stale, but unfetchable" do
797 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
803 nickname: "admin@mastodon.example.org",
804 ap_id: "http://mastodon.example.org/users/raymoo",
805 last_refreshed_at: a_week_ago
808 assert orig_user.last_refreshed_at == a_week_ago
810 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
812 assert user.last_refreshed_at == orig_user.last_refreshed_at
816 test "returns an ap_id for a user" do
819 assert User.ap_id(user) ==
820 Pleroma.Web.Router.Helpers.user_feed_url(
821 Pleroma.Web.Endpoint,
827 test "returns an ap_followers link for a user" do
830 assert User.ap_followers(user) ==
831 Pleroma.Web.Router.Helpers.user_feed_url(
832 Pleroma.Web.Endpoint,
838 describe "remote user changeset" do
844 avatar: %{some: "avatar"}
846 setup do: clear_config([:instance, :user_bio_length])
847 setup do: clear_config([:instance, :user_name_length])
849 test "it confirms validity" do
850 cs = User.remote_user_changeset(@valid_remote)
854 test "it sets the follower_adress" do
855 cs = User.remote_user_changeset(@valid_remote)
856 # remote users get a fake local follower address
857 assert cs.changes.follower_address ==
858 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
861 test "it enforces the fqn format for nicknames" do
862 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
863 assert Ecto.Changeset.get_field(cs, :local) == false
864 assert cs.changes.avatar
868 test "it has required fields" do
870 |> Enum.each(fn field ->
871 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
877 describe "followers and friends" do
878 test "gets all followers for a given user" do
880 follower_one = insert(:user)
881 follower_two = insert(:user)
882 not_follower = insert(:user)
884 {:ok, follower_one} = User.follow(follower_one, user)
885 {:ok, follower_two} = User.follow(follower_two, user)
887 res = User.get_followers(user)
889 assert Enum.member?(res, follower_one)
890 assert Enum.member?(res, follower_two)
891 refute Enum.member?(res, not_follower)
894 test "gets all friends (followed users) for a given user" do
896 followed_one = insert(:user)
897 followed_two = insert(:user)
898 not_followed = insert(:user)
900 {:ok, user} = User.follow(user, followed_one)
901 {:ok, user} = User.follow(user, followed_two)
903 res = User.get_friends(user)
905 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
906 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
907 assert Enum.member?(res, followed_one)
908 assert Enum.member?(res, followed_two)
909 refute Enum.member?(res, not_followed)
913 describe "updating note and follower count" do
914 test "it sets the note_count property" do
917 user = User.get_cached_by_ap_id(note.data["actor"])
919 assert user.note_count == 0
921 {:ok, user} = User.update_note_count(user)
923 assert user.note_count == 1
926 test "it increases the note_count property" do
928 user = User.get_cached_by_ap_id(note.data["actor"])
930 assert user.note_count == 0
932 {:ok, user} = User.increase_note_count(user)
934 assert user.note_count == 1
936 {:ok, user} = User.increase_note_count(user)
938 assert user.note_count == 2
941 test "it decreases the note_count property" do
943 user = User.get_cached_by_ap_id(note.data["actor"])
945 assert user.note_count == 0
947 {:ok, user} = User.increase_note_count(user)
949 assert user.note_count == 1
951 {:ok, user} = User.decrease_note_count(user)
953 assert user.note_count == 0
955 {:ok, user} = User.decrease_note_count(user)
957 assert user.note_count == 0
960 test "it sets the follower_count property" do
962 follower = insert(:user)
964 User.follow(follower, user)
966 assert user.follower_count == 0
968 {:ok, user} = User.update_follower_count(user)
970 assert user.follower_count == 1
974 describe "follow_import" do
975 test "it imports user followings from list" do
976 [user1, user2, user3] = insert_list(3, :user)
983 {:ok, job} = User.follow_import(user1, identifiers)
985 assert {:ok, result} = ObanHelpers.perform(job)
986 assert is_list(result)
987 assert result == [user2, user3]
992 test "it mutes people" do
994 muted_user = insert(:user)
996 refute User.mutes?(user, muted_user)
997 refute User.muted_notifications?(user, muted_user)
999 {:ok, _user_relationships} = User.mute(user, muted_user)
1001 assert User.mutes?(user, muted_user)
1002 assert User.muted_notifications?(user, muted_user)
1005 test "it unmutes users" do
1006 user = insert(:user)
1007 muted_user = insert(:user)
1009 {:ok, _user_relationships} = User.mute(user, muted_user)
1010 {:ok, _user_mute} = User.unmute(user, muted_user)
1012 refute User.mutes?(user, muted_user)
1013 refute User.muted_notifications?(user, muted_user)
1016 test "it mutes user without notifications" do
1017 user = insert(:user)
1018 muted_user = insert(:user)
1020 refute User.mutes?(user, muted_user)
1021 refute User.muted_notifications?(user, muted_user)
1023 {:ok, _user_relationships} = User.mute(user, muted_user, false)
1025 assert User.mutes?(user, muted_user)
1026 refute User.muted_notifications?(user, muted_user)
1030 describe "blocks" do
1031 test "it blocks people" do
1032 user = insert(:user)
1033 blocked_user = insert(:user)
1035 refute User.blocks?(user, blocked_user)
1037 {:ok, _user_relationship} = User.block(user, blocked_user)
1039 assert User.blocks?(user, blocked_user)
1042 test "it unblocks users" do
1043 user = insert(:user)
1044 blocked_user = insert(:user)
1046 {:ok, _user_relationship} = User.block(user, blocked_user)
1047 {:ok, _user_block} = User.unblock(user, blocked_user)
1049 refute User.blocks?(user, blocked_user)
1052 test "blocks tear down cyclical follow relationships" do
1053 blocker = insert(:user)
1054 blocked = insert(:user)
1056 {:ok, blocker} = User.follow(blocker, blocked)
1057 {:ok, blocked} = User.follow(blocked, blocker)
1059 assert User.following?(blocker, blocked)
1060 assert User.following?(blocked, blocker)
1062 {:ok, _user_relationship} = User.block(blocker, blocked)
1063 blocked = User.get_cached_by_id(blocked.id)
1065 assert User.blocks?(blocker, blocked)
1067 refute User.following?(blocker, blocked)
1068 refute User.following?(blocked, blocker)
1071 test "blocks tear down blocker->blocked follow relationships" do
1072 blocker = insert(:user)
1073 blocked = insert(:user)
1075 {:ok, blocker} = User.follow(blocker, blocked)
1077 assert User.following?(blocker, blocked)
1078 refute User.following?(blocked, blocker)
1080 {:ok, _user_relationship} = User.block(blocker, blocked)
1081 blocked = User.get_cached_by_id(blocked.id)
1083 assert User.blocks?(blocker, blocked)
1085 refute User.following?(blocker, blocked)
1086 refute User.following?(blocked, blocker)
1089 test "blocks tear down blocked->blocker follow relationships" do
1090 blocker = insert(:user)
1091 blocked = insert(:user)
1093 {:ok, blocked} = User.follow(blocked, blocker)
1095 refute User.following?(blocker, blocked)
1096 assert User.following?(blocked, blocker)
1098 {:ok, _user_relationship} = User.block(blocker, blocked)
1099 blocked = User.get_cached_by_id(blocked.id)
1101 assert User.blocks?(blocker, blocked)
1103 refute User.following?(blocker, blocked)
1104 refute User.following?(blocked, blocker)
1107 test "blocks tear down blocked->blocker subscription relationships" do
1108 blocker = insert(:user)
1109 blocked = insert(:user)
1111 {:ok, _subscription} = User.subscribe(blocked, blocker)
1113 assert User.subscribed_to?(blocked, blocker)
1114 refute User.subscribed_to?(blocker, blocked)
1116 {:ok, _user_relationship} = User.block(blocker, blocked)
1118 assert User.blocks?(blocker, blocked)
1119 refute User.subscribed_to?(blocker, blocked)
1120 refute User.subscribed_to?(blocked, blocker)
1124 describe "domain blocking" do
1125 test "blocks domains" do
1126 user = insert(:user)
1127 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1129 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1131 assert User.blocks?(user, collateral_user)
1134 test "does not block domain with same end" do
1135 user = insert(:user)
1138 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1140 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1142 refute User.blocks?(user, collateral_user)
1145 test "does not block domain with same end if wildcard added" do
1146 user = insert(:user)
1149 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1151 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1153 refute User.blocks?(user, collateral_user)
1156 test "blocks domain with wildcard for subdomain" do
1157 user = insert(:user)
1159 user_from_subdomain =
1160 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1162 user_with_two_subdomains =
1164 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1167 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1169 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1171 assert User.blocks?(user, user_from_subdomain)
1172 assert User.blocks?(user, user_with_two_subdomains)
1173 assert User.blocks?(user, user_domain)
1176 test "unblocks domains" do
1177 user = insert(:user)
1178 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1180 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1181 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1183 refute User.blocks?(user, collateral_user)
1186 test "follows take precedence over domain blocks" do
1187 user = insert(:user)
1188 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1190 {:ok, user} = User.block_domain(user, "meanies.social")
1191 {:ok, user} = User.follow(user, good_eggo)
1193 refute User.blocks?(user, good_eggo)
1197 describe "blocks_import" do
1198 test "it imports user blocks from list" do
1199 [user1, user2, user3] = insert_list(3, :user)
1206 {:ok, job} = User.blocks_import(user1, identifiers)
1208 assert {:ok, result} = ObanHelpers.perform(job)
1209 assert is_list(result)
1210 assert result == [user2, user3]
1214 describe "get_recipients_from_activity" do
1215 test "works for announces" do
1216 actor = insert(:user)
1217 user = insert(:user, local: true)
1219 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1220 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1222 recipients = User.get_recipients_from_activity(announce)
1224 assert user in recipients
1227 test "get recipients" do
1228 actor = insert(:user)
1229 user = insert(:user, local: true)
1230 user_two = insert(:user, local: false)
1231 addressed = insert(:user, local: true)
1232 addressed_remote = insert(:user, local: false)
1235 CommonAPI.post(actor, %{
1236 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1239 assert Enum.map([actor, addressed], & &1.ap_id) --
1240 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1242 {:ok, user} = User.follow(user, actor)
1243 {:ok, _user_two} = User.follow(user_two, actor)
1244 recipients = User.get_recipients_from_activity(activity)
1245 assert length(recipients) == 3
1246 assert user in recipients
1247 assert addressed in recipients
1250 test "has following" do
1251 actor = insert(:user)
1252 user = insert(:user)
1253 user_two = insert(:user)
1254 addressed = insert(:user, local: true)
1257 CommonAPI.post(actor, %{
1258 status: "hey @#{addressed.nickname}"
1261 assert Enum.map([actor, addressed], & &1.ap_id) --
1262 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1264 {:ok, _actor} = User.follow(actor, user)
1265 {:ok, _actor} = User.follow(actor, user_two)
1266 recipients = User.get_recipients_from_activity(activity)
1267 assert length(recipients) == 2
1268 assert addressed in recipients
1272 describe ".deactivate" do
1273 test "can de-activate then re-activate a user" do
1274 user = insert(:user)
1275 assert false == user.deactivated
1276 {:ok, user} = User.deactivate(user)
1277 assert true == user.deactivated
1278 {:ok, user} = User.deactivate(user, false)
1279 assert false == user.deactivated
1282 test "hide a user from followers" do
1283 user = insert(:user)
1284 user2 = insert(:user)
1286 {:ok, user} = User.follow(user, user2)
1287 {:ok, _user} = User.deactivate(user)
1289 user2 = User.get_cached_by_id(user2.id)
1291 assert user2.follower_count == 0
1292 assert [] = User.get_followers(user2)
1295 test "hide a user from friends" do
1296 user = insert(:user)
1297 user2 = insert(:user)
1299 {:ok, user2} = User.follow(user2, user)
1300 assert user2.following_count == 1
1301 assert User.following_count(user2) == 1
1303 {:ok, _user} = User.deactivate(user)
1305 user2 = User.get_cached_by_id(user2.id)
1307 assert refresh_record(user2).following_count == 0
1308 assert user2.following_count == 0
1309 assert User.following_count(user2) == 0
1310 assert [] = User.get_friends(user2)
1313 test "hide a user's statuses from timelines and notifications" do
1314 user = insert(:user)
1315 user2 = insert(:user)
1317 {:ok, user2} = User.follow(user2, user)
1319 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1321 activity = Repo.preload(activity, :bookmark)
1323 [notification] = Pleroma.Notification.for_user(user2)
1324 assert notification.activity.id == activity.id
1326 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1328 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1329 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1333 {:ok, _user} = User.deactivate(user)
1335 assert [] == ActivityPub.fetch_public_activities(%{})
1336 assert [] == Pleroma.Notification.for_user(user2)
1339 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1345 describe "approve" do
1346 test "approves a user" do
1347 user = insert(:user, approval_pending: true)
1348 assert true == user.approval_pending
1349 {:ok, user} = User.approve(user)
1350 assert false == user.approval_pending
1353 test "approves a list of users" do
1354 unapproved_users = [
1355 insert(:user, approval_pending: true),
1356 insert(:user, approval_pending: true),
1357 insert(:user, approval_pending: true)
1360 {:ok, users} = User.approve(unapproved_users)
1362 assert Enum.count(users) == 3
1364 Enum.each(users, fn user ->
1365 assert false == user.approval_pending
1370 describe "delete" do
1372 {:ok, user} = insert(:user) |> User.set_cache()
1377 setup do: clear_config([:instance, :federating])
1379 test ".delete_user_activities deletes all create activities", %{user: user} do
1380 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1382 User.delete_user_activities(user)
1384 # TODO: Test removal favorites, repeats, delete activities.
1385 refute Activity.get_by_id(activity.id)
1388 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1389 follower = insert(:user)
1390 {:ok, follower} = User.follow(follower, user)
1392 locked_user = insert(:user, name: "locked", locked: true)
1393 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1395 object = insert(:note, user: user)
1396 activity = insert(:note_activity, user: user, note: object)
1398 object_two = insert(:note, user: follower)
1399 activity_two = insert(:note_activity, user: follower, note: object_two)
1401 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1402 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1403 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1405 {:ok, job} = User.delete(user)
1406 {:ok, _user} = ObanHelpers.perform(job)
1408 follower = User.get_cached_by_id(follower.id)
1410 refute User.following?(follower, user)
1411 assert %{deactivated: true} = User.get_by_id(user.id)
1413 assert [] == User.get_follow_requests(locked_user)
1417 |> Activity.Queries.by_actor()
1419 |> Enum.map(fn act -> act.data["type"] end)
1421 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1423 refute Activity.get_by_id(activity.id)
1424 refute Activity.get_by_id(like.id)
1425 refute Activity.get_by_id(like_two.id)
1426 refute Activity.get_by_id(repeat.id)
1430 describe "delete/1 when confirmation is pending" do
1432 user = insert(:user, confirmation_pending: true)
1436 test "deletes user from database when activation required", %{user: user} do
1437 clear_config([:instance, :account_activation_required], true)
1439 {:ok, job} = User.delete(user)
1440 {:ok, _} = ObanHelpers.perform(job)
1442 refute User.get_cached_by_id(user.id)
1443 refute User.get_by_id(user.id)
1446 test "deactivates user when activation is not required", %{user: user} do
1447 clear_config([:instance, :account_activation_required], false)
1449 {:ok, job} = User.delete(user)
1450 {:ok, _} = ObanHelpers.perform(job)
1452 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1453 assert %{deactivated: true} = User.get_by_id(user.id)
1457 test "delete/1 when approval is pending deletes the user" do
1458 user = insert(:user, approval_pending: true)
1460 {:ok, job} = User.delete(user)
1461 {:ok, _} = ObanHelpers.perform(job)
1463 refute User.get_cached_by_id(user.id)
1464 refute User.get_by_id(user.id)
1467 test "delete/1 purges a user when they wouldn't be fully deleted" do
1472 password_hash: "pdfk2$1b3n159001",
1473 keys: "RSA begin buplic key",
1474 public_key: "--PRIVATE KEYE--",
1475 avatar: %{"a" => "b"},
1477 banner: %{"a" => "b"},
1478 background: %{"a" => "b"},
1481 following_count: 9001,
1483 confirmation_pending: true,
1484 password_reset_pending: true,
1485 approval_pending: true,
1486 registration_reason: "ahhhhh",
1487 confirmation_token: "qqqq",
1488 domain_blocks: ["lain.com"],
1493 mastofe_settings: %{"a" => "b"},
1494 mascot: %{"a" => "b"},
1495 emoji: %{"a" => "b"},
1496 pleroma_settings_store: %{"q" => "x"},
1497 fields: [%{"gg" => "qq"}],
1498 raw_fields: [%{"gg" => "qq"}],
1500 also_known_as: ["https://lol.olo/users/loll"]
1503 {:ok, job} = User.delete(user)
1504 {:ok, _} = ObanHelpers.perform(job)
1505 user = User.get_by_id(user.id)
1517 last_refreshed_at: nil,
1518 last_digest_emailed_at: nil,
1525 confirmation_pending: false,
1526 password_reset_pending: false,
1527 approval_pending: false,
1528 registration_reason: nil,
1529 confirmation_token: nil,
1533 is_moderator: false,
1535 mastofe_settings: nil,
1538 pleroma_settings_store: %{},
1541 discoverable: false,
1546 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1547 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1550 describe "per-user rich-text filtering" do
1551 test "html_filter_policy returns default policies, when rich-text is enabled" do
1552 user = insert(:user)
1554 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1557 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1558 user = insert(:user, no_rich_text: true)
1560 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1564 describe "caching" do
1565 test "invalidate_cache works" do
1566 user = insert(:user)
1568 User.set_cache(user)
1569 User.invalidate_cache(user)
1571 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1572 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1575 test "User.delete() plugs any possible zombie objects" do
1576 user = insert(:user)
1578 {:ok, job} = User.delete(user)
1579 {:ok, _} = ObanHelpers.perform(job)
1581 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1583 assert cached_user != user
1585 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1587 assert cached_user != user
1591 describe "account_status/1" do
1592 setup do: clear_config([:instance, :account_activation_required])
1594 test "return confirmation_pending for unconfirm user" do
1595 Pleroma.Config.put([:instance, :account_activation_required], true)
1596 user = insert(:user, confirmation_pending: true)
1597 assert User.account_status(user) == :confirmation_pending
1600 test "return active for confirmed user" do
1601 Pleroma.Config.put([:instance, :account_activation_required], true)
1602 user = insert(:user, confirmation_pending: false)
1603 assert User.account_status(user) == :active
1606 test "return active for remote user" do
1607 user = insert(:user, local: false)
1608 assert User.account_status(user) == :active
1611 test "returns :password_reset_pending for user with reset password" do
1612 user = insert(:user, password_reset_pending: true)
1613 assert User.account_status(user) == :password_reset_pending
1616 test "returns :deactivated for deactivated user" do
1617 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1618 assert User.account_status(user) == :deactivated
1621 test "returns :approval_pending for unapproved user" do
1622 user = insert(:user, local: true, approval_pending: true)
1623 assert User.account_status(user) == :approval_pending
1625 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1626 assert User.account_status(user) == :approval_pending
1630 describe "superuser?/1" do
1631 test "returns false for unprivileged users" do
1632 user = insert(:user, local: true)
1634 refute User.superuser?(user)
1637 test "returns false for remote users" do
1638 user = insert(:user, local: false)
1639 remote_admin_user = insert(:user, local: false, is_admin: true)
1641 refute User.superuser?(user)
1642 refute User.superuser?(remote_admin_user)
1645 test "returns true for local moderators" do
1646 user = insert(:user, local: true, is_moderator: true)
1648 assert User.superuser?(user)
1651 test "returns true for local admins" do
1652 user = insert(:user, local: true, is_admin: true)
1654 assert User.superuser?(user)
1658 describe "invisible?/1" do
1659 test "returns true for an invisible user" do
1660 user = insert(:user, local: true, invisible: true)
1662 assert User.invisible?(user)
1665 test "returns false for a non-invisible user" do
1666 user = insert(:user, local: true)
1668 refute User.invisible?(user)
1672 describe "visible_for/2" do
1673 test "returns true when the account is itself" do
1674 user = insert(:user, local: true)
1676 assert User.visible_for(user, user) == :visible
1679 test "returns false when the account is unconfirmed and confirmation is required" do
1680 Pleroma.Config.put([:instance, :account_activation_required], true)
1682 user = insert(:user, local: true, confirmation_pending: true)
1683 other_user = insert(:user, local: true)
1685 refute User.visible_for(user, other_user) == :visible
1688 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1689 Pleroma.Config.put([:instance, :account_activation_required], true)
1691 user = insert(:user, local: false, confirmation_pending: true)
1692 other_user = insert(:user, local: true)
1694 assert User.visible_for(user, other_user) == :visible
1697 test "returns true when the account is unconfirmed and confirmation is not required" do
1698 user = insert(:user, local: true, confirmation_pending: true)
1699 other_user = insert(:user, local: true)
1701 assert User.visible_for(user, other_user) == :visible
1704 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1705 Pleroma.Config.put([:instance, :account_activation_required], true)
1707 user = insert(:user, local: true, confirmation_pending: true)
1708 other_user = insert(:user, local: true, is_admin: true)
1710 assert User.visible_for(user, other_user) == :visible
1714 describe "parse_bio/2" do
1715 test "preserves hosts in user links text" do
1716 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1717 user = insert(:user)
1718 bio = "A.k.a. @nick@domain.com"
1721 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1723 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1725 assert expected_text == User.parse_bio(bio, user)
1728 test "Adds rel=me on linkbacked urls" do
1729 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1731 bio = "http://example.com/rel_me/null"
1732 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1733 assert expected_text == User.parse_bio(bio, user)
1735 bio = "http://example.com/rel_me/link"
1736 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1737 assert expected_text == User.parse_bio(bio, user)
1739 bio = "http://example.com/rel_me/anchor"
1740 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1741 assert expected_text == User.parse_bio(bio, user)
1745 test "follower count is updated when a follower is blocked" do
1746 user = insert(:user)
1747 follower = insert(:user)
1748 follower2 = insert(:user)
1749 follower3 = insert(:user)
1751 {:ok, follower} = User.follow(follower, user)
1752 {:ok, _follower2} = User.follow(follower2, user)
1753 {:ok, _follower3} = User.follow(follower3, user)
1755 {:ok, _user_relationship} = User.block(user, follower)
1756 user = refresh_record(user)
1758 assert user.follower_count == 2
1761 describe "list_inactive_users_query/1" do
1762 defp days_ago(days) do
1764 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1765 -days * 60 * 60 * 24,
1770 test "Users are inactive by default" do
1774 Enum.map(1..total, fn _ ->
1775 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1778 inactive_users_ids =
1779 Pleroma.User.list_inactive_users_query()
1780 |> Pleroma.Repo.all()
1781 |> Enum.map(& &1.id)
1783 Enum.each(users, fn user ->
1784 assert user.id in inactive_users_ids
1788 test "Only includes users who has no recent activity" do
1792 Enum.map(1..total, fn _ ->
1793 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1796 {inactive, active} = Enum.split(users, trunc(total / 2))
1798 Enum.map(active, fn user ->
1799 to = Enum.random(users -- [user])
1802 CommonAPI.post(user, %{
1803 status: "hey @#{to.nickname}"
1807 inactive_users_ids =
1808 Pleroma.User.list_inactive_users_query()
1809 |> Pleroma.Repo.all()
1810 |> Enum.map(& &1.id)
1812 Enum.each(active, fn user ->
1813 refute user.id in inactive_users_ids
1816 Enum.each(inactive, fn user ->
1817 assert user.id in inactive_users_ids
1821 test "Only includes users with no read notifications" do
1825 Enum.map(1..total, fn _ ->
1826 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1829 [sender | recipients] = users
1830 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1832 Enum.each(recipients, fn to ->
1834 CommonAPI.post(sender, %{
1835 status: "hey @#{to.nickname}"
1839 CommonAPI.post(sender, %{
1840 status: "hey again @#{to.nickname}"
1844 Enum.each(active, fn user ->
1845 [n1, _n2] = Pleroma.Notification.for_user(user)
1846 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1849 inactive_users_ids =
1850 Pleroma.User.list_inactive_users_query()
1851 |> Pleroma.Repo.all()
1852 |> Enum.map(& &1.id)
1854 Enum.each(active, fn user ->
1855 refute user.id in inactive_users_ids
1858 Enum.each(inactive, fn user ->
1859 assert user.id in inactive_users_ids
1864 describe "toggle_confirmation/1" do
1865 test "if user is confirmed" do
1866 user = insert(:user, confirmation_pending: false)
1867 {:ok, user} = User.toggle_confirmation(user)
1869 assert user.confirmation_pending
1870 assert user.confirmation_token
1873 test "if user is unconfirmed" do
1874 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1875 {:ok, user} = User.toggle_confirmation(user)
1877 refute user.confirmation_pending
1878 refute user.confirmation_token
1882 describe "ensure_keys_present" do
1883 test "it creates keys for a user and stores them in info" do
1884 user = insert(:user)
1885 refute is_binary(user.keys)
1886 {:ok, user} = User.ensure_keys_present(user)
1887 assert is_binary(user.keys)
1890 test "it doesn't create keys if there already are some" do
1891 user = insert(:user, keys: "xxx")
1892 {:ok, user} = User.ensure_keys_present(user)
1893 assert user.keys == "xxx"
1897 describe "get_ap_ids_by_nicknames" do
1898 test "it returns a list of AP ids for a given set of nicknames" do
1899 user = insert(:user)
1900 user_two = insert(:user)
1902 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1903 assert length(ap_ids) == 2
1904 assert user.ap_id in ap_ids
1905 assert user_two.ap_id in ap_ids
1909 describe "sync followers count" do
1911 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1912 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1913 insert(:user, local: true)
1914 insert(:user, local: false, deactivated: true)
1915 {:ok, user1: user1, user2: user2}
1918 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1919 [fdb_user1] = User.external_users(limit: 1)
1921 assert fdb_user1.ap_id
1922 assert fdb_user1.ap_id == user1.ap_id
1923 assert fdb_user1.id == user1.id
1925 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1927 assert fdb_user2.ap_id
1928 assert fdb_user2.ap_id == user2.ap_id
1929 assert fdb_user2.id == user2.id
1931 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1935 describe "is_internal_user?/1" do
1936 test "non-internal user returns false" do
1937 user = insert(:user)
1938 refute User.is_internal_user?(user)
1941 test "user with no nickname returns true" do
1942 user = insert(:user, %{nickname: nil})
1943 assert User.is_internal_user?(user)
1946 test "user with internal-prefixed nickname returns true" do
1947 user = insert(:user, %{nickname: "internal.test"})
1948 assert User.is_internal_user?(user)
1952 describe "update_and_set_cache/1" do
1953 test "returns error when user is stale instead Ecto.StaleEntryError" do
1954 user = insert(:user)
1956 changeset = Ecto.Changeset.change(user, bio: "test")
1960 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1961 User.update_and_set_cache(changeset)
1964 test "performs update cache if user updated" do
1965 user = insert(:user)
1966 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1968 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1970 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1971 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1972 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1976 describe "following/followers synchronization" do
1977 setup do: clear_config([:instance, :external_user_synchronization])
1979 test "updates the counters normally on following/getting a follow when disabled" do
1980 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1981 user = insert(:user)
1986 follower_address: "http://localhost:4001/users/masto_closed/followers",
1987 following_address: "http://localhost:4001/users/masto_closed/following",
1991 assert other_user.following_count == 0
1992 assert other_user.follower_count == 0
1994 {:ok, user} = Pleroma.User.follow(user, other_user)
1995 other_user = Pleroma.User.get_by_id(other_user.id)
1997 assert user.following_count == 1
1998 assert other_user.follower_count == 1
2001 test "syncronizes the counters with the remote instance for the followed when enabled" do
2002 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2004 user = insert(:user)
2009 follower_address: "http://localhost:4001/users/masto_closed/followers",
2010 following_address: "http://localhost:4001/users/masto_closed/following",
2014 assert other_user.following_count == 0
2015 assert other_user.follower_count == 0
2017 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2018 {:ok, _user} = User.follow(user, other_user)
2019 other_user = User.get_by_id(other_user.id)
2021 assert other_user.follower_count == 437
2024 test "syncronizes the counters with the remote instance for the follower when enabled" do
2025 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2027 user = insert(:user)
2032 follower_address: "http://localhost:4001/users/masto_closed/followers",
2033 following_address: "http://localhost:4001/users/masto_closed/following",
2037 assert other_user.following_count == 0
2038 assert other_user.follower_count == 0
2040 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2041 {:ok, other_user} = User.follow(other_user, user)
2043 assert other_user.following_count == 152
2047 describe "change_email/2" do
2049 [user: insert(:user)]
2052 test "blank email returns error", %{user: user} do
2053 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2054 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2057 test "non unique email returns error", %{user: user} do
2058 %{email: email} = insert(:user)
2060 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2061 User.change_email(user, email)
2064 test "invalid email returns error", %{user: user} do
2065 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2066 User.change_email(user, "cofe")
2069 test "changes email", %{user: user} do
2070 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2074 describe "get_cached_by_nickname_or_id" do
2076 local_user = insert(:user)
2077 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2079 [local_user: local_user, remote_user: remote_user]
2082 setup do: clear_config([:instance, :limit_to_local_content])
2084 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2085 remote_user: remote_user
2087 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2088 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2090 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2091 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2093 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2094 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2097 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2098 %{remote_user: remote_user} do
2099 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2100 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2103 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2104 %{remote_user: remote_user, local_user: local_user} do
2105 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2106 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2109 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2110 %{remote_user: remote_user} do
2111 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2112 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2115 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2116 %{local_user: local_user} do
2117 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2118 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2120 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2121 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2123 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2124 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2128 describe "update_email_notifications/2" do
2130 user = insert(:user, email_notifications: %{"digest" => true})
2135 test "Notifications are updated", %{user: user} do
2136 true = user.email_notifications["digest"]
2137 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2138 assert result.email_notifications["digest"] == false
2142 test "avatar fallback" do
2143 user = insert(:user)
2144 assert User.avatar_url(user) =~ "/images/avi.png"
2146 clear_config([:assets, :default_user_avatar], "avatar.png")
2148 user = User.get_cached_by_nickname_or_id(user.nickname)
2149 assert User.avatar_url(user) =~ "avatar.png"
2151 assert User.avatar_url(user, no_default: true) == nil