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 synchronizes 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
452 federated_timeline_removal: [],
466 Pleroma.Web.ActivityPub.MRF.SimplePolicy
470 test "it sends a welcome email message if it is set" do
471 welcome_user = insert(:user)
472 clear_config([:welcome, :email, :enabled], true)
473 clear_config([:welcome, :email, :sender], welcome_user.email)
476 [:welcome, :email, :subject],
477 "Hello, welcome to cool site: <%= instance_name %>"
480 instance_name = Pleroma.Config.get([:instance, :name])
482 cng = User.register_changeset(%User{}, @full_user_data)
483 {:ok, registered_user} = User.register(cng)
484 ObanHelpers.perform_all()
487 from: {instance_name, welcome_user.email},
488 to: {registered_user.name, registered_user.email},
489 subject: "Hello, welcome to cool site: #{instance_name}",
490 html_body: "Welcome to #{instance_name}"
494 test "it sends a confirm email" do
495 clear_config([:instance, :account_activation_required], true)
497 cng = User.register_changeset(%User{}, @full_user_data)
498 {:ok, registered_user} = User.register(cng)
499 ObanHelpers.perform_all()
501 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
502 # temporary hackney fix until hackney max_connections bug is fixed
503 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
504 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
505 |> assert_email_sent()
508 test "sends a pending approval email" do
509 clear_config([:instance, :account_approval_required], true)
512 User.register_changeset(%User{}, @full_user_data)
515 ObanHelpers.perform_all()
518 from: Pleroma.Config.Helpers.sender(),
519 to: {user.name, user.email},
520 subject: "Your account is awaiting approval"
524 test "it sends a registration confirmed email if no others will be sent" do
525 clear_config([:welcome, :email, :enabled], false)
526 clear_config([:instance, :account_activation_required], false)
527 clear_config([:instance, :account_approval_required], false)
530 User.register_changeset(%User{}, @full_user_data)
533 ObanHelpers.perform_all()
535 instance_name = Pleroma.Config.get([:instance, :name])
536 sender = Pleroma.Config.get([:instance, :notify_email])
539 from: {instance_name, sender},
540 to: {user.name, user.email},
541 subject: "Account registered on #{instance_name}"
545 test "it fails gracefully with invalid email config" do
546 cng = User.register_changeset(%User{}, @full_user_data)
548 # Disable the mailer but enable all the things that want to send emails
549 clear_config([Pleroma.Emails.Mailer, :enabled], false)
550 clear_config([:instance, :account_activation_required], true)
551 clear_config([:instance, :account_approval_required], true)
552 clear_config([:welcome, :email, :enabled], true)
553 clear_config([:welcome, :email, :sender], "lain@lain.com")
555 # The user is still created
556 assert {:ok, %User{nickname: "nick"}} = User.register(cng)
559 ObanHelpers.perform_all()
563 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
564 clear_config([:instance, :account_activation_required], true)
568 |> Enum.each(fn key ->
569 params = Map.delete(@full_user_data, key)
570 changeset = User.register_changeset(%User{}, params)
572 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
576 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
577 clear_config([:instance, :account_activation_required], false)
581 |> Enum.each(fn key ->
582 params = Map.delete(@full_user_data, key)
583 changeset = User.register_changeset(%User{}, params)
585 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
589 test "it restricts certain nicknames" do
590 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
592 assert is_bitstring(restricted_name)
596 |> Map.put(:nickname, restricted_name)
598 changeset = User.register_changeset(%User{}, params)
600 refute changeset.valid?
603 test "it blocks blacklisted email domains" do
604 clear_config([User, :email_blacklist], ["trolling.world"])
607 params = Map.put(@full_user_data, :email, "troll@trolling.world")
608 changeset = User.register_changeset(%User{}, params)
609 refute changeset.valid?
611 # Block with subdomain match
612 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
613 changeset = User.register_changeset(%User{}, params)
614 refute changeset.valid?
616 # Pass with different domains that are similar
617 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
618 changeset = User.register_changeset(%User{}, params)
619 assert changeset.valid?
621 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
622 changeset = User.register_changeset(%User{}, params)
623 assert changeset.valid?
626 test "it sets the password_hash, ap_id, private key and followers collection address" do
627 changeset = User.register_changeset(%User{}, @full_user_data)
629 assert changeset.valid?
631 assert is_binary(changeset.changes[:password_hash])
632 assert is_binary(changeset.changes[:keys])
633 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
634 assert is_binary(changeset.changes[:keys])
635 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
638 test "it creates a confirmed user" do
639 changeset = User.register_changeset(%User{}, @full_user_data)
640 assert changeset.valid?
642 {:ok, user} = Repo.insert(changeset)
644 assert user.is_confirmed
648 describe "user registration, with :account_activation_required" do
654 password_confirmation: "test",
655 email: "email@example.com"
657 setup do: clear_config([:instance, :account_activation_required], true)
659 test "it creates unconfirmed user" do
660 changeset = User.register_changeset(%User{}, @full_user_data)
661 assert changeset.valid?
663 {:ok, user} = Repo.insert(changeset)
665 refute user.is_confirmed
666 assert user.confirmation_token
669 test "it creates confirmed user if :confirmed option is given" do
670 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
671 assert changeset.valid?
673 {:ok, user} = Repo.insert(changeset)
675 assert user.is_confirmed
676 refute user.confirmation_token
680 describe "user registration, with :account_approval_required" do
686 password_confirmation: "test",
687 email: "email@example.com",
688 registration_reason: "I'm a cool guy :)"
690 setup do: clear_config([:instance, :account_approval_required], true)
692 test "it creates unapproved user" do
693 changeset = User.register_changeset(%User{}, @full_user_data)
694 assert changeset.valid?
696 {:ok, user} = Repo.insert(changeset)
698 refute user.is_approved
699 assert user.registration_reason == "I'm a cool guy :)"
702 test "it restricts length of registration reason" do
703 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
705 assert is_integer(reason_limit)
710 :registration_reason,
711 "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."
714 changeset = User.register_changeset(%User{}, params)
716 refute changeset.valid?
720 describe "get_or_fetch/1" do
721 test "gets an existing user by nickname" do
723 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
725 assert user == fetched_user
728 test "gets an existing user by ap_id" do
729 ap_id = "http://mastodon.example.org/users/admin"
735 nickname: "admin@mastodon.example.org",
739 {:ok, fetched_user} = User.get_or_fetch(ap_id)
740 freshed_user = refresh_record(user)
741 assert freshed_user == fetched_user
744 test "gets an existing user by nickname starting with http" do
745 user = insert(:user, nickname: "httpssome")
746 {:ok, fetched_user} = User.get_or_fetch("httpssome")
748 assert user == fetched_user
752 describe "get_or_fetch/1 remote users with tld, while BE is runned on subdomain" do
753 setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
755 test "for mastodon" do
757 %{url: "https://example.com/.well-known/host-meta"} ->
760 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
763 %{url: "https://sub.example.com/.well-known/host-meta"} ->
767 "test/fixtures/webfinger/masto-host-meta.xml"
769 |> String.replace("{{domain}}", "sub.example.com")
772 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
776 "test/fixtures/webfinger/masto-webfinger.json"
778 |> String.replace("{{nickname}}", "a")
779 |> String.replace("{{domain}}", "example.com")
780 |> String.replace("{{subdomain}}", "sub.example.com"),
781 headers: [{"content-type", "application/jrd+json"}]
784 %{url: "https://sub.example.com/users/a"} ->
788 "test/fixtures/webfinger/masto-user.json"
790 |> String.replace("{{nickname}}", "a")
791 |> String.replace("{{domain}}", "sub.example.com"),
792 headers: [{"content-type", "application/activity+json"}]
795 %{url: "https://sub.example.com/users/a/collections/featured"} ->
799 File.read!("test/fixtures/users_mock/masto_featured.json")
800 |> String.replace("{{domain}}", "sub.example.com")
801 |> String.replace("{{nickname}}", "a"),
802 headers: [{"content-type", "application/activity+json"}]
806 ap_id = "a@example.com"
807 {:ok, fetched_user} = User.get_or_fetch(ap_id)
809 assert fetched_user.ap_id == "https://sub.example.com/users/a"
810 assert fetched_user.nickname == "a@example.com"
813 test "for pleroma" do
815 %{url: "https://example.com/.well-known/host-meta"} ->
818 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
821 %{url: "https://sub.example.com/.well-known/host-meta"} ->
825 "test/fixtures/webfinger/pleroma-host-meta.xml"
827 |> String.replace("{{domain}}", "sub.example.com")
830 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
834 "test/fixtures/webfinger/pleroma-webfinger.json"
836 |> String.replace("{{nickname}}", "a")
837 |> String.replace("{{domain}}", "example.com")
838 |> String.replace("{{subdomain}}", "sub.example.com"),
839 headers: [{"content-type", "application/jrd+json"}]
842 %{url: "https://sub.example.com/users/a"} ->
846 "test/fixtures/webfinger/pleroma-user.json"
848 |> String.replace("{{nickname}}", "a")
849 |> String.replace("{{domain}}", "sub.example.com"),
850 headers: [{"content-type", "application/activity+json"}]
854 ap_id = "a@example.com"
855 {:ok, fetched_user} = User.get_or_fetch(ap_id)
857 assert fetched_user.ap_id == "https://sub.example.com/users/a"
858 assert fetched_user.nickname == "a@example.com"
862 describe "fetching a user from nickname or trying to build one" do
863 test "gets an existing user" do
865 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
867 assert user == fetched_user
870 test "gets an existing user, case insensitive" do
871 user = insert(:user, nickname: "nick")
872 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
874 assert user == fetched_user
877 test "gets an existing user by fully qualified nickname" do
880 {:ok, fetched_user} =
881 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
883 assert user == fetched_user
886 test "gets an existing user by fully qualified nickname, case insensitive" do
887 user = insert(:user, nickname: "nick")
888 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
890 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
892 assert user == fetched_user
895 @tag capture_log: true
896 test "returns nil if no user could be fetched" do
897 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
898 assert fetched_user == "not found nonexistant@social.heldscal.la"
901 test "returns nil for nonexistant local user" do
902 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
903 assert fetched_user == "not found nonexistant"
906 test "updates an existing user, if stale" do
907 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
913 nickname: "admin@mastodon.example.org",
914 ap_id: "http://mastodon.example.org/users/admin",
915 last_refreshed_at: a_week_ago
918 assert orig_user.last_refreshed_at == a_week_ago
920 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
924 refute user.last_refreshed_at == orig_user.last_refreshed_at
927 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
928 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
934 nickname: "admin@mastodon.example.org",
935 ap_id: "http://mastodon.example.org/users/harinezumigari",
936 last_refreshed_at: a_week_ago
939 assert orig_user.last_refreshed_at == a_week_ago
941 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
945 refute user.id == orig_user.id
947 orig_user = User.get_by_id(orig_user.id)
949 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
952 @tag capture_log: true
953 test "it returns the old user if stale, but unfetchable" do
954 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
960 nickname: "admin@mastodon.example.org",
961 ap_id: "http://mastodon.example.org/users/raymoo",
962 last_refreshed_at: a_week_ago
965 assert orig_user.last_refreshed_at == a_week_ago
967 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
969 assert user.last_refreshed_at == orig_user.last_refreshed_at
972 test "it doesn't fail on invalid alsoKnownAs entries" do
974 %{url: "https://mbp.example.com/"} ->
978 "test/fixtures/microblogpub/user_with_invalid_also_known_as.json"
980 headers: [{"content-type", "application/activity+json"}]
984 %Tesla.Env{status: 404}
987 assert {:ok, %User{also_known_as: []}} =
988 User.get_or_fetch_by_ap_id("https://mbp.example.com/")
992 test "returns an ap_id for a user" do
995 assert User.ap_id(user) ==
996 Pleroma.Web.Router.Helpers.user_feed_url(
997 Pleroma.Web.Endpoint,
1003 test "returns an ap_followers link for a user" do
1004 user = insert(:user)
1006 assert User.ap_followers(user) ==
1007 Pleroma.Web.Router.Helpers.user_feed_url(
1008 Pleroma.Web.Endpoint,
1014 describe "remote user changeset" do
1020 avatar: %{some: "avatar"}
1022 setup do: clear_config([:instance, :user_bio_length])
1023 setup do: clear_config([:instance, :user_name_length])
1025 test "it confirms validity" do
1026 cs = User.remote_user_changeset(@valid_remote)
1030 test "it sets the follower_adress" do
1031 cs = User.remote_user_changeset(@valid_remote)
1032 # remote users get a fake local follower address
1033 assert cs.changes.follower_address ==
1034 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
1037 test "it enforces the fqn format for nicknames" do
1038 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
1039 assert Ecto.Changeset.get_field(cs, :local) == false
1040 assert cs.changes.avatar
1044 test "it has required fields" do
1046 |> Enum.each(fn field ->
1047 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
1052 test "it is invalid given a local user" do
1053 user = insert(:user)
1054 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
1060 describe "followers and friends" do
1061 test "gets all followers for a given user" do
1062 user = insert(:user)
1063 follower_one = insert(:user)
1064 follower_two = insert(:user)
1065 not_follower = insert(:user)
1067 {:ok, follower_one, user} = User.follow(follower_one, user)
1068 {:ok, follower_two, user} = User.follow(follower_two, user)
1070 res = User.get_followers(user)
1072 assert Enum.member?(res, follower_one)
1073 assert Enum.member?(res, follower_two)
1074 refute Enum.member?(res, not_follower)
1077 test "gets all friends (followed users) for a given user" do
1078 user = insert(:user)
1079 followed_one = insert(:user)
1080 followed_two = insert(:user)
1081 not_followed = insert(:user)
1083 {:ok, user, followed_one} = User.follow(user, followed_one)
1084 {:ok, user, followed_two} = User.follow(user, followed_two)
1086 res = User.get_friends(user)
1088 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
1089 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
1090 assert Enum.member?(res, followed_one)
1091 assert Enum.member?(res, followed_two)
1092 refute Enum.member?(res, not_followed)
1096 describe "updating note and follower count" do
1097 test "it sets the note_count property" do
1098 note = insert(:note)
1100 user = User.get_cached_by_ap_id(note.data["actor"])
1102 assert user.note_count == 0
1104 {:ok, user} = User.update_note_count(user)
1106 assert user.note_count == 1
1109 test "it increases the note_count property" do
1110 note = insert(:note)
1111 user = User.get_cached_by_ap_id(note.data["actor"])
1113 assert user.note_count == 0
1115 {:ok, user} = User.increase_note_count(user)
1117 assert user.note_count == 1
1119 {:ok, user} = User.increase_note_count(user)
1121 assert user.note_count == 2
1124 test "it decreases the note_count property" do
1125 note = insert(:note)
1126 user = User.get_cached_by_ap_id(note.data["actor"])
1128 assert user.note_count == 0
1130 {:ok, user} = User.increase_note_count(user)
1132 assert user.note_count == 1
1134 {:ok, user} = User.decrease_note_count(user)
1136 assert user.note_count == 0
1138 {:ok, user} = User.decrease_note_count(user)
1140 assert user.note_count == 0
1143 test "it sets the follower_count property" do
1144 user = insert(:user)
1145 follower = insert(:user)
1147 User.follow(follower, user)
1149 assert user.follower_count == 0
1151 {:ok, user} = User.update_follower_count(user)
1153 assert user.follower_count == 1
1158 test "it mutes people" do
1159 user = insert(:user)
1160 muted_user = insert(:user)
1162 refute User.mutes?(user, muted_user)
1163 refute User.muted_notifications?(user, muted_user)
1165 {:ok, _user_relationships} = User.mute(user, muted_user)
1167 assert User.mutes?(user, muted_user)
1168 assert User.muted_notifications?(user, muted_user)
1172 user = insert(:user)
1173 muted_user = insert(:user)
1175 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1176 assert User.mutes?(user, muted_user)
1178 worker = Pleroma.Workers.MuteExpireWorker
1179 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1186 assert :ok = perform_job(worker, args)
1188 refute User.mutes?(user, muted_user)
1189 refute User.muted_notifications?(user, muted_user)
1192 test "it unmutes users" do
1193 user = insert(:user)
1194 muted_user = insert(:user)
1196 {:ok, _user_relationships} = User.mute(user, muted_user)
1197 {:ok, _user_mute} = User.unmute(user, muted_user)
1199 refute User.mutes?(user, muted_user)
1200 refute User.muted_notifications?(user, muted_user)
1203 test "it unmutes users by id" do
1204 user = insert(:user)
1205 muted_user = insert(:user)
1207 {:ok, _user_relationships} = User.mute(user, muted_user)
1208 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1210 refute User.mutes?(user, muted_user)
1211 refute User.muted_notifications?(user, muted_user)
1214 test "it mutes user without notifications" do
1215 user = insert(:user)
1216 muted_user = insert(:user)
1218 refute User.mutes?(user, muted_user)
1219 refute User.muted_notifications?(user, muted_user)
1221 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1223 assert User.mutes?(user, muted_user)
1224 refute User.muted_notifications?(user, muted_user)
1228 describe "blocks" do
1229 test "it blocks people" do
1230 user = insert(:user)
1231 blocked_user = insert(:user)
1233 refute User.blocks?(user, blocked_user)
1235 {:ok, _user_relationship} = User.block(user, blocked_user)
1237 assert User.blocks?(user, blocked_user)
1240 test "it unblocks users" do
1241 user = insert(:user)
1242 blocked_user = insert(:user)
1244 {:ok, _user_relationship} = User.block(user, blocked_user)
1245 {:ok, _user_block} = User.unblock(user, blocked_user)
1247 refute User.blocks?(user, blocked_user)
1250 test "blocks tear down cyclical follow relationships" do
1251 blocker = insert(:user)
1252 blocked = insert(:user)
1254 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1255 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1257 assert User.following?(blocker, blocked)
1258 assert User.following?(blocked, blocker)
1260 {:ok, _user_relationship} = User.block(blocker, blocked)
1261 blocked = User.get_cached_by_id(blocked.id)
1263 assert User.blocks?(blocker, blocked)
1265 refute User.following?(blocker, blocked)
1266 refute User.following?(blocked, blocker)
1269 test "blocks tear down blocker->blocked follow relationships" do
1270 blocker = insert(:user)
1271 blocked = insert(:user)
1273 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1275 assert User.following?(blocker, blocked)
1276 refute User.following?(blocked, blocker)
1278 {:ok, _user_relationship} = User.block(blocker, blocked)
1279 blocked = User.get_cached_by_id(blocked.id)
1281 assert User.blocks?(blocker, blocked)
1283 refute User.following?(blocker, blocked)
1284 refute User.following?(blocked, blocker)
1287 test "blocks tear down blocked->blocker follow relationships" do
1288 blocker = insert(:user)
1289 blocked = insert(:user)
1291 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1293 refute User.following?(blocker, blocked)
1294 assert User.following?(blocked, blocker)
1296 {:ok, _user_relationship} = User.block(blocker, blocked)
1297 blocked = User.get_cached_by_id(blocked.id)
1299 assert User.blocks?(blocker, blocked)
1301 refute User.following?(blocker, blocked)
1302 refute User.following?(blocked, blocker)
1305 test "blocks tear down blocked->blocker subscription relationships" do
1306 blocker = insert(:user)
1307 blocked = insert(:user)
1309 {:ok, _subscription} = User.subscribe(blocked, blocker)
1311 assert User.subscribed_to?(blocked, blocker)
1312 refute User.subscribed_to?(blocker, blocked)
1314 {:ok, _user_relationship} = User.block(blocker, blocked)
1316 assert User.blocks?(blocker, blocked)
1317 refute User.subscribed_to?(blocker, blocked)
1318 refute User.subscribed_to?(blocked, blocker)
1322 describe "domain blocking" do
1323 test "blocks domains" do
1324 user = insert(:user)
1325 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1327 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1329 assert User.blocks?(user, collateral_user)
1332 test "does not block domain with same end" do
1333 user = insert(:user)
1336 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1338 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1340 refute User.blocks?(user, collateral_user)
1343 test "does not block domain with same end if wildcard added" do
1344 user = insert(:user)
1347 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1349 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1351 refute User.blocks?(user, collateral_user)
1354 test "blocks domain with wildcard for subdomain" do
1355 user = insert(:user)
1357 user_from_subdomain =
1358 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1360 user_with_two_subdomains =
1362 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1365 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1367 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1369 assert User.blocks?(user, user_from_subdomain)
1370 assert User.blocks?(user, user_with_two_subdomains)
1371 assert User.blocks?(user, user_domain)
1374 test "unblocks domains" do
1375 user = insert(:user)
1376 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1378 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1379 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1381 refute User.blocks?(user, collateral_user)
1384 test "follows take precedence over domain blocks" do
1385 user = insert(:user)
1386 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1388 {:ok, user} = User.block_domain(user, "meanies.social")
1389 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1391 refute User.blocks?(user, good_eggo)
1395 describe "get_recipients_from_activity" do
1396 test "works for announces" do
1397 actor = insert(:user)
1398 user = insert(:user, local: true)
1400 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1401 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1403 recipients = User.get_recipients_from_activity(announce)
1405 assert user in recipients
1408 test "get recipients" do
1409 actor = insert(:user)
1410 user = insert(:user, local: true)
1411 user_two = insert(:user, local: false)
1412 addressed = insert(:user, local: true)
1413 addressed_remote = insert(:user, local: false)
1416 CommonAPI.post(actor, %{
1417 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1420 assert Enum.map([actor, addressed], & &1.ap_id) --
1421 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1423 {:ok, user, actor} = User.follow(user, actor)
1424 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1425 recipients = User.get_recipients_from_activity(activity)
1426 assert length(recipients) == 3
1427 assert user in recipients
1428 assert addressed in recipients
1431 test "has following" do
1432 actor = insert(:user)
1433 user = insert(:user)
1434 user_two = insert(:user)
1435 addressed = insert(:user, local: true)
1438 CommonAPI.post(actor, %{
1439 status: "hey @#{addressed.nickname}"
1442 assert Enum.map([actor, addressed], & &1.ap_id) --
1443 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1445 {:ok, _actor, _user} = User.follow(actor, user)
1446 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1447 recipients = User.get_recipients_from_activity(activity)
1448 assert length(recipients) == 2
1449 assert addressed in recipients
1453 describe ".set_activation" do
1454 test "can de-activate then re-activate a user" do
1455 user = insert(:user)
1456 assert user.is_active
1457 {:ok, user} = User.set_activation(user, false)
1458 refute user.is_active
1459 {:ok, user} = User.set_activation(user, true)
1460 assert user.is_active
1463 test "hide a user from followers" do
1464 user = insert(:user)
1465 user2 = insert(:user)
1467 {:ok, user, user2} = User.follow(user, user2)
1468 {:ok, _user} = User.set_activation(user, false)
1470 user2 = User.get_cached_by_id(user2.id)
1472 assert user2.follower_count == 0
1473 assert [] = User.get_followers(user2)
1476 test "hide a user from friends" do
1477 user = insert(:user)
1478 user2 = insert(:user)
1480 {:ok, user2, user} = User.follow(user2, user)
1481 assert user2.following_count == 1
1482 assert User.following_count(user2) == 1
1484 {:ok, _user} = User.set_activation(user, false)
1486 user2 = User.get_cached_by_id(user2.id)
1488 assert refresh_record(user2).following_count == 0
1489 assert user2.following_count == 0
1490 assert User.following_count(user2) == 0
1491 assert [] = User.get_friends(user2)
1494 test "hide a user's statuses from timelines and notifications" do
1495 user = insert(:user)
1496 user2 = insert(:user)
1498 {:ok, user2, user} = User.follow(user2, user)
1500 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1502 activity = Repo.preload(activity, :bookmark)
1504 [notification] = Pleroma.Notification.for_user(user2)
1505 assert notification.activity.id == activity.id
1507 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1509 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1510 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1514 {:ok, _user} = User.set_activation(user, false)
1516 assert [] == ActivityPub.fetch_public_activities(%{})
1517 assert [] == Pleroma.Notification.for_user(user2)
1520 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1526 describe "approve" do
1527 test "approves a user" do
1528 user = insert(:user, is_approved: false)
1529 refute user.is_approved
1530 {:ok, user} = User.approve(user)
1531 assert user.is_approved
1534 test "approves a list of users" do
1535 unapproved_users = [
1536 insert(:user, is_approved: false),
1537 insert(:user, is_approved: false),
1538 insert(:user, is_approved: false)
1541 {:ok, users} = User.approve(unapproved_users)
1543 assert Enum.count(users) == 3
1545 Enum.each(users, fn user ->
1546 assert user.is_approved
1550 test "it sends welcome email if it is set" do
1551 clear_config([:welcome, :email, :enabled], true)
1552 clear_config([:welcome, :email, :sender], "tester@test.me")
1554 user = insert(:user, is_approved: false)
1555 welcome_user = insert(:user, email: "tester@test.me")
1556 instance_name = Pleroma.Config.get([:instance, :name])
1560 ObanHelpers.perform_all()
1563 from: {instance_name, welcome_user.email},
1564 to: {user.name, user.email},
1565 html_body: "Welcome to #{instance_name}"
1569 test "approving an approved user does not trigger post-register actions" do
1570 clear_config([:welcome, :email, :enabled], true)
1572 user = insert(:user, is_approved: true)
1575 ObanHelpers.perform_all()
1577 assert_no_email_sent()
1581 describe "confirm" do
1582 test "confirms a user" do
1583 user = insert(:user, is_confirmed: false)
1584 refute user.is_confirmed
1585 {:ok, user} = User.confirm(user)
1586 assert user.is_confirmed
1589 test "confirms a list of users" do
1590 unconfirmed_users = [
1591 insert(:user, is_confirmed: false),
1592 insert(:user, is_confirmed: false),
1593 insert(:user, is_confirmed: false)
1596 {:ok, users} = User.confirm(unconfirmed_users)
1598 assert Enum.count(users) == 3
1600 Enum.each(users, fn user ->
1601 assert user.is_confirmed
1605 test "sends approval emails when `is_approved: false`" do
1606 admin = insert(:user, is_admin: true)
1607 user = insert(:user, is_confirmed: false, is_approved: false)
1610 ObanHelpers.perform_all()
1612 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1613 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1615 notify_email = Pleroma.Config.get([:instance, :notify_email])
1616 instance_name = Pleroma.Config.get([:instance, :name])
1618 # User approval email
1620 from: {instance_name, notify_email},
1621 to: {user.name, user.email},
1622 html_body: user_email.html_body
1627 from: {instance_name, notify_email},
1628 to: {admin.name, admin.email},
1629 html_body: admin_email.html_body
1633 test "confirming a confirmed user does not trigger post-register actions" do
1634 user = insert(:user, is_confirmed: true, is_approved: false)
1637 ObanHelpers.perform_all()
1639 assert_no_email_sent()
1643 describe "delete" do
1645 {:ok, user} = insert(:user) |> User.set_cache()
1650 setup do: clear_config([:instance, :federating])
1652 test ".delete_user_activities deletes all create activities", %{user: user} do
1653 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1655 User.delete_user_activities(user)
1657 # TODO: Test removal favorites, repeats, delete activities.
1658 refute Activity.get_by_id(activity.id)
1661 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1662 follower = insert(:user)
1663 {:ok, follower, user} = User.follow(follower, user)
1665 locked_user = insert(:user, name: "locked", is_locked: true)
1666 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1668 object = insert(:note, user: user)
1669 activity = insert(:note_activity, user: user, note: object)
1671 object_two = insert(:note, user: follower)
1672 activity_two = insert(:note_activity, user: follower, note: object_two)
1674 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1675 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1676 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1678 {:ok, job} = User.delete(user)
1679 {:ok, _user} = ObanHelpers.perform(job)
1681 follower = User.get_cached_by_id(follower.id)
1683 refute User.following?(follower, user)
1684 assert %{is_active: false} = User.get_by_id(user.id)
1686 assert [] == User.get_follow_requests(locked_user)
1690 |> Activity.Queries.by_actor()
1692 |> Enum.map(fn act -> act.data["type"] end)
1694 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1696 refute Activity.get_by_id(activity.id)
1697 refute Activity.get_by_id(like.id)
1698 refute Activity.get_by_id(like_two.id)
1699 refute Activity.get_by_id(repeat.id)
1703 test "delete/1 when confirmation is pending deletes the user" do
1704 clear_config([:instance, :account_activation_required], true)
1705 user = insert(:user, is_confirmed: false)
1707 {:ok, job} = User.delete(user)
1708 {:ok, _} = ObanHelpers.perform(job)
1710 refute User.get_cached_by_id(user.id)
1711 refute User.get_by_id(user.id)
1714 test "delete/1 when approval is pending deletes the user" do
1715 user = insert(:user, is_approved: false)
1717 {:ok, job} = User.delete(user)
1718 {:ok, _} = ObanHelpers.perform(job)
1720 refute User.get_cached_by_id(user.id)
1721 refute User.get_by_id(user.id)
1724 test "delete/1 purges a user when they wouldn't be fully deleted" do
1729 password_hash: "pdfk2$1b3n159001",
1730 keys: "RSA begin buplic key",
1731 public_key: "--PRIVATE KEYE--",
1732 avatar: %{"a" => "b"},
1734 banner: %{"a" => "b"},
1735 background: %{"a" => "b"},
1738 following_count: 9001,
1741 password_reset_pending: true,
1743 registration_reason: "ahhhhh",
1744 confirmation_token: "qqqq",
1745 domain_blocks: ["lain.com"],
1750 mastofe_settings: %{"a" => "b"},
1751 mascot: %{"a" => "b"},
1752 emoji: %{"a" => "b"},
1753 pleroma_settings_store: %{"q" => "x"},
1754 fields: [%{"gg" => "qq"}],
1755 raw_fields: [%{"gg" => "qq"}],
1756 is_discoverable: true,
1757 also_known_as: ["https://lol.olo/users/loll"]
1760 {:ok, job} = User.delete(user)
1761 {:ok, _} = ObanHelpers.perform(job)
1762 user = User.get_by_id(user.id)
1770 keys: "RSA begin buplic key",
1771 public_key: "--PRIVATE KEYE--",
1774 last_refreshed_at: nil,
1775 last_digest_emailed_at: nil,
1783 password_reset_pending: false,
1785 registration_reason: nil,
1786 confirmation_token: nil,
1790 is_moderator: false,
1792 mastofe_settings: nil,
1795 pleroma_settings_store: %{},
1798 is_discoverable: false,
1803 test "delete/1 purges a remote user" do
1807 avatar: %{"a" => "b"},
1808 banner: %{"a" => "b"},
1812 {:ok, job} = User.delete(user)
1813 {:ok, _} = ObanHelpers.perform(job)
1814 user = User.get_by_id(user.id)
1816 assert user.name == nil
1817 assert user.avatar == %{}
1818 assert user.banner == %{}
1821 describe "set_suggestion" do
1822 test "suggests a user" do
1823 user = insert(:user, is_suggested: false)
1824 refute user.is_suggested
1825 {:ok, user} = User.set_suggestion(user, true)
1826 assert user.is_suggested
1829 test "suggests a list of users" do
1830 unsuggested_users = [
1831 insert(:user, is_suggested: false),
1832 insert(:user, is_suggested: false),
1833 insert(:user, is_suggested: false)
1836 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1838 assert Enum.count(users) == 3
1840 Enum.each(users, fn user ->
1841 assert user.is_suggested
1845 test "unsuggests a user" do
1846 user = insert(:user, is_suggested: true)
1847 assert user.is_suggested
1848 {:ok, user} = User.set_suggestion(user, false)
1849 refute user.is_suggested
1853 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1854 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1857 describe "per-user rich-text filtering" do
1858 test "html_filter_policy returns default policies, when rich-text is enabled" do
1859 user = insert(:user)
1861 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1864 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1865 user = insert(:user, no_rich_text: true)
1867 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1871 describe "caching" do
1872 test "invalidate_cache works" do
1873 user = insert(:user)
1875 User.set_cache(user)
1876 User.invalidate_cache(user)
1878 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1879 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1882 test "User.delete() plugs any possible zombie objects" do
1883 user = insert(:user)
1885 {:ok, job} = User.delete(user)
1886 {:ok, _} = ObanHelpers.perform(job)
1888 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1890 assert cached_user != user
1892 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1894 assert cached_user != user
1898 describe "account_status/1" do
1899 setup do: clear_config([:instance, :account_activation_required])
1901 test "return confirmation_pending for unconfirm user" do
1902 clear_config([:instance, :account_activation_required], true)
1903 user = insert(:user, is_confirmed: false)
1904 assert User.account_status(user) == :confirmation_pending
1907 test "return active for confirmed user" do
1908 clear_config([:instance, :account_activation_required], true)
1909 user = insert(:user, is_confirmed: true)
1910 assert User.account_status(user) == :active
1913 test "return active for remote user" do
1914 user = insert(:user, local: false)
1915 assert User.account_status(user) == :active
1918 test "returns :password_reset_pending for user with reset password" do
1919 user = insert(:user, password_reset_pending: true)
1920 assert User.account_status(user) == :password_reset_pending
1923 test "returns :deactivated for deactivated user" do
1924 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1925 assert User.account_status(user) == :deactivated
1928 test "returns :approval_pending for unapproved user" do
1929 user = insert(:user, local: true, is_approved: false)
1930 assert User.account_status(user) == :approval_pending
1932 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1933 assert User.account_status(user) == :approval_pending
1937 describe "superuser?/1" do
1938 test "returns false for unprivileged users" do
1939 user = insert(:user, local: true)
1941 refute User.superuser?(user)
1944 test "returns false for remote users" do
1945 user = insert(:user, local: false)
1946 remote_admin_user = insert(:user, local: false, is_admin: true)
1948 refute User.superuser?(user)
1949 refute User.superuser?(remote_admin_user)
1952 test "returns true for local moderators" do
1953 user = insert(:user, local: true, is_moderator: true)
1955 assert User.superuser?(user)
1958 test "returns true for local admins" do
1959 user = insert(:user, local: true, is_admin: true)
1961 assert User.superuser?(user)
1965 describe "invisible?/1" do
1966 test "returns true for an invisible user" do
1967 user = insert(:user, local: true, invisible: true)
1969 assert User.invisible?(user)
1972 test "returns false for a non-invisible user" do
1973 user = insert(:user, local: true)
1975 refute User.invisible?(user)
1979 describe "visible_for/2" do
1980 test "returns true when the account is itself" do
1981 user = insert(:user, local: true)
1983 assert User.visible_for(user, user) == :visible
1986 test "returns false when the account is unconfirmed and confirmation is required" do
1987 clear_config([:instance, :account_activation_required], true)
1989 user = insert(:user, local: true, is_confirmed: false)
1990 other_user = insert(:user, local: true)
1992 refute User.visible_for(user, other_user) == :visible
1995 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1996 clear_config([:instance, :account_activation_required], true)
1998 user = insert(:user, local: false, is_confirmed: false)
1999 other_user = insert(:user, local: true)
2001 assert User.visible_for(user, other_user) == :visible
2004 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
2005 clear_config([:instance, :account_activation_required], true)
2007 user = insert(:user, local: true, is_confirmed: false)
2008 other_user = insert(:user, local: true, is_admin: true)
2010 assert User.visible_for(user, other_user) == :visible
2014 describe "parse_bio/2" do
2015 test "preserves hosts in user links text" do
2016 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
2017 user = insert(:user)
2018 bio = "A.k.a. @nick@domain.com"
2021 ~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>)
2023 assert expected_text == User.parse_bio(bio, user)
2026 test "Adds rel=me on linkbacked urls" do
2027 user = insert(:user, ap_id: "https://social.example.org/users/lain")
2029 bio = "http://example.com/rel_me/null"
2030 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
2031 assert expected_text == User.parse_bio(bio, user)
2033 bio = "http://example.com/rel_me/link"
2034 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2035 assert expected_text == User.parse_bio(bio, user)
2037 bio = "http://example.com/rel_me/anchor"
2038 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2039 assert expected_text == User.parse_bio(bio, user)
2043 test "follower count is updated when a follower is blocked" do
2044 user = insert(:user)
2045 follower = insert(:user)
2046 follower2 = insert(:user)
2047 follower3 = insert(:user)
2049 {:ok, follower, user} = User.follow(follower, user)
2050 {:ok, _follower2, _user} = User.follow(follower2, user)
2051 {:ok, _follower3, _user} = User.follow(follower3, user)
2053 {:ok, _user_relationship} = User.block(user, follower)
2054 user = refresh_record(user)
2056 assert user.follower_count == 2
2059 describe "list_inactive_users_query/1" do
2060 defp days_ago(days) do
2062 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
2063 -days * 60 * 60 * 24,
2068 test "Users are inactive by default" do
2072 Enum.map(1..total, fn _ ->
2073 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2076 inactive_users_ids =
2077 Pleroma.User.list_inactive_users_query()
2078 |> Pleroma.Repo.all()
2079 |> Enum.map(& &1.id)
2081 Enum.each(users, fn user ->
2082 assert user.id in inactive_users_ids
2086 test "Only includes users who has no recent activity" do
2090 Enum.map(1..total, fn _ ->
2091 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2094 {inactive, active} = Enum.split(users, trunc(total / 2))
2096 Enum.map(active, fn user ->
2097 to = Enum.random(users -- [user])
2100 CommonAPI.post(user, %{
2101 status: "hey @#{to.nickname}"
2105 inactive_users_ids =
2106 Pleroma.User.list_inactive_users_query()
2107 |> Pleroma.Repo.all()
2108 |> Enum.map(& &1.id)
2110 Enum.each(active, fn user ->
2111 refute user.id in inactive_users_ids
2114 Enum.each(inactive, fn user ->
2115 assert user.id in inactive_users_ids
2119 test "Only includes users with no read notifications" do
2123 Enum.map(1..total, fn _ ->
2124 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2127 [sender | recipients] = users
2128 {inactive, active} = Enum.split(recipients, trunc(total / 2))
2130 Enum.each(recipients, fn to ->
2132 CommonAPI.post(sender, %{
2133 status: "hey @#{to.nickname}"
2137 CommonAPI.post(sender, %{
2138 status: "hey again @#{to.nickname}"
2142 Enum.each(active, fn user ->
2143 [n1, _n2] = Pleroma.Notification.for_user(user)
2144 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2147 inactive_users_ids =
2148 Pleroma.User.list_inactive_users_query()
2149 |> Pleroma.Repo.all()
2150 |> Enum.map(& &1.id)
2152 Enum.each(active, fn user ->
2153 refute user.id in inactive_users_ids
2156 Enum.each(inactive, fn user ->
2157 assert user.id in inactive_users_ids
2162 describe "get_ap_ids_by_nicknames" do
2163 test "it returns a list of AP ids for a given set of nicknames" do
2164 user = insert(:user)
2165 user_two = insert(:user)
2167 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2168 assert length(ap_ids) == 2
2169 assert user.ap_id in ap_ids
2170 assert user_two.ap_id in ap_ids
2174 describe "sync followers count" do
2176 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2177 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2178 insert(:user, local: true)
2179 insert(:user, local: false, is_active: false)
2180 {:ok, user1: user1, user2: user2}
2183 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2184 [fdb_user1] = User.external_users(limit: 1)
2186 assert fdb_user1.ap_id
2187 assert fdb_user1.ap_id == user1.ap_id
2188 assert fdb_user1.id == user1.id
2190 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2192 assert fdb_user2.ap_id
2193 assert fdb_user2.ap_id == user2.ap_id
2194 assert fdb_user2.id == user2.id
2196 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2200 describe "is_internal_user?/1" do
2201 test "non-internal user returns false" do
2202 user = insert(:user)
2203 refute User.is_internal_user?(user)
2206 test "user with no nickname returns true" do
2207 user = insert(:user, %{nickname: nil})
2208 assert User.is_internal_user?(user)
2211 test "user with internal-prefixed nickname returns true" do
2212 user = insert(:user, %{nickname: "internal.test"})
2213 assert User.is_internal_user?(user)
2217 describe "update_and_set_cache/1" do
2218 test "returns error when user is stale instead Ecto.StaleEntryError" do
2219 user = insert(:user)
2221 changeset = Ecto.Changeset.change(user, bio: "test")
2225 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2226 User.update_and_set_cache(changeset)
2229 test "performs update cache if user updated" do
2230 user = insert(:user)
2231 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2233 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2235 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2236 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2237 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2240 test "removes report notifs when user isn't superuser any more" do
2241 report_activity = insert(:report_activity)
2242 user = insert(:user, is_moderator: true, is_admin: true)
2243 {:ok, _} = Notification.create_notifications(report_activity)
2245 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2247 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2248 # is still superuser because still admin
2249 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2251 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false})
2252 # is still superuser because still moderator
2253 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2255 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2256 # is not a superuser any more
2257 assert [] = Notification.for_user(user)
2261 describe "following/followers synchronization" do
2262 setup do: clear_config([:instance, :external_user_synchronization])
2264 test "updates the counters normally on following/getting a follow when disabled" do
2265 clear_config([:instance, :external_user_synchronization], false)
2266 user = insert(:user)
2271 follower_address: "http://localhost:4001/users/masto_closed/followers",
2272 following_address: "http://localhost:4001/users/masto_closed/following",
2276 assert other_user.following_count == 0
2277 assert other_user.follower_count == 0
2279 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2281 assert user.following_count == 1
2282 assert other_user.follower_count == 1
2285 test "synchronizes the counters with the remote instance for the followed when enabled" do
2286 clear_config([:instance, :external_user_synchronization], false)
2288 user = insert(:user)
2293 follower_address: "http://localhost:4001/users/masto_closed/followers",
2294 following_address: "http://localhost:4001/users/masto_closed/following",
2298 assert other_user.following_count == 0
2299 assert other_user.follower_count == 0
2301 clear_config([:instance, :external_user_synchronization], true)
2302 {:ok, _user, other_user} = User.follow(user, other_user)
2304 assert other_user.follower_count == 437
2307 test "synchronizes the counters with the remote instance for the follower when enabled" do
2308 clear_config([:instance, :external_user_synchronization], false)
2310 user = insert(:user)
2315 follower_address: "http://localhost:4001/users/masto_closed/followers",
2316 following_address: "http://localhost:4001/users/masto_closed/following",
2320 assert other_user.following_count == 0
2321 assert other_user.follower_count == 0
2323 clear_config([:instance, :external_user_synchronization], true)
2324 {:ok, other_user, _user} = User.follow(other_user, user)
2326 assert other_user.following_count == 152
2330 describe "change_email/2" do
2332 [user: insert(:user)]
2335 test "blank email returns error if we require an email on registration", %{user: user} do
2336 orig_account_activation_required =
2337 Pleroma.Config.get([:instance, :account_activation_required])
2339 Pleroma.Config.put([:instance, :account_activation_required], true)
2343 [:instance, :account_activation_required],
2344 orig_account_activation_required
2348 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2349 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2352 test "blank email should be fine if we do not require an email on registration", %{user: user} do
2353 orig_account_activation_required =
2354 Pleroma.Config.get([:instance, :account_activation_required])
2356 Pleroma.Config.put([:instance, :account_activation_required], false)
2360 [:instance, :account_activation_required],
2361 orig_account_activation_required
2365 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2366 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2369 test "non unique email returns error", %{user: user} do
2370 %{email: email} = insert(:user)
2372 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2373 User.change_email(user, email)
2376 test "invalid email returns error", %{user: user} do
2377 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2378 User.change_email(user, "cofe")
2381 test "changes email", %{user: user} do
2382 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2385 test "adds email", %{user: user} do
2386 orig_account_activation_required =
2387 Pleroma.Config.get([:instance, :account_activation_required])
2389 Pleroma.Config.put([:instance, :account_activation_required], false)
2393 [:instance, :account_activation_required],
2394 orig_account_activation_required
2398 assert {:ok, _} = User.change_email(user, "")
2399 Pleroma.Config.put([:instance, :account_activation_required], true)
2401 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2405 describe "get_cached_by_nickname_or_id" do
2407 local_user = insert(:user)
2408 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2410 [local_user: local_user, remote_user: remote_user]
2413 setup do: clear_config([:instance, :limit_to_local_content])
2415 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2416 remote_user: remote_user
2418 clear_config([:instance, :limit_to_local_content], false)
2419 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2421 clear_config([:instance, :limit_to_local_content], true)
2422 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2424 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2425 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2428 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2429 %{remote_user: remote_user} do
2430 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2431 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2434 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2435 %{remote_user: remote_user, local_user: local_user} do
2436 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2437 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2440 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2441 %{remote_user: remote_user} do
2442 clear_config([:instance, :limit_to_local_content], true)
2443 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2446 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2447 %{local_user: local_user} do
2448 clear_config([:instance, :limit_to_local_content], false)
2449 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2451 clear_config([:instance, :limit_to_local_content], true)
2452 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2454 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2455 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2459 describe "update_email_notifications/2" do
2461 user = insert(:user, email_notifications: %{"digest" => true})
2466 test "Notifications are updated", %{user: user} do
2467 true = user.email_notifications["digest"]
2468 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2469 assert result.email_notifications["digest"] == false
2473 describe "local_nickname/1" do
2474 test "returns nickname without host" do
2475 assert User.local_nickname("@mentioned") == "mentioned"
2476 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2477 assert User.local_nickname("nickname@host.com") == "nickname"
2481 describe "full_nickname/1" do
2482 test "returns fully qualified nickname for local and remote users" do
2484 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2486 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2488 assert User.full_nickname(local_user) == "local_user@somehost.com"
2489 assert User.full_nickname(remote_user) == "remote@host.com"
2492 test "strips leading @ from mentions" do
2493 assert User.full_nickname("@mentioned") == "mentioned"
2494 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2497 test "does not modify nicknames" do
2498 assert User.full_nickname("nickname") == "nickname"
2499 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2503 test "avatar fallback" do
2504 user = insert(:user)
2505 assert User.avatar_url(user) =~ "/images/avi.png"
2507 clear_config([:assets, :default_user_avatar], "avatar.png")
2509 user = User.get_cached_by_nickname_or_id(user.nickname)
2510 assert User.avatar_url(user) =~ "avatar.png"
2512 assert User.avatar_url(user, no_default: true) == nil
2515 test "get_host/1" do
2516 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2517 assert User.get_host(user) == "lain.com"
2520 test "update_last_active_at/1" do
2521 user = insert(:user)
2522 assert is_nil(user.last_active_at)
2524 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2526 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 NaiveDateTime.utc_now()
2533 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2534 |> NaiveDateTime.truncate(:second)
2536 assert {:ok, user} =
2538 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2539 |> User.update_and_set_cache()
2541 assert user.last_active_at == last_active_at
2542 assert {:ok, user} = User.update_last_active_at(user)
2543 assert user.last_active_at >= test_started_at
2544 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2547 test "active_user_count/1" do
2549 insert(:user, %{local: false})
2550 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2551 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2552 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2553 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2554 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2556 assert User.active_user_count() == 2
2557 assert User.active_user_count(180) == 3
2558 assert User.active_user_count(365) == 4
2559 assert User.active_user_count(1000) == 5
2564 user = insert(:user)
2566 [user: user, object_id: object_id_from_created_activity(user)]
2569 test "unique pins", %{user: user, object_id: object_id} do
2570 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2571 User.add_pinned_object_id(user, object_id)
2573 assert Enum.count(pins) == 1
2575 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2576 User.add_pinned_object_id(updated_user, object_id)
2578 assert pinned_at1 == pinned_at2
2580 assert Enum.count(pins) == 1
2583 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2584 clear_config([:instance, :max_pinned_statuses], 1)
2585 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2587 object_id2 = object_id_from_created_activity(user)
2589 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2590 assert Keyword.has_key?(errors, :pinned_objects)
2593 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2594 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2596 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2597 assert after_remove.pinned_objects == %{}
2601 defp object_id_from_created_activity(user) do
2602 %{id: id} = insert(:note_activity, user: user)
2603 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2607 describe "add_alias/2" do
2608 test "should add alias for another user" do
2609 user = insert(:user)
2610 user2 = insert(:user)
2612 assert {:ok, user_updated} = user |> User.add_alias(user2)
2614 assert user_updated.also_known_as |> length() == 1
2615 assert user2.ap_id in user_updated.also_known_as
2618 test "should add multiple aliases" do
2619 user = insert(:user)
2620 user2 = insert(:user)
2621 user3 = insert(:user)
2623 assert {:ok, user} = user |> User.add_alias(user2)
2624 assert {:ok, user_updated} = user |> User.add_alias(user3)
2626 assert user_updated.also_known_as |> length() == 2
2627 assert user2.ap_id in user_updated.also_known_as
2628 assert user3.ap_id in user_updated.also_known_as
2631 test "should not add duplicate aliases" do
2632 user = insert(:user)
2633 user2 = insert(:user)
2635 assert {:ok, user} = user |> User.add_alias(user2)
2637 assert {:ok, user_updated} = user |> User.add_alias(user2)
2639 assert user_updated.also_known_as |> length() == 1
2640 assert user2.ap_id in user_updated.also_known_as
2644 describe "alias_users/1" do
2645 test "should get aliases for a user" do
2646 user = insert(:user)
2647 user2 = insert(:user, also_known_as: [user.ap_id])
2649 aliases = user2 |> User.alias_users()
2651 assert aliases |> length() == 1
2653 alias_user = aliases |> Enum.at(0)
2655 assert alias_user.ap_id == user.ap_id
2659 describe "delete_alias/2" do
2660 test "should delete existing alias" do
2661 user = insert(:user)
2662 user2 = insert(:user, also_known_as: [user.ap_id])
2664 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2666 assert user_updated.also_known_as == []
2669 test "should report error on non-existing alias" do
2670 user = insert(:user)
2671 user2 = insert(:user)
2672 user3 = insert(:user, also_known_as: [user.ap_id])
2674 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2676 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2678 assert user3_updated.also_known_as |> length() == 1
2679 assert user.ap_id in user3_updated.also_known_as