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 |> 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
741 test "gets an existing user by nickname starting with http" do
742 user = insert(:user, nickname: "httpssome")
743 {:ok, fetched_user} = User.get_or_fetch("httpssome")
745 assert user == fetched_user
749 describe "get_or_fetch/1 remote users with tld, while BE is runned on subdomain" do
750 setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
752 test "for mastodon" do
754 %{url: "https://example.com/.well-known/host-meta"} ->
757 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
760 %{url: "https://sub.example.com/.well-known/host-meta"} ->
764 "test/fixtures/webfinger/masto-host-meta.xml"
766 |> String.replace("{{domain}}", "sub.example.com")
769 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
773 "test/fixtures/webfinger/masto-webfinger.json"
775 |> String.replace("{{nickname}}", "a")
776 |> String.replace("{{domain}}", "example.com")
777 |> String.replace("{{subdomain}}", "sub.example.com"),
778 headers: [{"content-type", "application/jrd+json"}]
781 %{url: "https://sub.example.com/users/a"} ->
785 "test/fixtures/webfinger/masto-user.json"
787 |> String.replace("{{nickname}}", "a")
788 |> String.replace("{{domain}}", "sub.example.com"),
789 headers: [{"content-type", "application/activity+json"}]
792 %{url: "https://sub.example.com/users/a/collections/featured"} ->
796 File.read!("test/fixtures/users_mock/masto_featured.json")
797 |> String.replace("{{domain}}", "sub.example.com")
798 |> String.replace("{{nickname}}", "a"),
799 headers: [{"content-type", "application/activity+json"}]
803 ap_id = "a@example.com"
804 {:ok, fetched_user} = User.get_or_fetch(ap_id)
806 assert fetched_user.ap_id == "https://sub.example.com/users/a"
807 assert fetched_user.nickname == "a@example.com"
810 test "for pleroma" do
812 %{url: "https://example.com/.well-known/host-meta"} ->
815 headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
818 %{url: "https://sub.example.com/.well-known/host-meta"} ->
822 "test/fixtures/webfinger/pleroma-host-meta.xml"
824 |> String.replace("{{domain}}", "sub.example.com")
827 %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
831 "test/fixtures/webfinger/pleroma-webfinger.json"
833 |> String.replace("{{nickname}}", "a")
834 |> String.replace("{{domain}}", "example.com")
835 |> String.replace("{{subdomain}}", "sub.example.com"),
836 headers: [{"content-type", "application/jrd+json"}]
839 %{url: "https://sub.example.com/users/a"} ->
843 "test/fixtures/webfinger/pleroma-user.json"
845 |> String.replace("{{nickname}}", "a")
846 |> String.replace("{{domain}}", "sub.example.com"),
847 headers: [{"content-type", "application/activity+json"}]
851 ap_id = "a@example.com"
852 {:ok, fetched_user} = User.get_or_fetch(ap_id)
854 assert fetched_user.ap_id == "https://sub.example.com/users/a"
855 assert fetched_user.nickname == "a@example.com"
859 describe "fetching a user from nickname or trying to build one" do
860 test "gets an existing user" do
862 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
864 assert user == fetched_user
867 test "gets an existing user, case insensitive" do
868 user = insert(:user, nickname: "nick")
869 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
871 assert user == fetched_user
874 test "gets an existing user by fully qualified nickname" do
877 {:ok, fetched_user} =
878 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
880 assert user == fetched_user
883 test "gets an existing user by fully qualified nickname, case insensitive" do
884 user = insert(:user, nickname: "nick")
885 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
887 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
889 assert user == fetched_user
892 @tag capture_log: true
893 test "returns nil if no user could be fetched" do
894 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
895 assert fetched_user == "not found nonexistant@social.heldscal.la"
898 test "returns nil for nonexistant local user" do
899 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
900 assert fetched_user == "not found nonexistant"
903 test "updates an existing user, if stale" do
904 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
910 nickname: "admin@mastodon.example.org",
911 ap_id: "http://mastodon.example.org/users/admin",
912 last_refreshed_at: a_week_ago
915 assert orig_user.last_refreshed_at == a_week_ago
917 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
921 refute user.last_refreshed_at == orig_user.last_refreshed_at
924 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
925 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
931 nickname: "admin@mastodon.example.org",
932 ap_id: "http://mastodon.example.org/users/harinezumigari",
933 last_refreshed_at: a_week_ago
936 assert orig_user.last_refreshed_at == a_week_ago
938 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
942 refute user.id == orig_user.id
944 orig_user = User.get_by_id(orig_user.id)
946 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
949 @tag capture_log: true
950 test "it returns the old user if stale, but unfetchable" do
951 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
957 nickname: "admin@mastodon.example.org",
958 ap_id: "http://mastodon.example.org/users/raymoo",
959 last_refreshed_at: a_week_ago
962 assert orig_user.last_refreshed_at == a_week_ago
964 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
966 assert user.last_refreshed_at == orig_user.last_refreshed_at
969 test "it doesn't fail on invalid alsoKnownAs entries" do
971 %{url: "https://mbp.example.com/"} ->
975 "test/fixtures/microblogpub/user_with_invalid_also_known_as.json"
977 headers: [{"content-type", "application/activity+json"}]
981 %Tesla.Env{status: 404}
984 assert {:ok, %User{also_known_as: []}} =
985 User.get_or_fetch_by_ap_id("https://mbp.example.com/")
989 test "returns an ap_id for a user" do
992 assert User.ap_id(user) ==
993 Pleroma.Web.Router.Helpers.user_feed_url(
994 Pleroma.Web.Endpoint,
1000 test "returns an ap_followers link for a user" do
1001 user = insert(:user)
1003 assert User.ap_followers(user) ==
1004 Pleroma.Web.Router.Helpers.user_feed_url(
1005 Pleroma.Web.Endpoint,
1011 describe "remote user changeset" do
1017 avatar: %{some: "avatar"}
1019 setup do: clear_config([:instance, :user_bio_length])
1020 setup do: clear_config([:instance, :user_name_length])
1022 test "it confirms validity" do
1023 cs = User.remote_user_changeset(@valid_remote)
1027 test "it sets the follower_adress" do
1028 cs = User.remote_user_changeset(@valid_remote)
1029 # remote users get a fake local follower address
1030 assert cs.changes.follower_address ==
1031 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
1034 test "it enforces the fqn format for nicknames" do
1035 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
1036 assert Ecto.Changeset.get_field(cs, :local) == false
1037 assert cs.changes.avatar
1041 test "it has required fields" do
1043 |> Enum.each(fn field ->
1044 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
1049 test "it is invalid given a local user" do
1050 user = insert(:user)
1051 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
1057 describe "followers and friends" do
1058 test "gets all followers for a given user" do
1059 user = insert(:user)
1060 follower_one = insert(:user)
1061 follower_two = insert(:user)
1062 not_follower = insert(:user)
1064 {:ok, follower_one, user} = User.follow(follower_one, user)
1065 {:ok, follower_two, user} = User.follow(follower_two, user)
1067 res = User.get_followers(user)
1069 assert Enum.member?(res, follower_one)
1070 assert Enum.member?(res, follower_two)
1071 refute Enum.member?(res, not_follower)
1074 test "gets all friends (followed users) for a given user" do
1075 user = insert(:user)
1076 followed_one = insert(:user)
1077 followed_two = insert(:user)
1078 not_followed = insert(:user)
1080 {:ok, user, followed_one} = User.follow(user, followed_one)
1081 {:ok, user, followed_two} = User.follow(user, followed_two)
1083 res = User.get_friends(user)
1085 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
1086 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
1087 assert Enum.member?(res, followed_one)
1088 assert Enum.member?(res, followed_two)
1089 refute Enum.member?(res, not_followed)
1093 describe "updating note and follower count" do
1094 test "it sets the note_count property" do
1095 note = insert(:note)
1097 user = User.get_cached_by_ap_id(note.data["actor"])
1099 assert user.note_count == 0
1101 {:ok, user} = User.update_note_count(user)
1103 assert user.note_count == 1
1106 test "it increases the note_count property" do
1107 note = insert(:note)
1108 user = User.get_cached_by_ap_id(note.data["actor"])
1110 assert user.note_count == 0
1112 {:ok, user} = User.increase_note_count(user)
1114 assert user.note_count == 1
1116 {:ok, user} = User.increase_note_count(user)
1118 assert user.note_count == 2
1121 test "it decreases the note_count property" do
1122 note = insert(:note)
1123 user = User.get_cached_by_ap_id(note.data["actor"])
1125 assert user.note_count == 0
1127 {:ok, user} = User.increase_note_count(user)
1129 assert user.note_count == 1
1131 {:ok, user} = User.decrease_note_count(user)
1133 assert user.note_count == 0
1135 {:ok, user} = User.decrease_note_count(user)
1137 assert user.note_count == 0
1140 test "it sets the follower_count property" do
1141 user = insert(:user)
1142 follower = insert(:user)
1144 User.follow(follower, user)
1146 assert user.follower_count == 0
1148 {:ok, user} = User.update_follower_count(user)
1150 assert user.follower_count == 1
1155 test "it mutes people" do
1156 user = insert(:user)
1157 muted_user = insert(:user)
1159 refute User.mutes?(user, muted_user)
1160 refute User.muted_notifications?(user, muted_user)
1162 {:ok, _user_relationships} = User.mute(user, muted_user)
1164 assert User.mutes?(user, muted_user)
1165 assert User.muted_notifications?(user, muted_user)
1169 user = insert(:user)
1170 muted_user = insert(:user)
1172 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1173 assert User.mutes?(user, muted_user)
1175 worker = Pleroma.Workers.MuteExpireWorker
1176 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1183 assert :ok = perform_job(worker, args)
1185 refute User.mutes?(user, muted_user)
1186 refute User.muted_notifications?(user, muted_user)
1189 test "it unmutes users" do
1190 user = insert(:user)
1191 muted_user = insert(:user)
1193 {:ok, _user_relationships} = User.mute(user, muted_user)
1194 {:ok, _user_mute} = User.unmute(user, muted_user)
1196 refute User.mutes?(user, muted_user)
1197 refute User.muted_notifications?(user, muted_user)
1200 test "it unmutes users by id" do
1201 user = insert(:user)
1202 muted_user = insert(:user)
1204 {:ok, _user_relationships} = User.mute(user, muted_user)
1205 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1207 refute User.mutes?(user, muted_user)
1208 refute User.muted_notifications?(user, muted_user)
1211 test "it mutes user without notifications" do
1212 user = insert(:user)
1213 muted_user = insert(:user)
1215 refute User.mutes?(user, muted_user)
1216 refute User.muted_notifications?(user, muted_user)
1218 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1220 assert User.mutes?(user, muted_user)
1221 refute User.muted_notifications?(user, muted_user)
1225 describe "blocks" do
1226 test "it blocks people" do
1227 user = insert(:user)
1228 blocked_user = insert(:user)
1230 refute User.blocks?(user, blocked_user)
1232 {:ok, _user_relationship} = User.block(user, blocked_user)
1234 assert User.blocks?(user, blocked_user)
1237 test "it unblocks users" do
1238 user = insert(:user)
1239 blocked_user = insert(:user)
1241 {:ok, _user_relationship} = User.block(user, blocked_user)
1242 {:ok, _user_block} = User.unblock(user, blocked_user)
1244 refute User.blocks?(user, blocked_user)
1247 test "blocks tear down cyclical follow relationships" do
1248 blocker = insert(:user)
1249 blocked = insert(:user)
1251 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1252 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1254 assert User.following?(blocker, blocked)
1255 assert User.following?(blocked, blocker)
1257 {:ok, _user_relationship} = User.block(blocker, blocked)
1258 blocked = User.get_cached_by_id(blocked.id)
1260 assert User.blocks?(blocker, blocked)
1262 refute User.following?(blocker, blocked)
1263 refute User.following?(blocked, blocker)
1266 test "blocks tear down blocker->blocked follow relationships" do
1267 blocker = insert(:user)
1268 blocked = insert(:user)
1270 {:ok, blocker, blocked} = User.follow(blocker, blocked)
1272 assert User.following?(blocker, blocked)
1273 refute User.following?(blocked, blocker)
1275 {:ok, _user_relationship} = User.block(blocker, blocked)
1276 blocked = User.get_cached_by_id(blocked.id)
1278 assert User.blocks?(blocker, blocked)
1280 refute User.following?(blocker, blocked)
1281 refute User.following?(blocked, blocker)
1284 test "blocks tear down blocked->blocker follow relationships" do
1285 blocker = insert(:user)
1286 blocked = insert(:user)
1288 {:ok, blocked, blocker} = User.follow(blocked, blocker)
1290 refute User.following?(blocker, blocked)
1291 assert User.following?(blocked, blocker)
1293 {:ok, _user_relationship} = User.block(blocker, blocked)
1294 blocked = User.get_cached_by_id(blocked.id)
1296 assert User.blocks?(blocker, blocked)
1298 refute User.following?(blocker, blocked)
1299 refute User.following?(blocked, blocker)
1302 test "blocks tear down blocked->blocker subscription relationships" do
1303 blocker = insert(:user)
1304 blocked = insert(:user)
1306 {:ok, _subscription} = User.subscribe(blocked, blocker)
1308 assert User.subscribed_to?(blocked, blocker)
1309 refute User.subscribed_to?(blocker, blocked)
1311 {:ok, _user_relationship} = User.block(blocker, blocked)
1313 assert User.blocks?(blocker, blocked)
1314 refute User.subscribed_to?(blocker, blocked)
1315 refute User.subscribed_to?(blocked, blocker)
1319 describe "domain blocking" do
1320 test "blocks domains" do
1321 user = insert(:user)
1322 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1324 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1326 assert User.blocks?(user, collateral_user)
1329 test "does not block domain with same end" do
1330 user = insert(:user)
1333 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1335 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1337 refute User.blocks?(user, collateral_user)
1340 test "does not block domain with same end if wildcard added" do
1341 user = insert(:user)
1344 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1346 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1348 refute User.blocks?(user, collateral_user)
1351 test "blocks domain with wildcard for subdomain" do
1352 user = insert(:user)
1354 user_from_subdomain =
1355 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1357 user_with_two_subdomains =
1359 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1362 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1364 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1366 assert User.blocks?(user, user_from_subdomain)
1367 assert User.blocks?(user, user_with_two_subdomains)
1368 assert User.blocks?(user, user_domain)
1371 test "unblocks domains" do
1372 user = insert(:user)
1373 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1375 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1376 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1378 refute User.blocks?(user, collateral_user)
1381 test "follows take precedence over domain blocks" do
1382 user = insert(:user)
1383 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1385 {:ok, user} = User.block_domain(user, "meanies.social")
1386 {:ok, user, good_eggo} = User.follow(user, good_eggo)
1388 refute User.blocks?(user, good_eggo)
1392 describe "get_recipients_from_activity" do
1393 test "works for announces" do
1394 actor = insert(:user)
1395 user = insert(:user, local: true)
1397 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1398 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1400 recipients = User.get_recipients_from_activity(announce)
1402 assert user in recipients
1405 test "get recipients" do
1406 actor = insert(:user)
1407 user = insert(:user, local: true)
1408 user_two = insert(:user, local: false)
1409 addressed = insert(:user, local: true)
1410 addressed_remote = insert(:user, local: false)
1413 CommonAPI.post(actor, %{
1414 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1417 assert Enum.map([actor, addressed], & &1.ap_id) --
1418 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1420 {:ok, user, actor} = User.follow(user, actor)
1421 {:ok, _user_two, _actor} = User.follow(user_two, actor)
1422 recipients = User.get_recipients_from_activity(activity)
1423 assert length(recipients) == 3
1424 assert user in recipients
1425 assert addressed in recipients
1428 test "has following" do
1429 actor = insert(:user)
1430 user = insert(:user)
1431 user_two = insert(:user)
1432 addressed = insert(:user, local: true)
1435 CommonAPI.post(actor, %{
1436 status: "hey @#{addressed.nickname}"
1439 assert Enum.map([actor, addressed], & &1.ap_id) --
1440 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1442 {:ok, _actor, _user} = User.follow(actor, user)
1443 {:ok, _actor, _user_two} = User.follow(actor, user_two)
1444 recipients = User.get_recipients_from_activity(activity)
1445 assert length(recipients) == 2
1446 assert addressed in recipients
1450 describe ".set_activation" do
1451 test "can de-activate then re-activate a user" do
1452 user = insert(:user)
1453 assert user.is_active
1454 {:ok, user} = User.set_activation(user, false)
1455 refute user.is_active
1456 {:ok, user} = User.set_activation(user, true)
1457 assert user.is_active
1460 test "hide a user from followers" do
1461 user = insert(:user)
1462 user2 = insert(:user)
1464 {:ok, user, user2} = User.follow(user, user2)
1465 {:ok, _user} = User.set_activation(user, false)
1467 user2 = User.get_cached_by_id(user2.id)
1469 assert user2.follower_count == 0
1470 assert [] = User.get_followers(user2)
1473 test "hide a user from friends" do
1474 user = insert(:user)
1475 user2 = insert(:user)
1477 {:ok, user2, user} = User.follow(user2, user)
1478 assert user2.following_count == 1
1479 assert User.following_count(user2) == 1
1481 {:ok, _user} = User.set_activation(user, false)
1483 user2 = User.get_cached_by_id(user2.id)
1485 assert refresh_record(user2).following_count == 0
1486 assert user2.following_count == 0
1487 assert User.following_count(user2) == 0
1488 assert [] = User.get_friends(user2)
1491 test "hide a user's statuses from timelines and notifications" do
1492 user = insert(:user)
1493 user2 = insert(:user)
1495 {:ok, user2, user} = User.follow(user2, user)
1497 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1499 activity = Repo.preload(activity, :bookmark)
1501 [notification] = Pleroma.Notification.for_user(user2)
1502 assert notification.activity.id == activity.id
1504 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1506 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1507 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1511 {:ok, _user} = User.set_activation(user, false)
1513 assert [] == ActivityPub.fetch_public_activities(%{})
1514 assert [] == Pleroma.Notification.for_user(user2)
1517 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1523 describe "approve" do
1524 test "approves a user" do
1525 user = insert(:user, is_approved: false)
1526 refute user.is_approved
1527 {:ok, user} = User.approve(user)
1528 assert user.is_approved
1531 test "approves a list of users" do
1532 unapproved_users = [
1533 insert(:user, is_approved: false),
1534 insert(:user, is_approved: false),
1535 insert(:user, is_approved: false)
1538 {:ok, users} = User.approve(unapproved_users)
1540 assert Enum.count(users) == 3
1542 Enum.each(users, fn user ->
1543 assert user.is_approved
1547 test "it sends welcome email if it is set" do
1548 clear_config([:welcome, :email, :enabled], true)
1549 clear_config([:welcome, :email, :sender], "tester@test.me")
1551 user = insert(:user, is_approved: false)
1552 welcome_user = insert(:user, email: "tester@test.me")
1553 instance_name = Pleroma.Config.get([:instance, :name])
1557 ObanHelpers.perform_all()
1560 from: {instance_name, welcome_user.email},
1561 to: {user.name, user.email},
1562 html_body: "Welcome to #{instance_name}"
1566 test "approving an approved user does not trigger post-register actions" do
1567 clear_config([:welcome, :email, :enabled], true)
1569 user = insert(:user, is_approved: true)
1572 ObanHelpers.perform_all()
1574 assert_no_email_sent()
1578 describe "confirm" do
1579 test "confirms a user" do
1580 user = insert(:user, is_confirmed: false)
1581 refute user.is_confirmed
1582 {:ok, user} = User.confirm(user)
1583 assert user.is_confirmed
1586 test "confirms a list of users" do
1587 unconfirmed_users = [
1588 insert(:user, is_confirmed: false),
1589 insert(:user, is_confirmed: false),
1590 insert(:user, is_confirmed: false)
1593 {:ok, users} = User.confirm(unconfirmed_users)
1595 assert Enum.count(users) == 3
1597 Enum.each(users, fn user ->
1598 assert user.is_confirmed
1602 test "sends approval emails when `is_approved: false`" do
1603 admin = insert(:user, is_admin: true)
1604 user = insert(:user, is_confirmed: false, is_approved: false)
1607 ObanHelpers.perform_all()
1609 user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
1610 admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
1612 notify_email = Pleroma.Config.get([:instance, :notify_email])
1613 instance_name = Pleroma.Config.get([:instance, :name])
1615 # User approval email
1617 from: {instance_name, notify_email},
1618 to: {user.name, user.email},
1619 html_body: user_email.html_body
1624 from: {instance_name, notify_email},
1625 to: {admin.name, admin.email},
1626 html_body: admin_email.html_body
1630 test "confirming a confirmed user does not trigger post-register actions" do
1631 user = insert(:user, is_confirmed: true, is_approved: false)
1634 ObanHelpers.perform_all()
1636 assert_no_email_sent()
1640 describe "delete" do
1642 {:ok, user} = insert(:user) |> User.set_cache()
1647 setup do: clear_config([:instance, :federating])
1649 test ".delete_user_activities deletes all create activities", %{user: user} do
1650 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1652 User.delete_user_activities(user)
1654 # TODO: Test removal favorites, repeats, delete activities.
1655 refute Activity.get_by_id(activity.id)
1658 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1659 follower = insert(:user)
1660 {:ok, follower, user} = User.follow(follower, user)
1662 locked_user = insert(:user, name: "locked", is_locked: true)
1663 {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
1665 object = insert(:note, user: user)
1666 activity = insert(:note_activity, user: user, note: object)
1668 object_two = insert(:note, user: follower)
1669 activity_two = insert(:note_activity, user: follower, note: object_two)
1671 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1672 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1673 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1675 {:ok, job} = User.delete(user)
1676 {:ok, _user} = ObanHelpers.perform(job)
1678 follower = User.get_cached_by_id(follower.id)
1680 refute User.following?(follower, user)
1681 assert %{is_active: false} = User.get_by_id(user.id)
1683 assert [] == User.get_follow_requests(locked_user)
1687 |> Activity.Queries.by_actor()
1689 |> Enum.map(fn act -> act.data["type"] end)
1691 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1693 refute Activity.get_by_id(activity.id)
1694 refute Activity.get_by_id(like.id)
1695 refute Activity.get_by_id(like_two.id)
1696 refute Activity.get_by_id(repeat.id)
1700 test "delete/1 when confirmation is pending deletes the user" do
1701 clear_config([:instance, :account_activation_required], true)
1702 user = insert(:user, is_confirmed: false)
1704 {:ok, job} = User.delete(user)
1705 {:ok, _} = ObanHelpers.perform(job)
1707 refute User.get_cached_by_id(user.id)
1708 refute User.get_by_id(user.id)
1711 test "delete/1 when approval is pending deletes the user" do
1712 user = insert(:user, is_approved: false)
1714 {:ok, job} = User.delete(user)
1715 {:ok, _} = ObanHelpers.perform(job)
1717 refute User.get_cached_by_id(user.id)
1718 refute User.get_by_id(user.id)
1721 test "delete/1 purges a user when they wouldn't be fully deleted" do
1726 password_hash: "pdfk2$1b3n159001",
1727 keys: "RSA begin buplic key",
1728 public_key: "--PRIVATE KEYE--",
1729 avatar: %{"a" => "b"},
1731 banner: %{"a" => "b"},
1732 background: %{"a" => "b"},
1735 following_count: 9001,
1738 password_reset_pending: true,
1740 registration_reason: "ahhhhh",
1741 confirmation_token: "qqqq",
1742 domain_blocks: ["lain.com"],
1747 mastofe_settings: %{"a" => "b"},
1748 mascot: %{"a" => "b"},
1749 emoji: %{"a" => "b"},
1750 pleroma_settings_store: %{"q" => "x"},
1751 fields: [%{"gg" => "qq"}],
1752 raw_fields: [%{"gg" => "qq"}],
1753 is_discoverable: true,
1754 also_known_as: ["https://lol.olo/users/loll"]
1757 {:ok, job} = User.delete(user)
1758 {:ok, _} = ObanHelpers.perform(job)
1759 user = User.get_by_id(user.id)
1767 keys: "RSA begin buplic key",
1768 public_key: "--PRIVATE KEYE--",
1771 last_refreshed_at: nil,
1772 last_digest_emailed_at: nil,
1780 password_reset_pending: false,
1782 registration_reason: nil,
1783 confirmation_token: nil,
1787 is_moderator: false,
1789 mastofe_settings: nil,
1792 pleroma_settings_store: %{},
1795 is_discoverable: false,
1800 test "delete/1 purges a remote user" do
1804 avatar: %{"a" => "b"},
1805 banner: %{"a" => "b"},
1809 {:ok, job} = User.delete(user)
1810 {:ok, _} = ObanHelpers.perform(job)
1811 user = User.get_by_id(user.id)
1813 assert user.name == nil
1814 assert user.avatar == %{}
1815 assert user.banner == %{}
1818 describe "set_suggestion" do
1819 test "suggests a user" do
1820 user = insert(:user, is_suggested: false)
1821 refute user.is_suggested
1822 {:ok, user} = User.set_suggestion(user, true)
1823 assert user.is_suggested
1826 test "suggests a list of users" do
1827 unsuggested_users = [
1828 insert(:user, is_suggested: false),
1829 insert(:user, is_suggested: false),
1830 insert(:user, is_suggested: false)
1833 {:ok, users} = User.set_suggestion(unsuggested_users, true)
1835 assert Enum.count(users) == 3
1837 Enum.each(users, fn user ->
1838 assert user.is_suggested
1842 test "unsuggests a user" do
1843 user = insert(:user, is_suggested: true)
1844 assert user.is_suggested
1845 {:ok, user} = User.set_suggestion(user, false)
1846 refute user.is_suggested
1850 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1851 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1854 describe "per-user rich-text filtering" do
1855 test "html_filter_policy returns default policies, when rich-text is enabled" do
1856 user = insert(:user)
1858 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1861 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1862 user = insert(:user, no_rich_text: true)
1864 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1868 describe "caching" do
1869 test "invalidate_cache works" do
1870 user = insert(:user)
1872 User.set_cache(user)
1873 User.invalidate_cache(user)
1875 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1876 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1879 test "User.delete() plugs any possible zombie objects" do
1880 user = insert(:user)
1882 {:ok, job} = User.delete(user)
1883 {:ok, _} = ObanHelpers.perform(job)
1885 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1887 assert cached_user != user
1889 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1891 assert cached_user != user
1895 describe "account_status/1" do
1896 setup do: clear_config([:instance, :account_activation_required])
1898 test "return confirmation_pending for unconfirm user" do
1899 clear_config([:instance, :account_activation_required], true)
1900 user = insert(:user, is_confirmed: false)
1901 assert User.account_status(user) == :confirmation_pending
1904 test "return active for confirmed user" do
1905 clear_config([:instance, :account_activation_required], true)
1906 user = insert(:user, is_confirmed: true)
1907 assert User.account_status(user) == :active
1910 test "return active for remote user" do
1911 user = insert(:user, local: false)
1912 assert User.account_status(user) == :active
1915 test "returns :password_reset_pending for user with reset password" do
1916 user = insert(:user, password_reset_pending: true)
1917 assert User.account_status(user) == :password_reset_pending
1920 test "returns :deactivated for deactivated user" do
1921 user = insert(:user, local: true, is_confirmed: true, is_active: false)
1922 assert User.account_status(user) == :deactivated
1925 test "returns :approval_pending for unapproved user" do
1926 user = insert(:user, local: true, is_approved: false)
1927 assert User.account_status(user) == :approval_pending
1929 user = insert(:user, local: true, is_confirmed: false, is_approved: false)
1930 assert User.account_status(user) == :approval_pending
1934 describe "superuser?/1" do
1935 test "returns false for unprivileged users" do
1936 user = insert(:user, local: true)
1938 refute User.superuser?(user)
1941 test "returns false for remote users" do
1942 user = insert(:user, local: false)
1943 remote_admin_user = insert(:user, local: false, is_admin: true)
1945 refute User.superuser?(user)
1946 refute User.superuser?(remote_admin_user)
1949 test "returns true for local moderators" do
1950 user = insert(:user, local: true, is_moderator: true)
1952 assert User.superuser?(user)
1955 test "returns true for local admins" do
1956 user = insert(:user, local: true, is_admin: true)
1958 assert User.superuser?(user)
1962 describe "invisible?/1" do
1963 test "returns true for an invisible user" do
1964 user = insert(:user, local: true, invisible: true)
1966 assert User.invisible?(user)
1969 test "returns false for a non-invisible user" do
1970 user = insert(:user, local: true)
1972 refute User.invisible?(user)
1976 describe "visible_for/2" do
1977 test "returns true when the account is itself" do
1978 user = insert(:user, local: true)
1980 assert User.visible_for(user, user) == :visible
1983 test "returns false when the account is unconfirmed and confirmation is required" do
1984 clear_config([:instance, :account_activation_required], true)
1986 user = insert(:user, local: true, is_confirmed: false)
1987 other_user = insert(:user, local: true)
1989 refute User.visible_for(user, other_user) == :visible
1992 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1993 clear_config([:instance, :account_activation_required], true)
1995 user = insert(:user, local: false, is_confirmed: false)
1996 other_user = insert(:user, local: true)
1998 assert User.visible_for(user, other_user) == :visible
2001 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
2002 clear_config([:instance, :account_activation_required], true)
2004 user = insert(:user, local: true, is_confirmed: false)
2005 other_user = insert(:user, local: true, is_admin: true)
2007 assert User.visible_for(user, other_user) == :visible
2011 describe "parse_bio/2" do
2012 test "preserves hosts in user links text" do
2013 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
2014 user = insert(:user)
2015 bio = "A.k.a. @nick@domain.com"
2018 ~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>)
2020 assert expected_text == User.parse_bio(bio, user)
2023 test "Adds rel=me on linkbacked urls" do
2024 user = insert(:user, ap_id: "https://social.example.org/users/lain")
2026 bio = "http://example.com/rel_me/null"
2027 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
2028 assert expected_text == User.parse_bio(bio, user)
2030 bio = "http://example.com/rel_me/link"
2031 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2032 assert expected_text == User.parse_bio(bio, user)
2034 bio = "http://example.com/rel_me/anchor"
2035 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
2036 assert expected_text == User.parse_bio(bio, user)
2040 test "follower count is updated when a follower is blocked" do
2041 user = insert(:user)
2042 follower = insert(:user)
2043 follower2 = insert(:user)
2044 follower3 = insert(:user)
2046 {:ok, follower, user} = User.follow(follower, user)
2047 {:ok, _follower2, _user} = User.follow(follower2, user)
2048 {:ok, _follower3, _user} = User.follow(follower3, user)
2050 {:ok, _user_relationship} = User.block(user, follower)
2051 user = refresh_record(user)
2053 assert user.follower_count == 2
2056 describe "list_inactive_users_query/1" do
2057 defp days_ago(days) do
2059 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
2060 -days * 60 * 60 * 24,
2065 test "Users are inactive by default" do
2069 Enum.map(1..total, fn _ ->
2070 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2073 inactive_users_ids =
2074 Pleroma.User.list_inactive_users_query()
2075 |> Pleroma.Repo.all()
2076 |> Enum.map(& &1.id)
2078 Enum.each(users, fn user ->
2079 assert user.id in inactive_users_ids
2083 test "Only includes users who has no recent activity" do
2087 Enum.map(1..total, fn _ ->
2088 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2091 {inactive, active} = Enum.split(users, trunc(total / 2))
2093 Enum.map(active, fn user ->
2094 to = Enum.random(users -- [user])
2097 CommonAPI.post(user, %{
2098 status: "hey @#{to.nickname}"
2102 inactive_users_ids =
2103 Pleroma.User.list_inactive_users_query()
2104 |> Pleroma.Repo.all()
2105 |> Enum.map(& &1.id)
2107 Enum.each(active, fn user ->
2108 refute user.id in inactive_users_ids
2111 Enum.each(inactive, fn user ->
2112 assert user.id in inactive_users_ids
2116 test "Only includes users with no read notifications" do
2120 Enum.map(1..total, fn _ ->
2121 insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
2124 [sender | recipients] = users
2125 {inactive, active} = Enum.split(recipients, trunc(total / 2))
2127 Enum.each(recipients, fn to ->
2129 CommonAPI.post(sender, %{
2130 status: "hey @#{to.nickname}"
2134 CommonAPI.post(sender, %{
2135 status: "hey again @#{to.nickname}"
2139 Enum.each(active, fn user ->
2140 [n1, _n2] = Pleroma.Notification.for_user(user)
2141 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
2144 inactive_users_ids =
2145 Pleroma.User.list_inactive_users_query()
2146 |> Pleroma.Repo.all()
2147 |> Enum.map(& &1.id)
2149 Enum.each(active, fn user ->
2150 refute user.id in inactive_users_ids
2153 Enum.each(inactive, fn user ->
2154 assert user.id in inactive_users_ids
2159 describe "get_ap_ids_by_nicknames" do
2160 test "it returns a list of AP ids for a given set of nicknames" do
2161 user = insert(:user)
2162 user_two = insert(:user)
2164 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
2165 assert length(ap_ids) == 2
2166 assert user.ap_id in ap_ids
2167 assert user_two.ap_id in ap_ids
2171 describe "sync followers count" do
2173 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
2174 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
2175 insert(:user, local: true)
2176 insert(:user, local: false, is_active: false)
2177 {:ok, user1: user1, user2: user2}
2180 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
2181 [fdb_user1] = User.external_users(limit: 1)
2183 assert fdb_user1.ap_id
2184 assert fdb_user1.ap_id == user1.ap_id
2185 assert fdb_user1.id == user1.id
2187 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
2189 assert fdb_user2.ap_id
2190 assert fdb_user2.ap_id == user2.ap_id
2191 assert fdb_user2.id == user2.id
2193 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
2197 describe "is_internal_user?/1" do
2198 test "non-internal user returns false" do
2199 user = insert(:user)
2200 refute User.is_internal_user?(user)
2203 test "user with no nickname returns true" do
2204 user = insert(:user, %{nickname: nil})
2205 assert User.is_internal_user?(user)
2208 test "user with internal-prefixed nickname returns true" do
2209 user = insert(:user, %{nickname: "internal.test"})
2210 assert User.is_internal_user?(user)
2214 describe "update_and_set_cache/1" do
2215 test "returns error when user is stale instead Ecto.StaleEntryError" do
2216 user = insert(:user)
2218 changeset = Ecto.Changeset.change(user, bio: "test")
2222 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
2223 User.update_and_set_cache(changeset)
2226 test "performs update cache if user updated" do
2227 user = insert(:user)
2228 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2230 changeset = Ecto.Changeset.change(user, bio: "test-bio")
2232 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
2233 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2234 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2237 test "removes report notifs when user isn't superuser any more" do
2238 report_activity = insert(:report_activity)
2239 user = insert(:user, is_moderator: true, is_admin: true)
2240 {:ok, _} = Notification.create_notifications(report_activity)
2242 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2244 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2245 # is still superuser because still admin
2246 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2248 {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false})
2249 # is still superuser because still moderator
2250 assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
2252 {:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
2253 # is not a superuser any more
2254 assert [] = Notification.for_user(user)
2258 describe "following/followers synchronization" do
2259 setup do: clear_config([:instance, :external_user_synchronization])
2261 test "updates the counters normally on following/getting a follow when disabled" do
2262 clear_config([:instance, :external_user_synchronization], false)
2263 user = insert(:user)
2268 follower_address: "http://localhost:4001/users/masto_closed/followers",
2269 following_address: "http://localhost:4001/users/masto_closed/following",
2273 assert other_user.following_count == 0
2274 assert other_user.follower_count == 0
2276 {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
2278 assert user.following_count == 1
2279 assert other_user.follower_count == 1
2282 test "synchronizes the counters with the remote instance for the followed when enabled" do
2283 clear_config([:instance, :external_user_synchronization], false)
2285 user = insert(:user)
2290 follower_address: "http://localhost:4001/users/masto_closed/followers",
2291 following_address: "http://localhost:4001/users/masto_closed/following",
2295 assert other_user.following_count == 0
2296 assert other_user.follower_count == 0
2298 clear_config([:instance, :external_user_synchronization], true)
2299 {:ok, _user, other_user} = User.follow(user, other_user)
2301 assert other_user.follower_count == 437
2304 test "synchronizes the counters with the remote instance for the follower when enabled" do
2305 clear_config([:instance, :external_user_synchronization], false)
2307 user = insert(:user)
2312 follower_address: "http://localhost:4001/users/masto_closed/followers",
2313 following_address: "http://localhost:4001/users/masto_closed/following",
2317 assert other_user.following_count == 0
2318 assert other_user.follower_count == 0
2320 clear_config([:instance, :external_user_synchronization], true)
2321 {:ok, other_user, _user} = User.follow(other_user, user)
2323 assert other_user.following_count == 152
2327 describe "change_email/2" do
2329 [user: insert(:user)]
2332 test "blank email returns error if we require an email on registration", %{user: user} do
2333 orig_account_activation_required =
2334 Pleroma.Config.get([:instance, :account_activation_required])
2336 Pleroma.Config.put([:instance, :account_activation_required], true)
2340 [:instance, :account_activation_required],
2341 orig_account_activation_required
2345 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2346 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2349 test "blank email should be fine if we do not require an email on registration", %{user: user} do
2350 orig_account_activation_required =
2351 Pleroma.Config.get([:instance, :account_activation_required])
2353 Pleroma.Config.put([:instance, :account_activation_required], false)
2357 [:instance, :account_activation_required],
2358 orig_account_activation_required
2362 assert {:ok, %User{email: nil}} = User.change_email(user, "")
2363 assert {:ok, %User{email: nil}} = User.change_email(user, nil)
2366 test "non unique email returns error", %{user: user} do
2367 %{email: email} = insert(:user)
2369 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2370 User.change_email(user, email)
2373 test "invalid email returns error", %{user: user} do
2374 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2375 User.change_email(user, "cofe")
2378 test "changes email", %{user: user} do
2379 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2382 test "adds email", %{user: user} do
2383 orig_account_activation_required =
2384 Pleroma.Config.get([:instance, :account_activation_required])
2386 Pleroma.Config.put([:instance, :account_activation_required], false)
2390 [:instance, :account_activation_required],
2391 orig_account_activation_required
2395 assert {:ok, _} = User.change_email(user, "")
2396 Pleroma.Config.put([:instance, :account_activation_required], true)
2398 assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
2402 describe "get_cached_by_nickname_or_id" do
2404 local_user = insert(:user)
2405 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2407 [local_user: local_user, remote_user: remote_user]
2410 setup do: clear_config([:instance, :limit_to_local_content])
2412 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2413 remote_user: remote_user
2415 clear_config([:instance, :limit_to_local_content], false)
2416 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2418 clear_config([:instance, :limit_to_local_content], true)
2419 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2421 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2422 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2425 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2426 %{remote_user: remote_user} do
2427 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2428 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2431 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2432 %{remote_user: remote_user, local_user: local_user} do
2433 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2434 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2437 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2438 %{remote_user: remote_user} do
2439 clear_config([:instance, :limit_to_local_content], true)
2440 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2443 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2444 %{local_user: local_user} do
2445 clear_config([:instance, :limit_to_local_content], false)
2446 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2448 clear_config([:instance, :limit_to_local_content], true)
2449 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2451 clear_config([:instance, :limit_to_local_content], :unauthenticated)
2452 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2456 describe "update_email_notifications/2" do
2458 user = insert(:user, email_notifications: %{"digest" => true})
2463 test "Notifications are updated", %{user: user} do
2464 true = user.email_notifications["digest"]
2465 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2466 assert result.email_notifications["digest"] == false
2470 describe "local_nickname/1" do
2471 test "returns nickname without host" do
2472 assert User.local_nickname("@mentioned") == "mentioned"
2473 assert User.local_nickname("a_local_nickname") == "a_local_nickname"
2474 assert User.local_nickname("nickname@host.com") == "nickname"
2478 describe "full_nickname/1" do
2479 test "returns fully qualified nickname for local and remote users" do
2481 insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
2483 remote_user = insert(:user, nickname: "remote@host.com", local: false)
2485 assert User.full_nickname(local_user) == "local_user@somehost.com"
2486 assert User.full_nickname(remote_user) == "remote@host.com"
2489 test "strips leading @ from mentions" do
2490 assert User.full_nickname("@mentioned") == "mentioned"
2491 assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
2494 test "does not modify nicknames" do
2495 assert User.full_nickname("nickname") == "nickname"
2496 assert User.full_nickname("nickname@host.com") == "nickname@host.com"
2500 test "avatar fallback" do
2501 user = insert(:user)
2502 assert User.avatar_url(user) =~ "/images/avi.png"
2504 clear_config([:assets, :default_user_avatar], "avatar.png")
2506 user = User.get_cached_by_nickname_or_id(user.nickname)
2507 assert User.avatar_url(user) =~ "avatar.png"
2509 assert User.avatar_url(user, no_default: true) == nil
2512 test "get_host/1" do
2513 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2514 assert User.get_host(user) == "lain.com"
2517 test "update_last_active_at/1" do
2518 user = insert(:user)
2519 assert is_nil(user.last_active_at)
2521 test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
2523 assert {:ok, user} = User.update_last_active_at(user)
2525 assert user.last_active_at >= test_started_at
2526 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2529 NaiveDateTime.utc_now()
2530 |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
2531 |> NaiveDateTime.truncate(:second)
2533 assert {:ok, user} =
2535 |> cast(%{last_active_at: last_active_at}, [:last_active_at])
2536 |> User.update_and_set_cache()
2538 assert user.last_active_at == last_active_at
2539 assert {:ok, user} = User.update_last_active_at(user)
2540 assert user.last_active_at >= test_started_at
2541 assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
2544 test "active_user_count/1" do
2546 insert(:user, %{local: false})
2547 insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
2548 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
2549 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
2550 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
2551 insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
2553 assert User.active_user_count() == 2
2554 assert User.active_user_count(180) == 3
2555 assert User.active_user_count(365) == 4
2556 assert User.active_user_count(1000) == 5
2561 user = insert(:user)
2563 [user: user, object_id: object_id_from_created_activity(user)]
2566 test "unique pins", %{user: user, object_id: object_id} do
2567 assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
2568 User.add_pinned_object_id(user, object_id)
2570 assert Enum.count(pins) == 1
2572 assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
2573 User.add_pinned_object_id(updated_user, object_id)
2575 assert pinned_at1 == pinned_at2
2577 assert Enum.count(pins) == 1
2580 test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
2581 clear_config([:instance, :max_pinned_statuses], 1)
2582 {:ok, updated} = User.add_pinned_object_id(user, object_id)
2584 object_id2 = object_id_from_created_activity(user)
2586 {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
2587 assert Keyword.has_key?(errors, :pinned_objects)
2590 test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
2591 assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
2593 {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
2594 assert after_remove.pinned_objects == %{}
2598 defp object_id_from_created_activity(user) do
2599 %{id: id} = insert(:note_activity, user: user)
2600 %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
2604 describe "add_alias/2" do
2605 test "should add alias for another user" do
2606 user = insert(:user)
2607 user2 = insert(:user)
2609 assert {:ok, user_updated} = user |> User.add_alias(user2)
2611 assert user_updated.also_known_as |> length() == 1
2612 assert user2.ap_id in user_updated.also_known_as
2615 test "should add multiple aliases" do
2616 user = insert(:user)
2617 user2 = insert(:user)
2618 user3 = insert(:user)
2620 assert {:ok, user} = user |> User.add_alias(user2)
2621 assert {:ok, user_updated} = user |> User.add_alias(user3)
2623 assert user_updated.also_known_as |> length() == 2
2624 assert user2.ap_id in user_updated.also_known_as
2625 assert user3.ap_id in user_updated.also_known_as
2628 test "should not add duplicate aliases" do
2629 user = insert(:user)
2630 user2 = insert(:user)
2632 assert {:ok, user} = user |> User.add_alias(user2)
2634 assert {:ok, user_updated} = user |> User.add_alias(user2)
2636 assert user_updated.also_known_as |> length() == 1
2637 assert user2.ap_id in user_updated.also_known_as
2641 describe "alias_users/1" do
2642 test "should get aliases for a user" do
2643 user = insert(:user)
2644 user2 = insert(:user, also_known_as: [user.ap_id])
2646 aliases = user2 |> User.alias_users()
2648 assert aliases |> length() == 1
2650 alias_user = aliases |> Enum.at(0)
2652 assert alias_user.ap_id == user.ap_id
2656 describe "delete_alias/2" do
2657 test "should delete existing alias" do
2658 user = insert(:user)
2659 user2 = insert(:user, also_known_as: [user.ap_id])
2661 assert {:ok, user_updated} = user2 |> User.delete_alias(user)
2663 assert user_updated.also_known_as == []
2666 test "should report error on non-existing alias" do
2667 user = insert(:user)
2668 user2 = insert(:user)
2669 user3 = insert(:user, also_known_as: [user.ap_id])
2671 assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2)
2673 user3_updated = User.get_cached_by_ap_id(user3.ap_id)
2675 assert user3_updated.also_known_as |> length() == 1
2676 assert user.ap_id in user3_updated.also_known_as
2680 describe "follow_hashtag/2" do
2681 test "should follow a hashtag" do
2682 user = insert(:user)
2683 hashtag = insert(:hashtag)
2685 assert {:ok, _} = user |> User.follow_hashtag(hashtag)
2687 user = User.get_cached_by_ap_id(user.ap_id)
2689 assert user.followed_hashtags |> Enum.count() == 1
2690 assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
2693 test "should not follow a hashtag twice" do
2694 user = insert(:user)
2695 hashtag = insert(:hashtag)
2697 assert {:ok, _} = user |> User.follow_hashtag(hashtag)
2699 assert {:ok, _} = user |> User.follow_hashtag(hashtag)
2701 user = User.get_cached_by_ap_id(user.ap_id)
2703 assert user.followed_hashtags |> Enum.count() == 1
2704 assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
2707 test "can follow multiple hashtags" do
2708 user = insert(:user)
2709 hashtag = insert(:hashtag)
2710 other_hashtag = insert(:hashtag)
2712 assert {:ok, _} = user |> User.follow_hashtag(hashtag)
2713 assert {:ok, _} = user |> User.follow_hashtag(other_hashtag)
2715 user = User.get_cached_by_ap_id(user.ap_id)
2717 assert user.followed_hashtags |> Enum.count() == 2
2718 assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
2719 assert other_hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
2723 describe "unfollow_hashtag/2" do
2724 test "should unfollow a hashtag" do
2725 user = insert(:user)
2726 hashtag = insert(:hashtag)
2728 assert {:ok, _} = user |> User.follow_hashtag(hashtag)
2729 assert {:ok, _} = user |> User.unfollow_hashtag(hashtag)
2731 user = User.get_cached_by_ap_id(user.ap_id)
2733 assert user.followed_hashtags |> Enum.count() == 0
2736 test "should not error when trying to unfollow a hashtag twice" do
2737 user = insert(:user)
2738 hashtag = insert(:hashtag)
2740 assert {:ok, _} = user |> User.follow_hashtag(hashtag)
2741 assert {:ok, _} = user |> User.unfollow_hashtag(hashtag)
2742 assert {:ok, _} = user |> User.unfollow_hashtag(hashtag)
2744 user = User.get_cached_by_ap_id(user.ap_id)
2746 assert user.followed_hashtags |> Enum.count() == 0