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, ap_id, private key and followers collection address" do
624 changeset = User.register_changeset(%User{}, @full_user_data)
626 assert changeset.valid?
628 assert is_binary(changeset.changes[:password_hash])
629 assert is_binary(changeset.changes[:keys])
630 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
631 assert is_binary(changeset.changes[:keys])
632 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
635 test "it creates a confirmed user" do
636 changeset = User.register_changeset(%User{}, @full_user_data)
637 assert changeset.valid?
639 {:ok, user} = Repo.insert(changeset)
641 assert user.is_confirmed
645 describe "user registration, with :account_activation_required" do
651 password_confirmation: "test",
652 email: "email@example.com"
654 setup do: clear_config([:instance, :account_activation_required], true)
656 test "it creates unconfirmed user" do
657 changeset = User.register_changeset(%User{}, @full_user_data)
658 assert changeset.valid?
660 {:ok, user} = Repo.insert(changeset)
662 refute user.is_confirmed
663 assert user.confirmation_token
666 test "it creates confirmed user if :confirmed option is given" do
667 changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
668 assert changeset.valid?
670 {:ok, user} = Repo.insert(changeset)
672 assert user.is_confirmed
673 refute user.confirmation_token
677 describe "user registration, with :account_approval_required" do
683 password_confirmation: "test",
684 email: "email@example.com",
685 registration_reason: "I'm a cool guy :)"
687 setup do: clear_config([:instance, :account_approval_required], true)
689 test "it creates unapproved user" do
690 changeset = User.register_changeset(%User{}, @full_user_data)
691 assert changeset.valid?
693 {:ok, user} = Repo.insert(changeset)
695 refute user.is_approved
696 assert user.registration_reason == "I'm a cool guy :)"
699 test "it restricts length of registration reason" do
700 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
702 assert is_integer(reason_limit)
707 :registration_reason,
708 "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."
711 changeset = User.register_changeset(%User{}, params)
713 refute changeset.valid?
717 describe "get_or_fetch/1" do
718 test "gets an existing user by nickname" do
720 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
722 assert user == fetched_user
725 test "gets an existing user by ap_id" do
726 ap_id = "http://mastodon.example.org/users/admin"
732 nickname: "admin@mastodon.example.org",
736 {:ok, fetched_user} = User.get_or_fetch(ap_id)
737 freshed_user = refresh_record(user)
738 assert freshed_user == fetched_user
742 describe "get_or_fetch/1 remote users with tld, while BE is runned on subdomain" do
743 setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
745 test "for mastodon" do
747 %{url: "https://example.com/.well-known/host-meta"} ->
750 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
753 %{url: "https://sub.example.com/.well-known/host-meta"} ->
757 "test/fixtures/webfinger/masto-host-meta.xml"
759 |> String.replace("{{domain}}", "sub.example.com")
762 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
766 "test/fixtures/webfinger/masto-webfinger.json"
768 |> String.replace("{{nickname}}", "a")
769 |> String.replace("{{domain}}", "example.com")
770 |> String.replace("{{subdomain}}", "sub.example.com"),
771 headers: [{"content-type", "application/jrd+json"}]
774 %{url: "https://sub.example.com/users/a"} ->
778 "test/fixtures/webfinger/masto-user.json"
780 |> String.replace("{{nickname}}", "a")
781 |> String.replace("{{domain}}", "sub.example.com"),
782 headers: [{"content-type", "application/activity+json"}]
785 %{url: "https://sub.example.com/users/a/collections/featured"} ->
789 File.read!("test/fixtures/users_mock/masto_featured.json")
790 |> String.replace("{{domain}}", "sub.example.com")
791 |> String.replace("{{nickname}}", "a"),
792 headers: [{"content-type", "application/activity+json"}]
796 ap_id = "a@example.com"
797 {:ok, fetched_user} = User.get_or_fetch(ap_id)
799 assert fetched_user.ap_id == "https://sub.example.com/users/a"
800 assert fetched_user.nickname == "a@example.com"
803 test "for pleroma" do
805 %{url: "https://example.com/.well-known/host-meta"} ->
808 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
811 %{url: "https://sub.example.com/.well-known/host-meta"} ->
815 "test/fixtures/webfinger/pleroma-host-meta.xml"
817 |> String.replace("{{domain}}", "sub.example.com")
820 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
824 "test/fixtures/webfinger/pleroma-webfinger.json"
826 |> String.replace("{{nickname}}", "a")
827 |> String.replace("{{domain}}", "example.com")
828 |> String.replace("{{subdomain}}", "sub.example.com"),
829 headers: [{"content-type", "application/jrd+json"}]
832 %{url: "https://sub.example.com/users/a"} ->
836 "test/fixtures/webfinger/pleroma-user.json"
838 |> String.replace("{{nickname}}", "a")
839 |> String.replace("{{domain}}", "sub.example.com"),
840 headers: [{"content-type", "application/activity+json"}]
844 ap_id = "a@example.com"
845 {:ok, fetched_user} = User.get_or_fetch(ap_id)
847 assert fetched_user.ap_id == "https://sub.example.com/users/a"
848 assert fetched_user.nickname == "a@example.com"
852 describe "fetching a user from nickname or trying to build one" do
853 test "gets an existing user" do
855 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
857 assert user == fetched_user
860 test "gets an existing user, case insensitive" do
861 user = insert(:user, nickname: "nick")
862 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
864 assert user == fetched_user
867 test "gets an existing user by fully qualified nickname" do
870 {:ok, fetched_user} =
871 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
873 assert user == fetched_user
876 test "gets an existing user by fully qualified nickname, case insensitive" do
877 user = insert(:user, nickname: "nick")
878 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
880 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
882 assert user == fetched_user
885 @tag capture_log: true
886 test "returns nil if no user could be fetched" do
887 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
888 assert fetched_user == "not found nonexistant@social.heldscal.la"
891 test "returns nil for nonexistant local user" do
892 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
893 assert fetched_user == "not found nonexistant"
896 test "updates an existing user, if stale" do
897 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
903 nickname: "admin@mastodon.example.org",
904 ap_id: "http://mastodon.example.org/users/admin",
905 last_refreshed_at: a_week_ago
908 assert orig_user.last_refreshed_at == a_week_ago
910 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
914 refute user.last_refreshed_at == orig_user.last_refreshed_at
917 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
918 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
924 nickname: "admin@mastodon.example.org",
925 ap_id: "http://mastodon.example.org/users/harinezumigari",
926 last_refreshed_at: a_week_ago
929 assert orig_user.last_refreshed_at == a_week_ago
931 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
935 refute user.id == orig_user.id
937 orig_user = User.get_by_id(orig_user.id)
939 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
942 @tag capture_log: true
943 test "it returns the old user if stale, but unfetchable" do
944 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
950 nickname: "admin@mastodon.example.org",
951 ap_id: "http://mastodon.example.org/users/raymoo",
952 last_refreshed_at: a_week_ago
955 assert orig_user.last_refreshed_at == a_week_ago
957 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
959 assert user.last_refreshed_at == orig_user.last_refreshed_at
963 test "returns an ap_id for a user" do
966 assert User.ap_id(user) ==
967 Pleroma.Web.Router.Helpers.user_feed_url(
968 Pleroma.Web.Endpoint,
974 test "returns an ap_followers link for a user" do
977 assert User.ap_followers(user) ==
978 Pleroma.Web.Router.Helpers.user_feed_url(
979 Pleroma.Web.Endpoint,
985 describe "remote user changeset" do
991 avatar: %{some: "avatar"}
993 setup do: clear_config([:instance, :user_bio_length])
994 setup do: clear_config([:instance, :user_name_length])
996 test "it confirms validity" do
997 cs = User.remote_user_changeset(@valid_remote)
1001 test "it sets the follower_adress" do
1002 cs = User.remote_user_changeset(@valid_remote)
1003 # remote users get a fake local follower address
1004 assert cs.changes.follower_address ==
1005 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
1008 test "it enforces the fqn format for nicknames" do
1009 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
1010 assert Ecto.Changeset.get_field(cs, :local) == false
1011 assert cs.changes.avatar
1015 test "it has required fields" do
1017 |> Enum.each(fn field ->
1018 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
1023 test "it is invalid given a local user" do
1024 user = insert(:user)
1025 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
1031 describe "followers and friends" do
1032 test "gets all followers for a given user" do
1033 user = insert(:user)
1034 follower_one = insert(:user)
1035 follower_two = insert(:user)
1036 not_follower = insert(:user)
1038 {:ok, follower_one, user} = User.follow(follower_one, user)
1039 {:ok, follower_two, user} = User.follow(follower_two, user)
1041 res = User.get_followers(user)
1043 assert Enum.member?(res, follower_one)
1044 assert Enum.member?(res, follower_two)
1045 refute Enum.member?(res, not_follower)
1048 test "gets all friends (followed users) for a given user" do
1049 user = insert(:user)
1050 followed_one = insert(:user)
1051 followed_two = insert(:user)
1052 not_followed = insert(:user)
1054 {:ok, user, followed_one} = User.follow(user, followed_one)
1055 {:ok, user, followed_two} = User.follow(user, followed_two)
1057 res = User.get_friends(user)
1059 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
1060 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
1061 assert Enum.member?(res, followed_one)
1062 assert Enum.member?(res, followed_two)
1063 refute Enum.member?(res, not_followed)
1067 describe "updating note and follower count" do
1068 test "it sets the note_count property" do
1069 note = insert(:note)
1071 user = User.get_cached_by_ap_id(note.data["actor"])
1073 assert user.note_count == 0
1075 {:ok, user} = User.update_note_count(user)
1077 assert user.note_count == 1
1080 test "it increases the note_count property" do
1081 note = insert(:note)
1082 user = User.get_cached_by_ap_id(note.data["actor"])
1084 assert user.note_count == 0
1086 {:ok, user} = User.increase_note_count(user)
1088 assert user.note_count == 1
1090 {:ok, user} = User.increase_note_count(user)
1092 assert user.note_count == 2
1095 test "it decreases the note_count property" do
1096 note = insert(:note)
1097 user = User.get_cached_by_ap_id(note.data["actor"])
1099 assert user.note_count == 0
1101 {:ok, user} = User.increase_note_count(user)
1103 assert user.note_count == 1
1105 {:ok, user} = User.decrease_note_count(user)
1107 assert user.note_count == 0
1109 {:ok, user} = User.decrease_note_count(user)
1111 assert user.note_count == 0
1114 test "it sets the follower_count property" do
1115 user = insert(:user)
1116 follower = insert(:user)
1118 User.follow(follower, user)
1120 assert user.follower_count == 0
1122 {:ok, user} = User.update_follower_count(user)
1124 assert user.follower_count == 1
1129 test "it mutes people" do
1130 user = insert(:user)
1131 muted_user = insert(:user)
1133 refute User.mutes?(user, muted_user)
1134 refute User.muted_notifications?(user, muted_user)
1136 {:ok, _user_relationships} = User.mute(user, muted_user)
1138 assert User.mutes?(user, muted_user)
1139 assert User.muted_notifications?(user, muted_user)
1143 user = insert(:user)
1144 muted_user = insert(:user)
1146 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1147 assert User.mutes?(user, muted_user)
1149 worker = Pleroma.Workers.MuteExpireWorker
1150 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1157 assert :ok = perform_job(worker, args)
1159 refute User.mutes?(user, muted_user)
1160 refute User.muted_notifications?(user, muted_user)
1163 test "it unmutes users" do
1164 user = insert(:user)
1165 muted_user = insert(:user)
1167 {:ok, _user_relationships} = User.mute(user, muted_user)
1168 {:ok, _user_mute} = User.unmute(user, muted_user)
1170 refute User.mutes?(user, muted_user)
1171 refute User.muted_notifications?(user, muted_user)
1174 test "it unmutes users by id" do
1175 user = insert(:user)
1176 muted_user = insert(:user)
1178 {:ok, _user_relationships} = User.mute(user, muted_user)
1179 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1181 refute User.mutes?(user, muted_user)
1182 refute User.muted_notifications?(user, muted_user)
1185 test "it mutes user without notifications" do
1186 user = insert(:user)
1187 muted_user = insert(:user)
1189 refute User.mutes?(user, muted_user)
1190 refute User.muted_notifications?(user, muted_user)
1192 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1194 assert User.mutes?(user, muted_user)
1195 refute User.muted_notifications?(user, muted_user)
1199 describe "blocks" do
1200 test "it blocks people" do
1201 user = insert(:user)
1202 blocked_user = insert(:user)
1204 refute User.blocks?(user, blocked_user)
1206 {:ok, _user_relationship} = User.block(user, blocked_user)
1208 assert User.blocks?(user, blocked_user)
1211 test "it unblocks users" do
1212 user = insert(:user)
1213 blocked_user = insert(:user)
1215 {:ok, _user_relationship} = User.block(user, blocked_user)
1216 {:ok, _user_block} = User.unblock(user, blocked_user)
1218 refute User.blocks?(user, blocked_user)
1221 test "blocks tear down cyclical follow relationships" do
1222 blocker = insert(:user)
1223 blocked = insert(:user)
1225 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1226 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1228 assert User.following?(blocker, blocked)
1229 assert User.following?(blocked, blocker)
1231 {:ok, _user_relationship} = User.block(blocker, blocked)
1232 blocked = User.get_cached_by_id(blocked.id)
1234 assert User.blocks?(blocker, blocked)
1236 refute User.following?(blocker, blocked)
1237 refute User.following?(blocked, blocker)
1240 test "blocks tear down blocker->blocked follow relationships" do
1241 blocker = insert(:user)
1242 blocked = insert(:user)
1244 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1246 assert User.following?(blocker, blocked)
1247 refute User.following?(blocked, blocker)
1249 {:ok, _user_relationship} = User.block(blocker, blocked)
1250 blocked = User.get_cached_by_id(blocked.id)
1252 assert User.blocks?(blocker, blocked)
1254 refute User.following?(blocker, blocked)
1255 refute User.following?(blocked, blocker)
1258 test "blocks tear down blocked->blocker follow relationships" do
1259 blocker = insert(:user)
1260 blocked = insert(:user)
1262 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1264 refute User.following?(blocker, blocked)
1265 assert User.following?(blocked, blocker)
1267 {:ok, _user_relationship} = User.block(blocker, blocked)
1268 blocked = User.get_cached_by_id(blocked.id)
1270 assert User.blocks?(blocker, blocked)
1272 refute User.following?(blocker, blocked)
1273 refute User.following?(blocked, blocker)
1276 test "blocks tear down blocked->blocker subscription relationships" do
1277 blocker = insert(:user)
1278 blocked = insert(:user)
1280 {:ok, _subscription} = User.subscribe(blocked, blocker)
1282 assert User.subscribed_to?(blocked, blocker)
1283 refute User.subscribed_to?(blocker, blocked)
1285 {:ok, _user_relationship} = User.block(blocker, blocked)
1287 assert User.blocks?(blocker, blocked)
1288 refute User.subscribed_to?(blocker, blocked)
1289 refute User.subscribed_to?(blocked, blocker)
1293 describe "domain blocking" do
1294 test "blocks domains" do
1295 user = insert(:user)
1296 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1298 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1300 assert User.blocks?(user, collateral_user)
1303 test "does not block domain with same end" do
1304 user = insert(:user)
1307 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1309 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1311 refute User.blocks?(user, collateral_user)
1314 test "does not block domain with same end if wildcard added" do
1315 user = insert(:user)
1318 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1320 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1322 refute User.blocks?(user, collateral_user)
1325 test "blocks domain with wildcard for subdomain" do
1326 user = insert(:user)
1328 user_from_subdomain =
1329 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1331 user_with_two_subdomains =
1333 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1336 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1338 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1340 assert User.blocks?(user, user_from_subdomain)
1341 assert User.blocks?(user, user_with_two_subdomains)
1342 assert User.blocks?(user, user_domain)
1345 test "unblocks domains" do
1346 user = insert(:user)
1347 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1349 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1350 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1352 refute User.blocks?(user, collateral_user)
1355 test "follows take precedence over domain blocks" do
1356 user = insert(:user)
1357 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1359 {:ok, user} = User.block_domain(user, "meanies.social")
1360 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1362 refute User.blocks?(user, good_eggo)
1366 describe "get_recipients_from_activity" do
1367 test "works for announces" do
1368 actor = insert(:user)
1369 user = insert(:user, local: true)
1371 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1372 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1374 recipients = User.get_recipients_from_activity(announce)
1376 assert user in recipients
1379 test "get recipients" do
1380 actor = insert(:user)
1381 user = insert(:user, local: true)
1382 user_two = insert(:user, local: false)
1383 addressed = insert(:user, local: true)
1384 addressed_remote = insert(:user, local: false)
1387 CommonAPI.post(actor, %{
1388 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1391 assert Enum.map([actor, addressed], & &1.ap_id) --
1392 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1394 {:ok, user, actor} = User.follow(user, actor)
1395 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1396 recipients = User.get_recipients_from_activity(activity)
1397 assert length(recipients) == 3
1398 assert user in recipients
1399 assert addressed in recipients
1402 test "has following" do
1403 actor = insert(:user)
1404 user = insert(:user)
1405 user_two = insert(:user)
1406 addressed = insert(:user, local: true)
1409 CommonAPI.post(actor, %{
1410 status: "hey @#{addressed.nickname}"
1413 assert Enum.map([actor, addressed], & &1.ap_id) --
1414 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1416 {:ok, _actor, _user} = User.follow(actor, user)
1417 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1418 recipients = User.get_recipients_from_activity(activity)
1419 assert length(recipients) == 2
1420 assert addressed in recipients
1424 describe ".set_activation" do
1425 test "can de-activate then re-activate a user" do
1426 user = insert(:user)
1427 assert user.is_active
1428 {:ok, user} = User.set_activation(user, false)
1429 refute user.is_active
1430 {:ok, user} = User.set_activation(user, true)
1431 assert user.is_active
1434 test "hide a user from followers" do
1435 user = insert(:user)
1436 user2 = insert(:user)
1438 {:ok, user, user2} = User.follow(user, user2)
1439 {:ok, _user} = User.set_activation(user, false)
1441 user2 = User.get_cached_by_id(user2.id)
1443 assert user2.follower_count == 0
1444 assert [] = User.get_followers(user2)
1447 test "hide a user from friends" do
1448 user = insert(:user)
1449 user2 = insert(:user)
1451 {:ok, user2, user} = User.follow(user2, user)
1452 assert user2.following_count == 1
1453 assert User.following_count(user2) == 1
1455 {:ok, _user} = User.set_activation(user, false)
1457 user2 = User.get_cached_by_id(user2.id)
1459 assert refresh_record(user2).following_count == 0
1460 assert user2.following_count == 0
1461 assert User.following_count(user2) == 0
1462 assert [] = User.get_friends(user2)
1465 test "hide a user's statuses from timelines and notifications" do
1466 user = insert(:user)
1467 user2 = insert(:user)
1469 {:ok, user2, user} = User.follow(user2, user)
1471 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1473 activity = Repo.preload(activity, :bookmark)
1475 [notification] = Pleroma.Notification.for_user(user2)
1476 assert notification.activity.id == activity.id
1478 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1480 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1481 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1485 {:ok, _user} = User.set_activation(user, false)
1487 assert [] == ActivityPub.fetch_public_activities(%{})
1488 assert [] == Pleroma.Notification.for_user(user2)
1491 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1497 describe "approve" do
1498 test "approves a user" do
1499 user = insert(:user, is_approved: false)
1500 refute user.is_approved
1501 {:ok, user} = User.approve(user)
1502 assert user.is_approved
1505 test "approves a list of users" do
1506 unapproved_users = [
1507 insert(:user, is_approved: false),
1508 insert(:user, is_approved: false),
1509 insert(:user, is_approved: false)
1512 {:ok, users} = User.approve(unapproved_users)
1514 assert Enum.count(users) == 3
1516 Enum.each(users, fn user ->
1517 assert user.is_approved
1521 test "it sends welcome email if it is set" do
1522 clear_config([:welcome, :email, :enabled], true)
1523 clear_config([:welcome, :email, :sender], "tester@test.me")
1525 user = insert(:user, is_approved: false)
1526 welcome_user = insert(:user, email: "tester@test.me")
1527 instance_name = Pleroma.Config.get([:instance, :name])
1531 ObanHelpers.perform_all()
1534 from: {instance_name, welcome_user.email},
1535 to: {user.name, user.email},
1536 html_body: "Welcome to #{instance_name}"
1540 test "approving an approved user does not trigger post-register actions" do
1541 clear_config([:welcome, :email, :enabled], true)
1543 user = insert(:user, is_approved: true)
1546 ObanHelpers.perform_all()
1548 assert_no_email_sent()
1552 describe "confirm" do
1553 test "confirms a user" do
1554 user = insert(:user, is_confirmed: false)
1555 refute user.is_confirmed
1556 {:ok, user} = User.confirm(user)
1557 assert user.is_confirmed
1560 test "confirms a list of users" do
1561 unconfirmed_users = [
1562 insert(:user, is_confirmed: false),
1563 insert(:user, is_confirmed: false),
1564 insert(:user, is_confirmed: false)
1567 {:ok, users} = User.confirm(unconfirmed_users)
1569 assert Enum.count(users) == 3
1571 Enum.each(users, fn user ->
1572 assert user.is_confirmed
1576 test "sends approval emails when `is_approved: false`" do
1577 admin = insert(:user, is_admin: true)
1578 user = insert(:user, is_confirmed: false, is_approved: false)
1581 ObanHelpers.perform_all()
1583 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1584 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1586 notify_email = Pleroma.Config.get([:instance, :notify_email])
1587 instance_name = Pleroma.Config.get([:instance, :name])
1589 # User approval email
1591 from: {instance_name, notify_email},
1592 to: {user.name, user.email},
1593 html_body: user_email.html_body
1598 from: {instance_name, notify_email},
1599 to: {admin.name, admin.email},
1600 html_body: admin_email.html_body
1604 test "confirming a confirmed user does not trigger post-register actions" do
1605 user = insert(:user, is_confirmed: true, is_approved: false)
1608 ObanHelpers.perform_all()
1610 assert_no_email_sent()
1614 describe "delete" do
1616 {:ok, user} = insert(:user) |> User.set_cache()
1621 setup do: clear_config([:instance, :federating])
1623 test ".delete_user_activities deletes all create activities", %{user: user} do
1624 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1626 User.delete_user_activities(user)
1628 # TODO: Test removal favorites, repeats, delete activities.
1629 refute Activity.get_by_id(activity.id)
1632 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1633 follower = insert(:user)
1634 {:ok, follower, user} = User.follow(follower, user)
1636 locked_user = insert(:user, name: "locked", is_locked: true)
1637 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1639 object = insert(:note, user: user)
1640 activity = insert(:note_activity, user: user, note: object)
1642 object_two = insert(:note, user: follower)
1643 activity_two = insert(:note_activity, user: follower, note: object_two)
1645 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1646 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1647 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1649 {:ok, job} = User.delete(user)
1650 {:ok, _user} = ObanHelpers.perform(job)
1652 follower = User.get_cached_by_id(follower.id)
1654 refute User.following?(follower, user)
1655 assert %{is_active: false} = User.get_by_id(user.id)
1657 assert [] == User.get_follow_requests(locked_user)
1661 |> Activity.Queries.by_actor()
1663 |> Enum.map(fn act -> act.data["type"] end)
1665 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1667 refute Activity.get_by_id(activity.id)
1668 refute Activity.get_by_id(like.id)
1669 refute Activity.get_by_id(like_two.id)
1670 refute Activity.get_by_id(repeat.id)
1674 test "delete/1 when confirmation is pending deletes the user" do
1675 clear_config([:instance, :account_activation_required], true)
1676 user = insert(:user, is_confirmed: false)
1678 {:ok, job} = User.delete(user)
1679 {:ok, _} = ObanHelpers.perform(job)
1681 refute User.get_cached_by_id(user.id)
1682 refute User.get_by_id(user.id)
1685 test "delete/1 when approval is pending deletes the user" do
1686 user = insert(:user, is_approved: false)
1688 {:ok, job} = User.delete(user)
1689 {:ok, _} = ObanHelpers.perform(job)
1691 refute User.get_cached_by_id(user.id)
1692 refute User.get_by_id(user.id)
1695 test "delete/1 purges a user when they wouldn't be fully deleted" do
1700 password_hash: "pdfk2$1b3n159001",
1701 keys: "RSA begin buplic key",
1702 public_key: "--PRIVATE KEYE--",
1703 avatar: %{"a" => "b"},
1705 banner: %{"a" => "b"},
1706 background: %{"a" => "b"},
1709 following_count: 9001,
1712 password_reset_pending: true,
1714 registration_reason: "ahhhhh",
1715 confirmation_token: "qqqq",
1716 domain_blocks: ["lain.com"],
1721 mastofe_settings: %{"a" => "b"},
1722 mascot: %{"a" => "b"},
1723 emoji: %{"a" => "b"},
1724 pleroma_settings_store: %{"q" => "x"},
1725 fields: [%{"gg" => "qq"}],
1726 raw_fields: [%{"gg" => "qq"}],
1727 is_discoverable: true,
1728 also_known_as: ["https://lol.olo/users/loll"]
1731 {:ok, job} = User.delete(user)
1732 {:ok, _} = ObanHelpers.perform(job)
1733 user = User.get_by_id(user.id)
1741 keys: "RSA begin buplic key",
1742 public_key: "--PRIVATE KEYE--",
1745 last_refreshed_at: nil,
1746 last_digest_emailed_at: nil,
1754 password_reset_pending: false,
1756 registration_reason: nil,
1757 confirmation_token: nil,
1761 is_moderator: false,
1763 mastofe_settings: nil,
1766 pleroma_settings_store: %{},
1769 is_discoverable: false,
1774 test "delete/1 purges a remote user" do
1778 avatar: %{"a" => "b"},
1779 banner: %{"a" => "b"},
1783 {:ok, job} = User.delete(user)
1784 {:ok, _} = ObanHelpers.perform(job)
1785 user = User.get_by_id(user.id)
1787 assert user.name == nil
1788 assert user.avatar == %{}
1789 assert user.banner == %{}
1792 describe "set_suggestion" do
1793 test "suggests a user" do
1794 user = insert(:user, is_suggested: false)
1795 refute user.is_suggested
1796 {:ok, user} = User.set_suggestion(user, true)
1797 assert user.is_suggested
1800 test "suggests a list of users" do
1801 unsuggested_users = [
1802 insert(:user, is_suggested: false),
1803 insert(:user, is_suggested: false),
1804 insert(:user, is_suggested: false)
1807 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1809 assert Enum.count(users) == 3
1811 Enum.each(users, fn user ->
1812 assert user.is_suggested
1816 test "unsuggests a user" do
1817 user = insert(:user, is_suggested: true)
1818 assert user.is_suggested
1819 {:ok, user} = User.set_suggestion(user, false)
1820 refute user.is_suggested
1824 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1825 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1828 describe "per-user rich-text filtering" do
1829 test "html_filter_policy returns default policies, when rich-text is enabled" do
1830 user = insert(:user)
1832 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1835 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1836 user = insert(:user, no_rich_text: true)
1838 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1842 describe "caching" do
1843 test "invalidate_cache works" do
1844 user = insert(:user)
1846 User.set_cache(user)
1847 User.invalidate_cache(user)
1849 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1850 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1853 test "User.delete() plugs any possible zombie objects" do
1854 user = insert(:user)
1856 {:ok, job} = User.delete(user)
1857 {:ok, _} = ObanHelpers.perform(job)
1859 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1861 assert cached_user != user
1863 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1865 assert cached_user != user
1869 describe "account_status/1" do
1870 setup do: clear_config([:instance, :account_activation_required])
1872 test "return confirmation_pending for unconfirm user" do
1873 clear_config([:instance, :account_activation_required], true)
1874 user = insert(:user, is_confirmed: false)
1875 assert User.account_status(user) == :confirmation_pending
1878 test "return active for confirmed user" do
1879 clear_config([:instance, :account_activation_required], true)
1880 user = insert(:user, is_confirmed: true)
1881 assert User.account_status(user) == :active
1884 test "return active for remote user" do
1885 user = insert(:user, local: false)
1886 assert User.account_status(user) == :active
1889 test "returns :password_reset_pending for user with reset password" do
1890 user = insert(:user, password_reset_pending: true)
1891 assert User.account_status(user) == :password_reset_pending
1894 test "returns :deactivated for deactivated user" do
1895 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1896 assert User.account_status(user) == :deactivated
1899 test "returns :approval_pending for unapproved user" do
1900 user = insert(:user, local: true, is_approved: false)
1901 assert User.account_status(user) == :approval_pending
1903 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1904 assert User.account_status(user) == :approval_pending
1908 describe "superuser?/1" do
1909 test "returns false for unprivileged users" do
1910 user = insert(:user, local: true)
1912 refute User.superuser?(user)
1915 test "returns false for remote users" do
1916 user = insert(:user, local: false)
1917 remote_admin_user = insert(:user, local: false, is_admin: true)
1919 refute User.superuser?(user)
1920 refute User.superuser?(remote_admin_user)
1923 test "returns true for local moderators" do
1924 user = insert(:user, local: true, is_moderator: true)
1926 assert User.superuser?(user)
1929 test "returns true for local admins" do
1930 user = insert(:user, local: true, is_admin: true)
1932 assert User.superuser?(user)
1936 describe "invisible?/1" do
1937 test "returns true for an invisible user" do
1938 user = insert(:user, local: true, invisible: true)
1940 assert User.invisible?(user)
1943 test "returns false for a non-invisible user" do
1944 user = insert(:user, local: true)
1946 refute User.invisible?(user)
1950 describe "visible_for/2" do
1951 test "returns true when the account is itself" do
1952 user = insert(:user, local: true)
1954 assert User.visible_for(user, user) == :visible
1957 test "returns false when the account is unconfirmed and confirmation is required" do
1958 clear_config([:instance, :account_activation_required], true)
1960 user = insert(:user, local: true, is_confirmed: false)
1961 other_user = insert(:user, local: true)
1963 refute User.visible_for(user, other_user) == :visible
1966 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1967 clear_config([:instance, :account_activation_required], true)
1969 user = insert(:user, local: false, is_confirmed: false)
1970 other_user = insert(:user, local: true)
1972 assert User.visible_for(user, other_user) == :visible
1975 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1976 clear_config([:instance, :account_activation_required], true)
1978 user = insert(:user, local: true, is_confirmed: false)
1979 other_user = insert(:user, local: true, is_admin: true)
1981 assert User.visible_for(user, other_user) == :visible
1985 describe "parse_bio/2" do
1986 test "preserves hosts in user links text" do
1987 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1988 user = insert(:user)
1989 bio = "A.k.a. @nick@domain.com"
1992 ~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>)
1994 assert expected_text == User.parse_bio(bio, user)
1997 test "Adds rel=me on linkbacked urls" do
1998 user = insert(:user, ap_id: "https://social.example.org/users/lain")
2000 bio = "http://example.com/rel_me/null"
2001 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
2002 assert expected_text == User.parse_bio(bio, user)
2004 bio = "http://example.com/rel_me/link"
2005 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2006 assert expected_text == User.parse_bio(bio, user)
2008 bio = "http://example.com/rel_me/anchor"
2009 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2010 assert expected_text == User.parse_bio(bio, user)
2014 test "follower count is updated when a follower is blocked" do
2015 user = insert(:user)
2016 follower = insert(:user)
2017 follower2 = insert(:user)
2018 follower3 = insert(:user)
2020 {:ok, follower, user} = User.follow(follower, user)
2021 {:ok, _follower2, _user} = User.follow(follower2, user)
2022 {:ok, _follower3, _user} = User.follow(follower3, user)
2024 {:ok, _user_relationship} = User.block(user, follower)
2025 user = refresh_record(user)
2027 assert user.follower_count == 2
2030 describe "list_inactive_users_query/1" do
2031 defp days_ago(days) do
2033 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
2034 -days * 60 * 60 * 24,
2039 test "Users are inactive by default" do
2043 Enum.map(1..total, fn _ ->
2044 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2047 inactive_users_ids =
2048 Pleroma.User.list_inactive_users_query()
2049 |> Pleroma.Repo.all()
2050 |> Enum.map(& &1.id)
2052 Enum.each(users, fn user ->
2053 assert user.id in inactive_users_ids
2057 test "Only includes users who has no recent activity" do
2061 Enum.map(1..total, fn _ ->
2062 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2065 {inactive, active} = Enum.split(users, trunc(total / 2))
2067 Enum.map(active, fn user ->
2068 to = Enum.random(users -- [user])
2071 CommonAPI.post(user, %{
2072 status: "hey @#{to.nickname}"
2076 inactive_users_ids =
2077 Pleroma.User.list_inactive_users_query()
2078 |> Pleroma.Repo.all()
2079 |> Enum.map(& &1.id)
2081 Enum.each(active, fn user ->
2082 refute user.id in inactive_users_ids
2085 Enum.each(inactive, fn user ->
2086 assert user.id in inactive_users_ids
2090 test "Only includes users with no read notifications" do
2094 Enum.map(1..total, fn _ ->
2095 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2098 [sender | recipients] = users
2099 {inactive, active} = Enum.split(recipients, trunc(total / 2))
2101 Enum.each(recipients, fn to ->
2103 CommonAPI.post(sender, %{
2104 status: "hey @#{to.nickname}"
2108 CommonAPI.post(sender, %{
2109 status: "hey again @#{to.nickname}"
2113 Enum.each(active, fn user ->
2114 [n1, _n2] = Pleroma.Notification.for_user(user)
2115 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2118 inactive_users_ids =
2119 Pleroma.User.list_inactive_users_query()
2120 |> Pleroma.Repo.all()
2121 |> Enum.map(& &1.id)
2123 Enum.each(active, fn user ->
2124 refute user.id in inactive_users_ids
2127 Enum.each(inactive, fn user ->
2128 assert user.id in inactive_users_ids
2133 describe "get_ap_ids_by_nicknames" do
2134 test "it returns a list of AP ids for a given set of nicknames" do
2135 user = insert(:user)
2136 user_two = insert(:user)
2138 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2139 assert length(ap_ids) == 2
2140 assert user.ap_id in ap_ids
2141 assert user_two.ap_id in ap_ids
2145 describe "sync followers count" do
2147 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2148 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2149 insert(:user, local: true)
2150 insert(:user, local: false, is_active: false)
2151 {:ok, user1: user1, user2: user2}
2154 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2155 [fdb_user1] = User.external_users(limit: 1)
2157 assert fdb_user1.ap_id
2158 assert fdb_user1.ap_id == user1.ap_id
2159 assert fdb_user1.id == user1.id
2161 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2163 assert fdb_user2.ap_id
2164 assert fdb_user2.ap_id == user2.ap_id
2165 assert fdb_user2.id == user2.id
2167 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2171 describe "is_internal_user?/1" do
2172 test "non-internal user returns false" do
2173 user = insert(:user)
2174 refute User.is_internal_user?(user)
2177 test "user with no nickname returns true" do
2178 user = insert(:user, %{nickname: nil})
2179 assert User.is_internal_user?(user)
2182 test "user with internal-prefixed nickname returns true" do
2183 user = insert(:user, %{nickname: "internal.test"})
2184 assert User.is_internal_user?(user)
2188 describe "update_and_set_cache/1" do
2189 test "returns error when user is stale instead Ecto.StaleEntryError" do
2190 user = insert(:user)
2192 changeset = Ecto.Changeset.change(user, bio: "test")
2196 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2197 User.update_and_set_cache(changeset)
2200 test "performs update cache if user updated" do
2201 user = insert(:user)
2202 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2204 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2206 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2207 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2208 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2211 test "removes report notifs when user isn't superuser any more" do
2212 report_activity = insert(:report_activity)
2213 user = insert(:user, is_moderator: true, is_admin: true)
2214 {:ok, _} = Notification.create_notifications(report_activity)
2216 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2218 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2219 # is still superuser because still admin
2220 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2222 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false})
2223 # is still superuser because still moderator
2224 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2226 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2227 # is not a superuser any more
2228 assert [] = Notification.for_user(user)
2232 describe "following/followers synchronization" do
2233 setup do: clear_config([:instance, :external_user_synchronization])
2235 test "updates the counters normally on following/getting a follow when disabled" do
2236 clear_config([:instance, :external_user_synchronization], false)
2237 user = insert(:user)
2242 follower_address: "http://localhost:4001/users/masto_closed/followers",
2243 following_address: "http://localhost:4001/users/masto_closed/following",
2247 assert other_user.following_count == 0
2248 assert other_user.follower_count == 0
2250 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2252 assert user.following_count == 1
2253 assert other_user.follower_count == 1
2256 test "syncronizes the counters with the remote instance for the followed when enabled" do
2257 clear_config([:instance, :external_user_synchronization], false)
2259 user = insert(:user)
2264 follower_address: "http://localhost:4001/users/masto_closed/followers",
2265 following_address: "http://localhost:4001/users/masto_closed/following",
2269 assert other_user.following_count == 0
2270 assert other_user.follower_count == 0
2272 clear_config([:instance, :external_user_synchronization], true)
2273 {:ok, _user, other_user} = User.follow(user, other_user)
2275 assert other_user.follower_count == 437
2278 test "syncronizes the counters with the remote instance for the follower when enabled" do
2279 clear_config([:instance, :external_user_synchronization], false)
2281 user = insert(:user)
2286 follower_address: "http://localhost:4001/users/masto_closed/followers",
2287 following_address: "http://localhost:4001/users/masto_closed/following",
2291 assert other_user.following_count == 0
2292 assert other_user.follower_count == 0
2294 clear_config([:instance, :external_user_synchronization], true)
2295 {:ok, other_user, _user} = User.follow(other_user, user)
2297 assert other_user.following_count == 152
2301 describe "change_email/2" do
2303 [user: insert(:user)]
2306 test "blank email returns error if we require an email on registration", %{user: user} do
2307 orig_account_activation_required =
2308 Pleroma.Config.get([:instance, :account_activation_required])
2310 Pleroma.Config.put([:instance, :account_activation_required], true)
2314 [:instance, :account_activation_required],
2315 orig_account_activation_required
2319 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2320 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2323 test "blank email should be fine if we do not require an email on registration", %{user: user} do
2324 orig_account_activation_required =
2325 Pleroma.Config.get([:instance, :account_activation_required])
2327 Pleroma.Config.put([:instance, :account_activation_required], false)
2331 [:instance, :account_activation_required],
2332 orig_account_activation_required
2336 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2337 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2340 test "non unique email returns error", %{user: user} do
2341 %{email: email} = insert(:user)
2343 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2344 User.change_email(user, email)
2347 test "invalid email returns error", %{user: user} do
2348 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2349 User.change_email(user, "cofe")
2352 test "changes email", %{user: user} do
2353 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2356 test "adds email", %{user: user} do
2357 orig_account_activation_required =
2358 Pleroma.Config.get([:instance, :account_activation_required])
2360 Pleroma.Config.put([:instance, :account_activation_required], false)
2364 [:instance, :account_activation_required],
2365 orig_account_activation_required
2369 assert {:ok, _} = User.change_email(user, "")
2370 Pleroma.Config.put([:instance, :account_activation_required], true)
2372 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2376 describe "get_cached_by_nickname_or_id" do
2378 local_user = insert(:user)
2379 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2381 [local_user: local_user, remote_user: remote_user]
2384 setup do: clear_config([:instance, :limit_to_local_content])
2386 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2387 remote_user: remote_user
2389 clear_config([:instance, :limit_to_local_content], false)
2390 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2392 clear_config([:instance, :limit_to_local_content], true)
2393 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2395 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2396 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2399 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2400 %{remote_user: remote_user} do
2401 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2402 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2405 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2406 %{remote_user: remote_user, local_user: local_user} do
2407 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2408 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2411 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2412 %{remote_user: remote_user} do
2413 clear_config([:instance, :limit_to_local_content], true)
2414 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2417 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2418 %{local_user: local_user} do
2419 clear_config([:instance, :limit_to_local_content], false)
2420 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2422 clear_config([:instance, :limit_to_local_content], true)
2423 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2425 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2426 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2430 describe "update_email_notifications/2" do
2432 user = insert(:user, email_notifications: %{"digest" => true})
2437 test "Notifications are updated", %{user: user} do
2438 true = user.email_notifications["digest"]
2439 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2440 assert result.email_notifications["digest"] == false
2444 describe "local_nickname/1" do
2445 test "returns nickname without host" do
2446 assert User.local_nickname("@mentioned") == "mentioned"
2447 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2448 assert User.local_nickname("nickname@host.com") == "nickname"
2452 describe "full_nickname/1" do
2453 test "returns fully qualified nickname for local and remote users" do
2455 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2457 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2459 assert User.full_nickname(local_user) == "local_user@somehost.com"
2460 assert User.full_nickname(remote_user) == "remote@host.com"
2463 test "strips leading @ from mentions" do
2464 assert User.full_nickname("@mentioned") == "mentioned"
2465 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2468 test "does not modify nicknames" do
2469 assert User.full_nickname("nickname") == "nickname"
2470 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2474 test "avatar fallback" do
2475 user = insert(:user)
2476 assert User.avatar_url(user) =~ "/images/avi.png"
2478 clear_config([:assets, :default_user_avatar], "avatar.png")
2480 user = User.get_cached_by_nickname_or_id(user.nickname)
2481 assert User.avatar_url(user) =~ "avatar.png"
2483 assert User.avatar_url(user, no_default: true) == nil
2486 test "get_host/1" do
2487 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2488 assert User.get_host(user) == "lain.com"
2491 test "update_last_active_at/1" do
2492 user = insert(:user)
2493 assert is_nil(user.last_active_at)
2495 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2497 assert {:ok, user} = User.update_last_active_at(user)
2499 assert user.last_active_at >= test_started_at
2500 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2503 NaiveDateTime.utc_now()
2504 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2505 |> NaiveDateTime.truncate(:second)
2507 assert {:ok, user} =
2509 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2510 |> User.update_and_set_cache()
2512 assert user.last_active_at == last_active_at
2513 assert {:ok, user} = User.update_last_active_at(user)
2514 assert user.last_active_at >= test_started_at
2515 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2518 test "active_user_count/1" do
2520 insert(:user, %{local: false})
2521 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2522 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2523 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2524 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2525 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2527 assert User.active_user_count() == 2
2528 assert User.active_user_count(180) == 3
2529 assert User.active_user_count(365) == 4
2530 assert User.active_user_count(1000) == 5
2535 user = insert(:user)
2537 [user: user, object_id: object_id_from_created_activity(user)]
2540 test "unique pins", %{user: user, object_id: object_id} do
2541 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2542 User.add_pinned_object_id(user, object_id)
2544 assert Enum.count(pins) == 1
2546 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2547 User.add_pinned_object_id(updated_user, object_id)
2549 assert pinned_at1 == pinned_at2
2551 assert Enum.count(pins) == 1
2554 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2555 clear_config([:instance, :max_pinned_statuses], 1)
2556 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2558 object_id2 = object_id_from_created_activity(user)
2560 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2561 assert Keyword.has_key?(errors, :pinned_objects)
2564 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2565 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2567 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2568 assert after_remove.pinned_objects == %{}
2572 defp object_id_from_created_activity(user) do
2573 %{id: id} = insert(:note_activity, user: user)
2574 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2578 describe "add_alias/2" do
2579 test "should add alias for another user" do
2580 user = insert(:user)
2581 user2 = insert(:user)
2583 assert {:ok, user_updated} = user |> User.add_alias(user2)
2585 assert user_updated.also_known_as |> length() == 1
2586 assert user2.ap_id in user_updated.also_known_as
2589 test "should add multiple aliases" do
2590 user = insert(:user)
2591 user2 = insert(:user)
2592 user3 = insert(:user)
2594 assert {:ok, user} = user |> User.add_alias(user2)
2595 assert {:ok, user_updated} = user |> User.add_alias(user3)
2597 assert user_updated.also_known_as |> length() == 2
2598 assert user2.ap_id in user_updated.also_known_as
2599 assert user3.ap_id in user_updated.also_known_as
2602 test "should not add duplicate aliases" do
2603 user = insert(:user)
2604 user2 = insert(:user)
2606 assert {:ok, user} = user |> User.add_alias(user2)
2608 assert {:ok, user_updated} = user |> User.add_alias(user2)
2610 assert user_updated.also_known_as |> length() == 1
2611 assert user2.ap_id in user_updated.also_known_as
2615 describe "alias_users/1" do
2616 test "should get aliases for a user" do
2617 user = insert(:user)
2618 user2 = insert(:user, also_known_as: [user.ap_id])
2620 aliases = user2 |> User.alias_users()
2622 assert aliases |> length() == 1
2624 alias_user = aliases |> Enum.at(0)
2626 assert alias_user.ap_id == user.ap_id
2630 describe "delete_alias/2" do
2631 test "should delete existing alias" do
2632 user = insert(:user)
2633 user2 = insert(:user, also_known_as: [user.ap_id])
2635 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2637 assert user_updated.also_known_as == []
2640 test "should report error on non-existing alias" do
2641 user = insert(:user)
2642 user2 = insert(:user)
2643 user3 = insert(:user, also_known_as: [user.ap_id])
2645 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2647 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2649 assert user3_updated.also_known_as |> length() == 1
2650 assert user.ap_id in user3_updated.also_known_as