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)
1012 user = insert(:user)
1013 muted_user = insert(:user)
1015 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1016 assert User.mutes?(user, muted_user)
1018 worker = Pleroma.Workers.MuteExpireWorker
1019 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1026 assert :ok = perform_job(worker, args)
1028 refute User.mutes?(user, muted_user)
1029 refute User.muted_notifications?(user, muted_user)
1032 test "it unmutes users" do
1033 user = insert(:user)
1034 muted_user = insert(:user)
1036 {:ok, _user_relationships} = User.mute(user, muted_user)
1037 {:ok, _user_mute} = User.unmute(user, muted_user)
1039 refute User.mutes?(user, muted_user)
1040 refute User.muted_notifications?(user, muted_user)
1043 test "it unmutes users by id" do
1044 user = insert(:user)
1045 muted_user = insert(:user)
1047 {:ok, _user_relationships} = User.mute(user, muted_user)
1048 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1050 refute User.mutes?(user, muted_user)
1051 refute User.muted_notifications?(user, muted_user)
1054 test "it mutes user without notifications" do
1055 user = insert(:user)
1056 muted_user = insert(:user)
1058 refute User.mutes?(user, muted_user)
1059 refute User.muted_notifications?(user, muted_user)
1061 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1063 assert User.mutes?(user, muted_user)
1064 refute User.muted_notifications?(user, muted_user)
1068 describe "blocks" do
1069 test "it blocks people" do
1070 user = insert(:user)
1071 blocked_user = insert(:user)
1073 refute User.blocks?(user, blocked_user)
1075 {:ok, _user_relationship} = User.block(user, blocked_user)
1077 assert User.blocks?(user, blocked_user)
1080 test "it unblocks users" do
1081 user = insert(:user)
1082 blocked_user = insert(:user)
1084 {:ok, _user_relationship} = User.block(user, blocked_user)
1085 {:ok, _user_block} = User.unblock(user, blocked_user)
1087 refute User.blocks?(user, blocked_user)
1090 test "blocks tear down cyclical follow relationships" do
1091 blocker = insert(:user)
1092 blocked = insert(:user)
1094 {:ok, blocker} = User.follow(blocker, blocked)
1095 {:ok, blocked} = User.follow(blocked, blocker)
1097 assert User.following?(blocker, blocked)
1098 assert User.following?(blocked, blocker)
1100 {:ok, _user_relationship} = User.block(blocker, blocked)
1101 blocked = User.get_cached_by_id(blocked.id)
1103 assert User.blocks?(blocker, blocked)
1105 refute User.following?(blocker, blocked)
1106 refute User.following?(blocked, blocker)
1109 test "blocks tear down blocker->blocked follow relationships" do
1110 blocker = insert(:user)
1111 blocked = insert(:user)
1113 {:ok, blocker} = User.follow(blocker, blocked)
1115 assert User.following?(blocker, blocked)
1116 refute User.following?(blocked, blocker)
1118 {:ok, _user_relationship} = User.block(blocker, blocked)
1119 blocked = User.get_cached_by_id(blocked.id)
1121 assert User.blocks?(blocker, blocked)
1123 refute User.following?(blocker, blocked)
1124 refute User.following?(blocked, blocker)
1127 test "blocks tear down blocked->blocker follow relationships" do
1128 blocker = insert(:user)
1129 blocked = insert(:user)
1131 {:ok, blocked} = User.follow(blocked, blocker)
1133 refute User.following?(blocker, blocked)
1134 assert User.following?(blocked, blocker)
1136 {:ok, _user_relationship} = User.block(blocker, blocked)
1137 blocked = User.get_cached_by_id(blocked.id)
1139 assert User.blocks?(blocker, blocked)
1141 refute User.following?(blocker, blocked)
1142 refute User.following?(blocked, blocker)
1145 test "blocks tear down blocked->blocker subscription relationships" do
1146 blocker = insert(:user)
1147 blocked = insert(:user)
1149 {:ok, _subscription} = User.subscribe(blocked, blocker)
1151 assert User.subscribed_to?(blocked, blocker)
1152 refute User.subscribed_to?(blocker, blocked)
1154 {:ok, _user_relationship} = User.block(blocker, blocked)
1156 assert User.blocks?(blocker, blocked)
1157 refute User.subscribed_to?(blocker, blocked)
1158 refute User.subscribed_to?(blocked, blocker)
1162 describe "domain blocking" do
1163 test "blocks domains" do
1164 user = insert(:user)
1165 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1167 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1169 assert User.blocks?(user, collateral_user)
1172 test "does not block domain with same end" do
1173 user = insert(:user)
1176 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1178 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1180 refute User.blocks?(user, collateral_user)
1183 test "does not block domain with same end if wildcard added" do
1184 user = insert(:user)
1187 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1189 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1191 refute User.blocks?(user, collateral_user)
1194 test "blocks domain with wildcard for subdomain" do
1195 user = insert(:user)
1197 user_from_subdomain =
1198 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1200 user_with_two_subdomains =
1202 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1205 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1207 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1209 assert User.blocks?(user, user_from_subdomain)
1210 assert User.blocks?(user, user_with_two_subdomains)
1211 assert User.blocks?(user, user_domain)
1214 test "unblocks domains" do
1215 user = insert(:user)
1216 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1218 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1219 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1221 refute User.blocks?(user, collateral_user)
1224 test "follows take precedence over domain blocks" do
1225 user = insert(:user)
1226 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1228 {:ok, user} = User.block_domain(user, "meanies.social")
1229 {:ok, user} = User.follow(user, good_eggo)
1231 refute User.blocks?(user, good_eggo)
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", is_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"}],
1520 is_discoverable: true,
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 is_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