1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.UserTest do
7 alias Pleroma.Builders.UserBuilder
10 alias Pleroma.Tests.ObanHelpers
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.CommonAPI
16 use Oban.Testing, repo: Pleroma.Repo
18 import Pleroma.Factory
19 import ExUnit.CaptureLog
20 import Swoosh.TestAssertions
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
27 setup do: clear_config([:instance, :account_activation_required])
29 describe "service actors" do
30 test "returns updated invisible actor" do
31 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
32 followers_uri = "#{uri}/followers"
41 follower_address: followers_uri
45 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
46 assert actor.invisible
49 test "returns relay user" do
50 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
51 followers_uri = "#{uri}/followers"
58 follower_address: ^followers_uri
59 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
61 assert capture_log(fn ->
62 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
63 end) =~ "Cannot create service actor:"
66 test "returns invisible actor" do
67 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
68 followers_uri = "#{uri}/followers"
69 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
72 nickname: "internal.fetch-test",
76 follower_address: ^followers_uri
79 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
80 assert user.id == user2.id
84 describe "AP ID user relationships" do
86 {:ok, user: insert(:user)}
89 test "outgoing_relationships_ap_ids/1", %{user: user} do
90 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
98 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
100 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
101 {rel_type, Enum.sort(ap_ids)}
105 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
106 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
108 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
109 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
111 assert ap_ids_by_rel[:notification_mute] ==
112 Enum.sort(User.notification_muted_users_ap_ids(user))
114 assert ap_ids_by_rel[:notification_mute] ==
115 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
117 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
119 assert ap_ids_by_rel[:reblog_mute] ==
120 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
122 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
124 assert ap_ids_by_rel[:inverse_subscription] ==
125 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
127 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
129 assert ap_ids_by_rel ==
130 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
134 describe "when tags are nil" do
135 test "tagging a user" do
136 user = insert(:user, %{tags: nil})
137 user = User.tag(user, ["cool", "dude"])
139 assert "cool" in user.tags
140 assert "dude" in user.tags
143 test "untagging a user" do
144 user = insert(:user, %{tags: nil})
145 user = User.untag(user, ["cool", "dude"])
147 assert user.tags == []
151 test "ap_id returns the activity pub id for the user" do
152 user = UserBuilder.build()
154 expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
156 assert expected_ap_id == User.ap_id(user)
159 test "ap_followers returns the followers collection for the user" do
160 user = UserBuilder.build()
162 expected_followers_collection = "#{User.ap_id(user)}/followers"
164 assert expected_followers_collection == User.ap_followers(user)
167 test "ap_following returns the following collection for the user" do
168 user = UserBuilder.build()
170 expected_followers_collection = "#{User.ap_id(user)}/following"
172 assert expected_followers_collection == User.ap_following(user)
175 test "returns all pending follow requests" do
176 unlocked = insert(:user)
177 locked = insert(:user, is_locked: true)
178 follower = insert(:user)
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, is_locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
200 assert [^pending_follower] = User.get_follow_requests(locked)
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, is_locked: true)
205 pending_follower = insert(:user, %{deactivated: true})
207 CommonAPI.follow(pending_follower, locked)
209 assert true == pending_follower.deactivated
210 assert [] = User.get_follow_requests(locked)
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, is_locked: true)
215 follower = insert(:user)
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
224 test "follow_all follows mutliple users" do
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
236 {:ok, user} = User.follow(user, followed_zero)
238 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
240 assert User.following?(user, followed_one)
241 assert User.following?(user, followed_two)
242 assert User.following?(user, followed_zero)
243 refute User.following?(user, not_followed)
244 refute User.following?(user, blocked)
245 refute User.following?(user, reverse_blocked)
248 test "follow_all follows mutliple users without duplicating" do
250 followed_zero = insert(:user)
251 followed_one = insert(:user)
252 followed_two = insert(:user)
254 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
255 assert length(User.following(user)) == 3
257 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
258 assert length(User.following(user)) == 4
261 test "follow takes a user and another user" do
263 followed = insert(:user)
265 {:ok, user} = User.follow(user, followed)
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
270 assert followed.follower_count == 1
271 assert user.following_count == 1
273 assert User.ap_followers(followed) in User.following(user)
276 test "can't follow a deactivated users" do
278 followed = insert(:user, %{deactivated: true})
280 {:error, _} = User.follow(user, followed)
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
287 {:ok, _user_relationship} = User.block(blocker, blockee)
289 {:error, _} = User.follow(blockee, blocker)
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
296 {:ok, _user_relationship} = User.block(blocker, blocked)
298 {:error, _} = User.subscribe(blocked, blocker)
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, is_locked: true)
303 followed = insert(:user, is_locked: true)
305 {:ok, follower} = User.maybe_direct_follow(follower, followed)
307 refute User.following?(follower, followed)
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
313 test "unfollow with syncronizes external user" do
314 Pleroma.Config.put([:instance, :external_user_synchronization], true)
319 follower_address: "http://localhost:4001/users/fuser1/followers",
320 following_address: "http://localhost:4001/users/fuser1/following",
321 ap_id: "http://localhost:4001/users/fuser1"
328 ap_id: "http://localhost:4001/users/fuser2",
329 follower_address: "http://localhost:4001/users/fuser2/followers",
330 following_address: "http://localhost:4001/users/fuser2/following"
333 {:ok, user} = User.follow(user, followed, :follow_accept)
335 {:ok, user, _activity} = User.unfollow(user, followed)
337 user = User.get_cached_by_id(user.id)
339 assert User.following(user) == []
342 test "unfollow takes a user and another user" do
343 followed = insert(:user)
346 {:ok, user} = User.follow(user, followed, :follow_accept)
348 assert User.following(user) == [user.follower_address, followed.follower_address]
350 {:ok, user, _activity} = User.unfollow(user, followed)
352 assert User.following(user) == [user.follower_address]
355 test "unfollow doesn't unfollow yourself" do
358 {:error, _} = User.unfollow(user, user)
360 assert User.following(user) == [user.follower_address]
364 test "test if a user is following another user" do
365 followed = insert(:user)
367 User.follow(user, followed, :follow_accept)
369 assert User.following?(user, followed)
370 refute User.following?(followed, user)
373 test "fetches correct profile for nickname beginning with number" do
374 # Use old-style integer ID to try to reproduce the problem
375 user = insert(:user, %{id: 1080})
376 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
377 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
380 describe "user registration" do
386 password_confirmation: "test",
387 email: "email@example.com"
390 setup do: clear_config([:instance, :autofollowed_nicknames])
391 setup do: clear_config([:instance, :autofollowing_nicknames])
392 setup do: clear_config([:welcome])
393 setup do: clear_config([:instance, :account_activation_required])
395 test "it autofollows accounts that are set for it" do
397 remote_user = insert(:user, %{local: false})
399 Pleroma.Config.put([:instance, :autofollowed_nicknames], [
404 cng = User.register_changeset(%User{}, @full_user_data)
406 {:ok, registered_user} = User.register(cng)
408 assert User.following?(registered_user, user)
409 refute User.following?(registered_user, remote_user)
412 test "it adds automatic followers for new registered accounts" do
413 user1 = insert(:user)
414 user2 = insert(:user)
416 Pleroma.Config.put([:instance, :autofollowing_nicknames], [
421 cng = User.register_changeset(%User{}, @full_user_data)
423 {:ok, registered_user} = User.register(cng)
425 assert User.following?(user1, registered_user)
426 assert User.following?(user2, registered_user)
429 test "it sends a welcome message if it is set" do
430 welcome_user = insert(:user)
431 Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
432 Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
433 Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message")
435 cng = User.register_changeset(%User{}, @full_user_data)
436 {:ok, registered_user} = User.register(cng)
437 ObanHelpers.perform_all()
439 activity = Repo.one(Pleroma.Activity)
440 assert registered_user.ap_id in activity.recipients
441 assert Object.normalize(activity).data["content"] =~ "direct message"
442 assert activity.actor == welcome_user.ap_id
445 test "it sends a welcome chat message if it is set" do
446 welcome_user = insert(:user)
447 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
448 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
449 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
451 cng = User.register_changeset(%User{}, @full_user_data)
452 {:ok, registered_user} = User.register(cng)
453 ObanHelpers.perform_all()
455 activity = Repo.one(Pleroma.Activity)
456 assert registered_user.ap_id in activity.recipients
457 assert Object.normalize(activity).data["content"] =~ "chat message"
458 assert activity.actor == welcome_user.ap_id
462 clear_config(:mrf_simple,
465 federated_timeline_removal: [],
478 Pleroma.Web.ActivityPub.MRF.SimplePolicy
482 test "it sends a welcome chat message when Simple policy applied to local instance" do
483 Pleroma.Config.put([:mrf_simple, :media_nsfw], ["localhost"])
485 welcome_user = insert(:user)
486 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
487 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
488 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
490 cng = User.register_changeset(%User{}, @full_user_data)
491 {:ok, registered_user} = User.register(cng)
492 ObanHelpers.perform_all()
494 activity = Repo.one(Pleroma.Activity)
495 assert registered_user.ap_id in activity.recipients
496 assert Object.normalize(activity).data["content"] =~ "chat message"
497 assert activity.actor == welcome_user.ap_id
500 test "it sends a welcome email message if it is set" do
501 welcome_user = insert(:user)
502 Pleroma.Config.put([:welcome, :email, :enabled], true)
503 Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
506 [:welcome, :email, :subject],
507 "Hello, welcome to cool site: <%= instance_name %>"
510 instance_name = Pleroma.Config.get([:instance, :name])
512 cng = User.register_changeset(%User{}, @full_user_data)
513 {:ok, registered_user} = User.register(cng)
514 ObanHelpers.perform_all()
517 from: {instance_name, welcome_user.email},
518 to: {registered_user.name, registered_user.email},
519 subject: "Hello, welcome to cool site: #{instance_name}",
520 html_body: "Welcome to #{instance_name}"
524 test "it sends a confirm email" do
525 Pleroma.Config.put([:instance, :account_activation_required], true)
527 cng = User.register_changeset(%User{}, @full_user_data)
528 {:ok, registered_user} = User.register(cng)
529 ObanHelpers.perform_all()
531 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
532 # temporary hackney fix until hackney max_connections bug is fixed
533 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
534 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
535 |> assert_email_sent()
538 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
539 Pleroma.Config.put([:instance, :account_activation_required], true)
543 |> Enum.each(fn key ->
544 params = Map.delete(@full_user_data, key)
545 changeset = User.register_changeset(%User{}, params)
547 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
551 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
552 Pleroma.Config.put([:instance, :account_activation_required], false)
556 |> Enum.each(fn key ->
557 params = Map.delete(@full_user_data, key)
558 changeset = User.register_changeset(%User{}, params)
560 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
564 test "it restricts certain nicknames" do
565 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
567 assert is_bitstring(restricted_name)
571 |> Map.put(:nickname, restricted_name)
573 changeset = User.register_changeset(%User{}, params)
575 refute changeset.valid?
578 test "it blocks blacklisted email domains" do
579 clear_config([User, :email_blacklist], ["trolling.world"])
582 params = Map.put(@full_user_data, :email, "troll@trolling.world")
583 changeset = User.register_changeset(%User{}, params)
584 refute changeset.valid?
586 # Block with subdomain match
587 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
588 changeset = User.register_changeset(%User{}, params)
589 refute changeset.valid?
591 # Pass with different domains that are similar
592 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
593 changeset = User.register_changeset(%User{}, params)
594 assert changeset.valid?
596 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
597 changeset = User.register_changeset(%User{}, params)
598 assert changeset.valid?
601 test "it sets the password_hash and ap_id" do
602 changeset = User.register_changeset(%User{}, @full_user_data)
604 assert changeset.valid?
606 assert is_binary(changeset.changes[:password_hash])
607 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
609 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
612 test "it sets the 'accepts_chat_messages' set to true" do
613 changeset = User.register_changeset(%User{}, @full_user_data)
614 assert changeset.valid?
616 {:ok, user} = Repo.insert(changeset)
618 assert user.accepts_chat_messages
621 test "it creates a confirmed user" do
622 changeset = User.register_changeset(%User{}, @full_user_data)
623 assert changeset.valid?
625 {:ok, user} = Repo.insert(changeset)
627 refute user.confirmation_pending
631 describe "user registration, with :account_activation_required" do
637 password_confirmation: "test",
638 email: "email@example.com"
640 setup do: clear_config([:instance, :account_activation_required], true)
642 test "it creates unconfirmed user" do
643 changeset = User.register_changeset(%User{}, @full_user_data)
644 assert changeset.valid?
646 {:ok, user} = Repo.insert(changeset)
648 assert user.confirmation_pending
649 assert user.confirmation_token
652 test "it creates confirmed user if :confirmed option is given" do
653 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
654 assert changeset.valid?
656 {:ok, user} = Repo.insert(changeset)
658 refute user.confirmation_pending
659 refute user.confirmation_token
663 describe "user registration, with :account_approval_required" do
669 password_confirmation: "test",
670 email: "email@example.com",
671 registration_reason: "I'm a cool guy :)"
673 setup do: clear_config([:instance, :account_approval_required], true)
675 test "it creates unapproved user" do
676 changeset = User.register_changeset(%User{}, @full_user_data)
677 assert changeset.valid?
679 {:ok, user} = Repo.insert(changeset)
681 assert user.approval_pending
682 assert user.registration_reason == "I'm a cool guy :)"
685 test "it restricts length of registration reason" do
686 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
688 assert is_integer(reason_limit)
693 :registration_reason,
694 "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."
697 changeset = User.register_changeset(%User{}, params)
699 refute changeset.valid?
703 describe "get_or_fetch/1" do
704 test "gets an existing user by nickname" do
706 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
708 assert user == fetched_user
711 test "gets an existing user by ap_id" do
712 ap_id = "http://mastodon.example.org/users/admin"
718 nickname: "admin@mastodon.example.org",
722 {:ok, fetched_user} = User.get_or_fetch(ap_id)
723 freshed_user = refresh_record(user)
724 assert freshed_user == fetched_user
728 describe "fetching a user from nickname or trying to build one" do
729 test "gets an existing user" do
731 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
733 assert user == fetched_user
736 test "gets an existing user, case insensitive" do
737 user = insert(:user, nickname: "nick")
738 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
740 assert user == fetched_user
743 test "gets an existing user by fully qualified nickname" do
746 {:ok, fetched_user} =
747 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
749 assert user == fetched_user
752 test "gets an existing user by fully qualified nickname, case insensitive" do
753 user = insert(:user, nickname: "nick")
754 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
756 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
758 assert user == fetched_user
761 @tag capture_log: true
762 test "returns nil if no user could be fetched" do
763 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
764 assert fetched_user == "not found nonexistant@social.heldscal.la"
767 test "returns nil for nonexistant local user" do
768 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
769 assert fetched_user == "not found nonexistant"
772 test "updates an existing user, if stale" do
773 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
779 nickname: "admin@mastodon.example.org",
780 ap_id: "http://mastodon.example.org/users/admin",
781 last_refreshed_at: a_week_ago
784 assert orig_user.last_refreshed_at == a_week_ago
786 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
790 refute user.last_refreshed_at == orig_user.last_refreshed_at
793 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
794 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
800 nickname: "admin@mastodon.example.org",
801 ap_id: "http://mastodon.example.org/users/harinezumigari",
802 last_refreshed_at: a_week_ago
805 assert orig_user.last_refreshed_at == a_week_ago
807 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
811 refute user.id == orig_user.id
813 orig_user = User.get_by_id(orig_user.id)
815 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
818 @tag capture_log: true
819 test "it returns the old user if stale, but unfetchable" do
820 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
826 nickname: "admin@mastodon.example.org",
827 ap_id: "http://mastodon.example.org/users/raymoo",
828 last_refreshed_at: a_week_ago
831 assert orig_user.last_refreshed_at == a_week_ago
833 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
835 assert user.last_refreshed_at == orig_user.last_refreshed_at
839 test "returns an ap_id for a user" do
842 assert User.ap_id(user) ==
843 Pleroma.Web.Router.Helpers.user_feed_url(
844 Pleroma.Web.Endpoint,
850 test "returns an ap_followers link for a user" do
853 assert User.ap_followers(user) ==
854 Pleroma.Web.Router.Helpers.user_feed_url(
855 Pleroma.Web.Endpoint,
861 describe "remote user changeset" do
867 avatar: %{some: "avatar"}
869 setup do: clear_config([:instance, :user_bio_length])
870 setup do: clear_config([:instance, :user_name_length])
872 test "it confirms validity" do
873 cs = User.remote_user_changeset(@valid_remote)
877 test "it sets the follower_adress" do
878 cs = User.remote_user_changeset(@valid_remote)
879 # remote users get a fake local follower address
880 assert cs.changes.follower_address ==
881 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
884 test "it enforces the fqn format for nicknames" do
885 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
886 assert Ecto.Changeset.get_field(cs, :local) == false
887 assert cs.changes.avatar
891 test "it has required fields" do
893 |> Enum.each(fn field ->
894 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
900 describe "followers and friends" do
901 test "gets all followers for a given user" do
903 follower_one = insert(:user)
904 follower_two = insert(:user)
905 not_follower = insert(:user)
907 {:ok, follower_one} = User.follow(follower_one, user)
908 {:ok, follower_two} = User.follow(follower_two, user)
910 res = User.get_followers(user)
912 assert Enum.member?(res, follower_one)
913 assert Enum.member?(res, follower_two)
914 refute Enum.member?(res, not_follower)
917 test "gets all friends (followed users) for a given user" do
919 followed_one = insert(:user)
920 followed_two = insert(:user)
921 not_followed = insert(:user)
923 {:ok, user} = User.follow(user, followed_one)
924 {:ok, user} = User.follow(user, followed_two)
926 res = User.get_friends(user)
928 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
929 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
930 assert Enum.member?(res, followed_one)
931 assert Enum.member?(res, followed_two)
932 refute Enum.member?(res, not_followed)
936 describe "updating note and follower count" do
937 test "it sets the note_count property" do
940 user = User.get_cached_by_ap_id(note.data["actor"])
942 assert user.note_count == 0
944 {:ok, user} = User.update_note_count(user)
946 assert user.note_count == 1
949 test "it increases the note_count property" do
951 user = User.get_cached_by_ap_id(note.data["actor"])
953 assert user.note_count == 0
955 {:ok, user} = User.increase_note_count(user)
957 assert user.note_count == 1
959 {:ok, user} = User.increase_note_count(user)
961 assert user.note_count == 2
964 test "it decreases the note_count property" do
966 user = User.get_cached_by_ap_id(note.data["actor"])
968 assert user.note_count == 0
970 {:ok, user} = User.increase_note_count(user)
972 assert user.note_count == 1
974 {:ok, user} = User.decrease_note_count(user)
976 assert user.note_count == 0
978 {:ok, user} = User.decrease_note_count(user)
980 assert user.note_count == 0
983 test "it sets the follower_count property" do
985 follower = insert(:user)
987 User.follow(follower, user)
989 assert user.follower_count == 0
991 {:ok, user} = User.update_follower_count(user)
993 assert user.follower_count == 1
998 test "it mutes people" do
1000 muted_user = insert(:user)
1002 refute User.mutes?(user, muted_user)
1003 refute User.muted_notifications?(user, muted_user)
1005 {:ok, _user_relationships} = User.mute(user, muted_user)
1007 assert User.mutes?(user, muted_user)
1008 assert User.muted_notifications?(user, muted_user)
1011 test "it unmutes users" do
1012 user = insert(:user)
1013 muted_user = insert(:user)
1015 {:ok, _user_relationships} = User.mute(user, muted_user)
1016 {:ok, _user_mute} = User.unmute(user, muted_user)
1018 refute User.mutes?(user, muted_user)
1019 refute User.muted_notifications?(user, muted_user)
1022 test "it mutes user without notifications" do
1023 user = insert(:user)
1024 muted_user = insert(:user)
1026 refute User.mutes?(user, muted_user)
1027 refute User.muted_notifications?(user, muted_user)
1029 {:ok, _user_relationships} = User.mute(user, muted_user, false)
1031 assert User.mutes?(user, muted_user)
1032 refute User.muted_notifications?(user, muted_user)
1036 describe "blocks" do
1037 test "it blocks people" do
1038 user = insert(:user)
1039 blocked_user = insert(:user)
1041 refute User.blocks?(user, blocked_user)
1043 {:ok, _user_relationship} = User.block(user, blocked_user)
1045 assert User.blocks?(user, blocked_user)
1048 test "it unblocks users" do
1049 user = insert(:user)
1050 blocked_user = insert(:user)
1052 {:ok, _user_relationship} = User.block(user, blocked_user)
1053 {:ok, _user_block} = User.unblock(user, blocked_user)
1055 refute User.blocks?(user, blocked_user)
1058 test "blocks tear down cyclical follow relationships" do
1059 blocker = insert(:user)
1060 blocked = insert(:user)
1062 {:ok, blocker} = User.follow(blocker, blocked)
1063 {:ok, blocked} = User.follow(blocked, blocker)
1065 assert User.following?(blocker, blocked)
1066 assert User.following?(blocked, blocker)
1068 {:ok, _user_relationship} = User.block(blocker, blocked)
1069 blocked = User.get_cached_by_id(blocked.id)
1071 assert User.blocks?(blocker, blocked)
1073 refute User.following?(blocker, blocked)
1074 refute User.following?(blocked, blocker)
1077 test "blocks tear down blocker->blocked follow relationships" do
1078 blocker = insert(:user)
1079 blocked = insert(:user)
1081 {:ok, blocker} = User.follow(blocker, blocked)
1083 assert User.following?(blocker, blocked)
1084 refute User.following?(blocked, blocker)
1086 {:ok, _user_relationship} = User.block(blocker, blocked)
1087 blocked = User.get_cached_by_id(blocked.id)
1089 assert User.blocks?(blocker, blocked)
1091 refute User.following?(blocker, blocked)
1092 refute User.following?(blocked, blocker)
1095 test "blocks tear down blocked->blocker follow relationships" do
1096 blocker = insert(:user)
1097 blocked = insert(:user)
1099 {:ok, blocked} = User.follow(blocked, blocker)
1101 refute User.following?(blocker, blocked)
1102 assert User.following?(blocked, blocker)
1104 {:ok, _user_relationship} = User.block(blocker, blocked)
1105 blocked = User.get_cached_by_id(blocked.id)
1107 assert User.blocks?(blocker, blocked)
1109 refute User.following?(blocker, blocked)
1110 refute User.following?(blocked, blocker)
1113 test "blocks tear down blocked->blocker subscription relationships" do
1114 blocker = insert(:user)
1115 blocked = insert(:user)
1117 {:ok, _subscription} = User.subscribe(blocked, blocker)
1119 assert User.subscribed_to?(blocked, blocker)
1120 refute User.subscribed_to?(blocker, blocked)
1122 {:ok, _user_relationship} = User.block(blocker, blocked)
1124 assert User.blocks?(blocker, blocked)
1125 refute User.subscribed_to?(blocker, blocked)
1126 refute User.subscribed_to?(blocked, blocker)
1130 describe "domain blocking" do
1131 test "blocks domains" do
1132 user = insert(:user)
1133 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1135 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1137 assert User.blocks?(user, collateral_user)
1140 test "does not block domain with same end" do
1141 user = insert(:user)
1144 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1146 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1148 refute User.blocks?(user, collateral_user)
1151 test "does not block domain with same end if wildcard added" do
1152 user = insert(:user)
1155 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1157 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1159 refute User.blocks?(user, collateral_user)
1162 test "blocks domain with wildcard for subdomain" do
1163 user = insert(:user)
1165 user_from_subdomain =
1166 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1168 user_with_two_subdomains =
1170 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1173 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1175 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1177 assert User.blocks?(user, user_from_subdomain)
1178 assert User.blocks?(user, user_with_two_subdomains)
1179 assert User.blocks?(user, user_domain)
1182 test "unblocks domains" do
1183 user = insert(:user)
1184 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1186 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1187 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1189 refute User.blocks?(user, collateral_user)
1192 test "follows take precedence over domain blocks" do
1193 user = insert(:user)
1194 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1196 {:ok, user} = User.block_domain(user, "meanies.social")
1197 {:ok, user} = User.follow(user, good_eggo)
1199 refute User.blocks?(user, good_eggo)
1203 describe "get_recipients_from_activity" do
1204 test "works for announces" do
1205 actor = insert(:user)
1206 user = insert(:user, local: true)
1208 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1209 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1211 recipients = User.get_recipients_from_activity(announce)
1213 assert user in recipients
1216 test "get recipients" do
1217 actor = insert(:user)
1218 user = insert(:user, local: true)
1219 user_two = insert(:user, local: false)
1220 addressed = insert(:user, local: true)
1221 addressed_remote = insert(:user, local: false)
1224 CommonAPI.post(actor, %{
1225 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1228 assert Enum.map([actor, addressed], & &1.ap_id) --
1229 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1231 {:ok, user} = User.follow(user, actor)
1232 {:ok, _user_two} = User.follow(user_two, actor)
1233 recipients = User.get_recipients_from_activity(activity)
1234 assert length(recipients) == 3
1235 assert user in recipients
1236 assert addressed in recipients
1239 test "has following" do
1240 actor = insert(:user)
1241 user = insert(:user)
1242 user_two = insert(:user)
1243 addressed = insert(:user, local: true)
1246 CommonAPI.post(actor, %{
1247 status: "hey @#{addressed.nickname}"
1250 assert Enum.map([actor, addressed], & &1.ap_id) --
1251 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1253 {:ok, _actor} = User.follow(actor, user)
1254 {:ok, _actor} = User.follow(actor, user_two)
1255 recipients = User.get_recipients_from_activity(activity)
1256 assert length(recipients) == 2
1257 assert addressed in recipients
1261 describe ".deactivate" do
1262 test "can de-activate then re-activate a user" do
1263 user = insert(:user)
1264 assert false == user.deactivated
1265 {:ok, user} = User.deactivate(user)
1266 assert true == user.deactivated
1267 {:ok, user} = User.deactivate(user, false)
1268 assert false == user.deactivated
1271 test "hide a user from followers" do
1272 user = insert(:user)
1273 user2 = insert(:user)
1275 {:ok, user} = User.follow(user, user2)
1276 {:ok, _user} = User.deactivate(user)
1278 user2 = User.get_cached_by_id(user2.id)
1280 assert user2.follower_count == 0
1281 assert [] = User.get_followers(user2)
1284 test "hide a user from friends" do
1285 user = insert(:user)
1286 user2 = insert(:user)
1288 {:ok, user2} = User.follow(user2, user)
1289 assert user2.following_count == 1
1290 assert User.following_count(user2) == 1
1292 {:ok, _user} = User.deactivate(user)
1294 user2 = User.get_cached_by_id(user2.id)
1296 assert refresh_record(user2).following_count == 0
1297 assert user2.following_count == 0
1298 assert User.following_count(user2) == 0
1299 assert [] = User.get_friends(user2)
1302 test "hide a user's statuses from timelines and notifications" do
1303 user = insert(:user)
1304 user2 = insert(:user)
1306 {:ok, user2} = User.follow(user2, user)
1308 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1310 activity = Repo.preload(activity, :bookmark)
1312 [notification] = Pleroma.Notification.for_user(user2)
1313 assert notification.activity.id == activity.id
1315 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1317 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1318 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1322 {:ok, _user} = User.deactivate(user)
1324 assert [] == ActivityPub.fetch_public_activities(%{})
1325 assert [] == Pleroma.Notification.for_user(user2)
1328 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1334 describe "approve" do
1335 test "approves a user" do
1336 user = insert(:user, approval_pending: true)
1337 assert true == user.approval_pending
1338 {:ok, user} = User.approve(user)
1339 assert false == user.approval_pending
1342 test "approves a list of users" do
1343 unapproved_users = [
1344 insert(:user, approval_pending: true),
1345 insert(:user, approval_pending: true),
1346 insert(:user, approval_pending: true)
1349 {:ok, users} = User.approve(unapproved_users)
1351 assert Enum.count(users) == 3
1353 Enum.each(users, fn user ->
1354 assert false == user.approval_pending
1359 describe "delete" do
1361 {:ok, user} = insert(:user) |> User.set_cache()
1366 setup do: clear_config([:instance, :federating])
1368 test ".delete_user_activities deletes all create activities", %{user: user} do
1369 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1371 User.delete_user_activities(user)
1373 # TODO: Test removal favorites, repeats, delete activities.
1374 refute Activity.get_by_id(activity.id)
1377 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1378 follower = insert(:user)
1379 {:ok, follower} = User.follow(follower, user)
1381 locked_user = insert(:user, name: "locked", is_locked: true)
1382 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1384 object = insert(:note, user: user)
1385 activity = insert(:note_activity, user: user, note: object)
1387 object_two = insert(:note, user: follower)
1388 activity_two = insert(:note_activity, user: follower, note: object_two)
1390 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1391 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1392 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1394 {:ok, job} = User.delete(user)
1395 {:ok, _user} = ObanHelpers.perform(job)
1397 follower = User.get_cached_by_id(follower.id)
1399 refute User.following?(follower, user)
1400 assert %{deactivated: true} = User.get_by_id(user.id)
1402 assert [] == User.get_follow_requests(locked_user)
1406 |> Activity.Queries.by_actor()
1408 |> Enum.map(fn act -> act.data["type"] end)
1410 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1412 refute Activity.get_by_id(activity.id)
1413 refute Activity.get_by_id(like.id)
1414 refute Activity.get_by_id(like_two.id)
1415 refute Activity.get_by_id(repeat.id)
1419 describe "delete/1 when confirmation is pending" do
1421 user = insert(:user, confirmation_pending: true)
1425 test "deletes user from database when activation required", %{user: user} do
1426 clear_config([:instance, :account_activation_required], true)
1428 {:ok, job} = User.delete(user)
1429 {:ok, _} = ObanHelpers.perform(job)
1431 refute User.get_cached_by_id(user.id)
1432 refute User.get_by_id(user.id)
1435 test "deactivates user when activation is not required", %{user: user} do
1436 clear_config([:instance, :account_activation_required], false)
1438 {:ok, job} = User.delete(user)
1439 {:ok, _} = ObanHelpers.perform(job)
1441 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1442 assert %{deactivated: true} = User.get_by_id(user.id)
1446 test "delete/1 when approval is pending deletes the user" do
1447 user = insert(:user, approval_pending: true)
1449 {:ok, job} = User.delete(user)
1450 {:ok, _} = ObanHelpers.perform(job)
1452 refute User.get_cached_by_id(user.id)
1453 refute User.get_by_id(user.id)
1456 test "delete/1 purges a user when they wouldn't be fully deleted" do
1461 password_hash: "pdfk2$1b3n159001",
1462 keys: "RSA begin buplic key",
1463 public_key: "--PRIVATE KEYE--",
1464 avatar: %{"a" => "b"},
1466 banner: %{"a" => "b"},
1467 background: %{"a" => "b"},
1470 following_count: 9001,
1472 confirmation_pending: true,
1473 password_reset_pending: true,
1474 approval_pending: true,
1475 registration_reason: "ahhhhh",
1476 confirmation_token: "qqqq",
1477 domain_blocks: ["lain.com"],
1482 mastofe_settings: %{"a" => "b"},
1483 mascot: %{"a" => "b"},
1484 emoji: %{"a" => "b"},
1485 pleroma_settings_store: %{"q" => "x"},
1486 fields: [%{"gg" => "qq"}],
1487 raw_fields: [%{"gg" => "qq"}],
1488 is_discoverable: true,
1489 also_known_as: ["https://lol.olo/users/loll"]
1492 {:ok, job} = User.delete(user)
1493 {:ok, _} = ObanHelpers.perform(job)
1494 user = User.get_by_id(user.id)
1506 last_refreshed_at: nil,
1507 last_digest_emailed_at: nil,
1514 confirmation_pending: false,
1515 password_reset_pending: false,
1516 approval_pending: false,
1517 registration_reason: nil,
1518 confirmation_token: nil,
1522 is_moderator: false,
1524 mastofe_settings: nil,
1527 pleroma_settings_store: %{},
1530 is_discoverable: false,
1535 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1536 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1539 describe "per-user rich-text filtering" do
1540 test "html_filter_policy returns default policies, when rich-text is enabled" do
1541 user = insert(:user)
1543 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1546 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1547 user = insert(:user, no_rich_text: true)
1549 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1553 describe "caching" do
1554 test "invalidate_cache works" do
1555 user = insert(:user)
1557 User.set_cache(user)
1558 User.invalidate_cache(user)
1560 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1561 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1564 test "User.delete() plugs any possible zombie objects" do
1565 user = insert(:user)
1567 {:ok, job} = User.delete(user)
1568 {:ok, _} = ObanHelpers.perform(job)
1570 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1572 assert cached_user != user
1574 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1576 assert cached_user != user
1580 describe "account_status/1" do
1581 setup do: clear_config([:instance, :account_activation_required])
1583 test "return confirmation_pending for unconfirm user" do
1584 Pleroma.Config.put([:instance, :account_activation_required], true)
1585 user = insert(:user, confirmation_pending: true)
1586 assert User.account_status(user) == :confirmation_pending
1589 test "return active for confirmed user" do
1590 Pleroma.Config.put([:instance, :account_activation_required], true)
1591 user = insert(:user, confirmation_pending: false)
1592 assert User.account_status(user) == :active
1595 test "return active for remote user" do
1596 user = insert(:user, local: false)
1597 assert User.account_status(user) == :active
1600 test "returns :password_reset_pending for user with reset password" do
1601 user = insert(:user, password_reset_pending: true)
1602 assert User.account_status(user) == :password_reset_pending
1605 test "returns :deactivated for deactivated user" do
1606 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1607 assert User.account_status(user) == :deactivated
1610 test "returns :approval_pending for unapproved user" do
1611 user = insert(:user, local: true, approval_pending: true)
1612 assert User.account_status(user) == :approval_pending
1614 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1615 assert User.account_status(user) == :approval_pending
1619 describe "superuser?/1" do
1620 test "returns false for unprivileged users" do
1621 user = insert(:user, local: true)
1623 refute User.superuser?(user)
1626 test "returns false for remote users" do
1627 user = insert(:user, local: false)
1628 remote_admin_user = insert(:user, local: false, is_admin: true)
1630 refute User.superuser?(user)
1631 refute User.superuser?(remote_admin_user)
1634 test "returns true for local moderators" do
1635 user = insert(:user, local: true, is_moderator: true)
1637 assert User.superuser?(user)
1640 test "returns true for local admins" do
1641 user = insert(:user, local: true, is_admin: true)
1643 assert User.superuser?(user)
1647 describe "invisible?/1" do
1648 test "returns true for an invisible user" do
1649 user = insert(:user, local: true, invisible: true)
1651 assert User.invisible?(user)
1654 test "returns false for a non-invisible user" do
1655 user = insert(:user, local: true)
1657 refute User.invisible?(user)
1661 describe "visible_for/2" do
1662 test "returns true when the account is itself" do
1663 user = insert(:user, local: true)
1665 assert User.visible_for(user, user) == :visible
1668 test "returns false when the account is unconfirmed and confirmation is required" do
1669 Pleroma.Config.put([:instance, :account_activation_required], true)
1671 user = insert(:user, local: true, confirmation_pending: true)
1672 other_user = insert(:user, local: true)
1674 refute User.visible_for(user, other_user) == :visible
1677 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1678 Pleroma.Config.put([:instance, :account_activation_required], true)
1680 user = insert(:user, local: false, confirmation_pending: true)
1681 other_user = insert(:user, local: true)
1683 assert User.visible_for(user, other_user) == :visible
1686 test "returns true when the account is unconfirmed and confirmation is not required" do
1687 user = insert(:user, local: true, confirmation_pending: true)
1688 other_user = insert(:user, local: true)
1690 assert User.visible_for(user, other_user) == :visible
1693 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1694 Pleroma.Config.put([:instance, :account_activation_required], true)
1696 user = insert(:user, local: true, confirmation_pending: true)
1697 other_user = insert(:user, local: true, is_admin: true)
1699 assert User.visible_for(user, other_user) == :visible
1703 describe "parse_bio/2" do
1704 test "preserves hosts in user links text" do
1705 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1706 user = insert(:user)
1707 bio = "A.k.a. @nick@domain.com"
1710 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1712 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1714 assert expected_text == User.parse_bio(bio, user)
1717 test "Adds rel=me on linkbacked urls" do
1718 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1720 bio = "http://example.com/rel_me/null"
1721 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1722 assert expected_text == User.parse_bio(bio, user)
1724 bio = "http://example.com/rel_me/link"
1725 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1726 assert expected_text == User.parse_bio(bio, user)
1728 bio = "http://example.com/rel_me/anchor"
1729 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1730 assert expected_text == User.parse_bio(bio, user)
1734 test "follower count is updated when a follower is blocked" do
1735 user = insert(:user)
1736 follower = insert(:user)
1737 follower2 = insert(:user)
1738 follower3 = insert(:user)
1740 {:ok, follower} = User.follow(follower, user)
1741 {:ok, _follower2} = User.follow(follower2, user)
1742 {:ok, _follower3} = User.follow(follower3, user)
1744 {:ok, _user_relationship} = User.block(user, follower)
1745 user = refresh_record(user)
1747 assert user.follower_count == 2
1750 describe "list_inactive_users_query/1" do
1751 defp days_ago(days) do
1753 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1754 -days * 60 * 60 * 24,
1759 test "Users are inactive by default" do
1763 Enum.map(1..total, fn _ ->
1764 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1767 inactive_users_ids =
1768 Pleroma.User.list_inactive_users_query()
1769 |> Pleroma.Repo.all()
1770 |> Enum.map(& &1.id)
1772 Enum.each(users, fn user ->
1773 assert user.id in inactive_users_ids
1777 test "Only includes users who has no recent activity" do
1781 Enum.map(1..total, fn _ ->
1782 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1785 {inactive, active} = Enum.split(users, trunc(total / 2))
1787 Enum.map(active, fn user ->
1788 to = Enum.random(users -- [user])
1791 CommonAPI.post(user, %{
1792 status: "hey @#{to.nickname}"
1796 inactive_users_ids =
1797 Pleroma.User.list_inactive_users_query()
1798 |> Pleroma.Repo.all()
1799 |> Enum.map(& &1.id)
1801 Enum.each(active, fn user ->
1802 refute user.id in inactive_users_ids
1805 Enum.each(inactive, fn user ->
1806 assert user.id in inactive_users_ids
1810 test "Only includes users with no read notifications" do
1814 Enum.map(1..total, fn _ ->
1815 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1818 [sender | recipients] = users
1819 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1821 Enum.each(recipients, fn to ->
1823 CommonAPI.post(sender, %{
1824 status: "hey @#{to.nickname}"
1828 CommonAPI.post(sender, %{
1829 status: "hey again @#{to.nickname}"
1833 Enum.each(active, fn user ->
1834 [n1, _n2] = Pleroma.Notification.for_user(user)
1835 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1838 inactive_users_ids =
1839 Pleroma.User.list_inactive_users_query()
1840 |> Pleroma.Repo.all()
1841 |> Enum.map(& &1.id)
1843 Enum.each(active, fn user ->
1844 refute user.id in inactive_users_ids
1847 Enum.each(inactive, fn user ->
1848 assert user.id in inactive_users_ids
1853 describe "toggle_confirmation/1" do
1854 test "if user is confirmed" do
1855 user = insert(:user, confirmation_pending: false)
1856 {:ok, user} = User.toggle_confirmation(user)
1858 assert user.confirmation_pending
1859 assert user.confirmation_token
1862 test "if user is unconfirmed" do
1863 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1864 {:ok, user} = User.toggle_confirmation(user)
1866 refute user.confirmation_pending
1867 refute user.confirmation_token
1871 describe "ensure_keys_present" do
1872 test "it creates keys for a user and stores them in info" do
1873 user = insert(:user)
1874 refute is_binary(user.keys)
1875 {:ok, user} = User.ensure_keys_present(user)
1876 assert is_binary(user.keys)
1879 test "it doesn't create keys if there already are some" do
1880 user = insert(:user, keys: "xxx")
1881 {:ok, user} = User.ensure_keys_present(user)
1882 assert user.keys == "xxx"
1886 describe "get_ap_ids_by_nicknames" do
1887 test "it returns a list of AP ids for a given set of nicknames" do
1888 user = insert(:user)
1889 user_two = insert(:user)
1891 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1892 assert length(ap_ids) == 2
1893 assert user.ap_id in ap_ids
1894 assert user_two.ap_id in ap_ids
1898 describe "sync followers count" do
1900 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1901 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1902 insert(:user, local: true)
1903 insert(:user, local: false, deactivated: true)
1904 {:ok, user1: user1, user2: user2}
1907 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1908 [fdb_user1] = User.external_users(limit: 1)
1910 assert fdb_user1.ap_id
1911 assert fdb_user1.ap_id == user1.ap_id
1912 assert fdb_user1.id == user1.id
1914 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1916 assert fdb_user2.ap_id
1917 assert fdb_user2.ap_id == user2.ap_id
1918 assert fdb_user2.id == user2.id
1920 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1924 describe "is_internal_user?/1" do
1925 test "non-internal user returns false" do
1926 user = insert(:user)
1927 refute User.is_internal_user?(user)
1930 test "user with no nickname returns true" do
1931 user = insert(:user, %{nickname: nil})
1932 assert User.is_internal_user?(user)
1935 test "user with internal-prefixed nickname returns true" do
1936 user = insert(:user, %{nickname: "internal.test"})
1937 assert User.is_internal_user?(user)
1941 describe "update_and_set_cache/1" do
1942 test "returns error when user is stale instead Ecto.StaleEntryError" do
1943 user = insert(:user)
1945 changeset = Ecto.Changeset.change(user, bio: "test")
1949 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1950 User.update_and_set_cache(changeset)
1953 test "performs update cache if user updated" do
1954 user = insert(:user)
1955 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1957 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1959 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1960 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1961 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1965 describe "following/followers synchronization" do
1966 setup do: clear_config([:instance, :external_user_synchronization])
1968 test "updates the counters normally on following/getting a follow when disabled" do
1969 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1970 user = insert(:user)
1975 follower_address: "http://localhost:4001/users/masto_closed/followers",
1976 following_address: "http://localhost:4001/users/masto_closed/following",
1980 assert other_user.following_count == 0
1981 assert other_user.follower_count == 0
1983 {:ok, user} = Pleroma.User.follow(user, other_user)
1984 other_user = Pleroma.User.get_by_id(other_user.id)
1986 assert user.following_count == 1
1987 assert other_user.follower_count == 1
1990 test "syncronizes the counters with the remote instance for the followed when enabled" do
1991 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1993 user = insert(:user)
1998 follower_address: "http://localhost:4001/users/masto_closed/followers",
1999 following_address: "http://localhost:4001/users/masto_closed/following",
2003 assert other_user.following_count == 0
2004 assert other_user.follower_count == 0
2006 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2007 {:ok, _user} = User.follow(user, other_user)
2008 other_user = User.get_by_id(other_user.id)
2010 assert other_user.follower_count == 437
2013 test "syncronizes the counters with the remote instance for the follower when enabled" do
2014 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2016 user = insert(:user)
2021 follower_address: "http://localhost:4001/users/masto_closed/followers",
2022 following_address: "http://localhost:4001/users/masto_closed/following",
2026 assert other_user.following_count == 0
2027 assert other_user.follower_count == 0
2029 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2030 {:ok, other_user} = User.follow(other_user, user)
2032 assert other_user.following_count == 152
2036 describe "change_email/2" do
2038 [user: insert(:user)]
2041 test "blank email returns error", %{user: user} do
2042 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2043 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2046 test "non unique email returns error", %{user: user} do
2047 %{email: email} = insert(:user)
2049 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2050 User.change_email(user, email)
2053 test "invalid email returns error", %{user: user} do
2054 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2055 User.change_email(user, "cofe")
2058 test "changes email", %{user: user} do
2059 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2063 describe "get_cached_by_nickname_or_id" do
2065 local_user = insert(:user)
2066 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2068 [local_user: local_user, remote_user: remote_user]
2071 setup do: clear_config([:instance, :limit_to_local_content])
2073 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2074 remote_user: remote_user
2076 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2077 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2079 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2080 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2082 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2083 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2086 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2087 %{remote_user: remote_user} do
2088 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2089 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2092 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2093 %{remote_user: remote_user, local_user: local_user} do
2094 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2095 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2098 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2099 %{remote_user: remote_user} do
2100 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2101 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2104 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2105 %{local_user: local_user} do
2106 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2107 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2109 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2110 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2112 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2113 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2117 describe "update_email_notifications/2" do
2119 user = insert(:user, email_notifications: %{"digest" => true})
2124 test "Notifications are updated", %{user: user} do
2125 true = user.email_notifications["digest"]
2126 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2127 assert result.email_notifications["digest"] == false
2131 test "avatar fallback" do
2132 user = insert(:user)
2133 assert User.avatar_url(user) =~ "/images/avi.png"
2135 clear_config([:assets, :default_user_avatar], "avatar.png")
2137 user = User.get_cached_by_nickname_or_id(user.nickname)
2138 assert User.avatar_url(user) =~ "avatar.png"
2140 assert User.avatar_url(user, no_default: true) == nil