1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.UserTest do
7 alias Pleroma.Builders.UserBuilder
8 alias Pleroma.Notification
11 alias Pleroma.Tests.ObanHelpers
13 alias Pleroma.Web.ActivityPub.ActivityPub
14 alias Pleroma.Web.CommonAPI
17 use Oban.Testing, repo: Pleroma.Repo
19 import Pleroma.Factory
20 import ExUnit.CaptureLog
21 import Swoosh.TestAssertions
24 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
28 setup do: clear_config([:instance, :account_activation_required])
30 describe "service actors" do
31 test "returns updated invisible actor" do
32 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
33 followers_uri = "#{uri}/followers"
42 follower_address: followers_uri
46 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
47 assert actor.invisible
50 test "returns relay user" do
51 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
52 followers_uri = "#{uri}/followers"
59 follower_address: ^followers_uri
60 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
62 assert capture_log(fn ->
63 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
64 end) =~ "Cannot create service actor:"
67 test "returns invisible actor" do
68 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
69 followers_uri = "#{uri}/followers"
70 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
73 nickname: "internal.fetch-test",
77 follower_address: ^followers_uri
80 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
81 assert user.id == user2.id
85 describe "AP ID user relationships" do
87 {:ok, user: insert(:user)}
90 test "outgoing_relationships_ap_ids/1", %{user: user} do
91 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
99 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
101 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
102 {rel_type, Enum.sort(ap_ids)}
106 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
107 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
109 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
110 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
112 assert ap_ids_by_rel[:notification_mute] ==
113 Enum.sort(User.notification_muted_users_ap_ids(user))
115 assert ap_ids_by_rel[:notification_mute] ==
116 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
118 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
120 assert ap_ids_by_rel[:reblog_mute] ==
121 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
123 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
125 assert ap_ids_by_rel[:inverse_subscription] ==
126 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
128 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
130 assert ap_ids_by_rel ==
131 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
135 describe "when tags are nil" do
136 test "tagging a user" do
137 user = insert(:user, %{tags: nil})
138 user = User.tag(user, ["cool", "dude"])
140 assert "cool" in user.tags
141 assert "dude" in user.tags
144 test "untagging a user" do
145 user = insert(:user, %{tags: nil})
146 user = User.untag(user, ["cool", "dude"])
148 assert user.tags == []
152 test "ap_id returns the activity pub id for the user" do
153 user = UserBuilder.build()
155 expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}"
157 assert expected_ap_id == User.ap_id(user)
160 test "ap_followers returns the followers collection for the user" do
161 user = UserBuilder.build()
163 expected_followers_collection = "#{User.ap_id(user)}/followers"
165 assert expected_followers_collection == User.ap_followers(user)
168 test "ap_following returns the following collection for the user" do
169 user = UserBuilder.build()
171 expected_followers_collection = "#{User.ap_id(user)}/following"
173 assert expected_followers_collection == User.ap_following(user)
176 test "returns all pending follow requests" do
177 unlocked = insert(:user)
178 locked = insert(:user, is_locked: true)
179 follower = insert(:user)
181 CommonAPI.follow(follower, unlocked)
182 CommonAPI.follow(follower, locked)
184 assert [] = User.get_follow_requests(unlocked)
185 assert [activity] = User.get_follow_requests(locked)
190 test "doesn't return already accepted or duplicate follow requests" do
191 locked = insert(:user, is_locked: true)
192 pending_follower = insert(:user)
193 accepted_follower = insert(:user)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(pending_follower, locked)
197 CommonAPI.follow(accepted_follower, locked)
199 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
201 assert [^pending_follower] = User.get_follow_requests(locked)
204 test "doesn't return follow requests for deactivated accounts" do
205 locked = insert(:user, is_locked: true)
206 pending_follower = insert(:user, %{is_active: false})
208 CommonAPI.follow(pending_follower, locked)
210 refute pending_follower.is_active
211 assert [] = User.get_follow_requests(locked)
214 test "clears follow requests when requester is blocked" do
215 followed = insert(:user, is_locked: true)
216 follower = insert(:user)
218 CommonAPI.follow(follower, followed)
219 assert [_activity] = User.get_follow_requests(followed)
221 {:ok, _user_relationship} = User.block(followed, follower)
222 assert [] = User.get_follow_requests(followed)
225 test "follow_all follows mutliple users" do
227 followed_zero = insert(:user)
228 followed_one = insert(:user)
229 followed_two = insert(:user)
230 blocked = insert(:user)
231 not_followed = insert(:user)
232 reverse_blocked = insert(:user)
234 {:ok, _user_relationship} = User.block(user, blocked)
235 {:ok, _user_relationship} = User.block(reverse_blocked, user)
237 {:ok, user, followed_zero} = User.follow(user, followed_zero)
239 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
241 assert User.following?(user, followed_one)
242 assert User.following?(user, followed_two)
243 assert User.following?(user, followed_zero)
244 refute User.following?(user, not_followed)
245 refute User.following?(user, blocked)
246 refute User.following?(user, reverse_blocked)
249 test "follow_all follows mutliple users without duplicating" do
251 followed_zero = insert(:user)
252 followed_one = insert(:user)
253 followed_two = insert(:user)
255 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
256 assert length(User.following(user)) == 3
258 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
259 assert length(User.following(user)) == 4
262 test "follow takes a user and another user" do
264 followed = insert(:user)
266 {:ok, user, followed} = User.follow(user, followed)
268 user = User.get_cached_by_id(user.id)
269 followed = User.get_cached_by_ap_id(followed.ap_id)
271 assert followed.follower_count == 1
272 assert user.following_count == 1
274 assert User.ap_followers(followed) in User.following(user)
277 test "can't follow a deactivated users" do
279 followed = insert(:user, %{is_active: false})
281 {:error, _} = User.follow(user, followed)
284 test "can't follow a user who blocked us" do
285 blocker = insert(:user)
286 blockee = insert(:user)
288 {:ok, _user_relationship} = User.block(blocker, blockee)
290 {:error, _} = User.follow(blockee, blocker)
293 test "can't subscribe to a user who blocked us" do
294 blocker = insert(:user)
295 blocked = insert(:user)
297 {:ok, _user_relationship} = User.block(blocker, blocked)
299 {:error, _} = User.subscribe(blocked, blocker)
302 test "local users do not automatically follow local locked accounts" do
303 follower = insert(:user, is_locked: true)
304 followed = insert(:user, is_locked: true)
306 {:ok, follower, followed} = User.maybe_direct_follow(follower, followed)
308 refute User.following?(follower, followed)
311 describe "unfollow/2" do
312 setup do: clear_config([:instance, :external_user_synchronization])
314 test "unfollow with syncronizes external user" do
315 clear_config([:instance, :external_user_synchronization], true)
320 follower_address: "http://localhost:4001/users/fuser1/followers",
321 following_address: "http://localhost:4001/users/fuser1/following",
322 ap_id: "http://localhost:4001/users/fuser1"
329 ap_id: "http://localhost:4001/users/fuser2",
330 follower_address: "http://localhost:4001/users/fuser2/followers",
331 following_address: "http://localhost:4001/users/fuser2/following"
334 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
336 {:ok, user, _activity} = User.unfollow(user, followed)
338 user = User.get_cached_by_id(user.id)
340 assert User.following(user) == []
343 test "unfollow takes a user and another user" do
344 followed = insert(:user)
347 {:ok, user, followed} = User.follow(user, followed, :follow_accept)
349 assert User.following(user) == [user.follower_address, followed.follower_address]
351 {:ok, user, _activity} = User.unfollow(user, followed)
353 assert User.following(user) == [user.follower_address]
356 test "unfollow doesn't unfollow yourself" do
359 {:error, _} = User.unfollow(user, user)
361 assert User.following(user) == [user.follower_address]
365 test "test if a user is following another user" do
366 followed = insert(:user)
368 User.follow(user, followed, :follow_accept)
370 assert User.following?(user, followed)
371 refute User.following?(followed, user)
374 test "fetches correct profile for nickname beginning with number" do
375 # Use old-style integer ID to try to reproduce the problem
376 user = insert(:user, %{id: 1080})
377 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
378 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
381 describe "user registration" do
387 password_confirmation: "test",
388 email: "email@example.com"
391 setup do: clear_config([:instance, :autofollowed_nicknames])
392 setup do: clear_config([:instance, :autofollowing_nicknames])
393 setup do: clear_config([:welcome])
394 setup do: clear_config([:instance, :account_activation_required])
396 test "it autofollows accounts that are set for it" do
398 remote_user = insert(:user, %{local: false})
400 clear_config([:instance, :autofollowed_nicknames], [
405 cng = User.register_changeset(%User{}, @full_user_data)
407 {:ok, registered_user} = User.register(cng)
409 assert User.following?(registered_user, user)
410 refute User.following?(registered_user, remote_user)
413 test "it adds automatic followers for new registered accounts" do
414 user1 = insert(:user)
415 user2 = insert(:user)
417 clear_config([:instance, :autofollowing_nicknames], [
422 cng = User.register_changeset(%User{}, @full_user_data)
424 {:ok, registered_user} = User.register(cng)
426 assert User.following?(user1, registered_user)
427 assert User.following?(user2, registered_user)
430 test "it sends a welcome message if it is set" do
431 welcome_user = insert(:user)
432 clear_config([:welcome, :direct_message, :enabled], true)
433 clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
434 clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message")
436 cng = User.register_changeset(%User{}, @full_user_data)
437 {:ok, registered_user} = User.register(cng)
438 ObanHelpers.perform_all()
440 activity = Repo.one(Pleroma.Activity)
441 assert registered_user.ap_id in activity.recipients
442 assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message"
443 assert activity.actor == welcome_user.ap_id
447 clear_config(:mrf_simple,
450 federated_timeline_removal: [],
463 Pleroma.Web.ActivityPub.MRF.SimplePolicy
467 test "it sends a welcome email message if it is set" do
468 welcome_user = insert(:user)
469 clear_config([:welcome, :email, :enabled], true)
470 clear_config([:welcome, :email, :sender], welcome_user.email)
473 [:welcome, :email, :subject],
474 "Hello, welcome to cool site: <%= instance_name %>"
477 instance_name = Pleroma.Config.get([:instance, :name])
479 cng = User.register_changeset(%User{}, @full_user_data)
480 {:ok, registered_user} = User.register(cng)
481 ObanHelpers.perform_all()
484 from: {instance_name, welcome_user.email},
485 to: {registered_user.name, registered_user.email},
486 subject: "Hello, welcome to cool site: #{instance_name}",
487 html_body: "Welcome to #{instance_name}"
491 test "it sends a confirm email" do
492 clear_config([:instance, :account_activation_required], true)
494 cng = User.register_changeset(%User{}, @full_user_data)
495 {:ok, registered_user} = User.register(cng)
496 ObanHelpers.perform_all()
498 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
499 # temporary hackney fix until hackney max_connections bug is fixed
500 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
501 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
502 |> assert_email_sent()
505 test "sends a pending approval email" do
506 clear_config([:instance, :account_approval_required], true)
509 User.register_changeset(%User{}, @full_user_data)
512 ObanHelpers.perform_all()
515 from: Pleroma.Config.Helpers.sender(),
516 to: {user.name, user.email},
517 subject: "Your account is awaiting approval"
521 test "it sends a registration confirmed email if no others will be sent" do
522 clear_config([:welcome, :email, :enabled], false)
523 clear_config([:instance, :account_activation_required], false)
524 clear_config([:instance, :account_approval_required], false)
527 User.register_changeset(%User{}, @full_user_data)
530 ObanHelpers.perform_all()
532 instance_name = Pleroma.Config.get([:instance, :name])
533 sender = Pleroma.Config.get([:instance, :notify_email])
536 from: {instance_name, sender},
537 to: {user.name, user.email},
538 subject: "Account registered on #{instance_name}"
542 test "it fails gracefully with invalid email config" do
543 cng = User.register_changeset(%User{}, @full_user_data)
545 # Disable the mailer but enable all the things that want to send emails
546 clear_config([Pleroma.Emails.Mailer, :enabled], false)
547 clear_config([:instance, :account_activation_required], true)
548 clear_config([:instance, :account_approval_required], true)
549 clear_config([:welcome, :email, :enabled], true)
550 clear_config([:welcome, :email, :sender], "lain@lain.com")
552 # The user is still created
553 assert {:ok, %User{nickname: "nick"}} = User.register(cng)
556 ObanHelpers.perform_all()
560 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
561 clear_config([:instance, :account_activation_required], true)
565 |> Enum.each(fn key ->
566 params = Map.delete(@full_user_data, key)
567 changeset = User.register_changeset(%User{}, params)
569 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
573 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
574 clear_config([:instance, :account_activation_required], false)
578 |> Enum.each(fn key ->
579 params = Map.delete(@full_user_data, key)
580 changeset = User.register_changeset(%User{}, params)
582 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
586 test "it restricts certain nicknames" do
587 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
589 assert is_bitstring(restricted_name)
593 |> Map.put(:nickname, restricted_name)
595 changeset = User.register_changeset(%User{}, params)
597 refute changeset.valid?
600 test "it blocks blacklisted email domains" do
601 clear_config([User, :email_blacklist], ["trolling.world"])
604 params = Map.put(@full_user_data, :email, "troll@trolling.world")
605 changeset = User.register_changeset(%User{}, params)
606 refute changeset.valid?
608 # Block with subdomain match
609 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
610 changeset = User.register_changeset(%User{}, params)
611 refute changeset.valid?
613 # Pass with different domains that are similar
614 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
615 changeset = User.register_changeset(%User{}, params)
616 assert changeset.valid?
618 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
619 changeset = User.register_changeset(%User{}, params)
620 assert changeset.valid?
623 test "it sets the password_hash and ap_id" do
624 changeset = User.register_changeset(%User{}, @full_user_data)
626 assert changeset.valid?
628 assert is_binary(changeset.changes[:password_hash])
629 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
631 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
634 test "it creates a confirmed user" do
635 changeset = User.register_changeset(%User{}, @full_user_data)
636 assert changeset.valid?
638 {:ok, user} = Repo.insert(changeset)
640 assert user.is_confirmed
644 describe "user registration, with :account_activation_required" do
650 password_confirmation: "test",
651 email: "email@example.com"
653 setup do: clear_config([:instance, :account_activation_required], true)
655 test "it creates unconfirmed user" do
656 changeset = User.register_changeset(%User{}, @full_user_data)
657 assert changeset.valid?
659 {:ok, user} = Repo.insert(changeset)
661 refute user.is_confirmed
662 assert user.confirmation_token
665 test "it creates confirmed user if :confirmed option is given" do
666 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
667 assert changeset.valid?
669 {:ok, user} = Repo.insert(changeset)
671 assert user.is_confirmed
672 refute user.confirmation_token
676 describe "user registration, with :account_approval_required" do
682 password_confirmation: "test",
683 email: "email@example.com",
684 registration_reason: "I'm a cool guy :)"
686 setup do: clear_config([:instance, :account_approval_required], true)
688 test "it creates unapproved user" do
689 changeset = User.register_changeset(%User{}, @full_user_data)
690 assert changeset.valid?
692 {:ok, user} = Repo.insert(changeset)
694 refute user.is_approved
695 assert user.registration_reason == "I'm a cool guy :)"
698 test "it restricts length of registration reason" do
699 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
701 assert is_integer(reason_limit)
706 :registration_reason,
707 "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."
710 changeset = User.register_changeset(%User{}, params)
712 refute changeset.valid?
716 describe "get_or_fetch/1" do
717 test "gets an existing user by nickname" do
719 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
721 assert user == fetched_user
724 test "gets an existing user by ap_id" do
725 ap_id = "http://mastodon.example.org/users/admin"
731 nickname: "admin@mastodon.example.org",
735 {:ok, fetched_user} = User.get_or_fetch(ap_id)
736 freshed_user = refresh_record(user)
737 assert freshed_user == fetched_user
741 describe "get_or_fetch/1 remote users with tld, while BE is runned on subdomain" do
742 setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
744 test "for mastodon" do
746 %{url: "https://example.com/.well-known/host-meta"} ->
749 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
752 %{url: "https://sub.example.com/.well-known/host-meta"} ->
756 "test/fixtures/webfinger/masto-host-meta.xml"
758 |> String.replace("{{domain}}", "sub.example.com")
761 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
765 "test/fixtures/webfinger/masto-webfinger.json"
767 |> String.replace("{{nickname}}", "a")
768 |> String.replace("{{domain}}", "example.com")
769 |> String.replace("{{subdomain}}", "sub.example.com"),
770 headers: [{"content-type", "application/jrd+json"}]
773 %{url: "https://sub.example.com/users/a"} ->
777 "test/fixtures/webfinger/masto-user.json"
779 |> String.replace("{{nickname}}", "a")
780 |> String.replace("{{domain}}", "sub.example.com"),
781 headers: [{"content-type", "application/activity+json"}]
784 %{url: "https://sub.example.com/users/a/collections/featured"} ->
788 File.read!("test/fixtures/users_mock/masto_featured.json")
789 |> String.replace("{{domain}}", "sub.example.com")
790 |> String.replace("{{nickname}}", "a"),
791 headers: [{"content-type", "application/activity+json"}]
795 ap_id = "a@example.com"
796 {:ok, fetched_user} = User.get_or_fetch(ap_id)
798 assert fetched_user.ap_id == "https://sub.example.com/users/a"
799 assert fetched_user.nickname == "a@example.com"
802 test "for pleroma" do
804 %{url: "https://example.com/.well-known/host-meta"} ->
807 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
810 %{url: "https://sub.example.com/.well-known/host-meta"} ->
814 "test/fixtures/webfinger/pleroma-host-meta.xml"
816 |> String.replace("{{domain}}", "sub.example.com")
819 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
823 "test/fixtures/webfinger/pleroma-webfinger.json"
825 |> String.replace("{{nickname}}", "a")
826 |> String.replace("{{domain}}", "example.com")
827 |> String.replace("{{subdomain}}", "sub.example.com"),
828 headers: [{"content-type", "application/jrd+json"}]
831 %{url: "https://sub.example.com/users/a"} ->
835 "test/fixtures/webfinger/pleroma-user.json"
837 |> String.replace("{{nickname}}", "a")
838 |> String.replace("{{domain}}", "sub.example.com"),
839 headers: [{"content-type", "application/activity+json"}]
843 ap_id = "a@example.com"
844 {:ok, fetched_user} = User.get_or_fetch(ap_id)
846 assert fetched_user.ap_id == "https://sub.example.com/users/a"
847 assert fetched_user.nickname == "a@example.com"
851 describe "fetching a user from nickname or trying to build one" do
852 test "gets an existing user" do
854 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
856 assert user == fetched_user
859 test "gets an existing user, case insensitive" do
860 user = insert(:user, nickname: "nick")
861 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
863 assert user == fetched_user
866 test "gets an existing user by fully qualified nickname" do
869 {:ok, fetched_user} =
870 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
872 assert user == fetched_user
875 test "gets an existing user by fully qualified nickname, case insensitive" do
876 user = insert(:user, nickname: "nick")
877 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
879 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
881 assert user == fetched_user
884 @tag capture_log: true
885 test "returns nil if no user could be fetched" do
886 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
887 assert fetched_user == "not found nonexistant@social.heldscal.la"
890 test "returns nil for nonexistant local user" do
891 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
892 assert fetched_user == "not found nonexistant"
895 test "updates an existing user, if stale" do
896 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
902 nickname: "admin@mastodon.example.org",
903 ap_id: "http://mastodon.example.org/users/admin",
904 last_refreshed_at: a_week_ago
907 assert orig_user.last_refreshed_at == a_week_ago
909 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
913 refute user.last_refreshed_at == orig_user.last_refreshed_at
916 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
917 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
923 nickname: "admin@mastodon.example.org",
924 ap_id: "http://mastodon.example.org/users/harinezumigari",
925 last_refreshed_at: a_week_ago
928 assert orig_user.last_refreshed_at == a_week_ago
930 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
934 refute user.id == orig_user.id
936 orig_user = User.get_by_id(orig_user.id)
938 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
941 @tag capture_log: true
942 test "it returns the old user if stale, but unfetchable" do
943 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
949 nickname: "admin@mastodon.example.org",
950 ap_id: "http://mastodon.example.org/users/raymoo",
951 last_refreshed_at: a_week_ago
954 assert orig_user.last_refreshed_at == a_week_ago
956 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
958 assert user.last_refreshed_at == orig_user.last_refreshed_at
962 test "returns an ap_id for a user" do
965 assert User.ap_id(user) ==
966 Pleroma.Web.Router.Helpers.user_feed_url(
967 Pleroma.Web.Endpoint,
973 test "returns an ap_followers link for a user" do
976 assert User.ap_followers(user) ==
977 Pleroma.Web.Router.Helpers.user_feed_url(
978 Pleroma.Web.Endpoint,
984 describe "remote user changeset" do
990 avatar: %{some: "avatar"}
992 setup do: clear_config([:instance, :user_bio_length])
993 setup do: clear_config([:instance, :user_name_length])
995 test "it confirms validity" do
996 cs = User.remote_user_changeset(@valid_remote)
1000 test "it sets the follower_adress" do
1001 cs = User.remote_user_changeset(@valid_remote)
1002 # remote users get a fake local follower address
1003 assert cs.changes.follower_address ==
1004 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
1007 test "it enforces the fqn format for nicknames" do
1008 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
1009 assert Ecto.Changeset.get_field(cs, :local) == false
1010 assert cs.changes.avatar
1014 test "it has required fields" do
1016 |> Enum.each(fn field ->
1017 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
1022 test "it is invalid given a local user" do
1023 user = insert(:user)
1024 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
1030 describe "followers and friends" do
1031 test "gets all followers for a given user" do
1032 user = insert(:user)
1033 follower_one = insert(:user)
1034 follower_two = insert(:user)
1035 not_follower = insert(:user)
1037 {:ok, follower_one, user} = User.follow(follower_one, user)
1038 {:ok, follower_two, user} = User.follow(follower_two, user)
1040 res = User.get_followers(user)
1042 assert Enum.member?(res, follower_one)
1043 assert Enum.member?(res, follower_two)
1044 refute Enum.member?(res, not_follower)
1047 test "gets all friends (followed users) for a given user" do
1048 user = insert(:user)
1049 followed_one = insert(:user)
1050 followed_two = insert(:user)
1051 not_followed = insert(:user)
1053 {:ok, user, followed_one} = User.follow(user, followed_one)
1054 {:ok, user, followed_two} = User.follow(user, followed_two)
1056 res = User.get_friends(user)
1058 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
1059 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
1060 assert Enum.member?(res, followed_one)
1061 assert Enum.member?(res, followed_two)
1062 refute Enum.member?(res, not_followed)
1066 describe "updating note and follower count" do
1067 test "it sets the note_count property" do
1068 note = insert(:note)
1070 user = User.get_cached_by_ap_id(note.data["actor"])
1072 assert user.note_count == 0
1074 {:ok, user} = User.update_note_count(user)
1076 assert user.note_count == 1
1079 test "it increases the note_count property" do
1080 note = insert(:note)
1081 user = User.get_cached_by_ap_id(note.data["actor"])
1083 assert user.note_count == 0
1085 {:ok, user} = User.increase_note_count(user)
1087 assert user.note_count == 1
1089 {:ok, user} = User.increase_note_count(user)
1091 assert user.note_count == 2
1094 test "it decreases the note_count property" do
1095 note = insert(:note)
1096 user = User.get_cached_by_ap_id(note.data["actor"])
1098 assert user.note_count == 0
1100 {:ok, user} = User.increase_note_count(user)
1102 assert user.note_count == 1
1104 {:ok, user} = User.decrease_note_count(user)
1106 assert user.note_count == 0
1108 {:ok, user} = User.decrease_note_count(user)
1110 assert user.note_count == 0
1113 test "it sets the follower_count property" do
1114 user = insert(:user)
1115 follower = insert(:user)
1117 User.follow(follower, user)
1119 assert user.follower_count == 0
1121 {:ok, user} = User.update_follower_count(user)
1123 assert user.follower_count == 1
1128 test "it mutes people" do
1129 user = insert(:user)
1130 muted_user = insert(:user)
1132 refute User.mutes?(user, muted_user)
1133 refute User.muted_notifications?(user, muted_user)
1135 {:ok, _user_relationships} = User.mute(user, muted_user)
1137 assert User.mutes?(user, muted_user)
1138 assert User.muted_notifications?(user, muted_user)
1142 user = insert(:user)
1143 muted_user = insert(:user)
1145 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1146 assert User.mutes?(user, muted_user)
1148 worker = Pleroma.Workers.MuteExpireWorker
1149 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1156 assert :ok = perform_job(worker, args)
1158 refute User.mutes?(user, muted_user)
1159 refute User.muted_notifications?(user, muted_user)
1162 test "it unmutes users" do
1163 user = insert(:user)
1164 muted_user = insert(:user)
1166 {:ok, _user_relationships} = User.mute(user, muted_user)
1167 {:ok, _user_mute} = User.unmute(user, muted_user)
1169 refute User.mutes?(user, muted_user)
1170 refute User.muted_notifications?(user, muted_user)
1173 test "it unmutes users by id" do
1174 user = insert(:user)
1175 muted_user = insert(:user)
1177 {:ok, _user_relationships} = User.mute(user, muted_user)
1178 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1180 refute User.mutes?(user, muted_user)
1181 refute User.muted_notifications?(user, muted_user)
1184 test "it mutes user without notifications" do
1185 user = insert(:user)
1186 muted_user = insert(:user)
1188 refute User.mutes?(user, muted_user)
1189 refute User.muted_notifications?(user, muted_user)
1191 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1193 assert User.mutes?(user, muted_user)
1194 refute User.muted_notifications?(user, muted_user)
1198 describe "blocks" do
1199 test "it blocks people" do
1200 user = insert(:user)
1201 blocked_user = insert(:user)
1203 refute User.blocks?(user, blocked_user)
1205 {:ok, _user_relationship} = User.block(user, blocked_user)
1207 assert User.blocks?(user, blocked_user)
1210 test "it unblocks users" do
1211 user = insert(:user)
1212 blocked_user = insert(:user)
1214 {:ok, _user_relationship} = User.block(user, blocked_user)
1215 {:ok, _user_block} = User.unblock(user, blocked_user)
1217 refute User.blocks?(user, blocked_user)
1220 test "blocks tear down cyclical follow relationships" do
1221 blocker = insert(:user)
1222 blocked = insert(:user)
1224 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1225 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1227 assert User.following?(blocker, blocked)
1228 assert User.following?(blocked, blocker)
1230 {:ok, _user_relationship} = User.block(blocker, blocked)
1231 blocked = User.get_cached_by_id(blocked.id)
1233 assert User.blocks?(blocker, blocked)
1235 refute User.following?(blocker, blocked)
1236 refute User.following?(blocked, blocker)
1239 test "blocks tear down blocker->blocked follow relationships" do
1240 blocker = insert(:user)
1241 blocked = insert(:user)
1243 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1245 assert User.following?(blocker, blocked)
1246 refute User.following?(blocked, blocker)
1248 {:ok, _user_relationship} = User.block(blocker, blocked)
1249 blocked = User.get_cached_by_id(blocked.id)
1251 assert User.blocks?(blocker, blocked)
1253 refute User.following?(blocker, blocked)
1254 refute User.following?(blocked, blocker)
1257 test "blocks tear down blocked->blocker follow relationships" do
1258 blocker = insert(:user)
1259 blocked = insert(:user)
1261 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1263 refute User.following?(blocker, blocked)
1264 assert User.following?(blocked, blocker)
1266 {:ok, _user_relationship} = User.block(blocker, blocked)
1267 blocked = User.get_cached_by_id(blocked.id)
1269 assert User.blocks?(blocker, blocked)
1271 refute User.following?(blocker, blocked)
1272 refute User.following?(blocked, blocker)
1275 test "blocks tear down blocked->blocker subscription relationships" do
1276 blocker = insert(:user)
1277 blocked = insert(:user)
1279 {:ok, _subscription} = User.subscribe(blocked, blocker)
1281 assert User.subscribed_to?(blocked, blocker)
1282 refute User.subscribed_to?(blocker, blocked)
1284 {:ok, _user_relationship} = User.block(blocker, blocked)
1286 assert User.blocks?(blocker, blocked)
1287 refute User.subscribed_to?(blocker, blocked)
1288 refute User.subscribed_to?(blocked, blocker)
1292 describe "domain blocking" do
1293 test "blocks domains" do
1294 user = insert(:user)
1295 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1297 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1299 assert User.blocks?(user, collateral_user)
1302 test "does not block domain with same end" do
1303 user = insert(:user)
1306 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1308 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1310 refute User.blocks?(user, collateral_user)
1313 test "does not block domain with same end if wildcard added" do
1314 user = insert(:user)
1317 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1319 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1321 refute User.blocks?(user, collateral_user)
1324 test "blocks domain with wildcard for subdomain" do
1325 user = insert(:user)
1327 user_from_subdomain =
1328 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1330 user_with_two_subdomains =
1332 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1335 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1337 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1339 assert User.blocks?(user, user_from_subdomain)
1340 assert User.blocks?(user, user_with_two_subdomains)
1341 assert User.blocks?(user, user_domain)
1344 test "unblocks domains" do
1345 user = insert(:user)
1346 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1348 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1349 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1351 refute User.blocks?(user, collateral_user)
1354 test "follows take precedence over domain blocks" do
1355 user = insert(:user)
1356 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1358 {:ok, user} = User.block_domain(user, "meanies.social")
1359 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1361 refute User.blocks?(user, good_eggo)
1365 describe "get_recipients_from_activity" do
1366 test "works for announces" do
1367 actor = insert(:user)
1368 user = insert(:user, local: true)
1370 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1371 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1373 recipients = User.get_recipients_from_activity(announce)
1375 assert user in recipients
1378 test "get recipients" do
1379 actor = insert(:user)
1380 user = insert(:user, local: true)
1381 user_two = insert(:user, local: false)
1382 addressed = insert(:user, local: true)
1383 addressed_remote = insert(:user, local: false)
1386 CommonAPI.post(actor, %{
1387 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1390 assert Enum.map([actor, addressed], & &1.ap_id) --
1391 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1393 {:ok, user, actor} = User.follow(user, actor)
1394 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1395 recipients = User.get_recipients_from_activity(activity)
1396 assert length(recipients) == 3
1397 assert user in recipients
1398 assert addressed in recipients
1401 test "has following" do
1402 actor = insert(:user)
1403 user = insert(:user)
1404 user_two = insert(:user)
1405 addressed = insert(:user, local: true)
1408 CommonAPI.post(actor, %{
1409 status: "hey @#{addressed.nickname}"
1412 assert Enum.map([actor, addressed], & &1.ap_id) --
1413 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1415 {:ok, _actor, _user} = User.follow(actor, user)
1416 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1417 recipients = User.get_recipients_from_activity(activity)
1418 assert length(recipients) == 2
1419 assert addressed in recipients
1423 describe ".set_activation" do
1424 test "can de-activate then re-activate a user" do
1425 user = insert(:user)
1426 assert user.is_active
1427 {:ok, user} = User.set_activation(user, false)
1428 refute user.is_active
1429 {:ok, user} = User.set_activation(user, true)
1430 assert user.is_active
1433 test "hide a user from followers" do
1434 user = insert(:user)
1435 user2 = insert(:user)
1437 {:ok, user, user2} = User.follow(user, user2)
1438 {:ok, _user} = User.set_activation(user, false)
1440 user2 = User.get_cached_by_id(user2.id)
1442 assert user2.follower_count == 0
1443 assert [] = User.get_followers(user2)
1446 test "hide a user from friends" do
1447 user = insert(:user)
1448 user2 = insert(:user)
1450 {:ok, user2, user} = User.follow(user2, user)
1451 assert user2.following_count == 1
1452 assert User.following_count(user2) == 1
1454 {:ok, _user} = User.set_activation(user, false)
1456 user2 = User.get_cached_by_id(user2.id)
1458 assert refresh_record(user2).following_count == 0
1459 assert user2.following_count == 0
1460 assert User.following_count(user2) == 0
1461 assert [] = User.get_friends(user2)
1464 test "hide a user's statuses from timelines and notifications" do
1465 user = insert(:user)
1466 user2 = insert(:user)
1468 {:ok, user2, user} = User.follow(user2, user)
1470 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1472 activity = Repo.preload(activity, :bookmark)
1474 [notification] = Pleroma.Notification.for_user(user2)
1475 assert notification.activity.id == activity.id
1477 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1479 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1480 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1484 {:ok, _user} = User.set_activation(user, false)
1486 assert [] == ActivityPub.fetch_public_activities(%{})
1487 assert [] == Pleroma.Notification.for_user(user2)
1490 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1496 describe "approve" do
1497 test "approves a user" do
1498 user = insert(:user, is_approved: false)
1499 refute user.is_approved
1500 {:ok, user} = User.approve(user)
1501 assert user.is_approved
1504 test "approves a list of users" do
1505 unapproved_users = [
1506 insert(:user, is_approved: false),
1507 insert(:user, is_approved: false),
1508 insert(:user, is_approved: false)
1511 {:ok, users} = User.approve(unapproved_users)
1513 assert Enum.count(users) == 3
1515 Enum.each(users, fn user ->
1516 assert user.is_approved
1520 test "it sends welcome email if it is set" do
1521 clear_config([:welcome, :email, :enabled], true)
1522 clear_config([:welcome, :email, :sender], "tester@test.me")
1524 user = insert(:user, is_approved: false)
1525 welcome_user = insert(:user, email: "tester@test.me")
1526 instance_name = Pleroma.Config.get([:instance, :name])
1530 ObanHelpers.perform_all()
1533 from: {instance_name, welcome_user.email},
1534 to: {user.name, user.email},
1535 html_body: "Welcome to #{instance_name}"
1539 test "approving an approved user does not trigger post-register actions" do
1540 clear_config([:welcome, :email, :enabled], true)
1542 user = insert(:user, is_approved: true)
1545 ObanHelpers.perform_all()
1547 assert_no_email_sent()
1551 describe "confirm" do
1552 test "confirms a user" do
1553 user = insert(:user, is_confirmed: false)
1554 refute user.is_confirmed
1555 {:ok, user} = User.confirm(user)
1556 assert user.is_confirmed
1559 test "confirms a list of users" do
1560 unconfirmed_users = [
1561 insert(:user, is_confirmed: false),
1562 insert(:user, is_confirmed: false),
1563 insert(:user, is_confirmed: false)
1566 {:ok, users} = User.confirm(unconfirmed_users)
1568 assert Enum.count(users) == 3
1570 Enum.each(users, fn user ->
1571 assert user.is_confirmed
1575 test "sends approval emails when `is_approved: false`" do
1576 admin = insert(:user, is_admin: true)
1577 user = insert(:user, is_confirmed: false, is_approved: false)
1580 ObanHelpers.perform_all()
1582 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1583 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1585 notify_email = Pleroma.Config.get([:instance, :notify_email])
1586 instance_name = Pleroma.Config.get([:instance, :name])
1588 # User approval email
1590 from: {instance_name, notify_email},
1591 to: {user.name, user.email},
1592 html_body: user_email.html_body
1597 from: {instance_name, notify_email},
1598 to: {admin.name, admin.email},
1599 html_body: admin_email.html_body
1603 test "confirming a confirmed user does not trigger post-register actions" do
1604 user = insert(:user, is_confirmed: true, is_approved: false)
1607 ObanHelpers.perform_all()
1609 assert_no_email_sent()
1613 describe "delete" do
1615 {:ok, user} = insert(:user) |> User.set_cache()
1620 setup do: clear_config([:instance, :federating])
1622 test ".delete_user_activities deletes all create activities", %{user: user} do
1623 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1625 User.delete_user_activities(user)
1627 # TODO: Test removal favorites, repeats, delete activities.
1628 refute Activity.get_by_id(activity.id)
1631 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1632 follower = insert(:user)
1633 {:ok, follower, user} = User.follow(follower, user)
1635 locked_user = insert(:user, name: "locked", is_locked: true)
1636 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1638 object = insert(:note, user: user)
1639 activity = insert(:note_activity, user: user, note: object)
1641 object_two = insert(:note, user: follower)
1642 activity_two = insert(:note_activity, user: follower, note: object_two)
1644 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1645 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1646 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1648 {:ok, job} = User.delete(user)
1649 {:ok, _user} = ObanHelpers.perform(job)
1651 follower = User.get_cached_by_id(follower.id)
1653 refute User.following?(follower, user)
1654 assert %{is_active: false} = User.get_by_id(user.id)
1656 assert [] == User.get_follow_requests(locked_user)
1660 |> Activity.Queries.by_actor()
1662 |> Enum.map(fn act -> act.data["type"] end)
1664 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1666 refute Activity.get_by_id(activity.id)
1667 refute Activity.get_by_id(like.id)
1668 refute Activity.get_by_id(like_two.id)
1669 refute Activity.get_by_id(repeat.id)
1673 test "delete/1 when confirmation is pending deletes the user" do
1674 clear_config([:instance, :account_activation_required], true)
1675 user = insert(:user, is_confirmed: false)
1677 {:ok, job} = User.delete(user)
1678 {:ok, _} = ObanHelpers.perform(job)
1680 refute User.get_cached_by_id(user.id)
1681 refute User.get_by_id(user.id)
1684 test "delete/1 when approval is pending deletes the user" do
1685 user = insert(:user, is_approved: false)
1687 {:ok, job} = User.delete(user)
1688 {:ok, _} = ObanHelpers.perform(job)
1690 refute User.get_cached_by_id(user.id)
1691 refute User.get_by_id(user.id)
1694 test "delete/1 purges a user when they wouldn't be fully deleted" do
1699 password_hash: "pdfk2$1b3n159001",
1700 keys: "RSA begin buplic key",
1701 public_key: "--PRIVATE KEYE--",
1702 avatar: %{"a" => "b"},
1704 banner: %{"a" => "b"},
1705 background: %{"a" => "b"},
1708 following_count: 9001,
1711 password_reset_pending: true,
1713 registration_reason: "ahhhhh",
1714 confirmation_token: "qqqq",
1715 domain_blocks: ["lain.com"],
1720 mastofe_settings: %{"a" => "b"},
1721 mascot: %{"a" => "b"},
1722 emoji: %{"a" => "b"},
1723 pleroma_settings_store: %{"q" => "x"},
1724 fields: [%{"gg" => "qq"}],
1725 raw_fields: [%{"gg" => "qq"}],
1726 is_discoverable: true,
1727 also_known_as: ["https://lol.olo/users/loll"]
1730 {:ok, job} = User.delete(user)
1731 {:ok, _} = ObanHelpers.perform(job)
1732 user = User.get_by_id(user.id)
1740 keys: "RSA begin buplic key",
1741 public_key: "--PRIVATE KEYE--",
1744 last_refreshed_at: nil,
1745 last_digest_emailed_at: nil,
1753 password_reset_pending: false,
1755 registration_reason: nil,
1756 confirmation_token: nil,
1760 is_moderator: false,
1762 mastofe_settings: nil,
1765 pleroma_settings_store: %{},
1768 is_discoverable: false,
1773 test "delete/1 purges a remote user" do
1777 avatar: %{"a" => "b"},
1778 banner: %{"a" => "b"},
1782 {:ok, job} = User.delete(user)
1783 {:ok, _} = ObanHelpers.perform(job)
1784 user = User.get_by_id(user.id)
1786 assert user.name == nil
1787 assert user.avatar == %{}
1788 assert user.banner == %{}
1791 describe "set_suggestion" do
1792 test "suggests a user" do
1793 user = insert(:user, is_suggested: false)
1794 refute user.is_suggested
1795 {:ok, user} = User.set_suggestion(user, true)
1796 assert user.is_suggested
1799 test "suggests a list of users" do
1800 unsuggested_users = [
1801 insert(:user, is_suggested: false),
1802 insert(:user, is_suggested: false),
1803 insert(:user, is_suggested: false)
1806 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1808 assert Enum.count(users) == 3
1810 Enum.each(users, fn user ->
1811 assert user.is_suggested
1815 test "unsuggests a user" do
1816 user = insert(:user, is_suggested: true)
1817 assert user.is_suggested
1818 {:ok, user} = User.set_suggestion(user, false)
1819 refute user.is_suggested
1823 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1824 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1827 describe "per-user rich-text filtering" do
1828 test "html_filter_policy returns default policies, when rich-text is enabled" do
1829 user = insert(:user)
1831 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1834 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1835 user = insert(:user, no_rich_text: true)
1837 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1841 describe "caching" do
1842 test "invalidate_cache works" do
1843 user = insert(:user)
1845 User.set_cache(user)
1846 User.invalidate_cache(user)
1848 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1849 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1852 test "User.delete() plugs any possible zombie objects" do
1853 user = insert(:user)
1855 {:ok, job} = User.delete(user)
1856 {:ok, _} = ObanHelpers.perform(job)
1858 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1860 assert cached_user != user
1862 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1864 assert cached_user != user
1868 describe "account_status/1" do
1869 setup do: clear_config([:instance, :account_activation_required])
1871 test "return confirmation_pending for unconfirm user" do
1872 clear_config([:instance, :account_activation_required], true)
1873 user = insert(:user, is_confirmed: false)
1874 assert User.account_status(user) == :confirmation_pending
1877 test "return active for confirmed user" do
1878 clear_config([:instance, :account_activation_required], true)
1879 user = insert(:user, is_confirmed: true)
1880 assert User.account_status(user) == :active
1883 test "return active for remote user" do
1884 user = insert(:user, local: false)
1885 assert User.account_status(user) == :active
1888 test "returns :password_reset_pending for user with reset password" do
1889 user = insert(:user, password_reset_pending: true)
1890 assert User.account_status(user) == :password_reset_pending
1893 test "returns :deactivated for deactivated user" do
1894 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1895 assert User.account_status(user) == :deactivated
1898 test "returns :approval_pending for unapproved user" do
1899 user = insert(:user, local: true, is_approved: false)
1900 assert User.account_status(user) == :approval_pending
1902 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1903 assert User.account_status(user) == :approval_pending
1907 describe "superuser?/1" do
1908 test "returns false for unprivileged users" do
1909 user = insert(:user, local: true)
1911 refute User.superuser?(user)
1914 test "returns false for remote users" do
1915 user = insert(:user, local: false)
1916 remote_admin_user = insert(:user, local: false, is_admin: true)
1918 refute User.superuser?(user)
1919 refute User.superuser?(remote_admin_user)
1922 test "returns true for local moderators" do
1923 user = insert(:user, local: true, is_moderator: true)
1925 assert User.superuser?(user)
1928 test "returns true for local admins" do
1929 user = insert(:user, local: true, is_admin: true)
1931 assert User.superuser?(user)
1935 describe "invisible?/1" do
1936 test "returns true for an invisible user" do
1937 user = insert(:user, local: true, invisible: true)
1939 assert User.invisible?(user)
1942 test "returns false for a non-invisible user" do
1943 user = insert(:user, local: true)
1945 refute User.invisible?(user)
1949 describe "visible_for/2" do
1950 test "returns true when the account is itself" do
1951 user = insert(:user, local: true)
1953 assert User.visible_for(user, user) == :visible
1956 test "returns false when the account is unconfirmed and confirmation is required" do
1957 clear_config([:instance, :account_activation_required], true)
1959 user = insert(:user, local: true, is_confirmed: false)
1960 other_user = insert(:user, local: true)
1962 refute User.visible_for(user, other_user) == :visible
1965 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1966 clear_config([:instance, :account_activation_required], true)
1968 user = insert(:user, local: false, is_confirmed: false)
1969 other_user = insert(:user, local: true)
1971 assert User.visible_for(user, other_user) == :visible
1974 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1975 clear_config([:instance, :account_activation_required], true)
1977 user = insert(:user, local: true, is_confirmed: false)
1978 other_user = insert(:user, local: true, is_admin: true)
1980 assert User.visible_for(user, other_user) == :visible
1984 describe "parse_bio/2" do
1985 test "preserves hosts in user links text" do
1986 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1987 user = insert(:user)
1988 bio = "A.k.a. @nick@domain.com"
1991 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{remote_user.ap_id}" rel="ugc">@<span>nick@domain.com</span></a></span>)
1993 assert expected_text == User.parse_bio(bio, user)
1996 test "Adds rel=me on linkbacked urls" do
1997 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1999 bio = "http://example.com/rel_me/null"
2000 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
2001 assert expected_text == User.parse_bio(bio, user)
2003 bio = "http://example.com/rel_me/link"
2004 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2005 assert expected_text == User.parse_bio(bio, user)
2007 bio = "http://example.com/rel_me/anchor"
2008 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2009 assert expected_text == User.parse_bio(bio, user)
2013 test "follower count is updated when a follower is blocked" do
2014 user = insert(:user)
2015 follower = insert(:user)
2016 follower2 = insert(:user)
2017 follower3 = insert(:user)
2019 {:ok, follower, user} = User.follow(follower, user)
2020 {:ok, _follower2, _user} = User.follow(follower2, user)
2021 {:ok, _follower3, _user} = User.follow(follower3, user)
2023 {:ok, _user_relationship} = User.block(user, follower)
2024 user = refresh_record(user)
2026 assert user.follower_count == 2
2029 describe "list_inactive_users_query/1" do
2030 defp days_ago(days) do
2032 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
2033 -days * 60 * 60 * 24,
2038 test "Users are inactive by default" do
2042 Enum.map(1..total, fn _ ->
2043 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2046 inactive_users_ids =
2047 Pleroma.User.list_inactive_users_query()
2048 |> Pleroma.Repo.all()
2049 |> Enum.map(& &1.id)
2051 Enum.each(users, fn user ->
2052 assert user.id in inactive_users_ids
2056 test "Only includes users who has no recent activity" do
2060 Enum.map(1..total, fn _ ->
2061 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2064 {inactive, active} = Enum.split(users, trunc(total / 2))
2066 Enum.map(active, fn user ->
2067 to = Enum.random(users -- [user])
2070 CommonAPI.post(user, %{
2071 status: "hey @#{to.nickname}"
2075 inactive_users_ids =
2076 Pleroma.User.list_inactive_users_query()
2077 |> Pleroma.Repo.all()
2078 |> Enum.map(& &1.id)
2080 Enum.each(active, fn user ->
2081 refute user.id in inactive_users_ids
2084 Enum.each(inactive, fn user ->
2085 assert user.id in inactive_users_ids
2089 test "Only includes users with no read notifications" do
2093 Enum.map(1..total, fn _ ->
2094 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2097 [sender | recipients] = users
2098 {inactive, active} = Enum.split(recipients, trunc(total / 2))
2100 Enum.each(recipients, fn to ->
2102 CommonAPI.post(sender, %{
2103 status: "hey @#{to.nickname}"
2107 CommonAPI.post(sender, %{
2108 status: "hey again @#{to.nickname}"
2112 Enum.each(active, fn user ->
2113 [n1, _n2] = Pleroma.Notification.for_user(user)
2114 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2117 inactive_users_ids =
2118 Pleroma.User.list_inactive_users_query()
2119 |> Pleroma.Repo.all()
2120 |> Enum.map(& &1.id)
2122 Enum.each(active, fn user ->
2123 refute user.id in inactive_users_ids
2126 Enum.each(inactive, fn user ->
2127 assert user.id in inactive_users_ids
2132 describe "ensure_keys_present" do
2133 test "it creates keys for a user and stores them in info" do
2134 user = insert(:user)
2135 refute is_binary(user.keys)
2136 {:ok, user} = User.ensure_keys_present(user)
2137 assert is_binary(user.keys)
2140 test "it doesn't create keys if there already are some" do
2141 user = insert(:user, keys: "xxx")
2142 {:ok, user} = User.ensure_keys_present(user)
2143 assert user.keys == "xxx"
2147 describe "get_ap_ids_by_nicknames" do
2148 test "it returns a list of AP ids for a given set of nicknames" do
2149 user = insert(:user)
2150 user_two = insert(:user)
2152 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2153 assert length(ap_ids) == 2
2154 assert user.ap_id in ap_ids
2155 assert user_two.ap_id in ap_ids
2159 describe "sync followers count" do
2161 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2162 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2163 insert(:user, local: true)
2164 insert(:user, local: false, is_active: false)
2165 {:ok, user1: user1, user2: user2}
2168 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2169 [fdb_user1] = User.external_users(limit: 1)
2171 assert fdb_user1.ap_id
2172 assert fdb_user1.ap_id == user1.ap_id
2173 assert fdb_user1.id == user1.id
2175 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2177 assert fdb_user2.ap_id
2178 assert fdb_user2.ap_id == user2.ap_id
2179 assert fdb_user2.id == user2.id
2181 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2185 describe "is_internal_user?/1" do
2186 test "non-internal user returns false" do
2187 user = insert(:user)
2188 refute User.is_internal_user?(user)
2191 test "user with no nickname returns true" do
2192 user = insert(:user, %{nickname: nil})
2193 assert User.is_internal_user?(user)
2196 test "user with internal-prefixed nickname returns true" do
2197 user = insert(:user, %{nickname: "internal.test"})
2198 assert User.is_internal_user?(user)
2202 describe "update_and_set_cache/1" do
2203 test "returns error when user is stale instead Ecto.StaleEntryError" do
2204 user = insert(:user)
2206 changeset = Ecto.Changeset.change(user, bio: "test")
2210 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2211 User.update_and_set_cache(changeset)
2214 test "performs update cache if user updated" do
2215 user = insert(:user)
2216 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2218 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2220 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2221 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2222 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2225 test "removes report notifs when user isn't superuser any more" do
2226 report_activity = insert(:report_activity)
2227 user = insert(:user, is_moderator: true, is_admin: true)
2228 {:ok, _} = Notification.create_notifications(report_activity)
2230 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2232 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2233 # is still superuser because still admin
2234 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2236 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false})
2237 # is still superuser because still moderator
2238 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2240 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2241 # is not a superuser any more
2242 assert [] = Notification.for_user(user)
2246 describe "following/followers synchronization" do
2247 setup do: clear_config([:instance, :external_user_synchronization])
2249 test "updates the counters normally on following/getting a follow when disabled" do
2250 clear_config([:instance, :external_user_synchronization], false)
2251 user = insert(:user)
2256 follower_address: "http://localhost:4001/users/masto_closed/followers",
2257 following_address: "http://localhost:4001/users/masto_closed/following",
2261 assert other_user.following_count == 0
2262 assert other_user.follower_count == 0
2264 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2266 assert user.following_count == 1
2267 assert other_user.follower_count == 1
2270 test "syncronizes the counters with the remote instance for the followed when enabled" do
2271 clear_config([:instance, :external_user_synchronization], false)
2273 user = insert(:user)
2278 follower_address: "http://localhost:4001/users/masto_closed/followers",
2279 following_address: "http://localhost:4001/users/masto_closed/following",
2283 assert other_user.following_count == 0
2284 assert other_user.follower_count == 0
2286 clear_config([:instance, :external_user_synchronization], true)
2287 {:ok, _user, other_user} = User.follow(user, other_user)
2289 assert other_user.follower_count == 437
2292 test "syncronizes the counters with the remote instance for the follower when enabled" do
2293 clear_config([:instance, :external_user_synchronization], false)
2295 user = insert(:user)
2300 follower_address: "http://localhost:4001/users/masto_closed/followers",
2301 following_address: "http://localhost:4001/users/masto_closed/following",
2305 assert other_user.following_count == 0
2306 assert other_user.follower_count == 0
2308 clear_config([:instance, :external_user_synchronization], true)
2309 {:ok, other_user, _user} = User.follow(other_user, user)
2311 assert other_user.following_count == 152
2315 describe "change_email/2" do
2317 [user: insert(:user)]
2320 test "blank email returns error if we require an email on registration", %{user: user} do
2321 orig_account_activation_required =
2322 Pleroma.Config.get([:instance, :account_activation_required])
2324 Pleroma.Config.put([:instance, :account_activation_required], true)
2328 [:instance, :account_activation_required],
2329 orig_account_activation_required
2333 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2334 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2337 test "blank email should be fine if we do not require an email on registration", %{user: user} do
2338 orig_account_activation_required =
2339 Pleroma.Config.get([:instance, :account_activation_required])
2341 Pleroma.Config.put([:instance, :account_activation_required], false)
2345 [:instance, :account_activation_required],
2346 orig_account_activation_required
2350 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2351 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2354 test "non unique email returns error", %{user: user} do
2355 %{email: email} = insert(:user)
2357 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2358 User.change_email(user, email)
2361 test "invalid email returns error", %{user: user} do
2362 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2363 User.change_email(user, "cofe")
2366 test "changes email", %{user: user} do
2367 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2370 test "adds email", %{user: user} do
2371 orig_account_activation_required =
2372 Pleroma.Config.get([:instance, :account_activation_required])
2374 Pleroma.Config.put([:instance, :account_activation_required], false)
2378 [:instance, :account_activation_required],
2379 orig_account_activation_required
2383 assert {:ok, _} = User.change_email(user, "")
2384 Pleroma.Config.put([:instance, :account_activation_required], true)
2386 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2390 describe "get_cached_by_nickname_or_id" do
2392 local_user = insert(:user)
2393 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2395 [local_user: local_user, remote_user: remote_user]
2398 setup do: clear_config([:instance, :limit_to_local_content])
2400 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2401 remote_user: remote_user
2403 clear_config([:instance, :limit_to_local_content], false)
2404 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2406 clear_config([:instance, :limit_to_local_content], true)
2407 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2409 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2410 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2413 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2414 %{remote_user: remote_user} do
2415 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2416 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2419 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2420 %{remote_user: remote_user, local_user: local_user} do
2421 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2422 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2425 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2426 %{remote_user: remote_user} do
2427 clear_config([:instance, :limit_to_local_content], true)
2428 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2431 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2432 %{local_user: local_user} do
2433 clear_config([:instance, :limit_to_local_content], false)
2434 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2436 clear_config([:instance, :limit_to_local_content], true)
2437 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2439 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2440 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2444 describe "update_email_notifications/2" do
2446 user = insert(:user, email_notifications: %{"digest" => true})
2451 test "Notifications are updated", %{user: user} do
2452 true = user.email_notifications["digest"]
2453 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2454 assert result.email_notifications["digest"] == false
2458 describe "local_nickname/1" do
2459 test "returns nickname without host" do
2460 assert User.local_nickname("@mentioned") == "mentioned"
2461 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2462 assert User.local_nickname("nickname@host.com") == "nickname"
2466 describe "full_nickname/1" do
2467 test "returns fully qualified nickname for local and remote users" do
2469 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2471 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2473 assert User.full_nickname(local_user) == "local_user@somehost.com"
2474 assert User.full_nickname(remote_user) == "remote@host.com"
2477 test "strips leading @ from mentions" do
2478 assert User.full_nickname("@mentioned") == "mentioned"
2479 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2482 test "does not modify nicknames" do
2483 assert User.full_nickname("nickname") == "nickname"
2484 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2488 test "avatar fallback" do
2489 user = insert(:user)
2490 assert User.avatar_url(user) =~ "/images/avi.png"
2492 clear_config([:assets, :default_user_avatar], "avatar.png")
2494 user = User.get_cached_by_nickname_or_id(user.nickname)
2495 assert User.avatar_url(user) =~ "avatar.png"
2497 assert User.avatar_url(user, no_default: true) == nil
2500 test "get_host/1" do
2501 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2502 assert User.get_host(user) == "lain.com"
2505 test "update_last_active_at/1" do
2506 user = insert(:user)
2507 assert is_nil(user.last_active_at)
2509 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2511 assert {:ok, user} = User.update_last_active_at(user)
2513 assert user.last_active_at >= test_started_at
2514 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2517 NaiveDateTime.utc_now()
2518 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2519 |> NaiveDateTime.truncate(:second)
2521 assert {:ok, user} =
2523 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2524 |> User.update_and_set_cache()
2526 assert user.last_active_at == last_active_at
2527 assert {:ok, user} = User.update_last_active_at(user)
2528 assert user.last_active_at >= test_started_at
2529 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2532 test "active_user_count/1" do
2534 insert(:user, %{local: false})
2535 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2536 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2537 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2538 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2539 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2541 assert User.active_user_count() == 2
2542 assert User.active_user_count(180) == 3
2543 assert User.active_user_count(365) == 4
2544 assert User.active_user_count(1000) == 5
2549 user = insert(:user)
2551 [user: user, object_id: object_id_from_created_activity(user)]
2554 test "unique pins", %{user: user, object_id: object_id} do
2555 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2556 User.add_pinned_object_id(user, object_id)
2558 assert Enum.count(pins) == 1
2560 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2561 User.add_pinned_object_id(updated_user, object_id)
2563 assert pinned_at1 == pinned_at2
2565 assert Enum.count(pins) == 1
2568 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2569 clear_config([:instance, :max_pinned_statuses], 1)
2570 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2572 object_id2 = object_id_from_created_activity(user)
2574 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2575 assert Keyword.has_key?(errors, :pinned_objects)
2578 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2579 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2581 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2582 assert after_remove.pinned_objects == %{}
2586 defp object_id_from_created_activity(user) do
2587 %{id: id} = insert(:note_activity, user: user)
2588 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2592 describe "add_alias/2" do
2593 test "should add alias for another user" do
2594 user = insert(:user)
2595 user2 = insert(:user)
2597 assert {:ok, user_updated} = user |> User.add_alias(user2)
2599 assert user_updated.also_known_as |> length() == 1
2600 assert user2.ap_id in user_updated.also_known_as
2603 test "should add multiple aliases" do
2604 user = insert(:user)
2605 user2 = insert(:user)
2606 user3 = insert(:user)
2608 assert {:ok, user} = user |> User.add_alias(user2)
2609 assert {:ok, user_updated} = user |> User.add_alias(user3)
2611 assert user_updated.also_known_as |> length() == 2
2612 assert user2.ap_id in user_updated.also_known_as
2613 assert user3.ap_id in user_updated.also_known_as
2616 test "should not add duplicate aliases" do
2617 user = insert(:user)
2618 user2 = insert(:user)
2620 assert {:ok, user} = user |> User.add_alias(user2)
2622 assert {:ok, user_updated} = user |> User.add_alias(user2)
2624 assert user_updated.also_known_as |> length() == 1
2625 assert user2.ap_id in user_updated.also_known_as
2629 describe "alias_users/1" do
2630 test "should get aliases for a user" do
2631 user = insert(:user)
2632 user2 = insert(:user, also_known_as: [user.ap_id])
2634 aliases = user2 |> User.alias_users()
2636 assert aliases |> length() == 1
2638 alias_user = aliases |> Enum.at(0)
2640 assert alias_user.ap_id == user.ap_id
2644 describe "delete_alias/2" do
2645 test "should delete existing alias" do
2646 user = insert(:user)
2647 user2 = insert(:user, also_known_as: [user.ap_id])
2649 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2651 assert user_updated.also_known_as == []
2654 test "should report error on non-existing alias" do
2655 user = insert(:user)
2656 user2 = insert(:user)
2657 user3 = insert(:user, also_known_as: [user.ap_id])
2659 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2661 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2663 assert user3_updated.also_known_as |> length() == 1
2664 assert user.ap_id in user3_updated.also_known_as