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
443 test "it sends a welcome email message if it is set" do
444 welcome_user = insert(:user)
445 Pleroma.Config.put([:welcome, :email, :enabled], true)
446 Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
449 [:welcome, :email, :subject],
450 "Hello, welcome to cool site: <%= instance_name %>"
453 instance_name = Pleroma.Config.get([:instance, :name])
455 cng = User.register_changeset(%User{}, @full_user_data)
456 {:ok, registered_user} = User.register(cng)
457 ObanHelpers.perform_all()
460 from: {instance_name, welcome_user.email},
461 to: {registered_user.name, registered_user.email},
462 subject: "Hello, welcome to cool site: #{instance_name}",
463 html_body: "Welcome to #{instance_name}"
467 test "it sends a confirm email" do
468 Pleroma.Config.put([:instance, :account_activation_required], true)
470 cng = User.register_changeset(%User{}, @full_user_data)
471 {:ok, registered_user} = User.register(cng)
472 ObanHelpers.perform_all()
473 assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
476 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
477 Pleroma.Config.put([:instance, :account_activation_required], true)
481 |> Enum.each(fn key ->
482 params = Map.delete(@full_user_data, key)
483 changeset = User.register_changeset(%User{}, params)
485 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
489 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
490 Pleroma.Config.put([:instance, :account_activation_required], false)
494 |> Enum.each(fn key ->
495 params = Map.delete(@full_user_data, key)
496 changeset = User.register_changeset(%User{}, params)
498 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
502 test "it restricts certain nicknames" do
503 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
505 assert is_bitstring(restricted_name)
509 |> Map.put(:nickname, restricted_name)
511 changeset = User.register_changeset(%User{}, params)
513 refute changeset.valid?
516 test "it blocks blacklisted email domains" do
517 clear_config([User, :email_blacklist], ["trolling.world"])
520 params = Map.put(@full_user_data, :email, "troll@trolling.world")
521 changeset = User.register_changeset(%User{}, params)
522 refute changeset.valid?
524 # Block with subdomain match
525 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
526 changeset = User.register_changeset(%User{}, params)
527 refute changeset.valid?
529 # Pass with different domains that are similar
530 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
531 changeset = User.register_changeset(%User{}, params)
532 assert changeset.valid?
534 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
535 changeset = User.register_changeset(%User{}, params)
536 assert changeset.valid?
539 test "it sets the password_hash and ap_id" do
540 changeset = User.register_changeset(%User{}, @full_user_data)
542 assert changeset.valid?
544 assert is_binary(changeset.changes[:password_hash])
545 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
547 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
550 test "it sets the 'accepts_chat_messages' set to true" do
551 changeset = User.register_changeset(%User{}, @full_user_data)
552 assert changeset.valid?
554 {:ok, user} = Repo.insert(changeset)
556 assert user.accepts_chat_messages
559 test "it creates a confirmed user" do
560 changeset = User.register_changeset(%User{}, @full_user_data)
561 assert changeset.valid?
563 {:ok, user} = Repo.insert(changeset)
565 refute user.confirmation_pending
569 describe "user registration, with :account_activation_required" do
575 password_confirmation: "test",
576 email: "email@example.com"
578 setup do: clear_config([:instance, :account_activation_required], true)
580 test "it creates unconfirmed user" do
581 changeset = User.register_changeset(%User{}, @full_user_data)
582 assert changeset.valid?
584 {:ok, user} = Repo.insert(changeset)
586 assert user.confirmation_pending
587 assert user.confirmation_token
590 test "it creates confirmed user if :confirmed option is given" do
591 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
592 assert changeset.valid?
594 {:ok, user} = Repo.insert(changeset)
596 refute user.confirmation_pending
597 refute user.confirmation_token
601 describe "user registration, with :account_approval_required" do
607 password_confirmation: "test",
608 email: "email@example.com",
609 registration_reason: "I'm a cool guy :)"
611 setup do: clear_config([:instance, :account_approval_required], true)
613 test "it creates unapproved user" do
614 changeset = User.register_changeset(%User{}, @full_user_data)
615 assert changeset.valid?
617 {:ok, user} = Repo.insert(changeset)
619 assert user.approval_pending
620 assert user.registration_reason == "I'm a cool guy :)"
623 test "it restricts length of registration reason" do
624 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
626 assert is_integer(reason_limit)
631 :registration_reason,
632 "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."
635 changeset = User.register_changeset(%User{}, params)
637 refute changeset.valid?
641 describe "get_or_fetch/1" do
642 test "gets an existing user by nickname" do
644 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
646 assert user == fetched_user
649 test "gets an existing user by ap_id" do
650 ap_id = "http://mastodon.example.org/users/admin"
656 nickname: "admin@mastodon.example.org",
660 {:ok, fetched_user} = User.get_or_fetch(ap_id)
661 freshed_user = refresh_record(user)
662 assert freshed_user == fetched_user
666 describe "fetching a user from nickname or trying to build one" do
667 test "gets an existing user" do
669 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
671 assert user == fetched_user
674 test "gets an existing user, case insensitive" do
675 user = insert(:user, nickname: "nick")
676 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
678 assert user == fetched_user
681 test "gets an existing user by fully qualified nickname" do
684 {:ok, fetched_user} =
685 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
687 assert user == fetched_user
690 test "gets an existing user by fully qualified nickname, case insensitive" do
691 user = insert(:user, nickname: "nick")
692 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
694 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
696 assert user == fetched_user
699 @tag capture_log: true
700 test "returns nil if no user could be fetched" do
701 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
702 assert fetched_user == "not found nonexistant@social.heldscal.la"
705 test "returns nil for nonexistant local user" do
706 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
707 assert fetched_user == "not found nonexistant"
710 test "updates an existing user, if stale" do
711 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
717 nickname: "admin@mastodon.example.org",
718 ap_id: "http://mastodon.example.org/users/admin",
719 last_refreshed_at: a_week_ago
722 assert orig_user.last_refreshed_at == a_week_ago
724 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
728 refute user.last_refreshed_at == orig_user.last_refreshed_at
731 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
732 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
738 nickname: "admin@mastodon.example.org",
739 ap_id: "http://mastodon.example.org/users/harinezumigari",
740 last_refreshed_at: a_week_ago
743 assert orig_user.last_refreshed_at == a_week_ago
745 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
749 refute user.id == orig_user.id
751 orig_user = User.get_by_id(orig_user.id)
753 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
756 @tag capture_log: true
757 test "it returns the old user if stale, but unfetchable" do
758 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
764 nickname: "admin@mastodon.example.org",
765 ap_id: "http://mastodon.example.org/users/raymoo",
766 last_refreshed_at: a_week_ago
769 assert orig_user.last_refreshed_at == a_week_ago
771 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
773 assert user.last_refreshed_at == orig_user.last_refreshed_at
777 test "returns an ap_id for a user" do
780 assert User.ap_id(user) ==
781 Pleroma.Web.Router.Helpers.user_feed_url(
782 Pleroma.Web.Endpoint,
788 test "returns an ap_followers link for a user" do
791 assert User.ap_followers(user) ==
792 Pleroma.Web.Router.Helpers.user_feed_url(
793 Pleroma.Web.Endpoint,
799 describe "remote user changeset" do
805 avatar: %{some: "avatar"}
807 setup do: clear_config([:instance, :user_bio_length])
808 setup do: clear_config([:instance, :user_name_length])
810 test "it confirms validity" do
811 cs = User.remote_user_changeset(@valid_remote)
815 test "it sets the follower_adress" do
816 cs = User.remote_user_changeset(@valid_remote)
817 # remote users get a fake local follower address
818 assert cs.changes.follower_address ==
819 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
822 test "it enforces the fqn format for nicknames" do
823 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
824 assert Ecto.Changeset.get_field(cs, :local) == false
825 assert cs.changes.avatar
829 test "it has required fields" do
831 |> Enum.each(fn field ->
832 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
838 describe "followers and friends" do
839 test "gets all followers for a given user" do
841 follower_one = insert(:user)
842 follower_two = insert(:user)
843 not_follower = insert(:user)
845 {:ok, follower_one} = User.follow(follower_one, user)
846 {:ok, follower_two} = User.follow(follower_two, user)
848 res = User.get_followers(user)
850 assert Enum.member?(res, follower_one)
851 assert Enum.member?(res, follower_two)
852 refute Enum.member?(res, not_follower)
855 test "gets all friends (followed users) for a given user" do
857 followed_one = insert(:user)
858 followed_two = insert(:user)
859 not_followed = insert(:user)
861 {:ok, user} = User.follow(user, followed_one)
862 {:ok, user} = User.follow(user, followed_two)
864 res = User.get_friends(user)
866 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
867 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
868 assert Enum.member?(res, followed_one)
869 assert Enum.member?(res, followed_two)
870 refute Enum.member?(res, not_followed)
874 describe "updating note and follower count" do
875 test "it sets the note_count property" do
878 user = User.get_cached_by_ap_id(note.data["actor"])
880 assert user.note_count == 0
882 {:ok, user} = User.update_note_count(user)
884 assert user.note_count == 1
887 test "it increases the note_count property" do
889 user = User.get_cached_by_ap_id(note.data["actor"])
891 assert user.note_count == 0
893 {:ok, user} = User.increase_note_count(user)
895 assert user.note_count == 1
897 {:ok, user} = User.increase_note_count(user)
899 assert user.note_count == 2
902 test "it decreases the note_count property" do
904 user = User.get_cached_by_ap_id(note.data["actor"])
906 assert user.note_count == 0
908 {:ok, user} = User.increase_note_count(user)
910 assert user.note_count == 1
912 {:ok, user} = User.decrease_note_count(user)
914 assert user.note_count == 0
916 {:ok, user} = User.decrease_note_count(user)
918 assert user.note_count == 0
921 test "it sets the follower_count property" do
923 follower = insert(:user)
925 User.follow(follower, user)
927 assert user.follower_count == 0
929 {:ok, user} = User.update_follower_count(user)
931 assert user.follower_count == 1
935 describe "follow_import" do
936 test "it imports user followings from list" do
937 [user1, user2, user3] = insert_list(3, :user)
944 {:ok, job} = User.follow_import(user1, identifiers)
946 assert {:ok, result} = ObanHelpers.perform(job)
947 assert is_list(result)
948 assert result == [user2, user3]
953 test "it mutes people" do
955 muted_user = insert(:user)
957 refute User.mutes?(user, muted_user)
958 refute User.muted_notifications?(user, muted_user)
960 {:ok, _user_relationships} = User.mute(user, muted_user)
962 assert User.mutes?(user, muted_user)
963 assert User.muted_notifications?(user, muted_user)
968 muted_user = insert(:user)
970 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
971 assert User.mutes?(user, muted_user)
974 worker: Pleroma.Workers.MuteExpireWorker,
975 args: %{"op" => "unmute", "muter" => user.id, "mutee" => muted_user.id}
979 test "it unmutes users" do
981 muted_user = insert(:user)
983 {:ok, _user_relationships} = User.mute(user, muted_user)
984 {:ok, _user_mute} = User.unmute(user, muted_user)
986 refute User.mutes?(user, muted_user)
987 refute User.muted_notifications?(user, muted_user)
990 test "it mutes user without notifications" do
992 muted_user = insert(:user)
994 refute User.mutes?(user, muted_user)
995 refute User.muted_notifications?(user, muted_user)
997 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
999 assert User.mutes?(user, muted_user)
1000 refute User.muted_notifications?(user, muted_user)
1004 describe "blocks" do
1005 test "it blocks people" do
1006 user = insert(:user)
1007 blocked_user = insert(:user)
1009 refute User.blocks?(user, blocked_user)
1011 {:ok, _user_relationship} = User.block(user, blocked_user)
1013 assert User.blocks?(user, blocked_user)
1016 test "it unblocks users" do
1017 user = insert(:user)
1018 blocked_user = insert(:user)
1020 {:ok, _user_relationship} = User.block(user, blocked_user)
1021 {:ok, _user_block} = User.unblock(user, blocked_user)
1023 refute User.blocks?(user, blocked_user)
1026 test "blocks tear down cyclical follow relationships" do
1027 blocker = insert(:user)
1028 blocked = insert(:user)
1030 {:ok, blocker} = User.follow(blocker, blocked)
1031 {:ok, blocked} = User.follow(blocked, blocker)
1033 assert User.following?(blocker, blocked)
1034 assert User.following?(blocked, blocker)
1036 {:ok, _user_relationship} = User.block(blocker, blocked)
1037 blocked = User.get_cached_by_id(blocked.id)
1039 assert User.blocks?(blocker, blocked)
1041 refute User.following?(blocker, blocked)
1042 refute User.following?(blocked, blocker)
1045 test "blocks tear down blocker->blocked follow relationships" do
1046 blocker = insert(:user)
1047 blocked = insert(:user)
1049 {:ok, blocker} = User.follow(blocker, blocked)
1051 assert User.following?(blocker, blocked)
1052 refute User.following?(blocked, blocker)
1054 {:ok, _user_relationship} = User.block(blocker, blocked)
1055 blocked = User.get_cached_by_id(blocked.id)
1057 assert User.blocks?(blocker, blocked)
1059 refute User.following?(blocker, blocked)
1060 refute User.following?(blocked, blocker)
1063 test "blocks tear down blocked->blocker follow relationships" do
1064 blocker = insert(:user)
1065 blocked = insert(:user)
1067 {:ok, blocked} = User.follow(blocked, blocker)
1069 refute User.following?(blocker, blocked)
1070 assert User.following?(blocked, blocker)
1072 {:ok, _user_relationship} = User.block(blocker, blocked)
1073 blocked = User.get_cached_by_id(blocked.id)
1075 assert User.blocks?(blocker, blocked)
1077 refute User.following?(blocker, blocked)
1078 refute User.following?(blocked, blocker)
1081 test "blocks tear down blocked->blocker subscription relationships" do
1082 blocker = insert(:user)
1083 blocked = insert(:user)
1085 {:ok, _subscription} = User.subscribe(blocked, blocker)
1087 assert User.subscribed_to?(blocked, blocker)
1088 refute User.subscribed_to?(blocker, blocked)
1090 {:ok, _user_relationship} = User.block(blocker, blocked)
1092 assert User.blocks?(blocker, blocked)
1093 refute User.subscribed_to?(blocker, blocked)
1094 refute User.subscribed_to?(blocked, blocker)
1098 describe "domain blocking" do
1099 test "blocks domains" do
1100 user = insert(:user)
1101 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1103 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1105 assert User.blocks?(user, collateral_user)
1108 test "does not block domain with same end" do
1109 user = insert(:user)
1112 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1114 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1116 refute User.blocks?(user, collateral_user)
1119 test "does not block domain with same end if wildcard added" do
1120 user = insert(:user)
1123 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1125 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1127 refute User.blocks?(user, collateral_user)
1130 test "blocks domain with wildcard for subdomain" do
1131 user = insert(:user)
1133 user_from_subdomain =
1134 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1136 user_with_two_subdomains =
1138 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1141 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1143 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1145 assert User.blocks?(user, user_from_subdomain)
1146 assert User.blocks?(user, user_with_two_subdomains)
1147 assert User.blocks?(user, user_domain)
1150 test "unblocks domains" do
1151 user = insert(:user)
1152 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1154 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1155 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1157 refute User.blocks?(user, collateral_user)
1160 test "follows take precedence over domain blocks" do
1161 user = insert(:user)
1162 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1164 {:ok, user} = User.block_domain(user, "meanies.social")
1165 {:ok, user} = User.follow(user, good_eggo)
1167 refute User.blocks?(user, good_eggo)
1171 describe "blocks_import" do
1172 test "it imports user blocks from list" do
1173 [user1, user2, user3] = insert_list(3, :user)
1180 {:ok, job} = User.blocks_import(user1, identifiers)
1182 assert {:ok, result} = ObanHelpers.perform(job)
1183 assert is_list(result)
1184 assert result == [user2, user3]
1188 describe "get_recipients_from_activity" do
1189 test "works for announces" do
1190 actor = insert(:user)
1191 user = insert(:user, local: true)
1193 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1194 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1196 recipients = User.get_recipients_from_activity(announce)
1198 assert user in recipients
1201 test "get recipients" do
1202 actor = insert(:user)
1203 user = insert(:user, local: true)
1204 user_two = insert(:user, local: false)
1205 addressed = insert(:user, local: true)
1206 addressed_remote = insert(:user, local: false)
1209 CommonAPI.post(actor, %{
1210 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1213 assert Enum.map([actor, addressed], & &1.ap_id) --
1214 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1216 {:ok, user} = User.follow(user, actor)
1217 {:ok, _user_two} = User.follow(user_two, actor)
1218 recipients = User.get_recipients_from_activity(activity)
1219 assert length(recipients) == 3
1220 assert user in recipients
1221 assert addressed in recipients
1224 test "has following" do
1225 actor = insert(:user)
1226 user = insert(:user)
1227 user_two = insert(:user)
1228 addressed = insert(:user, local: true)
1231 CommonAPI.post(actor, %{
1232 status: "hey @#{addressed.nickname}"
1235 assert Enum.map([actor, addressed], & &1.ap_id) --
1236 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1238 {:ok, _actor} = User.follow(actor, user)
1239 {:ok, _actor} = User.follow(actor, user_two)
1240 recipients = User.get_recipients_from_activity(activity)
1241 assert length(recipients) == 2
1242 assert addressed in recipients
1246 describe ".deactivate" do
1247 test "can de-activate then re-activate a user" do
1248 user = insert(:user)
1249 assert false == user.deactivated
1250 {:ok, user} = User.deactivate(user)
1251 assert true == user.deactivated
1252 {:ok, user} = User.deactivate(user, false)
1253 assert false == user.deactivated
1256 test "hide a user from followers" do
1257 user = insert(:user)
1258 user2 = insert(:user)
1260 {:ok, user} = User.follow(user, user2)
1261 {:ok, _user} = User.deactivate(user)
1263 user2 = User.get_cached_by_id(user2.id)
1265 assert user2.follower_count == 0
1266 assert [] = User.get_followers(user2)
1269 test "hide a user from friends" do
1270 user = insert(:user)
1271 user2 = insert(:user)
1273 {:ok, user2} = User.follow(user2, user)
1274 assert user2.following_count == 1
1275 assert User.following_count(user2) == 1
1277 {:ok, _user} = User.deactivate(user)
1279 user2 = User.get_cached_by_id(user2.id)
1281 assert refresh_record(user2).following_count == 0
1282 assert user2.following_count == 0
1283 assert User.following_count(user2) == 0
1284 assert [] = User.get_friends(user2)
1287 test "hide a user's statuses from timelines and notifications" do
1288 user = insert(:user)
1289 user2 = insert(:user)
1291 {:ok, user2} = User.follow(user2, user)
1293 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1295 activity = Repo.preload(activity, :bookmark)
1297 [notification] = Pleroma.Notification.for_user(user2)
1298 assert notification.activity.id == activity.id
1300 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1302 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1303 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1307 {:ok, _user} = User.deactivate(user)
1309 assert [] == ActivityPub.fetch_public_activities(%{})
1310 assert [] == Pleroma.Notification.for_user(user2)
1313 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1319 describe "approve" do
1320 test "approves a user" do
1321 user = insert(:user, approval_pending: true)
1322 assert true == user.approval_pending
1323 {:ok, user} = User.approve(user)
1324 assert false == user.approval_pending
1327 test "approves a list of users" do
1328 unapproved_users = [
1329 insert(:user, approval_pending: true),
1330 insert(:user, approval_pending: true),
1331 insert(:user, approval_pending: true)
1334 {:ok, users} = User.approve(unapproved_users)
1336 assert Enum.count(users) == 3
1338 Enum.each(users, fn user ->
1339 assert false == user.approval_pending
1344 describe "delete" do
1346 {:ok, user} = insert(:user) |> User.set_cache()
1351 setup do: clear_config([:instance, :federating])
1353 test ".delete_user_activities deletes all create activities", %{user: user} do
1354 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1356 User.delete_user_activities(user)
1358 # TODO: Test removal favorites, repeats, delete activities.
1359 refute Activity.get_by_id(activity.id)
1362 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1363 follower = insert(:user)
1364 {:ok, follower} = User.follow(follower, user)
1366 locked_user = insert(:user, name: "locked", locked: true)
1367 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1369 object = insert(:note, user: user)
1370 activity = insert(:note_activity, user: user, note: object)
1372 object_two = insert(:note, user: follower)
1373 activity_two = insert(:note_activity, user: follower, note: object_two)
1375 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1376 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1377 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1379 {:ok, job} = User.delete(user)
1380 {:ok, _user} = ObanHelpers.perform(job)
1382 follower = User.get_cached_by_id(follower.id)
1384 refute User.following?(follower, user)
1385 assert %{deactivated: true} = User.get_by_id(user.id)
1387 assert [] == User.get_follow_requests(locked_user)
1391 |> Activity.Queries.by_actor()
1393 |> Enum.map(fn act -> act.data["type"] end)
1395 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1397 refute Activity.get_by_id(activity.id)
1398 refute Activity.get_by_id(like.id)
1399 refute Activity.get_by_id(like_two.id)
1400 refute Activity.get_by_id(repeat.id)
1404 describe "delete/1 when confirmation is pending" do
1406 user = insert(:user, confirmation_pending: true)
1410 test "deletes user from database when activation required", %{user: user} do
1411 clear_config([:instance, :account_activation_required], true)
1413 {:ok, job} = User.delete(user)
1414 {:ok, _} = ObanHelpers.perform(job)
1416 refute User.get_cached_by_id(user.id)
1417 refute User.get_by_id(user.id)
1420 test "deactivates user when activation is not required", %{user: user} do
1421 clear_config([:instance, :account_activation_required], false)
1423 {:ok, job} = User.delete(user)
1424 {:ok, _} = ObanHelpers.perform(job)
1426 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1427 assert %{deactivated: true} = User.get_by_id(user.id)
1431 test "delete/1 when approval is pending deletes the user" do
1432 user = insert(:user, approval_pending: true)
1434 {:ok, job} = User.delete(user)
1435 {:ok, _} = ObanHelpers.perform(job)
1437 refute User.get_cached_by_id(user.id)
1438 refute User.get_by_id(user.id)
1441 test "delete/1 purges a user when they wouldn't be fully deleted" do
1446 password_hash: "pdfk2$1b3n159001",
1447 keys: "RSA begin buplic key",
1448 public_key: "--PRIVATE KEYE--",
1449 avatar: %{"a" => "b"},
1451 banner: %{"a" => "b"},
1452 background: %{"a" => "b"},
1455 following_count: 9001,
1457 confirmation_pending: true,
1458 password_reset_pending: true,
1459 approval_pending: true,
1460 registration_reason: "ahhhhh",
1461 confirmation_token: "qqqq",
1462 domain_blocks: ["lain.com"],
1467 mastofe_settings: %{"a" => "b"},
1468 mascot: %{"a" => "b"},
1469 emoji: %{"a" => "b"},
1470 pleroma_settings_store: %{"q" => "x"},
1471 fields: [%{"gg" => "qq"}],
1472 raw_fields: [%{"gg" => "qq"}],
1474 also_known_as: ["https://lol.olo/users/loll"]
1477 {:ok, job} = User.delete(user)
1478 {:ok, _} = ObanHelpers.perform(job)
1479 user = User.get_by_id(user.id)
1491 last_refreshed_at: nil,
1492 last_digest_emailed_at: nil,
1499 confirmation_pending: false,
1500 password_reset_pending: false,
1501 approval_pending: false,
1502 registration_reason: nil,
1503 confirmation_token: nil,
1507 is_moderator: false,
1509 mastofe_settings: nil,
1512 pleroma_settings_store: %{},
1515 discoverable: false,
1520 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1521 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1524 describe "per-user rich-text filtering" do
1525 test "html_filter_policy returns default policies, when rich-text is enabled" do
1526 user = insert(:user)
1528 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1531 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1532 user = insert(:user, no_rich_text: true)
1534 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1538 describe "caching" do
1539 test "invalidate_cache works" do
1540 user = insert(:user)
1542 User.set_cache(user)
1543 User.invalidate_cache(user)
1545 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1546 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1549 test "User.delete() plugs any possible zombie objects" do
1550 user = insert(:user)
1552 {:ok, job} = User.delete(user)
1553 {:ok, _} = ObanHelpers.perform(job)
1555 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1557 assert cached_user != user
1559 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1561 assert cached_user != user
1565 describe "account_status/1" do
1566 setup do: clear_config([:instance, :account_activation_required])
1568 test "return confirmation_pending for unconfirm user" do
1569 Pleroma.Config.put([:instance, :account_activation_required], true)
1570 user = insert(:user, confirmation_pending: true)
1571 assert User.account_status(user) == :confirmation_pending
1574 test "return active for confirmed user" do
1575 Pleroma.Config.put([:instance, :account_activation_required], true)
1576 user = insert(:user, confirmation_pending: false)
1577 assert User.account_status(user) == :active
1580 test "return active for remote user" do
1581 user = insert(:user, local: false)
1582 assert User.account_status(user) == :active
1585 test "returns :password_reset_pending for user with reset password" do
1586 user = insert(:user, password_reset_pending: true)
1587 assert User.account_status(user) == :password_reset_pending
1590 test "returns :deactivated for deactivated user" do
1591 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1592 assert User.account_status(user) == :deactivated
1595 test "returns :approval_pending for unapproved user" do
1596 user = insert(:user, local: true, approval_pending: true)
1597 assert User.account_status(user) == :approval_pending
1599 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1600 assert User.account_status(user) == :approval_pending
1604 describe "superuser?/1" do
1605 test "returns false for unprivileged users" do
1606 user = insert(:user, local: true)
1608 refute User.superuser?(user)
1611 test "returns false for remote users" do
1612 user = insert(:user, local: false)
1613 remote_admin_user = insert(:user, local: false, is_admin: true)
1615 refute User.superuser?(user)
1616 refute User.superuser?(remote_admin_user)
1619 test "returns true for local moderators" do
1620 user = insert(:user, local: true, is_moderator: true)
1622 assert User.superuser?(user)
1625 test "returns true for local admins" do
1626 user = insert(:user, local: true, is_admin: true)
1628 assert User.superuser?(user)
1632 describe "invisible?/1" do
1633 test "returns true for an invisible user" do
1634 user = insert(:user, local: true, invisible: true)
1636 assert User.invisible?(user)
1639 test "returns false for a non-invisible user" do
1640 user = insert(:user, local: true)
1642 refute User.invisible?(user)
1646 describe "visible_for/2" do
1647 test "returns true when the account is itself" do
1648 user = insert(:user, local: true)
1650 assert User.visible_for(user, user) == :visible
1653 test "returns false when the account is unauthenticated and auth is required" do
1654 Pleroma.Config.put([:instance, :account_activation_required], true)
1656 user = insert(:user, local: true, confirmation_pending: true)
1657 other_user = insert(:user, local: true)
1659 refute User.visible_for(user, other_user) == :visible
1662 test "returns true when the account is unauthenticated and auth is not required" do
1663 user = insert(:user, local: true, confirmation_pending: true)
1664 other_user = insert(:user, local: true)
1666 assert User.visible_for(user, other_user) == :visible
1669 test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do
1670 Pleroma.Config.put([:instance, :account_activation_required], true)
1672 user = insert(:user, local: true, confirmation_pending: true)
1673 other_user = insert(:user, local: true, is_admin: true)
1675 assert User.visible_for(user, other_user) == :visible
1679 describe "parse_bio/2" do
1680 test "preserves hosts in user links text" do
1681 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1682 user = insert(:user)
1683 bio = "A.k.a. @nick@domain.com"
1686 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1688 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1690 assert expected_text == User.parse_bio(bio, user)
1693 test "Adds rel=me on linkbacked urls" do
1694 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1696 bio = "http://example.com/rel_me/null"
1697 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1698 assert expected_text == User.parse_bio(bio, user)
1700 bio = "http://example.com/rel_me/link"
1701 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1702 assert expected_text == User.parse_bio(bio, user)
1704 bio = "http://example.com/rel_me/anchor"
1705 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1706 assert expected_text == User.parse_bio(bio, user)
1710 test "follower count is updated when a follower is blocked" do
1711 user = insert(:user)
1712 follower = insert(:user)
1713 follower2 = insert(:user)
1714 follower3 = insert(:user)
1716 {:ok, follower} = User.follow(follower, user)
1717 {:ok, _follower2} = User.follow(follower2, user)
1718 {:ok, _follower3} = User.follow(follower3, user)
1720 {:ok, _user_relationship} = User.block(user, follower)
1721 user = refresh_record(user)
1723 assert user.follower_count == 2
1726 describe "list_inactive_users_query/1" do
1727 defp days_ago(days) do
1729 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1730 -days * 60 * 60 * 24,
1735 test "Users are inactive by default" do
1739 Enum.map(1..total, fn _ ->
1740 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1743 inactive_users_ids =
1744 Pleroma.User.list_inactive_users_query()
1745 |> Pleroma.Repo.all()
1746 |> Enum.map(& &1.id)
1748 Enum.each(users, fn user ->
1749 assert user.id in inactive_users_ids
1753 test "Only includes users who has no recent activity" do
1757 Enum.map(1..total, fn _ ->
1758 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1761 {inactive, active} = Enum.split(users, trunc(total / 2))
1763 Enum.map(active, fn user ->
1764 to = Enum.random(users -- [user])
1767 CommonAPI.post(user, %{
1768 status: "hey @#{to.nickname}"
1772 inactive_users_ids =
1773 Pleroma.User.list_inactive_users_query()
1774 |> Pleroma.Repo.all()
1775 |> Enum.map(& &1.id)
1777 Enum.each(active, fn user ->
1778 refute user.id in inactive_users_ids
1781 Enum.each(inactive, fn user ->
1782 assert user.id in inactive_users_ids
1786 test "Only includes users with no read notifications" do
1790 Enum.map(1..total, fn _ ->
1791 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1794 [sender | recipients] = users
1795 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1797 Enum.each(recipients, fn to ->
1799 CommonAPI.post(sender, %{
1800 status: "hey @#{to.nickname}"
1804 CommonAPI.post(sender, %{
1805 status: "hey again @#{to.nickname}"
1809 Enum.each(active, fn user ->
1810 [n1, _n2] = Pleroma.Notification.for_user(user)
1811 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1814 inactive_users_ids =
1815 Pleroma.User.list_inactive_users_query()
1816 |> Pleroma.Repo.all()
1817 |> Enum.map(& &1.id)
1819 Enum.each(active, fn user ->
1820 refute user.id in inactive_users_ids
1823 Enum.each(inactive, fn user ->
1824 assert user.id in inactive_users_ids
1829 describe "toggle_confirmation/1" do
1830 test "if user is confirmed" do
1831 user = insert(:user, confirmation_pending: false)
1832 {:ok, user} = User.toggle_confirmation(user)
1834 assert user.confirmation_pending
1835 assert user.confirmation_token
1838 test "if user is unconfirmed" do
1839 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1840 {:ok, user} = User.toggle_confirmation(user)
1842 refute user.confirmation_pending
1843 refute user.confirmation_token
1847 describe "ensure_keys_present" do
1848 test "it creates keys for a user and stores them in info" do
1849 user = insert(:user)
1850 refute is_binary(user.keys)
1851 {:ok, user} = User.ensure_keys_present(user)
1852 assert is_binary(user.keys)
1855 test "it doesn't create keys if there already are some" do
1856 user = insert(:user, keys: "xxx")
1857 {:ok, user} = User.ensure_keys_present(user)
1858 assert user.keys == "xxx"
1862 describe "get_ap_ids_by_nicknames" do
1863 test "it returns a list of AP ids for a given set of nicknames" do
1864 user = insert(:user)
1865 user_two = insert(:user)
1867 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1868 assert length(ap_ids) == 2
1869 assert user.ap_id in ap_ids
1870 assert user_two.ap_id in ap_ids
1874 describe "sync followers count" do
1876 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1877 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1878 insert(:user, local: true)
1879 insert(:user, local: false, deactivated: true)
1880 {:ok, user1: user1, user2: user2}
1883 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1884 [fdb_user1] = User.external_users(limit: 1)
1886 assert fdb_user1.ap_id
1887 assert fdb_user1.ap_id == user1.ap_id
1888 assert fdb_user1.id == user1.id
1890 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1892 assert fdb_user2.ap_id
1893 assert fdb_user2.ap_id == user2.ap_id
1894 assert fdb_user2.id == user2.id
1896 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1900 describe "is_internal_user?/1" do
1901 test "non-internal user returns false" do
1902 user = insert(:user)
1903 refute User.is_internal_user?(user)
1906 test "user with no nickname returns true" do
1907 user = insert(:user, %{nickname: nil})
1908 assert User.is_internal_user?(user)
1911 test "user with internal-prefixed nickname returns true" do
1912 user = insert(:user, %{nickname: "internal.test"})
1913 assert User.is_internal_user?(user)
1917 describe "update_and_set_cache/1" do
1918 test "returns error when user is stale instead Ecto.StaleEntryError" do
1919 user = insert(:user)
1921 changeset = Ecto.Changeset.change(user, bio: "test")
1925 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1926 User.update_and_set_cache(changeset)
1929 test "performs update cache if user updated" do
1930 user = insert(:user)
1931 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1933 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1935 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1936 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1937 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1941 describe "following/followers synchronization" do
1942 setup do: clear_config([:instance, :external_user_synchronization])
1944 test "updates the counters normally on following/getting a follow when disabled" do
1945 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1946 user = insert(:user)
1951 follower_address: "http://localhost:4001/users/masto_closed/followers",
1952 following_address: "http://localhost:4001/users/masto_closed/following",
1956 assert other_user.following_count == 0
1957 assert other_user.follower_count == 0
1959 {:ok, user} = Pleroma.User.follow(user, other_user)
1960 other_user = Pleroma.User.get_by_id(other_user.id)
1962 assert user.following_count == 1
1963 assert other_user.follower_count == 1
1966 test "syncronizes the counters with the remote instance for the followed when enabled" do
1967 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1969 user = insert(:user)
1974 follower_address: "http://localhost:4001/users/masto_closed/followers",
1975 following_address: "http://localhost:4001/users/masto_closed/following",
1979 assert other_user.following_count == 0
1980 assert other_user.follower_count == 0
1982 Pleroma.Config.put([:instance, :external_user_synchronization], true)
1983 {:ok, _user} = User.follow(user, other_user)
1984 other_user = User.get_by_id(other_user.id)
1986 assert other_user.follower_count == 437
1989 test "syncronizes the counters with the remote instance for the follower when enabled" do
1990 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1992 user = insert(:user)
1997 follower_address: "http://localhost:4001/users/masto_closed/followers",
1998 following_address: "http://localhost:4001/users/masto_closed/following",
2002 assert other_user.following_count == 0
2003 assert other_user.follower_count == 0
2005 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2006 {:ok, other_user} = User.follow(other_user, user)
2008 assert other_user.following_count == 152
2012 describe "change_email/2" do
2014 [user: insert(:user)]
2017 test "blank email returns error", %{user: user} do
2018 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2019 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2022 test "non unique email returns error", %{user: user} do
2023 %{email: email} = insert(:user)
2025 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2026 User.change_email(user, email)
2029 test "invalid email returns error", %{user: user} do
2030 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2031 User.change_email(user, "cofe")
2034 test "changes email", %{user: user} do
2035 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2039 describe "get_cached_by_nickname_or_id" do
2041 local_user = insert(:user)
2042 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2044 [local_user: local_user, remote_user: remote_user]
2047 setup do: clear_config([:instance, :limit_to_local_content])
2049 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2050 remote_user: remote_user
2052 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2053 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2055 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2056 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2058 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2059 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2062 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2063 %{remote_user: remote_user} do
2064 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2065 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2068 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2069 %{remote_user: remote_user, local_user: local_user} do
2070 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2071 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2074 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2075 %{remote_user: remote_user} do
2076 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2077 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2080 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2081 %{local_user: local_user} do
2082 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2083 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2085 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2086 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2088 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2089 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2093 describe "update_email_notifications/2" do
2095 user = insert(:user, email_notifications: %{"digest" => true})
2100 test "Notifications are updated", %{user: user} do
2101 true = user.email_notifications["digest"]
2102 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2103 assert result.email_notifications["digest"] == false
2107 test "avatar fallback" do
2108 user = insert(:user)
2109 assert User.avatar_url(user) =~ "/images/avi.png"
2111 clear_config([:assets, :default_user_avatar], "avatar.png")
2113 user = User.get_cached_by_nickname_or_id(user.nickname)
2114 assert User.avatar_url(user) =~ "avatar.png"
2116 assert User.avatar_url(user, no_default: true) == nil