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 cool site")
417 Pleroma.Config.put([:welcome, :email, :enabled], true)
418 Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
421 [:welcome, :email, :subject],
422 "Hello, welcome to cool site: <%= instance_name %>"
425 instance_name = Pleroma.Config.get([:instance, :name])
427 cng = User.register_changeset(%User{}, @full_user_data)
428 {:ok, registered_user} = User.register(cng)
429 ObanHelpers.perform_all()
431 activity = Repo.one(Pleroma.Activity)
432 assert registered_user.ap_id in activity.recipients
433 assert Object.normalize(activity).data["content"] =~ "cool site"
434 assert activity.actor == welcome_user.ap_id
437 from: {instance_name, welcome_user.email},
438 to: {registered_user.name, registered_user.email},
439 subject: "Hello, welcome to cool site: #{instance_name}",
440 html_body: "Welcome to #{instance_name}"
444 test "it sends a confirm email" do
445 Pleroma.Config.put([:instance, :account_activation_required], true)
447 cng = User.register_changeset(%User{}, @full_user_data)
448 {:ok, registered_user} = User.register(cng)
449 ObanHelpers.perform_all()
450 assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
453 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
454 Pleroma.Config.put([:instance, :account_activation_required], true)
458 |> Enum.each(fn key ->
459 params = Map.delete(@full_user_data, key)
460 changeset = User.register_changeset(%User{}, params)
462 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
466 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
467 Pleroma.Config.put([:instance, :account_activation_required], false)
471 |> Enum.each(fn key ->
472 params = Map.delete(@full_user_data, key)
473 changeset = User.register_changeset(%User{}, params)
475 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
479 test "it restricts certain nicknames" do
480 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
482 assert is_bitstring(restricted_name)
486 |> Map.put(:nickname, restricted_name)
488 changeset = User.register_changeset(%User{}, params)
490 refute changeset.valid?
493 test "it blocks blacklisted email domains" do
494 clear_config([User, :email_blacklist], ["trolling.world"])
497 params = Map.put(@full_user_data, :email, "troll@trolling.world")
498 changeset = User.register_changeset(%User{}, params)
499 refute changeset.valid?
501 # Block with subdomain match
502 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
503 changeset = User.register_changeset(%User{}, params)
504 refute changeset.valid?
506 # Pass with different domains that are similar
507 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
508 changeset = User.register_changeset(%User{}, params)
509 assert changeset.valid?
511 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
512 changeset = User.register_changeset(%User{}, params)
513 assert changeset.valid?
516 test "it sets the password_hash and ap_id" do
517 changeset = User.register_changeset(%User{}, @full_user_data)
519 assert changeset.valid?
521 assert is_binary(changeset.changes[:password_hash])
522 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
524 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
527 test "it sets the 'accepts_chat_messages' set to true" do
528 changeset = User.register_changeset(%User{}, @full_user_data)
529 assert changeset.valid?
531 {:ok, user} = Repo.insert(changeset)
533 assert user.accepts_chat_messages
536 test "it creates a confirmed user" do
537 changeset = User.register_changeset(%User{}, @full_user_data)
538 assert changeset.valid?
540 {:ok, user} = Repo.insert(changeset)
542 refute user.confirmation_pending
546 describe "user registration, with :account_activation_required" do
552 password_confirmation: "test",
553 email: "email@example.com"
555 setup do: clear_config([:instance, :account_activation_required], true)
557 test "it creates unconfirmed user" do
558 changeset = User.register_changeset(%User{}, @full_user_data)
559 assert changeset.valid?
561 {:ok, user} = Repo.insert(changeset)
563 assert user.confirmation_pending
564 assert user.confirmation_token
567 test "it creates confirmed user if :confirmed option is given" do
568 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
569 assert changeset.valid?
571 {:ok, user} = Repo.insert(changeset)
573 refute user.confirmation_pending
574 refute user.confirmation_token
578 describe "user registration, with :account_approval_required" do
584 password_confirmation: "test",
585 email: "email@example.com",
586 registration_reason: "I'm a cool guy :)"
588 setup do: clear_config([:instance, :account_approval_required], true)
590 test "it creates unapproved user" do
591 changeset = User.register_changeset(%User{}, @full_user_data)
592 assert changeset.valid?
594 {:ok, user} = Repo.insert(changeset)
596 assert user.approval_pending
597 assert user.registration_reason == "I'm a cool guy :)"
600 test "it restricts length of registration reason" do
601 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
603 assert is_integer(reason_limit)
608 :registration_reason,
609 "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."
612 changeset = User.register_changeset(%User{}, params)
614 refute changeset.valid?
618 describe "get_or_fetch/1" do
619 test "gets an existing user by nickname" do
621 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
623 assert user == fetched_user
626 test "gets an existing user by ap_id" do
627 ap_id = "http://mastodon.example.org/users/admin"
633 nickname: "admin@mastodon.example.org",
637 {:ok, fetched_user} = User.get_or_fetch(ap_id)
638 freshed_user = refresh_record(user)
639 assert freshed_user == fetched_user
643 describe "fetching a user from nickname or trying to build one" do
644 test "gets an existing user" do
646 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
648 assert user == fetched_user
651 test "gets an existing user, case insensitive" do
652 user = insert(:user, nickname: "nick")
653 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
655 assert user == fetched_user
658 test "gets an existing user by fully qualified nickname" do
661 {:ok, fetched_user} =
662 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
664 assert user == fetched_user
667 test "gets an existing user by fully qualified nickname, case insensitive" do
668 user = insert(:user, nickname: "nick")
669 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
671 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
673 assert user == fetched_user
676 @tag capture_log: true
677 test "returns nil if no user could be fetched" do
678 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
679 assert fetched_user == "not found nonexistant@social.heldscal.la"
682 test "returns nil for nonexistant local user" do
683 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
684 assert fetched_user == "not found nonexistant"
687 test "updates an existing user, if stale" do
688 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
694 nickname: "admin@mastodon.example.org",
695 ap_id: "http://mastodon.example.org/users/admin",
696 last_refreshed_at: a_week_ago
699 assert orig_user.last_refreshed_at == a_week_ago
701 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
705 refute user.last_refreshed_at == orig_user.last_refreshed_at
708 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
709 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
715 nickname: "admin@mastodon.example.org",
716 ap_id: "http://mastodon.example.org/users/harinezumigari",
717 last_refreshed_at: a_week_ago
720 assert orig_user.last_refreshed_at == a_week_ago
722 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
726 refute user.id == orig_user.id
728 orig_user = User.get_by_id(orig_user.id)
730 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
733 @tag capture_log: true
734 test "it returns the old user if stale, but unfetchable" do
735 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
741 nickname: "admin@mastodon.example.org",
742 ap_id: "http://mastodon.example.org/users/raymoo",
743 last_refreshed_at: a_week_ago
746 assert orig_user.last_refreshed_at == a_week_ago
748 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
750 assert user.last_refreshed_at == orig_user.last_refreshed_at
754 test "returns an ap_id for a user" do
757 assert User.ap_id(user) ==
758 Pleroma.Web.Router.Helpers.user_feed_url(
759 Pleroma.Web.Endpoint,
765 test "returns an ap_followers link for a user" do
768 assert User.ap_followers(user) ==
769 Pleroma.Web.Router.Helpers.user_feed_url(
770 Pleroma.Web.Endpoint,
776 describe "remote user changeset" do
782 avatar: %{some: "avatar"}
784 setup do: clear_config([:instance, :user_bio_length])
785 setup do: clear_config([:instance, :user_name_length])
787 test "it confirms validity" do
788 cs = User.remote_user_changeset(@valid_remote)
792 test "it sets the follower_adress" do
793 cs = User.remote_user_changeset(@valid_remote)
794 # remote users get a fake local follower address
795 assert cs.changes.follower_address ==
796 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
799 test "it enforces the fqn format for nicknames" do
800 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
801 assert Ecto.Changeset.get_field(cs, :local) == false
802 assert cs.changes.avatar
806 test "it has required fields" do
808 |> Enum.each(fn field ->
809 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
815 describe "followers and friends" do
816 test "gets all followers for a given user" do
818 follower_one = insert(:user)
819 follower_two = insert(:user)
820 not_follower = insert(:user)
822 {:ok, follower_one} = User.follow(follower_one, user)
823 {:ok, follower_two} = User.follow(follower_two, user)
825 res = User.get_followers(user)
827 assert Enum.member?(res, follower_one)
828 assert Enum.member?(res, follower_two)
829 refute Enum.member?(res, not_follower)
832 test "gets all friends (followed users) for a given user" do
834 followed_one = insert(:user)
835 followed_two = insert(:user)
836 not_followed = insert(:user)
838 {:ok, user} = User.follow(user, followed_one)
839 {:ok, user} = User.follow(user, followed_two)
841 res = User.get_friends(user)
843 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
844 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
845 assert Enum.member?(res, followed_one)
846 assert Enum.member?(res, followed_two)
847 refute Enum.member?(res, not_followed)
851 describe "updating note and follower count" do
852 test "it sets the note_count property" do
855 user = User.get_cached_by_ap_id(note.data["actor"])
857 assert user.note_count == 0
859 {:ok, user} = User.update_note_count(user)
861 assert user.note_count == 1
864 test "it increases the note_count property" do
866 user = User.get_cached_by_ap_id(note.data["actor"])
868 assert user.note_count == 0
870 {:ok, user} = User.increase_note_count(user)
872 assert user.note_count == 1
874 {:ok, user} = User.increase_note_count(user)
876 assert user.note_count == 2
879 test "it decreases the note_count property" do
881 user = User.get_cached_by_ap_id(note.data["actor"])
883 assert user.note_count == 0
885 {:ok, user} = User.increase_note_count(user)
887 assert user.note_count == 1
889 {:ok, user} = User.decrease_note_count(user)
891 assert user.note_count == 0
893 {:ok, user} = User.decrease_note_count(user)
895 assert user.note_count == 0
898 test "it sets the follower_count property" do
900 follower = insert(:user)
902 User.follow(follower, user)
904 assert user.follower_count == 0
906 {:ok, user} = User.update_follower_count(user)
908 assert user.follower_count == 1
912 describe "follow_import" do
913 test "it imports user followings from list" do
914 [user1, user2, user3] = insert_list(3, :user)
921 {:ok, job} = User.follow_import(user1, identifiers)
923 assert {:ok, result} = ObanHelpers.perform(job)
924 assert is_list(result)
925 assert result == [user2, user3]
930 test "it mutes people" do
932 muted_user = insert(:user)
934 refute User.mutes?(user, muted_user)
935 refute User.muted_notifications?(user, muted_user)
937 {:ok, _user_relationships} = User.mute(user, muted_user)
939 assert User.mutes?(user, muted_user)
940 assert User.muted_notifications?(user, muted_user)
943 test "it unmutes users" do
945 muted_user = insert(:user)
947 {:ok, _user_relationships} = User.mute(user, muted_user)
948 {:ok, _user_mute} = User.unmute(user, muted_user)
950 refute User.mutes?(user, muted_user)
951 refute User.muted_notifications?(user, muted_user)
954 test "it mutes user without notifications" do
956 muted_user = insert(:user)
958 refute User.mutes?(user, muted_user)
959 refute User.muted_notifications?(user, muted_user)
961 {:ok, _user_relationships} = User.mute(user, muted_user, false)
963 assert User.mutes?(user, muted_user)
964 refute User.muted_notifications?(user, muted_user)
969 test "it blocks people" do
971 blocked_user = insert(:user)
973 refute User.blocks?(user, blocked_user)
975 {:ok, _user_relationship} = User.block(user, blocked_user)
977 assert User.blocks?(user, blocked_user)
980 test "it unblocks users" do
982 blocked_user = insert(:user)
984 {:ok, _user_relationship} = User.block(user, blocked_user)
985 {:ok, _user_block} = User.unblock(user, blocked_user)
987 refute User.blocks?(user, blocked_user)
990 test "blocks tear down cyclical follow relationships" do
991 blocker = insert(:user)
992 blocked = insert(:user)
994 {:ok, blocker} = User.follow(blocker, blocked)
995 {:ok, blocked} = User.follow(blocked, blocker)
997 assert User.following?(blocker, blocked)
998 assert User.following?(blocked, blocker)
1000 {:ok, _user_relationship} = User.block(blocker, blocked)
1001 blocked = User.get_cached_by_id(blocked.id)
1003 assert User.blocks?(blocker, blocked)
1005 refute User.following?(blocker, blocked)
1006 refute User.following?(blocked, blocker)
1009 test "blocks tear down blocker->blocked follow relationships" do
1010 blocker = insert(:user)
1011 blocked = insert(:user)
1013 {:ok, blocker} = User.follow(blocker, blocked)
1015 assert User.following?(blocker, blocked)
1016 refute User.following?(blocked, blocker)
1018 {:ok, _user_relationship} = User.block(blocker, blocked)
1019 blocked = User.get_cached_by_id(blocked.id)
1021 assert User.blocks?(blocker, blocked)
1023 refute User.following?(blocker, blocked)
1024 refute User.following?(blocked, blocker)
1027 test "blocks tear down blocked->blocker follow relationships" do
1028 blocker = insert(:user)
1029 blocked = insert(:user)
1031 {:ok, blocked} = User.follow(blocked, blocker)
1033 refute 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 blocked->blocker subscription relationships" do
1046 blocker = insert(:user)
1047 blocked = insert(:user)
1049 {:ok, _subscription} = User.subscribe(blocked, blocker)
1051 assert User.subscribed_to?(blocked, blocker)
1052 refute User.subscribed_to?(blocker, blocked)
1054 {:ok, _user_relationship} = User.block(blocker, blocked)
1056 assert User.blocks?(blocker, blocked)
1057 refute User.subscribed_to?(blocker, blocked)
1058 refute User.subscribed_to?(blocked, blocker)
1062 describe "domain blocking" do
1063 test "blocks domains" do
1064 user = insert(:user)
1065 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1067 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1069 assert User.blocks?(user, collateral_user)
1072 test "does not block domain with same end" do
1073 user = insert(:user)
1076 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1078 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1080 refute User.blocks?(user, collateral_user)
1083 test "does not block domain with same end if wildcard added" do
1084 user = insert(:user)
1087 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1089 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1091 refute User.blocks?(user, collateral_user)
1094 test "blocks domain with wildcard for subdomain" do
1095 user = insert(:user)
1097 user_from_subdomain =
1098 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1100 user_with_two_subdomains =
1102 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1105 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1107 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1109 assert User.blocks?(user, user_from_subdomain)
1110 assert User.blocks?(user, user_with_two_subdomains)
1111 assert User.blocks?(user, user_domain)
1114 test "unblocks domains" do
1115 user = insert(:user)
1116 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1118 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1119 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1121 refute User.blocks?(user, collateral_user)
1124 test "follows take precedence over domain blocks" do
1125 user = insert(:user)
1126 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1128 {:ok, user} = User.block_domain(user, "meanies.social")
1129 {:ok, user} = User.follow(user, good_eggo)
1131 refute User.blocks?(user, good_eggo)
1135 describe "blocks_import" do
1136 test "it imports user blocks from list" do
1137 [user1, user2, user3] = insert_list(3, :user)
1144 {:ok, job} = User.blocks_import(user1, identifiers)
1146 assert {:ok, result} = ObanHelpers.perform(job)
1147 assert is_list(result)
1148 assert result == [user2, user3]
1152 describe "get_recipients_from_activity" do
1153 test "works for announces" do
1154 actor = insert(:user)
1155 user = insert(:user, local: true)
1157 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1158 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1160 recipients = User.get_recipients_from_activity(announce)
1162 assert user in recipients
1165 test "get recipients" do
1166 actor = insert(:user)
1167 user = insert(:user, local: true)
1168 user_two = insert(:user, local: false)
1169 addressed = insert(:user, local: true)
1170 addressed_remote = insert(:user, local: false)
1173 CommonAPI.post(actor, %{
1174 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1177 assert Enum.map([actor, addressed], & &1.ap_id) --
1178 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1180 {:ok, user} = User.follow(user, actor)
1181 {:ok, _user_two} = User.follow(user_two, actor)
1182 recipients = User.get_recipients_from_activity(activity)
1183 assert length(recipients) == 3
1184 assert user in recipients
1185 assert addressed in recipients
1188 test "has following" do
1189 actor = insert(:user)
1190 user = insert(:user)
1191 user_two = insert(:user)
1192 addressed = insert(:user, local: true)
1195 CommonAPI.post(actor, %{
1196 status: "hey @#{addressed.nickname}"
1199 assert Enum.map([actor, addressed], & &1.ap_id) --
1200 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1202 {:ok, _actor} = User.follow(actor, user)
1203 {:ok, _actor} = User.follow(actor, user_two)
1204 recipients = User.get_recipients_from_activity(activity)
1205 assert length(recipients) == 2
1206 assert addressed in recipients
1210 describe ".deactivate" do
1211 test "can de-activate then re-activate a user" do
1212 user = insert(:user)
1213 assert false == user.deactivated
1214 {:ok, user} = User.deactivate(user)
1215 assert true == user.deactivated
1216 {:ok, user} = User.deactivate(user, false)
1217 assert false == user.deactivated
1220 test "hide a user from followers" do
1221 user = insert(:user)
1222 user2 = insert(:user)
1224 {:ok, user} = User.follow(user, user2)
1225 {:ok, _user} = User.deactivate(user)
1227 user2 = User.get_cached_by_id(user2.id)
1229 assert user2.follower_count == 0
1230 assert [] = User.get_followers(user2)
1233 test "hide a user from friends" do
1234 user = insert(:user)
1235 user2 = insert(:user)
1237 {:ok, user2} = User.follow(user2, user)
1238 assert user2.following_count == 1
1239 assert User.following_count(user2) == 1
1241 {:ok, _user} = User.deactivate(user)
1243 user2 = User.get_cached_by_id(user2.id)
1245 assert refresh_record(user2).following_count == 0
1246 assert user2.following_count == 0
1247 assert User.following_count(user2) == 0
1248 assert [] = User.get_friends(user2)
1251 test "hide a user's statuses from timelines and notifications" do
1252 user = insert(:user)
1253 user2 = insert(:user)
1255 {:ok, user2} = User.follow(user2, user)
1257 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1259 activity = Repo.preload(activity, :bookmark)
1261 [notification] = Pleroma.Notification.for_user(user2)
1262 assert notification.activity.id == activity.id
1264 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1266 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1267 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1271 {:ok, _user} = User.deactivate(user)
1273 assert [] == ActivityPub.fetch_public_activities(%{})
1274 assert [] == Pleroma.Notification.for_user(user2)
1277 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1283 describe "approve" do
1284 test "approves a user" do
1285 user = insert(:user, approval_pending: true)
1286 assert true == user.approval_pending
1287 {:ok, user} = User.approve(user)
1288 assert false == user.approval_pending
1291 test "approves a list of users" do
1292 unapproved_users = [
1293 insert(:user, approval_pending: true),
1294 insert(:user, approval_pending: true),
1295 insert(:user, approval_pending: true)
1298 {:ok, users} = User.approve(unapproved_users)
1300 assert Enum.count(users) == 3
1302 Enum.each(users, fn user ->
1303 assert false == user.approval_pending
1308 describe "delete" do
1310 {:ok, user} = insert(:user) |> User.set_cache()
1315 setup do: clear_config([:instance, :federating])
1317 test ".delete_user_activities deletes all create activities", %{user: user} do
1318 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1320 User.delete_user_activities(user)
1322 # TODO: Test removal favorites, repeats, delete activities.
1323 refute Activity.get_by_id(activity.id)
1326 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1327 follower = insert(:user)
1328 {:ok, follower} = User.follow(follower, user)
1330 locked_user = insert(:user, name: "locked", locked: true)
1331 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1333 object = insert(:note, user: user)
1334 activity = insert(:note_activity, user: user, note: object)
1336 object_two = insert(:note, user: follower)
1337 activity_two = insert(:note_activity, user: follower, note: object_two)
1339 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1340 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1341 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1343 {:ok, job} = User.delete(user)
1344 {:ok, _user} = ObanHelpers.perform(job)
1346 follower = User.get_cached_by_id(follower.id)
1348 refute User.following?(follower, user)
1349 assert %{deactivated: true} = User.get_by_id(user.id)
1351 assert [] == User.get_follow_requests(locked_user)
1355 |> Activity.Queries.by_actor()
1357 |> Enum.map(fn act -> act.data["type"] end)
1359 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1361 refute Activity.get_by_id(activity.id)
1362 refute Activity.get_by_id(like.id)
1363 refute Activity.get_by_id(like_two.id)
1364 refute Activity.get_by_id(repeat.id)
1368 describe "delete/1 when confirmation is pending" do
1370 user = insert(:user, confirmation_pending: true)
1374 test "deletes user from database when activation required", %{user: user} do
1375 clear_config([:instance, :account_activation_required], true)
1377 {:ok, job} = User.delete(user)
1378 {:ok, _} = ObanHelpers.perform(job)
1380 refute User.get_cached_by_id(user.id)
1381 refute User.get_by_id(user.id)
1384 test "deactivates user when activation is not required", %{user: user} do
1385 clear_config([:instance, :account_activation_required], false)
1387 {:ok, job} = User.delete(user)
1388 {:ok, _} = ObanHelpers.perform(job)
1390 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1391 assert %{deactivated: true} = User.get_by_id(user.id)
1395 test "delete/1 when approval is pending deletes the user" do
1396 user = insert(:user, approval_pending: true)
1399 {:ok, job} = User.delete(user)
1400 {:ok, _} = ObanHelpers.perform(job)
1402 refute User.get_cached_by_id(user.id)
1403 refute User.get_by_id(user.id)
1406 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1407 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1410 describe "per-user rich-text filtering" do
1411 test "html_filter_policy returns default policies, when rich-text is enabled" do
1412 user = insert(:user)
1414 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1417 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1418 user = insert(:user, no_rich_text: true)
1420 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1424 describe "caching" do
1425 test "invalidate_cache works" do
1426 user = insert(:user)
1428 User.set_cache(user)
1429 User.invalidate_cache(user)
1431 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1432 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1435 test "User.delete() plugs any possible zombie objects" do
1436 user = insert(:user)
1438 {:ok, job} = User.delete(user)
1439 {:ok, _} = ObanHelpers.perform(job)
1441 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1443 assert cached_user != user
1445 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1447 assert cached_user != user
1451 describe "account_status/1" do
1452 setup do: clear_config([:instance, :account_activation_required])
1454 test "return confirmation_pending for unconfirm user" do
1455 Pleroma.Config.put([:instance, :account_activation_required], true)
1456 user = insert(:user, confirmation_pending: true)
1457 assert User.account_status(user) == :confirmation_pending
1460 test "return active for confirmed user" do
1461 Pleroma.Config.put([:instance, :account_activation_required], true)
1462 user = insert(:user, confirmation_pending: false)
1463 assert User.account_status(user) == :active
1466 test "return active for remote user" do
1467 user = insert(:user, local: false)
1468 assert User.account_status(user) == :active
1471 test "returns :password_reset_pending for user with reset password" do
1472 user = insert(:user, password_reset_pending: true)
1473 assert User.account_status(user) == :password_reset_pending
1476 test "returns :deactivated for deactivated user" do
1477 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1478 assert User.account_status(user) == :deactivated
1481 test "returns :approval_pending for unapproved user" do
1482 user = insert(:user, local: true, approval_pending: true)
1483 assert User.account_status(user) == :approval_pending
1485 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1486 assert User.account_status(user) == :approval_pending
1490 describe "superuser?/1" do
1491 test "returns false for unprivileged users" do
1492 user = insert(:user, local: true)
1494 refute User.superuser?(user)
1497 test "returns false for remote users" do
1498 user = insert(:user, local: false)
1499 remote_admin_user = insert(:user, local: false, is_admin: true)
1501 refute User.superuser?(user)
1502 refute User.superuser?(remote_admin_user)
1505 test "returns true for local moderators" do
1506 user = insert(:user, local: true, is_moderator: true)
1508 assert User.superuser?(user)
1511 test "returns true for local admins" do
1512 user = insert(:user, local: true, is_admin: true)
1514 assert User.superuser?(user)
1518 describe "invisible?/1" do
1519 test "returns true for an invisible user" do
1520 user = insert(:user, local: true, invisible: true)
1522 assert User.invisible?(user)
1525 test "returns false for a non-invisible user" do
1526 user = insert(:user, local: true)
1528 refute User.invisible?(user)
1532 describe "visible_for/2" do
1533 test "returns true when the account is itself" do
1534 user = insert(:user, local: true)
1536 assert User.visible_for(user, user) == :visible
1539 test "returns false when the account is unauthenticated and auth is required" do
1540 Pleroma.Config.put([:instance, :account_activation_required], true)
1542 user = insert(:user, local: true, confirmation_pending: true)
1543 other_user = insert(:user, local: true)
1545 refute User.visible_for(user, other_user) == :visible
1548 test "returns true when the account is unauthenticated and auth is not required" do
1549 user = insert(:user, local: true, confirmation_pending: true)
1550 other_user = insert(:user, local: true)
1552 assert User.visible_for(user, other_user) == :visible
1555 test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do
1556 Pleroma.Config.put([:instance, :account_activation_required], true)
1558 user = insert(:user, local: true, confirmation_pending: true)
1559 other_user = insert(:user, local: true, is_admin: true)
1561 assert User.visible_for(user, other_user) == :visible
1565 describe "parse_bio/2" do
1566 test "preserves hosts in user links text" do
1567 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1568 user = insert(:user)
1569 bio = "A.k.a. @nick@domain.com"
1572 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1574 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1576 assert expected_text == User.parse_bio(bio, user)
1579 test "Adds rel=me on linkbacked urls" do
1580 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1582 bio = "http://example.com/rel_me/null"
1583 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1584 assert expected_text == User.parse_bio(bio, user)
1586 bio = "http://example.com/rel_me/link"
1587 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1588 assert expected_text == User.parse_bio(bio, user)
1590 bio = "http://example.com/rel_me/anchor"
1591 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1592 assert expected_text == User.parse_bio(bio, user)
1596 test "follower count is updated when a follower is blocked" do
1597 user = insert(:user)
1598 follower = insert(:user)
1599 follower2 = insert(:user)
1600 follower3 = insert(:user)
1602 {:ok, follower} = User.follow(follower, user)
1603 {:ok, _follower2} = User.follow(follower2, user)
1604 {:ok, _follower3} = User.follow(follower3, user)
1606 {:ok, _user_relationship} = User.block(user, follower)
1607 user = refresh_record(user)
1609 assert user.follower_count == 2
1612 describe "list_inactive_users_query/1" do
1613 defp days_ago(days) do
1615 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1616 -days * 60 * 60 * 24,
1621 test "Users are inactive by default" do
1625 Enum.map(1..total, fn _ ->
1626 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1629 inactive_users_ids =
1630 Pleroma.User.list_inactive_users_query()
1631 |> Pleroma.Repo.all()
1632 |> Enum.map(& &1.id)
1634 Enum.each(users, fn user ->
1635 assert user.id in inactive_users_ids
1639 test "Only includes users who has no recent activity" do
1643 Enum.map(1..total, fn _ ->
1644 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1647 {inactive, active} = Enum.split(users, trunc(total / 2))
1649 Enum.map(active, fn user ->
1650 to = Enum.random(users -- [user])
1653 CommonAPI.post(user, %{
1654 status: "hey @#{to.nickname}"
1658 inactive_users_ids =
1659 Pleroma.User.list_inactive_users_query()
1660 |> Pleroma.Repo.all()
1661 |> Enum.map(& &1.id)
1663 Enum.each(active, fn user ->
1664 refute user.id in inactive_users_ids
1667 Enum.each(inactive, fn user ->
1668 assert user.id in inactive_users_ids
1672 test "Only includes users with no read notifications" do
1676 Enum.map(1..total, fn _ ->
1677 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1680 [sender | recipients] = users
1681 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1683 Enum.each(recipients, fn to ->
1685 CommonAPI.post(sender, %{
1686 status: "hey @#{to.nickname}"
1690 CommonAPI.post(sender, %{
1691 status: "hey again @#{to.nickname}"
1695 Enum.each(active, fn user ->
1696 [n1, _n2] = Pleroma.Notification.for_user(user)
1697 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1700 inactive_users_ids =
1701 Pleroma.User.list_inactive_users_query()
1702 |> Pleroma.Repo.all()
1703 |> Enum.map(& &1.id)
1705 Enum.each(active, fn user ->
1706 refute user.id in inactive_users_ids
1709 Enum.each(inactive, fn user ->
1710 assert user.id in inactive_users_ids
1715 describe "toggle_confirmation/1" do
1716 test "if user is confirmed" do
1717 user = insert(:user, confirmation_pending: false)
1718 {:ok, user} = User.toggle_confirmation(user)
1720 assert user.confirmation_pending
1721 assert user.confirmation_token
1724 test "if user is unconfirmed" do
1725 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1726 {:ok, user} = User.toggle_confirmation(user)
1728 refute user.confirmation_pending
1729 refute user.confirmation_token
1733 describe "ensure_keys_present" do
1734 test "it creates keys for a user and stores them in info" do
1735 user = insert(:user)
1736 refute is_binary(user.keys)
1737 {:ok, user} = User.ensure_keys_present(user)
1738 assert is_binary(user.keys)
1741 test "it doesn't create keys if there already are some" do
1742 user = insert(:user, keys: "xxx")
1743 {:ok, user} = User.ensure_keys_present(user)
1744 assert user.keys == "xxx"
1748 describe "get_ap_ids_by_nicknames" do
1749 test "it returns a list of AP ids for a given set of nicknames" do
1750 user = insert(:user)
1751 user_two = insert(:user)
1753 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1754 assert length(ap_ids) == 2
1755 assert user.ap_id in ap_ids
1756 assert user_two.ap_id in ap_ids
1760 describe "sync followers count" do
1762 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1763 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1764 insert(:user, local: true)
1765 insert(:user, local: false, deactivated: true)
1766 {:ok, user1: user1, user2: user2}
1769 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1770 [fdb_user1] = User.external_users(limit: 1)
1772 assert fdb_user1.ap_id
1773 assert fdb_user1.ap_id == user1.ap_id
1774 assert fdb_user1.id == user1.id
1776 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1778 assert fdb_user2.ap_id
1779 assert fdb_user2.ap_id == user2.ap_id
1780 assert fdb_user2.id == user2.id
1782 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1786 describe "is_internal_user?/1" do
1787 test "non-internal user returns false" do
1788 user = insert(:user)
1789 refute User.is_internal_user?(user)
1792 test "user with no nickname returns true" do
1793 user = insert(:user, %{nickname: nil})
1794 assert User.is_internal_user?(user)
1797 test "user with internal-prefixed nickname returns true" do
1798 user = insert(:user, %{nickname: "internal.test"})
1799 assert User.is_internal_user?(user)
1803 describe "update_and_set_cache/1" do
1804 test "returns error when user is stale instead Ecto.StaleEntryError" do
1805 user = insert(:user)
1807 changeset = Ecto.Changeset.change(user, bio: "test")
1811 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1812 User.update_and_set_cache(changeset)
1815 test "performs update cache if user updated" do
1816 user = insert(:user)
1817 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1819 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1821 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1822 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1823 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1827 describe "following/followers synchronization" do
1828 setup do: clear_config([:instance, :external_user_synchronization])
1830 test "updates the counters normally on following/getting a follow when disabled" do
1831 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1832 user = insert(:user)
1837 follower_address: "http://localhost:4001/users/masto_closed/followers",
1838 following_address: "http://localhost:4001/users/masto_closed/following",
1842 assert other_user.following_count == 0
1843 assert other_user.follower_count == 0
1845 {:ok, user} = Pleroma.User.follow(user, other_user)
1846 other_user = Pleroma.User.get_by_id(other_user.id)
1848 assert user.following_count == 1
1849 assert other_user.follower_count == 1
1852 test "syncronizes the counters with the remote instance for the followed when enabled" do
1853 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1855 user = insert(:user)
1860 follower_address: "http://localhost:4001/users/masto_closed/followers",
1861 following_address: "http://localhost:4001/users/masto_closed/following",
1865 assert other_user.following_count == 0
1866 assert other_user.follower_count == 0
1868 Pleroma.Config.put([:instance, :external_user_synchronization], true)
1869 {:ok, _user} = User.follow(user, other_user)
1870 other_user = User.get_by_id(other_user.id)
1872 assert other_user.follower_count == 437
1875 test "syncronizes the counters with the remote instance for the follower when enabled" do
1876 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1878 user = insert(:user)
1883 follower_address: "http://localhost:4001/users/masto_closed/followers",
1884 following_address: "http://localhost:4001/users/masto_closed/following",
1888 assert other_user.following_count == 0
1889 assert other_user.follower_count == 0
1891 Pleroma.Config.put([:instance, :external_user_synchronization], true)
1892 {:ok, other_user} = User.follow(other_user, user)
1894 assert other_user.following_count == 152
1898 describe "change_email/2" do
1900 [user: insert(:user)]
1903 test "blank email returns error", %{user: user} do
1904 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
1905 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
1908 test "non unique email returns error", %{user: user} do
1909 %{email: email} = insert(:user)
1911 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
1912 User.change_email(user, email)
1915 test "invalid email returns error", %{user: user} do
1916 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
1917 User.change_email(user, "cofe")
1920 test "changes email", %{user: user} do
1921 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
1925 describe "get_cached_by_nickname_or_id" do
1927 local_user = insert(:user)
1928 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
1930 [local_user: local_user, remote_user: remote_user]
1933 setup do: clear_config([:instance, :limit_to_local_content])
1935 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
1936 remote_user: remote_user
1938 Pleroma.Config.put([:instance, :limit_to_local_content], false)
1939 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
1941 Pleroma.Config.put([:instance, :limit_to_local_content], true)
1942 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
1944 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
1945 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
1948 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
1949 %{remote_user: remote_user} do
1950 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
1951 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
1954 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
1955 %{remote_user: remote_user, local_user: local_user} do
1956 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
1957 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
1960 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
1961 %{remote_user: remote_user} do
1962 Pleroma.Config.put([:instance, :limit_to_local_content], true)
1963 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
1966 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
1967 %{local_user: local_user} do
1968 Pleroma.Config.put([:instance, :limit_to_local_content], false)
1969 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
1971 Pleroma.Config.put([:instance, :limit_to_local_content], true)
1972 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
1974 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
1975 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
1979 describe "update_email_notifications/2" do
1981 user = insert(:user, email_notifications: %{"digest" => true})
1986 test "Notifications are updated", %{user: user} do
1987 true = user.email_notifications["digest"]
1988 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
1989 assert result.email_notifications["digest"] == false
1993 test "avatar fallback" do
1994 user = insert(:user)
1995 assert User.avatar_url(user) =~ "/images/avi.png"
1997 clear_config([:assets, :default_user_avatar], "avatar.png")
1999 user = User.get_cached_by_nickname_or_id(user.nickname)
2000 assert User.avatar_url(user) =~ "avatar.png"
2002 assert User.avatar_url(user, no_default: true) == nil