1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.UserTest do
7 alias Pleroma.Builders.UserBuilder
10 alias Pleroma.Tests.ObanHelpers
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.CommonAPI
16 use Oban.Testing, repo: Pleroma.Repo
18 import Pleroma.Factory
19 import ExUnit.CaptureLog
20 import Swoosh.TestAssertions
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
27 setup do: clear_config([:instance, :account_activation_required])
29 describe "service actors" do
30 test "returns updated invisible actor" do
31 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
32 followers_uri = "#{uri}/followers"
41 follower_address: followers_uri
45 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
46 assert actor.invisible
49 test "returns relay user" do
50 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
51 followers_uri = "#{uri}/followers"
58 follower_address: ^followers_uri
59 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
61 assert capture_log(fn ->
62 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
63 end) =~ "Cannot create service actor:"
66 test "returns invisible actor" do
67 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
68 followers_uri = "#{uri}/followers"
69 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
72 nickname: "internal.fetch-test",
76 follower_address: ^followers_uri
79 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
80 assert user.id == user2.id
84 describe "AP ID user relationships" do
86 {:ok, user: insert(:user)}
89 test "outgoing_relationships_ap_ids/1", %{user: user} do
90 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
98 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
100 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
101 {rel_type, Enum.sort(ap_ids)}
105 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
106 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
108 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
109 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
111 assert ap_ids_by_rel[:notification_mute] ==
112 Enum.sort(User.notification_muted_users_ap_ids(user))
114 assert ap_ids_by_rel[:notification_mute] ==
115 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
117 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
119 assert ap_ids_by_rel[:reblog_mute] ==
120 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
122 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
124 assert ap_ids_by_rel[:inverse_subscription] ==
125 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
127 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
129 assert ap_ids_by_rel ==
130 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
134 describe "when tags are nil" do
135 test "tagging a user" do
136 user = insert(:user, %{tags: nil})
137 user = User.tag(user, ["cool", "dude"])
139 assert "cool" in user.tags
140 assert "dude" in user.tags
143 test "untagging a user" do
144 user = insert(:user, %{tags: nil})
145 user = User.untag(user, ["cool", "dude"])
147 assert user.tags == []
151 test "ap_id returns the activity pub id for the user" do
152 user = UserBuilder.build()
154 expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
156 assert expected_ap_id == User.ap_id(user)
159 test "ap_followers returns the followers collection for the user" do
160 user = UserBuilder.build()
162 expected_followers_collection = "#{User.ap_id(user)}/followers"
164 assert expected_followers_collection == User.ap_followers(user)
167 test "ap_following returns the following collection for the user" do
168 user = UserBuilder.build()
170 expected_followers_collection = "#{User.ap_id(user)}/following"
172 assert expected_followers_collection == User.ap_following(user)
175 test "returns all pending follow requests" do
176 unlocked = insert(:user)
177 locked = insert(:user, locked: true)
178 follower = insert(:user)
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
200 assert [^pending_follower] = User.get_follow_requests(locked)
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, locked: true)
205 pending_follower = insert(:user, %{deactivated: true})
207 CommonAPI.follow(pending_follower, locked)
209 assert true == pending_follower.deactivated
210 assert [] = User.get_follow_requests(locked)
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, locked: true)
215 follower = insert(:user)
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
224 test "follow_all follows mutliple users" do
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
236 {:ok, user} = User.follow(user, followed_zero)
238 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
240 assert User.following?(user, followed_one)
241 assert User.following?(user, followed_two)
242 assert User.following?(user, followed_zero)
243 refute User.following?(user, not_followed)
244 refute User.following?(user, blocked)
245 refute User.following?(user, reverse_blocked)
248 test "follow_all follows mutliple users without duplicating" do
250 followed_zero = insert(:user)
251 followed_one = insert(:user)
252 followed_two = insert(:user)
254 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
255 assert length(User.following(user)) == 3
257 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
258 assert length(User.following(user)) == 4
261 test "follow takes a user and another user" do
263 followed = insert(:user)
265 {:ok, user} = User.follow(user, followed)
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
270 assert followed.follower_count == 1
271 assert user.following_count == 1
273 assert User.ap_followers(followed) in User.following(user)
276 test "can't follow a deactivated users" do
278 followed = insert(:user, %{deactivated: true})
280 {:error, _} = User.follow(user, followed)
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
287 {:ok, _user_relationship} = User.block(blocker, blockee)
289 {:error, _} = User.follow(blockee, blocker)
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
296 {:ok, _user_relationship} = User.block(blocker, blocked)
298 {:error, _} = User.subscribe(blocked, blocker)
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, locked: true)
303 followed = insert(:user, locked: true)
305 {:ok, follower} = User.maybe_direct_follow(follower, followed)
307 refute User.following?(follower, followed)
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
313 test "unfollow with syncronizes external user" do
314 Pleroma.Config.put([:instance, :external_user_synchronization], true)
319 follower_address: "http://localhost:4001/users/fuser1/followers",
320 following_address: "http://localhost:4001/users/fuser1/following",
321 ap_id: "http://localhost:4001/users/fuser1"
328 ap_id: "http://localhost:4001/users/fuser2",
329 follower_address: "http://localhost:4001/users/fuser2/followers",
330 following_address: "http://localhost:4001/users/fuser2/following"
333 {:ok, user} = User.follow(user, followed, :follow_accept)
335 {:ok, user, _activity} = User.unfollow(user, followed)
337 user = User.get_cached_by_id(user.id)
339 assert User.following(user) == []
342 test "unfollow takes a user and another user" do
343 followed = insert(:user)
346 {:ok, user} = User.follow(user, followed, :follow_accept)
348 assert User.following(user) == [user.follower_address, followed.follower_address]
350 {:ok, user, _activity} = User.unfollow(user, followed)
352 assert User.following(user) == [user.follower_address]
355 test "unfollow doesn't unfollow yourself" do
358 {:error, _} = User.unfollow(user, user)
360 assert User.following(user) == [user.follower_address]
364 test "test if a user is following another user" do
365 followed = insert(:user)
367 User.follow(user, followed, :follow_accept)
369 assert User.following?(user, followed)
370 refute User.following?(followed, user)
373 test "fetches correct profile for nickname beginning with number" do
374 # Use old-style integer ID to try to reproduce the problem
375 user = insert(:user, %{id: 1080})
376 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
377 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
380 describe "user registration" do
386 password_confirmation: "test",
387 email: "email@example.com"
390 setup do: clear_config([:instance, :autofollowed_nicknames])
391 setup do: clear_config([:welcome])
392 setup do: clear_config([:instance, :account_activation_required])
394 test "it autofollows accounts that are set for it" do
396 remote_user = insert(:user, %{local: false})
398 Pleroma.Config.put([:instance, :autofollowed_nicknames], [
403 cng = User.register_changeset(%User{}, @full_user_data)
405 {:ok, registered_user} = User.register(cng)
407 assert User.following?(registered_user, user)
408 refute User.following?(registered_user, remote_user)
411 test "it sends a welcome message if it is set" do
412 welcome_user = insert(:user)
413 Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
414 Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
415 Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message")
417 cng = User.register_changeset(%User{}, @full_user_data)
418 {:ok, registered_user} = User.register(cng)
419 ObanHelpers.perform_all()
421 activity = Repo.one(Pleroma.Activity)
422 assert registered_user.ap_id in activity.recipients
423 assert Object.normalize(activity).data["content"] =~ "direct message"
424 assert activity.actor == welcome_user.ap_id
427 test "it sends a welcome chat message if it is set" do
428 welcome_user = insert(:user)
429 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
430 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
431 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
433 cng = User.register_changeset(%User{}, @full_user_data)
434 {:ok, registered_user} = User.register(cng)
435 ObanHelpers.perform_all()
437 activity = Repo.one(Pleroma.Activity)
438 assert registered_user.ap_id in activity.recipients
439 assert Object.normalize(activity).data["content"] =~ "chat message"
440 assert activity.actor == welcome_user.ap_id
444 clear_config(:mrf_simple,
447 federated_timeline_removal: [],
460 Pleroma.Web.ActivityPub.MRF.SimplePolicy
464 test "it sends a welcome chat message when Simple policy applied to local instance" do
465 Pleroma.Config.put([:mrf_simple, :media_nsfw], ["localhost"])
467 welcome_user = insert(:user)
468 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
469 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
470 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
472 cng = User.register_changeset(%User{}, @full_user_data)
473 {:ok, registered_user} = User.register(cng)
474 ObanHelpers.perform_all()
476 activity = Repo.one(Pleroma.Activity)
477 assert registered_user.ap_id in activity.recipients
478 assert Object.normalize(activity).data["content"] =~ "chat message"
479 assert activity.actor == welcome_user.ap_id
482 test "it sends a welcome email message if it is set" do
483 welcome_user = insert(:user)
484 Pleroma.Config.put([:welcome, :email, :enabled], true)
485 Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
488 [:welcome, :email, :subject],
489 "Hello, welcome to cool site: <%= instance_name %>"
492 instance_name = Pleroma.Config.get([:instance, :name])
494 cng = User.register_changeset(%User{}, @full_user_data)
495 {:ok, registered_user} = User.register(cng)
496 ObanHelpers.perform_all()
499 from: {instance_name, welcome_user.email},
500 to: {registered_user.name, registered_user.email},
501 subject: "Hello, welcome to cool site: #{instance_name}",
502 html_body: "Welcome to #{instance_name}"
506 test "it sends a confirm email" do
507 Pleroma.Config.put([:instance, :account_activation_required], true)
509 cng = User.register_changeset(%User{}, @full_user_data)
510 {:ok, registered_user} = User.register(cng)
511 ObanHelpers.perform_all()
512 assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
515 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
516 Pleroma.Config.put([:instance, :account_activation_required], true)
520 |> Enum.each(fn key ->
521 params = Map.delete(@full_user_data, key)
522 changeset = User.register_changeset(%User{}, params)
524 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
528 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
529 Pleroma.Config.put([:instance, :account_activation_required], false)
533 |> Enum.each(fn key ->
534 params = Map.delete(@full_user_data, key)
535 changeset = User.register_changeset(%User{}, params)
537 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
541 test "it restricts certain nicknames" do
542 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
544 assert is_bitstring(restricted_name)
548 |> Map.put(:nickname, restricted_name)
550 changeset = User.register_changeset(%User{}, params)
552 refute changeset.valid?
555 test "it blocks blacklisted email domains" do
556 clear_config([User, :email_blacklist], ["trolling.world"])
559 params = Map.put(@full_user_data, :email, "troll@trolling.world")
560 changeset = User.register_changeset(%User{}, params)
561 refute changeset.valid?
563 # Block with subdomain match
564 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
565 changeset = User.register_changeset(%User{}, params)
566 refute changeset.valid?
568 # Pass with different domains that are similar
569 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
570 changeset = User.register_changeset(%User{}, params)
571 assert changeset.valid?
573 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
574 changeset = User.register_changeset(%User{}, params)
575 assert changeset.valid?
578 test "it sets the password_hash and ap_id" do
579 changeset = User.register_changeset(%User{}, @full_user_data)
581 assert changeset.valid?
583 assert is_binary(changeset.changes[:password_hash])
584 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
586 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
589 test "it sets the 'accepts_chat_messages' set to true" do
590 changeset = User.register_changeset(%User{}, @full_user_data)
591 assert changeset.valid?
593 {:ok, user} = Repo.insert(changeset)
595 assert user.accepts_chat_messages
598 test "it creates a confirmed user" do
599 changeset = User.register_changeset(%User{}, @full_user_data)
600 assert changeset.valid?
602 {:ok, user} = Repo.insert(changeset)
604 refute user.confirmation_pending
608 describe "user registration, with :account_activation_required" do
614 password_confirmation: "test",
615 email: "email@example.com"
617 setup do: clear_config([:instance, :account_activation_required], true)
619 test "it creates unconfirmed user" do
620 changeset = User.register_changeset(%User{}, @full_user_data)
621 assert changeset.valid?
623 {:ok, user} = Repo.insert(changeset)
625 assert user.confirmation_pending
626 assert user.confirmation_token
629 test "it creates confirmed user if :confirmed option is given" do
630 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
631 assert changeset.valid?
633 {:ok, user} = Repo.insert(changeset)
635 refute user.confirmation_pending
636 refute user.confirmation_token
640 describe "user registration, with :account_approval_required" do
646 password_confirmation: "test",
647 email: "email@example.com",
648 registration_reason: "I'm a cool guy :)"
650 setup do: clear_config([:instance, :account_approval_required], true)
652 test "it creates unapproved user" do
653 changeset = User.register_changeset(%User{}, @full_user_data)
654 assert changeset.valid?
656 {:ok, user} = Repo.insert(changeset)
658 assert user.approval_pending
659 assert user.registration_reason == "I'm a cool guy :)"
662 test "it restricts length of registration reason" do
663 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
665 assert is_integer(reason_limit)
670 :registration_reason,
671 "Quia et nesciunt dolores numquam ipsam nisi sapiente soluta. Ullam repudiandae nisi quam porro officiis officiis ad. Consequatur animi velit ex quia. Odit voluptatem perferendis quia ut nisi. Dignissimos sit soluta atque aliquid dolorem ut dolorum ut. Labore voluptates iste iusto amet voluptatum earum. Ad fugit illum nam eos ut nemo. Pariatur ea fuga non aspernatur. Dignissimos debitis officia corporis est nisi ab et. Atque itaque alias eius voluptas minus. Accusamus numquam tempore occaecati in."
674 changeset = User.register_changeset(%User{}, params)
676 refute changeset.valid?
680 describe "get_or_fetch/1" do
681 test "gets an existing user by nickname" do
683 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
685 assert user == fetched_user
688 test "gets an existing user by ap_id" do
689 ap_id = "http://mastodon.example.org/users/admin"
695 nickname: "admin@mastodon.example.org",
699 {:ok, fetched_user} = User.get_or_fetch(ap_id)
700 freshed_user = refresh_record(user)
701 assert freshed_user == fetched_user
705 describe "fetching a user from nickname or trying to build one" do
706 test "gets an existing user" do
708 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
710 assert user == fetched_user
713 test "gets an existing user, case insensitive" do
714 user = insert(:user, nickname: "nick")
715 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
717 assert user == fetched_user
720 test "gets an existing user by fully qualified nickname" do
723 {:ok, fetched_user} =
724 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
726 assert user == fetched_user
729 test "gets an existing user by fully qualified nickname, case insensitive" do
730 user = insert(:user, nickname: "nick")
731 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
733 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
735 assert user == fetched_user
738 @tag capture_log: true
739 test "returns nil if no user could be fetched" do
740 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
741 assert fetched_user == "not found nonexistant@social.heldscal.la"
744 test "returns nil for nonexistant local user" do
745 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
746 assert fetched_user == "not found nonexistant"
749 test "updates an existing user, if stale" do
750 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
756 nickname: "admin@mastodon.example.org",
757 ap_id: "http://mastodon.example.org/users/admin",
758 last_refreshed_at: a_week_ago
761 assert orig_user.last_refreshed_at == a_week_ago
763 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
767 refute user.last_refreshed_at == orig_user.last_refreshed_at
770 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
771 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
777 nickname: "admin@mastodon.example.org",
778 ap_id: "http://mastodon.example.org/users/harinezumigari",
779 last_refreshed_at: a_week_ago
782 assert orig_user.last_refreshed_at == a_week_ago
784 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
788 refute user.id == orig_user.id
790 orig_user = User.get_by_id(orig_user.id)
792 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
795 @tag capture_log: true
796 test "it returns the old user if stale, but unfetchable" do
797 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
803 nickname: "admin@mastodon.example.org",
804 ap_id: "http://mastodon.example.org/users/raymoo",
805 last_refreshed_at: a_week_ago
808 assert orig_user.last_refreshed_at == a_week_ago
810 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
812 assert user.last_refreshed_at == orig_user.last_refreshed_at
816 test "returns an ap_id for a user" do
819 assert User.ap_id(user) ==
820 Pleroma.Web.Router.Helpers.user_feed_url(
821 Pleroma.Web.Endpoint,
827 test "returns an ap_followers link for a user" do
830 assert User.ap_followers(user) ==
831 Pleroma.Web.Router.Helpers.user_feed_url(
832 Pleroma.Web.Endpoint,
838 describe "remote user changeset" do
844 avatar: %{some: "avatar"}
846 setup do: clear_config([:instance, :user_bio_length])
847 setup do: clear_config([:instance, :user_name_length])
849 test "it confirms validity" do
850 cs = User.remote_user_changeset(@valid_remote)
854 test "it sets the follower_adress" do
855 cs = User.remote_user_changeset(@valid_remote)
856 # remote users get a fake local follower address
857 assert cs.changes.follower_address ==
858 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
861 test "it enforces the fqn format for nicknames" do
862 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
863 assert Ecto.Changeset.get_field(cs, :local) == false
864 assert cs.changes.avatar
868 test "it has required fields" do
870 |> Enum.each(fn field ->
871 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
877 describe "followers and friends" do
878 test "gets all followers for a given user" do
880 follower_one = insert(:user)
881 follower_two = insert(:user)
882 not_follower = insert(:user)
884 {:ok, follower_one} = User.follow(follower_one, user)
885 {:ok, follower_two} = User.follow(follower_two, user)
887 res = User.get_followers(user)
889 assert Enum.member?(res, follower_one)
890 assert Enum.member?(res, follower_two)
891 refute Enum.member?(res, not_follower)
894 test "gets all friends (followed users) for a given user" do
896 followed_one = insert(:user)
897 followed_two = insert(:user)
898 not_followed = insert(:user)
900 {:ok, user} = User.follow(user, followed_one)
901 {:ok, user} = User.follow(user, followed_two)
903 res = User.get_friends(user)
905 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
906 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
907 assert Enum.member?(res, followed_one)
908 assert Enum.member?(res, followed_two)
909 refute Enum.member?(res, not_followed)
913 describe "updating note and follower count" do
914 test "it sets the note_count property" do
917 user = User.get_cached_by_ap_id(note.data["actor"])
919 assert user.note_count == 0
921 {:ok, user} = User.update_note_count(user)
923 assert user.note_count == 1
926 test "it increases the note_count property" do
928 user = User.get_cached_by_ap_id(note.data["actor"])
930 assert user.note_count == 0
932 {:ok, user} = User.increase_note_count(user)
934 assert user.note_count == 1
936 {:ok, user} = User.increase_note_count(user)
938 assert user.note_count == 2
941 test "it decreases the note_count property" do
943 user = User.get_cached_by_ap_id(note.data["actor"])
945 assert user.note_count == 0
947 {:ok, user} = User.increase_note_count(user)
949 assert user.note_count == 1
951 {:ok, user} = User.decrease_note_count(user)
953 assert user.note_count == 0
955 {:ok, user} = User.decrease_note_count(user)
957 assert user.note_count == 0
960 test "it sets the follower_count property" do
962 follower = insert(:user)
964 User.follow(follower, user)
966 assert user.follower_count == 0
968 {:ok, user} = User.update_follower_count(user)
970 assert user.follower_count == 1
974 describe "follow_import" do
975 test "it imports user followings from list" do
976 [user1, user2, user3] = insert_list(3, :user)
983 {:ok, job} = User.follow_import(user1, identifiers)
985 assert {:ok, result} = ObanHelpers.perform(job)
986 assert is_list(result)
987 assert result == [user2, user3]
992 test "it mutes people" do
994 muted_user = insert(:user)
996 refute User.mutes?(user, muted_user)
997 refute User.muted_notifications?(user, muted_user)
999 {:ok, _user_relationships} = User.mute(user, muted_user)
1001 assert User.mutes?(user, muted_user)
1002 assert User.muted_notifications?(user, muted_user)
1006 user = insert(:user)
1007 muted_user = insert(:user)
1009 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1010 assert User.mutes?(user, muted_user)
1012 worker = Pleroma.Workers.MuteExpireWorker
1013 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1020 assert :ok = perform_job(worker, args)
1022 refute User.mutes?(user, muted_user)
1023 refute User.muted_notifications?(user, muted_user)
1026 test "it unmutes users" do
1027 user = insert(:user)
1028 muted_user = insert(:user)
1030 {:ok, _user_relationships} = User.mute(user, muted_user)
1031 {:ok, _user_mute} = User.unmute(user, muted_user)
1033 refute User.mutes?(user, muted_user)
1034 refute User.muted_notifications?(user, muted_user)
1037 test "it mutes user without notifications" do
1038 user = insert(:user)
1039 muted_user = insert(:user)
1041 refute User.mutes?(user, muted_user)
1042 refute User.muted_notifications?(user, muted_user)
1044 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1046 assert User.mutes?(user, muted_user)
1047 refute User.muted_notifications?(user, muted_user)
1051 describe "blocks" do
1052 test "it blocks people" do
1053 user = insert(:user)
1054 blocked_user = insert(:user)
1056 refute User.blocks?(user, blocked_user)
1058 {:ok, _user_relationship} = User.block(user, blocked_user)
1060 assert User.blocks?(user, blocked_user)
1063 test "it unblocks users" do
1064 user = insert(:user)
1065 blocked_user = insert(:user)
1067 {:ok, _user_relationship} = User.block(user, blocked_user)
1068 {:ok, _user_block} = User.unblock(user, blocked_user)
1070 refute User.blocks?(user, blocked_user)
1073 test "blocks tear down cyclical follow relationships" do
1074 blocker = insert(:user)
1075 blocked = insert(:user)
1077 {:ok, blocker} = User.follow(blocker, blocked)
1078 {:ok, blocked} = User.follow(blocked, blocker)
1080 assert User.following?(blocker, blocked)
1081 assert User.following?(blocked, blocker)
1083 {:ok, _user_relationship} = User.block(blocker, blocked)
1084 blocked = User.get_cached_by_id(blocked.id)
1086 assert User.blocks?(blocker, blocked)
1088 refute User.following?(blocker, blocked)
1089 refute User.following?(blocked, blocker)
1092 test "blocks tear down blocker->blocked follow relationships" do
1093 blocker = insert(:user)
1094 blocked = insert(:user)
1096 {:ok, blocker} = User.follow(blocker, blocked)
1098 assert User.following?(blocker, blocked)
1099 refute User.following?(blocked, blocker)
1101 {:ok, _user_relationship} = User.block(blocker, blocked)
1102 blocked = User.get_cached_by_id(blocked.id)
1104 assert User.blocks?(blocker, blocked)
1106 refute User.following?(blocker, blocked)
1107 refute User.following?(blocked, blocker)
1110 test "blocks tear down blocked->blocker follow relationships" do
1111 blocker = insert(:user)
1112 blocked = insert(:user)
1114 {:ok, blocked} = User.follow(blocked, blocker)
1116 refute User.following?(blocker, blocked)
1117 assert User.following?(blocked, blocker)
1119 {:ok, _user_relationship} = User.block(blocker, blocked)
1120 blocked = User.get_cached_by_id(blocked.id)
1122 assert User.blocks?(blocker, blocked)
1124 refute User.following?(blocker, blocked)
1125 refute User.following?(blocked, blocker)
1128 test "blocks tear down blocked->blocker subscription relationships" do
1129 blocker = insert(:user)
1130 blocked = insert(:user)
1132 {:ok, _subscription} = User.subscribe(blocked, blocker)
1134 assert User.subscribed_to?(blocked, blocker)
1135 refute User.subscribed_to?(blocker, blocked)
1137 {:ok, _user_relationship} = User.block(blocker, blocked)
1139 assert User.blocks?(blocker, blocked)
1140 refute User.subscribed_to?(blocker, blocked)
1141 refute User.subscribed_to?(blocked, blocker)
1145 describe "domain blocking" do
1146 test "blocks domains" do
1147 user = insert(:user)
1148 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1150 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1152 assert User.blocks?(user, collateral_user)
1155 test "does not block domain with same end" do
1156 user = insert(:user)
1159 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1161 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1163 refute User.blocks?(user, collateral_user)
1166 test "does not block domain with same end if wildcard added" do
1167 user = insert(:user)
1170 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1172 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1174 refute User.blocks?(user, collateral_user)
1177 test "blocks domain with wildcard for subdomain" do
1178 user = insert(:user)
1180 user_from_subdomain =
1181 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1183 user_with_two_subdomains =
1185 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1188 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1190 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1192 assert User.blocks?(user, user_from_subdomain)
1193 assert User.blocks?(user, user_with_two_subdomains)
1194 assert User.blocks?(user, user_domain)
1197 test "unblocks domains" do
1198 user = insert(:user)
1199 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1201 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1202 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1204 refute User.blocks?(user, collateral_user)
1207 test "follows take precedence over domain blocks" do
1208 user = insert(:user)
1209 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1211 {:ok, user} = User.block_domain(user, "meanies.social")
1212 {:ok, user} = User.follow(user, good_eggo)
1214 refute User.blocks?(user, good_eggo)
1218 describe "blocks_import" do
1219 test "it imports user blocks from list" do
1220 [user1, user2, user3] = insert_list(3, :user)
1227 {:ok, job} = User.blocks_import(user1, identifiers)
1229 assert {:ok, result} = ObanHelpers.perform(job)
1230 assert is_list(result)
1231 assert result == [user2, user3]
1235 describe "get_recipients_from_activity" do
1236 test "works for announces" do
1237 actor = insert(:user)
1238 user = insert(:user, local: true)
1240 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1241 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1243 recipients = User.get_recipients_from_activity(announce)
1245 assert user in recipients
1248 test "get recipients" do
1249 actor = insert(:user)
1250 user = insert(:user, local: true)
1251 user_two = insert(:user, local: false)
1252 addressed = insert(:user, local: true)
1253 addressed_remote = insert(:user, local: false)
1256 CommonAPI.post(actor, %{
1257 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1260 assert Enum.map([actor, addressed], & &1.ap_id) --
1261 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1263 {:ok, user} = User.follow(user, actor)
1264 {:ok, _user_two} = User.follow(user_two, actor)
1265 recipients = User.get_recipients_from_activity(activity)
1266 assert length(recipients) == 3
1267 assert user in recipients
1268 assert addressed in recipients
1271 test "has following" do
1272 actor = insert(:user)
1273 user = insert(:user)
1274 user_two = insert(:user)
1275 addressed = insert(:user, local: true)
1278 CommonAPI.post(actor, %{
1279 status: "hey @#{addressed.nickname}"
1282 assert Enum.map([actor, addressed], & &1.ap_id) --
1283 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1285 {:ok, _actor} = User.follow(actor, user)
1286 {:ok, _actor} = User.follow(actor, user_two)
1287 recipients = User.get_recipients_from_activity(activity)
1288 assert length(recipients) == 2
1289 assert addressed in recipients
1293 describe ".deactivate" do
1294 test "can de-activate then re-activate a user" do
1295 user = insert(:user)
1296 assert false == user.deactivated
1297 {:ok, user} = User.deactivate(user)
1298 assert true == user.deactivated
1299 {:ok, user} = User.deactivate(user, false)
1300 assert false == user.deactivated
1303 test "hide a user from followers" do
1304 user = insert(:user)
1305 user2 = insert(:user)
1307 {:ok, user} = User.follow(user, user2)
1308 {:ok, _user} = User.deactivate(user)
1310 user2 = User.get_cached_by_id(user2.id)
1312 assert user2.follower_count == 0
1313 assert [] = User.get_followers(user2)
1316 test "hide a user from friends" do
1317 user = insert(:user)
1318 user2 = insert(:user)
1320 {:ok, user2} = User.follow(user2, user)
1321 assert user2.following_count == 1
1322 assert User.following_count(user2) == 1
1324 {:ok, _user} = User.deactivate(user)
1326 user2 = User.get_cached_by_id(user2.id)
1328 assert refresh_record(user2).following_count == 0
1329 assert user2.following_count == 0
1330 assert User.following_count(user2) == 0
1331 assert [] = User.get_friends(user2)
1334 test "hide a user's statuses from timelines and notifications" do
1335 user = insert(:user)
1336 user2 = insert(:user)
1338 {:ok, user2} = User.follow(user2, user)
1340 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1342 activity = Repo.preload(activity, :bookmark)
1344 [notification] = Pleroma.Notification.for_user(user2)
1345 assert notification.activity.id == activity.id
1347 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1349 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1350 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1354 {:ok, _user} = User.deactivate(user)
1356 assert [] == ActivityPub.fetch_public_activities(%{})
1357 assert [] == Pleroma.Notification.for_user(user2)
1360 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1366 describe "approve" do
1367 test "approves a user" do
1368 user = insert(:user, approval_pending: true)
1369 assert true == user.approval_pending
1370 {:ok, user} = User.approve(user)
1371 assert false == user.approval_pending
1374 test "approves a list of users" do
1375 unapproved_users = [
1376 insert(:user, approval_pending: true),
1377 insert(:user, approval_pending: true),
1378 insert(:user, approval_pending: true)
1381 {:ok, users} = User.approve(unapproved_users)
1383 assert Enum.count(users) == 3
1385 Enum.each(users, fn user ->
1386 assert false == user.approval_pending
1391 describe "delete" do
1393 {:ok, user} = insert(:user) |> User.set_cache()
1398 setup do: clear_config([:instance, :federating])
1400 test ".delete_user_activities deletes all create activities", %{user: user} do
1401 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1403 User.delete_user_activities(user)
1405 # TODO: Test removal favorites, repeats, delete activities.
1406 refute Activity.get_by_id(activity.id)
1409 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1410 follower = insert(:user)
1411 {:ok, follower} = User.follow(follower, user)
1413 locked_user = insert(:user, name: "locked", locked: true)
1414 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1416 object = insert(:note, user: user)
1417 activity = insert(:note_activity, user: user, note: object)
1419 object_two = insert(:note, user: follower)
1420 activity_two = insert(:note_activity, user: follower, note: object_two)
1422 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1423 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1424 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1426 {:ok, job} = User.delete(user)
1427 {:ok, _user} = ObanHelpers.perform(job)
1429 follower = User.get_cached_by_id(follower.id)
1431 refute User.following?(follower, user)
1432 assert %{deactivated: true} = User.get_by_id(user.id)
1434 assert [] == User.get_follow_requests(locked_user)
1438 |> Activity.Queries.by_actor()
1440 |> Enum.map(fn act -> act.data["type"] end)
1442 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1444 refute Activity.get_by_id(activity.id)
1445 refute Activity.get_by_id(like.id)
1446 refute Activity.get_by_id(like_two.id)
1447 refute Activity.get_by_id(repeat.id)
1451 describe "delete/1 when confirmation is pending" do
1453 user = insert(:user, confirmation_pending: true)
1457 test "deletes user from database when activation required", %{user: user} do
1458 clear_config([:instance, :account_activation_required], true)
1460 {:ok, job} = User.delete(user)
1461 {:ok, _} = ObanHelpers.perform(job)
1463 refute User.get_cached_by_id(user.id)
1464 refute User.get_by_id(user.id)
1467 test "deactivates user when activation is not required", %{user: user} do
1468 clear_config([:instance, :account_activation_required], false)
1470 {:ok, job} = User.delete(user)
1471 {:ok, _} = ObanHelpers.perform(job)
1473 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1474 assert %{deactivated: true} = User.get_by_id(user.id)
1478 test "delete/1 when approval is pending deletes the user" do
1479 user = insert(:user, approval_pending: true)
1481 {:ok, job} = User.delete(user)
1482 {:ok, _} = ObanHelpers.perform(job)
1484 refute User.get_cached_by_id(user.id)
1485 refute User.get_by_id(user.id)
1488 test "delete/1 purges a user when they wouldn't be fully deleted" do
1493 password_hash: "pdfk2$1b3n159001",
1494 keys: "RSA begin buplic key",
1495 public_key: "--PRIVATE KEYE--",
1496 avatar: %{"a" => "b"},
1498 banner: %{"a" => "b"},
1499 background: %{"a" => "b"},
1502 following_count: 9001,
1504 confirmation_pending: true,
1505 password_reset_pending: true,
1506 approval_pending: true,
1507 registration_reason: "ahhhhh",
1508 confirmation_token: "qqqq",
1509 domain_blocks: ["lain.com"],
1514 mastofe_settings: %{"a" => "b"},
1515 mascot: %{"a" => "b"},
1516 emoji: %{"a" => "b"},
1517 pleroma_settings_store: %{"q" => "x"},
1518 fields: [%{"gg" => "qq"}],
1519 raw_fields: [%{"gg" => "qq"}],
1521 also_known_as: ["https://lol.olo/users/loll"]
1524 {:ok, job} = User.delete(user)
1525 {:ok, _} = ObanHelpers.perform(job)
1526 user = User.get_by_id(user.id)
1538 last_refreshed_at: nil,
1539 last_digest_emailed_at: nil,
1546 confirmation_pending: false,
1547 password_reset_pending: false,
1548 approval_pending: false,
1549 registration_reason: nil,
1550 confirmation_token: nil,
1554 is_moderator: false,
1556 mastofe_settings: nil,
1559 pleroma_settings_store: %{},
1562 discoverable: false,
1567 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1568 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1571 describe "per-user rich-text filtering" do
1572 test "html_filter_policy returns default policies, when rich-text is enabled" do
1573 user = insert(:user)
1575 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1578 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1579 user = insert(:user, no_rich_text: true)
1581 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1585 describe "caching" do
1586 test "invalidate_cache works" do
1587 user = insert(:user)
1589 User.set_cache(user)
1590 User.invalidate_cache(user)
1592 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1593 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1596 test "User.delete() plugs any possible zombie objects" do
1597 user = insert(:user)
1599 {:ok, job} = User.delete(user)
1600 {:ok, _} = ObanHelpers.perform(job)
1602 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1604 assert cached_user != user
1606 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1608 assert cached_user != user
1612 describe "account_status/1" do
1613 setup do: clear_config([:instance, :account_activation_required])
1615 test "return confirmation_pending for unconfirm user" do
1616 Pleroma.Config.put([:instance, :account_activation_required], true)
1617 user = insert(:user, confirmation_pending: true)
1618 assert User.account_status(user) == :confirmation_pending
1621 test "return active for confirmed user" do
1622 Pleroma.Config.put([:instance, :account_activation_required], true)
1623 user = insert(:user, confirmation_pending: false)
1624 assert User.account_status(user) == :active
1627 test "return active for remote user" do
1628 user = insert(:user, local: false)
1629 assert User.account_status(user) == :active
1632 test "returns :password_reset_pending for user with reset password" do
1633 user = insert(:user, password_reset_pending: true)
1634 assert User.account_status(user) == :password_reset_pending
1637 test "returns :deactivated for deactivated user" do
1638 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1639 assert User.account_status(user) == :deactivated
1642 test "returns :approval_pending for unapproved user" do
1643 user = insert(:user, local: true, approval_pending: true)
1644 assert User.account_status(user) == :approval_pending
1646 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1647 assert User.account_status(user) == :approval_pending
1651 describe "superuser?/1" do
1652 test "returns false for unprivileged users" do
1653 user = insert(:user, local: true)
1655 refute User.superuser?(user)
1658 test "returns false for remote users" do
1659 user = insert(:user, local: false)
1660 remote_admin_user = insert(:user, local: false, is_admin: true)
1662 refute User.superuser?(user)
1663 refute User.superuser?(remote_admin_user)
1666 test "returns true for local moderators" do
1667 user = insert(:user, local: true, is_moderator: true)
1669 assert User.superuser?(user)
1672 test "returns true for local admins" do
1673 user = insert(:user, local: true, is_admin: true)
1675 assert User.superuser?(user)
1679 describe "invisible?/1" do
1680 test "returns true for an invisible user" do
1681 user = insert(:user, local: true, invisible: true)
1683 assert User.invisible?(user)
1686 test "returns false for a non-invisible user" do
1687 user = insert(:user, local: true)
1689 refute User.invisible?(user)
1693 describe "visible_for/2" do
1694 test "returns true when the account is itself" do
1695 user = insert(:user, local: true)
1697 assert User.visible_for(user, user) == :visible
1700 test "returns false when the account is unconfirmed and confirmation is required" do
1701 Pleroma.Config.put([:instance, :account_activation_required], true)
1703 user = insert(:user, local: true, confirmation_pending: true)
1704 other_user = insert(:user, local: true)
1706 refute User.visible_for(user, other_user) == :visible
1709 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1710 Pleroma.Config.put([:instance, :account_activation_required], true)
1712 user = insert(:user, local: false, confirmation_pending: true)
1713 other_user = insert(:user, local: true)
1715 assert User.visible_for(user, other_user) == :visible
1718 test "returns true when the account is unconfirmed and confirmation is not required" do
1719 user = insert(:user, local: true, confirmation_pending: true)
1720 other_user = insert(:user, local: true)
1722 assert User.visible_for(user, other_user) == :visible
1725 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1726 Pleroma.Config.put([:instance, :account_activation_required], true)
1728 user = insert(:user, local: true, confirmation_pending: true)
1729 other_user = insert(:user, local: true, is_admin: true)
1731 assert User.visible_for(user, other_user) == :visible
1735 describe "parse_bio/2" do
1736 test "preserves hosts in user links text" do
1737 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1738 user = insert(:user)
1739 bio = "A.k.a. @nick@domain.com"
1742 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1744 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1746 assert expected_text == User.parse_bio(bio, user)
1749 test "Adds rel=me on linkbacked urls" do
1750 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1752 bio = "http://example.com/rel_me/null"
1753 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1754 assert expected_text == User.parse_bio(bio, user)
1756 bio = "http://example.com/rel_me/link"
1757 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1758 assert expected_text == User.parse_bio(bio, user)
1760 bio = "http://example.com/rel_me/anchor"
1761 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1762 assert expected_text == User.parse_bio(bio, user)
1766 test "follower count is updated when a follower is blocked" do
1767 user = insert(:user)
1768 follower = insert(:user)
1769 follower2 = insert(:user)
1770 follower3 = insert(:user)
1772 {:ok, follower} = User.follow(follower, user)
1773 {:ok, _follower2} = User.follow(follower2, user)
1774 {:ok, _follower3} = User.follow(follower3, user)
1776 {:ok, _user_relationship} = User.block(user, follower)
1777 user = refresh_record(user)
1779 assert user.follower_count == 2
1782 describe "list_inactive_users_query/1" do
1783 defp days_ago(days) do
1785 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1786 -days * 60 * 60 * 24,
1791 test "Users are inactive by default" do
1795 Enum.map(1..total, fn _ ->
1796 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1799 inactive_users_ids =
1800 Pleroma.User.list_inactive_users_query()
1801 |> Pleroma.Repo.all()
1802 |> Enum.map(& &1.id)
1804 Enum.each(users, fn user ->
1805 assert user.id in inactive_users_ids
1809 test "Only includes users who has no recent activity" do
1813 Enum.map(1..total, fn _ ->
1814 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1817 {inactive, active} = Enum.split(users, trunc(total / 2))
1819 Enum.map(active, fn user ->
1820 to = Enum.random(users -- [user])
1823 CommonAPI.post(user, %{
1824 status: "hey @#{to.nickname}"
1828 inactive_users_ids =
1829 Pleroma.User.list_inactive_users_query()
1830 |> Pleroma.Repo.all()
1831 |> Enum.map(& &1.id)
1833 Enum.each(active, fn user ->
1834 refute user.id in inactive_users_ids
1837 Enum.each(inactive, fn user ->
1838 assert user.id in inactive_users_ids
1842 test "Only includes users with no read notifications" do
1846 Enum.map(1..total, fn _ ->
1847 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1850 [sender | recipients] = users
1851 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1853 Enum.each(recipients, fn to ->
1855 CommonAPI.post(sender, %{
1856 status: "hey @#{to.nickname}"
1860 CommonAPI.post(sender, %{
1861 status: "hey again @#{to.nickname}"
1865 Enum.each(active, fn user ->
1866 [n1, _n2] = Pleroma.Notification.for_user(user)
1867 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1870 inactive_users_ids =
1871 Pleroma.User.list_inactive_users_query()
1872 |> Pleroma.Repo.all()
1873 |> Enum.map(& &1.id)
1875 Enum.each(active, fn user ->
1876 refute user.id in inactive_users_ids
1879 Enum.each(inactive, fn user ->
1880 assert user.id in inactive_users_ids
1885 describe "toggle_confirmation/1" do
1886 test "if user is confirmed" do
1887 user = insert(:user, confirmation_pending: false)
1888 {:ok, user} = User.toggle_confirmation(user)
1890 assert user.confirmation_pending
1891 assert user.confirmation_token
1894 test "if user is unconfirmed" do
1895 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1896 {:ok, user} = User.toggle_confirmation(user)
1898 refute user.confirmation_pending
1899 refute user.confirmation_token
1903 describe "ensure_keys_present" do
1904 test "it creates keys for a user and stores them in info" do
1905 user = insert(:user)
1906 refute is_binary(user.keys)
1907 {:ok, user} = User.ensure_keys_present(user)
1908 assert is_binary(user.keys)
1911 test "it doesn't create keys if there already are some" do
1912 user = insert(:user, keys: "xxx")
1913 {:ok, user} = User.ensure_keys_present(user)
1914 assert user.keys == "xxx"
1918 describe "get_ap_ids_by_nicknames" do
1919 test "it returns a list of AP ids for a given set of nicknames" do
1920 user = insert(:user)
1921 user_two = insert(:user)
1923 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1924 assert length(ap_ids) == 2
1925 assert user.ap_id in ap_ids
1926 assert user_two.ap_id in ap_ids
1930 describe "sync followers count" do
1932 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1933 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1934 insert(:user, local: true)
1935 insert(:user, local: false, deactivated: true)
1936 {:ok, user1: user1, user2: user2}
1939 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1940 [fdb_user1] = User.external_users(limit: 1)
1942 assert fdb_user1.ap_id
1943 assert fdb_user1.ap_id == user1.ap_id
1944 assert fdb_user1.id == user1.id
1946 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1948 assert fdb_user2.ap_id
1949 assert fdb_user2.ap_id == user2.ap_id
1950 assert fdb_user2.id == user2.id
1952 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1956 describe "is_internal_user?/1" do
1957 test "non-internal user returns false" do
1958 user = insert(:user)
1959 refute User.is_internal_user?(user)
1962 test "user with no nickname returns true" do
1963 user = insert(:user, %{nickname: nil})
1964 assert User.is_internal_user?(user)
1967 test "user with internal-prefixed nickname returns true" do
1968 user = insert(:user, %{nickname: "internal.test"})
1969 assert User.is_internal_user?(user)
1973 describe "update_and_set_cache/1" do
1974 test "returns error when user is stale instead Ecto.StaleEntryError" do
1975 user = insert(:user)
1977 changeset = Ecto.Changeset.change(user, bio: "test")
1981 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1982 User.update_and_set_cache(changeset)
1985 test "performs update cache if user updated" do
1986 user = insert(:user)
1987 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1989 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1991 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1992 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1993 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1997 describe "following/followers synchronization" do
1998 setup do: clear_config([:instance, :external_user_synchronization])
2000 test "updates the counters normally on following/getting a follow when disabled" do
2001 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2002 user = insert(:user)
2007 follower_address: "http://localhost:4001/users/masto_closed/followers",
2008 following_address: "http://localhost:4001/users/masto_closed/following",
2012 assert other_user.following_count == 0
2013 assert other_user.follower_count == 0
2015 {:ok, user} = Pleroma.User.follow(user, other_user)
2016 other_user = Pleroma.User.get_by_id(other_user.id)
2018 assert user.following_count == 1
2019 assert other_user.follower_count == 1
2022 test "syncronizes the counters with the remote instance for the followed when enabled" do
2023 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2025 user = insert(:user)
2030 follower_address: "http://localhost:4001/users/masto_closed/followers",
2031 following_address: "http://localhost:4001/users/masto_closed/following",
2035 assert other_user.following_count == 0
2036 assert other_user.follower_count == 0
2038 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2039 {:ok, _user} = User.follow(user, other_user)
2040 other_user = User.get_by_id(other_user.id)
2042 assert other_user.follower_count == 437
2045 test "syncronizes the counters with the remote instance for the follower when enabled" do
2046 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2048 user = insert(:user)
2053 follower_address: "http://localhost:4001/users/masto_closed/followers",
2054 following_address: "http://localhost:4001/users/masto_closed/following",
2058 assert other_user.following_count == 0
2059 assert other_user.follower_count == 0
2061 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2062 {:ok, other_user} = User.follow(other_user, user)
2064 assert other_user.following_count == 152
2068 describe "change_email/2" do
2070 [user: insert(:user)]
2073 test "blank email returns error", %{user: user} do
2074 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2075 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2078 test "non unique email returns error", %{user: user} do
2079 %{email: email} = insert(:user)
2081 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2082 User.change_email(user, email)
2085 test "invalid email returns error", %{user: user} do
2086 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2087 User.change_email(user, "cofe")
2090 test "changes email", %{user: user} do
2091 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2095 describe "get_cached_by_nickname_or_id" do
2097 local_user = insert(:user)
2098 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2100 [local_user: local_user, remote_user: remote_user]
2103 setup do: clear_config([:instance, :limit_to_local_content])
2105 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2106 remote_user: remote_user
2108 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2109 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2111 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2112 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2114 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2115 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2118 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2119 %{remote_user: remote_user} do
2120 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2121 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2124 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2125 %{remote_user: remote_user, local_user: local_user} do
2126 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2127 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2130 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2131 %{remote_user: remote_user} do
2132 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2133 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2136 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2137 %{local_user: local_user} do
2138 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2139 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2141 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2142 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2144 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2145 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2149 describe "update_email_notifications/2" do
2151 user = insert(:user, email_notifications: %{"digest" => true})
2156 test "Notifications are updated", %{user: user} do
2157 true = user.email_notifications["digest"]
2158 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2159 assert result.email_notifications["digest"] == false
2163 test "avatar fallback" do
2164 user = insert(:user)
2165 assert User.avatar_url(user) =~ "/images/avi.png"
2167 clear_config([:assets, :default_user_avatar], "avatar.png")
2169 user = User.get_cached_by_nickname_or_id(user.nickname)
2170 assert User.avatar_url(user) =~ "avatar.png"
2172 assert User.avatar_url(user, no_default: true) == nil