X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=test%2Fpleroma%2Fuser_test.exs;h=617d9b755fff0b8b6eb734382d31a3dc37c68101;hb=4f2f2c9125e9888e58e865042726ae0fbfcdb8f2;hp=9ae52d594e0d961a7afc39d0c1834730a2b861b9;hpb=ddf36b096e3f6e2fa1cdca5d59db98ade696df20;p=akkoma diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 9ae52d594..cc6634aba 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -1,10 +1,11 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors +# Copyright © 2017-2021 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UserTest do alias Pleroma.Activity alias Pleroma.Builders.UserBuilder + alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo alias Pleroma.Tests.ObanHelpers @@ -151,7 +152,7 @@ defmodule Pleroma.UserTest do test "ap_id returns the activity pub id for the user" do user = UserBuilder.build() - expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}" + expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}" assert expected_ap_id == User.ap_id(user) end @@ -202,11 +203,11 @@ defmodule Pleroma.UserTest do test "doesn't return follow requests for deactivated accounts" do locked = insert(:user, is_locked: true) - pending_follower = insert(:user, %{deactivated: true}) + pending_follower = insert(:user, %{is_active: false}) CommonAPI.follow(pending_follower, locked) - assert true == pending_follower.deactivated + refute pending_follower.is_active assert [] = User.get_follow_requests(locked) end @@ -233,7 +234,7 @@ defmodule Pleroma.UserTest do {:ok, _user_relationship} = User.block(user, blocked) {:ok, _user_relationship} = User.block(reverse_blocked, user) - {:ok, user} = User.follow(user, followed_zero) + {:ok, user, followed_zero} = User.follow(user, followed_zero) {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked]) @@ -262,7 +263,7 @@ defmodule Pleroma.UserTest do user = insert(:user) followed = insert(:user) - {:ok, user} = User.follow(user, followed) + {:ok, user, followed} = User.follow(user, followed) user = User.get_cached_by_id(user.id) followed = User.get_cached_by_ap_id(followed.ap_id) @@ -275,7 +276,7 @@ defmodule Pleroma.UserTest do test "can't follow a deactivated users" do user = insert(:user) - followed = insert(:user, %{deactivated: true}) + followed = insert(:user, %{is_active: false}) {:error, _} = User.follow(user, followed) end @@ -302,7 +303,7 @@ defmodule Pleroma.UserTest do follower = insert(:user, is_locked: true) followed = insert(:user, is_locked: true) - {:ok, follower} = User.maybe_direct_follow(follower, followed) + {:ok, follower, followed} = User.maybe_direct_follow(follower, followed) refute User.following?(follower, followed) end @@ -310,8 +311,8 @@ defmodule Pleroma.UserTest do describe "unfollow/2" do setup do: clear_config([:instance, :external_user_synchronization]) - test "unfollow with syncronizes external user" do - Pleroma.Config.put([:instance, :external_user_synchronization], true) + test "unfollow with synchronizes external user" do + clear_config([:instance, :external_user_synchronization], true) followed = insert(:user, @@ -330,7 +331,7 @@ defmodule Pleroma.UserTest do following_address: "http://localhost:4001/users/fuser2/following" }) - {:ok, user} = User.follow(user, followed, :follow_accept) + {:ok, user, followed} = User.follow(user, followed, :follow_accept) {:ok, user, _activity} = User.unfollow(user, followed) @@ -343,7 +344,7 @@ defmodule Pleroma.UserTest do followed = insert(:user) user = insert(:user) - {:ok, user} = User.follow(user, followed, :follow_accept) + {:ok, user, followed} = User.follow(user, followed, :follow_accept) assert User.following(user) == [user.follower_address, followed.follower_address] @@ -396,7 +397,7 @@ defmodule Pleroma.UserTest do user = insert(:user) remote_user = insert(:user, %{local: false}) - Pleroma.Config.put([:instance, :autofollowed_nicknames], [ + clear_config([:instance, :autofollowed_nicknames], [ user.nickname, remote_user.nickname ]) @@ -413,7 +414,7 @@ defmodule Pleroma.UserTest do user1 = insert(:user) user2 = insert(:user) - Pleroma.Config.put([:instance, :autofollowing_nicknames], [ + clear_config([:instance, :autofollowing_nicknames], [ user1.nickname, user2.nickname ]) @@ -428,9 +429,9 @@ defmodule Pleroma.UserTest do test "it sends a welcome message if it is set" do welcome_user = insert(:user) - Pleroma.Config.put([:welcome, :direct_message, :enabled], true) - Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname) - Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message") + clear_config([:welcome, :direct_message, :enabled], true) + clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname) + clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message") cng = User.register_changeset(%User{}, @full_user_data) {:ok, registered_user} = User.register(cng) @@ -438,38 +439,25 @@ defmodule Pleroma.UserTest do activity = Repo.one(Pleroma.Activity) assert registered_user.ap_id in activity.recipients - assert Object.normalize(activity).data["content"] =~ "direct message" - assert activity.actor == welcome_user.ap_id - end - - test "it sends a welcome chat message if it is set" do - welcome_user = insert(:user) - Pleroma.Config.put([:welcome, :chat_message, :enabled], true) - Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname) - Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message") - - cng = User.register_changeset(%User{}, @full_user_data) - {:ok, registered_user} = User.register(cng) - ObanHelpers.perform_all() - - activity = Repo.one(Pleroma.Activity) - assert registered_user.ap_id in activity.recipients - assert Object.normalize(activity).data["content"] =~ "chat message" + assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message" assert activity.actor == welcome_user.ap_id end setup do: - clear_config(:mrf_simple, - media_removal: [], - media_nsfw: [], - federated_timeline_removal: [], - report_removal: [], - reject: [], - followers_only: [], - accept: [], - avatar_removal: [], - banner_removal: [], - reject_deletes: [] + clear_config( + [:mrf_simple], + %{ + media_removal: [], + media_nsfw: [], + federated_timeline_removal: [], + report_removal: [], + reject: [], + followers_only: [], + accept: [], + avatar_removal: [], + banner_removal: [], + reject_deletes: [] + } ) setup do: @@ -479,30 +467,12 @@ defmodule Pleroma.UserTest do ] ) - test "it sends a welcome chat message when Simple policy applied to local instance" do - Pleroma.Config.put([:mrf_simple, :media_nsfw], ["localhost"]) - - welcome_user = insert(:user) - Pleroma.Config.put([:welcome, :chat_message, :enabled], true) - Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname) - Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message") - - cng = User.register_changeset(%User{}, @full_user_data) - {:ok, registered_user} = User.register(cng) - ObanHelpers.perform_all() - - activity = Repo.one(Pleroma.Activity) - assert registered_user.ap_id in activity.recipients - assert Object.normalize(activity).data["content"] =~ "chat message" - assert activity.actor == welcome_user.ap_id - end - test "it sends a welcome email message if it is set" do welcome_user = insert(:user) - Pleroma.Config.put([:welcome, :email, :enabled], true) - Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email) + clear_config([:welcome, :email, :enabled], true) + clear_config([:welcome, :email, :sender], welcome_user.email) - Pleroma.Config.put( + clear_config( [:welcome, :email, :subject], "Hello, welcome to cool site: <%= instance_name %>" ) @@ -522,7 +492,7 @@ defmodule Pleroma.UserTest do end test "it sends a confirm email" do - Pleroma.Config.put([:instance, :account_activation_required], true) + clear_config([:instance, :account_activation_required], true) cng = User.register_changeset(%User{}, @full_user_data) {:ok, registered_user} = User.register(cng) @@ -535,8 +505,63 @@ defmodule Pleroma.UserTest do |> assert_email_sent() end + test "sends a pending approval email" do + clear_config([:instance, :account_approval_required], true) + + {:ok, user} = + User.register_changeset(%User{}, @full_user_data) + |> User.register() + + ObanHelpers.perform_all() + + assert_email_sent( + from: Pleroma.Config.Helpers.sender(), + to: {user.name, user.email}, + subject: "Your account is awaiting approval" + ) + end + + test "it sends a registration confirmed email if no others will be sent" do + clear_config([:welcome, :email, :enabled], false) + clear_config([:instance, :account_activation_required], false) + clear_config([:instance, :account_approval_required], false) + + {:ok, user} = + User.register_changeset(%User{}, @full_user_data) + |> User.register() + + ObanHelpers.perform_all() + + instance_name = Pleroma.Config.get([:instance, :name]) + sender = Pleroma.Config.get([:instance, :notify_email]) + + assert_email_sent( + from: {instance_name, sender}, + to: {user.name, user.email}, + subject: "Account registered on #{instance_name}" + ) + end + + test "it fails gracefully with invalid email config" do + cng = User.register_changeset(%User{}, @full_user_data) + + # Disable the mailer but enable all the things that want to send emails + clear_config([Pleroma.Emails.Mailer, :enabled], false) + clear_config([:instance, :account_activation_required], true) + clear_config([:instance, :account_approval_required], true) + clear_config([:welcome, :email, :enabled], true) + clear_config([:welcome, :email, :sender], "lain@lain.com") + + # The user is still created + assert {:ok, %User{nickname: "nick"}} = User.register(cng) + + # No emails are sent + ObanHelpers.perform_all() + refute_email_sent() + end + test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do - Pleroma.Config.put([:instance, :account_activation_required], true) + clear_config([:instance, :account_activation_required], true) @full_user_data |> Map.keys() @@ -549,7 +574,7 @@ defmodule Pleroma.UserTest do end test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do - Pleroma.Config.put([:instance, :account_activation_required], false) + clear_config([:instance, :account_activation_required], false) @full_user_data |> Map.keys() @@ -598,33 +623,25 @@ defmodule Pleroma.UserTest do assert changeset.valid? end - test "it sets the password_hash and ap_id" do + test "it sets the password_hash, ap_id, private key and followers collection address" do changeset = User.register_changeset(%User{}, @full_user_data) assert changeset.valid? assert is_binary(changeset.changes[:password_hash]) + assert is_binary(changeset.changes[:keys]) assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname}) - + assert is_binary(changeset.changes[:keys]) assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers" end - test "it sets the 'accepts_chat_messages' set to true" do - changeset = User.register_changeset(%User{}, @full_user_data) - assert changeset.valid? - - {:ok, user} = Repo.insert(changeset) - - assert user.accepts_chat_messages - end - test "it creates a confirmed user" do changeset = User.register_changeset(%User{}, @full_user_data) assert changeset.valid? {:ok, user} = Repo.insert(changeset) - refute user.confirmation_pending + assert user.is_confirmed end end @@ -645,17 +662,17 @@ defmodule Pleroma.UserTest do {:ok, user} = Repo.insert(changeset) - assert user.confirmation_pending + refute user.is_confirmed assert user.confirmation_token end test "it creates confirmed user if :confirmed option is given" do - changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false) + changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true) assert changeset.valid? {:ok, user} = Repo.insert(changeset) - refute user.confirmation_pending + assert user.is_confirmed refute user.confirmation_token end end @@ -678,7 +695,7 @@ defmodule Pleroma.UserTest do {:ok, user} = Repo.insert(changeset) - assert user.approval_pending + refute user.is_approved assert user.registration_reason == "I'm a cool guy :)" end @@ -723,6 +740,123 @@ defmodule Pleroma.UserTest do freshed_user = refresh_record(user) assert freshed_user == fetched_user end + + test "gets an existing user by nickname starting with http" do + user = insert(:user, nickname: "httpssome") + {:ok, fetched_user} = User.get_or_fetch("httpssome") + + assert user == fetched_user + end + end + + describe "get_or_fetch/1 remote users with tld, while BE is runned on subdomain" do + setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true) + + test "for mastodon" do + Tesla.Mock.mock(fn + %{url: "https://example.com/.well-known/host-meta"} -> + %Tesla.Env{ + status: 302, + headers: [{"location", "https://sub.example.com/.well-known/host-meta"}] + } + + %{url: "https://sub.example.com/.well-known/host-meta"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/masto-host-meta.xml" + |> File.read!() + |> String.replace("{{domain}}", "sub.example.com") + } + + %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/masto-webfinger.json" + |> File.read!() + |> String.replace("{{nickname}}", "a") + |> String.replace("{{domain}}", "example.com") + |> String.replace("{{subdomain}}", "sub.example.com"), + headers: [{"content-type", "application/jrd+json"}] + } + + %{url: "https://sub.example.com/users/a"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/masto-user.json" + |> File.read!() + |> String.replace("{{nickname}}", "a") + |> String.replace("{{domain}}", "sub.example.com"), + headers: [{"content-type", "application/activity+json"}] + } + + %{url: "https://sub.example.com/users/a/collections/featured"} -> + %Tesla.Env{ + status: 200, + body: + File.read!("test/fixtures/users_mock/masto_featured.json") + |> String.replace("{{domain}}", "sub.example.com") + |> String.replace("{{nickname}}", "a"), + headers: [{"content-type", "application/activity+json"}] + } + end) + + ap_id = "a@example.com" + {:ok, fetched_user} = User.get_or_fetch(ap_id) + + assert fetched_user.ap_id == "https://sub.example.com/users/a" + assert fetched_user.nickname == "a@example.com" + end + + test "for pleroma" do + Tesla.Mock.mock(fn + %{url: "https://example.com/.well-known/host-meta"} -> + %Tesla.Env{ + status: 302, + headers: [{"location", "https://sub.example.com/.well-known/host-meta"}] + } + + %{url: "https://sub.example.com/.well-known/host-meta"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/pleroma-host-meta.xml" + |> File.read!() + |> String.replace("{{domain}}", "sub.example.com") + } + + %{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/pleroma-webfinger.json" + |> File.read!() + |> String.replace("{{nickname}}", "a") + |> String.replace("{{domain}}", "example.com") + |> String.replace("{{subdomain}}", "sub.example.com"), + headers: [{"content-type", "application/jrd+json"}] + } + + %{url: "https://sub.example.com/users/a"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/webfinger/pleroma-user.json" + |> File.read!() + |> String.replace("{{nickname}}", "a") + |> String.replace("{{domain}}", "sub.example.com"), + headers: [{"content-type", "application/activity+json"}] + } + end) + + ap_id = "a@example.com" + {:ok, fetched_user} = User.get_or_fetch(ap_id) + + assert fetched_user.ap_id == "https://sub.example.com/users/a" + assert fetched_user.nickname == "a@example.com" + end end describe "fetching a user from nickname or trying to build one" do @@ -834,6 +968,25 @@ defmodule Pleroma.UserTest do assert user.last_refreshed_at == orig_user.last_refreshed_at end + + test "it doesn't fail on invalid alsoKnownAs entries" do + Tesla.Mock.mock(fn + %{url: "https://mbp.example.com/"} -> + %Tesla.Env{ + status: 200, + body: + "test/fixtures/microblogpub/user_with_invalid_also_known_as.json" + |> File.read!(), + headers: [{"content-type", "application/activity+json"}] + } + + _ -> + %Tesla.Env{status: 404} + end) + + assert {:ok, %User{also_known_as: []}} = + User.get_or_fetch_by_ap_id("https://mbp.example.com/") + end end test "returns an ap_id for a user" do @@ -895,6 +1048,13 @@ defmodule Pleroma.UserTest do refute cs.valid? end) end + + test "it is invalid given a local user" do + user = insert(:user) + cs = User.remote_user_changeset(user, %{name: "tom from myspace"}) + + refute cs.valid? + end end describe "followers and friends" do @@ -904,8 +1064,8 @@ defmodule Pleroma.UserTest do follower_two = insert(:user) not_follower = insert(:user) - {:ok, follower_one} = User.follow(follower_one, user) - {:ok, follower_two} = User.follow(follower_two, user) + {:ok, follower_one, user} = User.follow(follower_one, user) + {:ok, follower_two, user} = User.follow(follower_two, user) res = User.get_followers(user) @@ -920,8 +1080,8 @@ defmodule Pleroma.UserTest do followed_two = insert(:user) not_followed = insert(:user) - {:ok, user} = User.follow(user, followed_one) - {:ok, user} = User.follow(user, followed_two) + {:ok, user, followed_one} = User.follow(user, followed_one) + {:ok, user, followed_two} = User.follow(user, followed_two) res = User.get_friends(user) @@ -1008,6 +1168,27 @@ defmodule Pleroma.UserTest do assert User.muted_notifications?(user, muted_user) end + test "expiring" do + user = insert(:user) + muted_user = insert(:user) + + {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60}) + assert User.mutes?(user, muted_user) + + worker = Pleroma.Workers.MuteExpireWorker + args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id} + + assert_enqueued( + worker: worker, + args: args + ) + + assert :ok = perform_job(worker, args) + + refute User.mutes?(user, muted_user) + refute User.muted_notifications?(user, muted_user) + end + test "it unmutes users" do user = insert(:user) muted_user = insert(:user) @@ -1019,6 +1200,17 @@ defmodule Pleroma.UserTest do refute User.muted_notifications?(user, muted_user) end + test "it unmutes users by id" do + user = insert(:user) + muted_user = insert(:user) + + {:ok, _user_relationships} = User.mute(user, muted_user) + {:ok, _user_mute} = User.unmute(user.id, muted_user.id) + + refute User.mutes?(user, muted_user) + refute User.muted_notifications?(user, muted_user) + end + test "it mutes user without notifications" do user = insert(:user) muted_user = insert(:user) @@ -1026,7 +1218,7 @@ defmodule Pleroma.UserTest do refute User.mutes?(user, muted_user) refute User.muted_notifications?(user, muted_user) - {:ok, _user_relationships} = User.mute(user, muted_user, false) + {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false}) assert User.mutes?(user, muted_user) refute User.muted_notifications?(user, muted_user) @@ -1059,8 +1251,8 @@ defmodule Pleroma.UserTest do blocker = insert(:user) blocked = insert(:user) - {:ok, blocker} = User.follow(blocker, blocked) - {:ok, blocked} = User.follow(blocked, blocker) + {:ok, blocker, blocked} = User.follow(blocker, blocked) + {:ok, blocked, blocker} = User.follow(blocked, blocker) assert User.following?(blocker, blocked) assert User.following?(blocked, blocker) @@ -1078,7 +1270,7 @@ defmodule Pleroma.UserTest do blocker = insert(:user) blocked = insert(:user) - {:ok, blocker} = User.follow(blocker, blocked) + {:ok, blocker, blocked} = User.follow(blocker, blocked) assert User.following?(blocker, blocked) refute User.following?(blocked, blocker) @@ -1096,7 +1288,7 @@ defmodule Pleroma.UserTest do blocker = insert(:user) blocked = insert(:user) - {:ok, blocked} = User.follow(blocked, blocker) + {:ok, blocked, blocker} = User.follow(blocked, blocker) refute User.following?(blocker, blocked) assert User.following?(blocked, blocker) @@ -1154,7 +1346,7 @@ defmodule Pleroma.UserTest do collateral_user = insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"}) - {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com") + {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com") refute User.blocks?(user, collateral_user) end @@ -1172,7 +1364,7 @@ defmodule Pleroma.UserTest do user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"}) - {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com") + {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com") assert User.blocks?(user, user_from_subdomain) assert User.blocks?(user, user_with_two_subdomains) @@ -1194,7 +1386,7 @@ defmodule Pleroma.UserTest do good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"}) {:ok, user} = User.block_domain(user, "meanies.social") - {:ok, user} = User.follow(user, good_eggo) + {:ok, user, good_eggo} = User.follow(user, good_eggo) refute User.blocks?(user, good_eggo) end @@ -1228,8 +1420,8 @@ defmodule Pleroma.UserTest do assert Enum.map([actor, addressed], & &1.ap_id) -- Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == [] - {:ok, user} = User.follow(user, actor) - {:ok, _user_two} = User.follow(user_two, actor) + {:ok, user, actor} = User.follow(user, actor) + {:ok, _user_two, _actor} = User.follow(user_two, actor) recipients = User.get_recipients_from_activity(activity) assert length(recipients) == 3 assert user in recipients @@ -1250,30 +1442,30 @@ defmodule Pleroma.UserTest do assert Enum.map([actor, addressed], & &1.ap_id) -- Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == [] - {:ok, _actor} = User.follow(actor, user) - {:ok, _actor} = User.follow(actor, user_two) + {:ok, _actor, _user} = User.follow(actor, user) + {:ok, _actor, _user_two} = User.follow(actor, user_two) recipients = User.get_recipients_from_activity(activity) assert length(recipients) == 2 assert addressed in recipients end end - describe ".deactivate" do + describe ".set_activation" do test "can de-activate then re-activate a user" do user = insert(:user) - assert false == user.deactivated - {:ok, user} = User.deactivate(user) - assert true == user.deactivated - {:ok, user} = User.deactivate(user, false) - assert false == user.deactivated + assert user.is_active + {:ok, user} = User.set_activation(user, false) + refute user.is_active + {:ok, user} = User.set_activation(user, true) + assert user.is_active end test "hide a user from followers" do user = insert(:user) user2 = insert(:user) - {:ok, user} = User.follow(user, user2) - {:ok, _user} = User.deactivate(user) + {:ok, user, user2} = User.follow(user, user2) + {:ok, _user} = User.set_activation(user, false) user2 = User.get_cached_by_id(user2.id) @@ -1285,11 +1477,11 @@ defmodule Pleroma.UserTest do user = insert(:user) user2 = insert(:user) - {:ok, user2} = User.follow(user2, user) + {:ok, user2, user} = User.follow(user2, user) assert user2.following_count == 1 assert User.following_count(user2) == 1 - {:ok, _user} = User.deactivate(user) + {:ok, _user} = User.set_activation(user, false) user2 = User.get_cached_by_id(user2.id) @@ -1303,7 +1495,7 @@ defmodule Pleroma.UserTest do user = insert(:user) user2 = insert(:user) - {:ok, user2} = User.follow(user2, user) + {:ok, user2, user} = User.follow(user2, user) {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"}) @@ -1319,7 +1511,7 @@ defmodule Pleroma.UserTest do user: user2 }) - {:ok, _user} = User.deactivate(user) + {:ok, _user} = User.set_activation(user, false) assert [] == ActivityPub.fetch_public_activities(%{}) assert [] == Pleroma.Notification.for_user(user2) @@ -1333,17 +1525,17 @@ defmodule Pleroma.UserTest do describe "approve" do test "approves a user" do - user = insert(:user, approval_pending: true) - assert true == user.approval_pending + user = insert(:user, is_approved: false) + refute user.is_approved {:ok, user} = User.approve(user) - assert false == user.approval_pending + assert user.is_approved end test "approves a list of users" do unapproved_users = [ - insert(:user, approval_pending: true), - insert(:user, approval_pending: true), - insert(:user, approval_pending: true) + insert(:user, is_approved: false), + insert(:user, is_approved: false), + insert(:user, is_approved: false) ] {:ok, users} = User.approve(unapproved_users) @@ -1351,9 +1543,101 @@ defmodule Pleroma.UserTest do assert Enum.count(users) == 3 Enum.each(users, fn user -> - assert false == user.approval_pending + assert user.is_approved end) end + + test "it sends welcome email if it is set" do + clear_config([:welcome, :email, :enabled], true) + clear_config([:welcome, :email, :sender], "tester@test.me") + + user = insert(:user, is_approved: false) + welcome_user = insert(:user, email: "tester@test.me") + instance_name = Pleroma.Config.get([:instance, :name]) + + User.approve(user) + + ObanHelpers.perform_all() + + assert_email_sent( + from: {instance_name, welcome_user.email}, + to: {user.name, user.email}, + html_body: "Welcome to #{instance_name}" + ) + end + + test "approving an approved user does not trigger post-register actions" do + clear_config([:welcome, :email, :enabled], true) + + user = insert(:user, is_approved: true) + User.approve(user) + + ObanHelpers.perform_all() + + assert_no_email_sent() + end + end + + describe "confirm" do + test "confirms a user" do + user = insert(:user, is_confirmed: false) + refute user.is_confirmed + {:ok, user} = User.confirm(user) + assert user.is_confirmed + end + + test "confirms a list of users" do + unconfirmed_users = [ + insert(:user, is_confirmed: false), + insert(:user, is_confirmed: false), + insert(:user, is_confirmed: false) + ] + + {:ok, users} = User.confirm(unconfirmed_users) + + assert Enum.count(users) == 3 + + Enum.each(users, fn user -> + assert user.is_confirmed + end) + end + + test "sends approval emails when `is_approved: false`" do + admin = insert(:user, is_admin: true) + user = insert(:user, is_confirmed: false, is_approved: false) + User.confirm(user) + + ObanHelpers.perform_all() + + user_email = Pleroma.Emails.UserEmail.approval_pending_email(user) + admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user) + + notify_email = Pleroma.Config.get([:instance, :notify_email]) + instance_name = Pleroma.Config.get([:instance, :name]) + + # User approval email + assert_email_sent( + from: {instance_name, notify_email}, + to: {user.name, user.email}, + html_body: user_email.html_body + ) + + # Admin email + assert_email_sent( + from: {instance_name, notify_email}, + to: {admin.name, admin.email}, + html_body: admin_email.html_body + ) + end + + test "confirming a confirmed user does not trigger post-register actions" do + user = insert(:user, is_confirmed: true, is_approved: false) + User.confirm(user) + + ObanHelpers.perform_all() + + assert_no_email_sent() + end end describe "delete" do @@ -1376,10 +1660,10 @@ defmodule Pleroma.UserTest do test "it deactivates a user, all follow relationships and all activities", %{user: user} do follower = insert(:user) - {:ok, follower} = User.follow(follower, user) + {:ok, follower, user} = User.follow(follower, user) locked_user = insert(:user, name: "locked", is_locked: true) - {:ok, _} = User.follow(user, locked_user, :follow_pending) + {:ok, _, _} = User.follow(user, locked_user, :follow_pending) object = insert(:note, user: user) activity = insert(:note_activity, user: user, note: object) @@ -1397,7 +1681,7 @@ defmodule Pleroma.UserTest do follower = User.get_cached_by_id(follower.id) refute User.following?(follower, user) - assert %{deactivated: true} = User.get_by_id(user.id) + assert %{is_active: false} = User.get_by_id(user.id) assert [] == User.get_follow_requests(locked_user) @@ -1416,35 +1700,19 @@ defmodule Pleroma.UserTest do end end - describe "delete/1 when confirmation is pending" do - setup do - user = insert(:user, confirmation_pending: true) - {:ok, user: user} - end - - test "deletes user from database when activation required", %{user: user} do - clear_config([:instance, :account_activation_required], true) - - {:ok, job} = User.delete(user) - {:ok, _} = ObanHelpers.perform(job) - - refute User.get_cached_by_id(user.id) - refute User.get_by_id(user.id) - end - - test "deactivates user when activation is not required", %{user: user} do - clear_config([:instance, :account_activation_required], false) + test "delete/1 when confirmation is pending deletes the user" do + clear_config([:instance, :account_activation_required], true) + user = insert(:user, is_confirmed: false) - {:ok, job} = User.delete(user) - {:ok, _} = ObanHelpers.perform(job) + {:ok, job} = User.delete(user) + {:ok, _} = ObanHelpers.perform(job) - assert %{deactivated: true} = User.get_cached_by_id(user.id) - assert %{deactivated: true} = User.get_by_id(user.id) - end + refute User.get_cached_by_id(user.id) + refute User.get_by_id(user.id) end test "delete/1 when approval is pending deletes the user" do - user = insert(:user, approval_pending: true) + user = insert(:user, is_approved: false) {:ok, job} = User.delete(user) {:ok, _} = ObanHelpers.perform(job) @@ -1469,13 +1737,13 @@ defmodule Pleroma.UserTest do follower_count: 9, following_count: 9001, is_locked: true, - confirmation_pending: true, + is_confirmed: true, password_reset_pending: true, - approval_pending: true, + is_approved: true, registration_reason: "ahhhhh", confirmation_token: "qqqq", domain_blocks: ["lain.com"], - deactivated: true, + is_active: false, ap_enabled: true, is_moderator: true, is_admin: true, @@ -1499,8 +1767,8 @@ defmodule Pleroma.UserTest do email: nil, name: nil, password_hash: nil, - keys: nil, - public_key: nil, + keys: "RSA begin buplic key", + public_key: "--PRIVATE KEYE--", avatar: %{}, tags: [], last_refreshed_at: nil, @@ -1511,13 +1779,13 @@ defmodule Pleroma.UserTest do follower_count: 0, following_count: 0, is_locked: false, - confirmation_pending: false, + is_confirmed: true, password_reset_pending: false, - approval_pending: false, + is_approved: true, registration_reason: nil, confirmation_token: nil, domain_blocks: [], - deactivated: true, + is_active: false, ap_enabled: false, is_moderator: false, is_admin: false, @@ -1532,6 +1800,56 @@ defmodule Pleroma.UserTest do } = user end + test "delete/1 purges a remote user" do + user = + insert(:user, %{ + name: "qqqqqqq", + avatar: %{"a" => "b"}, + banner: %{"a" => "b"}, + local: false + }) + + {:ok, job} = User.delete(user) + {:ok, _} = ObanHelpers.perform(job) + user = User.get_by_id(user.id) + + assert user.name == nil + assert user.avatar == %{} + assert user.banner == %{} + end + + describe "set_suggestion" do + test "suggests a user" do + user = insert(:user, is_suggested: false) + refute user.is_suggested + {:ok, user} = User.set_suggestion(user, true) + assert user.is_suggested + end + + test "suggests a list of users" do + unsuggested_users = [ + insert(:user, is_suggested: false), + insert(:user, is_suggested: false), + insert(:user, is_suggested: false) + ] + + {:ok, users} = User.set_suggestion(unsuggested_users, true) + + assert Enum.count(users) == 3 + + Enum.each(users, fn user -> + assert user.is_suggested + end) + end + + test "unsuggests a user" do + user = insert(:user, is_suggested: true) + assert user.is_suggested + {:ok, user} = User.set_suggestion(user, false) + refute user.is_suggested + end + end + test "get_public_key_for_ap_id fetches a user that's not in the db" do assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin") end @@ -1581,14 +1899,14 @@ defmodule Pleroma.UserTest do setup do: clear_config([:instance, :account_activation_required]) test "return confirmation_pending for unconfirm user" do - Pleroma.Config.put([:instance, :account_activation_required], true) - user = insert(:user, confirmation_pending: true) + clear_config([:instance, :account_activation_required], true) + user = insert(:user, is_confirmed: false) assert User.account_status(user) == :confirmation_pending end test "return active for confirmed user" do - Pleroma.Config.put([:instance, :account_activation_required], true) - user = insert(:user, confirmation_pending: false) + clear_config([:instance, :account_activation_required], true) + user = insert(:user, is_confirmed: true) assert User.account_status(user) == :active end @@ -1603,15 +1921,15 @@ defmodule Pleroma.UserTest do end test "returns :deactivated for deactivated user" do - user = insert(:user, local: true, confirmation_pending: false, deactivated: true) + user = insert(:user, local: true, is_confirmed: true, is_active: false) assert User.account_status(user) == :deactivated end test "returns :approval_pending for unapproved user" do - user = insert(:user, local: true, approval_pending: true) + user = insert(:user, local: true, is_approved: false) assert User.account_status(user) == :approval_pending - user = insert(:user, local: true, confirmation_pending: true, approval_pending: true) + user = insert(:user, local: true, is_confirmed: false, is_approved: false) assert User.account_status(user) == :approval_pending end end @@ -1666,34 +1984,27 @@ defmodule Pleroma.UserTest do end test "returns false when the account is unconfirmed and confirmation is required" do - Pleroma.Config.put([:instance, :account_activation_required], true) + clear_config([:instance, :account_activation_required], true) - user = insert(:user, local: true, confirmation_pending: true) + user = insert(:user, local: true, is_confirmed: false) other_user = insert(:user, local: true) refute User.visible_for(user, other_user) == :visible end test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do - Pleroma.Config.put([:instance, :account_activation_required], true) - - user = insert(:user, local: false, confirmation_pending: true) - other_user = insert(:user, local: true) - - assert User.visible_for(user, other_user) == :visible - end + clear_config([:instance, :account_activation_required], true) - test "returns true when the account is unconfirmed and confirmation is not required" do - user = insert(:user, local: true, confirmation_pending: true) + user = insert(:user, local: false, is_confirmed: false) other_user = insert(:user, local: true) assert User.visible_for(user, other_user) == :visible end test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do - Pleroma.Config.put([:instance, :account_activation_required], true) + clear_config([:instance, :account_activation_required], true) - user = insert(:user, local: true, confirmation_pending: true) + user = insert(:user, local: true, is_confirmed: false) other_user = insert(:user, local: true, is_admin: true) assert User.visible_for(user, other_user) == :visible @@ -1707,9 +2018,7 @@ defmodule Pleroma.UserTest do bio = "A.k.a. @nick@domain.com" expected_text = - ~s(A.k.a. @nick@domain.com) + ~s(A.k.a. @nick@domain.com) assert expected_text == User.parse_bio(bio, user) end @@ -1737,9 +2046,9 @@ defmodule Pleroma.UserTest do follower2 = insert(:user) follower3 = insert(:user) - {:ok, follower} = User.follow(follower, user) - {:ok, _follower2} = User.follow(follower2, user) - {:ok, _follower3} = User.follow(follower3, user) + {:ok, follower, user} = User.follow(follower, user) + {:ok, _follower2, _user} = User.follow(follower2, user) + {:ok, _follower3, _user} = User.follow(follower3, user) {:ok, _user_relationship} = User.block(user, follower) user = refresh_record(user) @@ -1761,7 +2070,7 @@ defmodule Pleroma.UserTest do users = Enum.map(1..total, fn _ -> - insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false) + insert(:user, last_digest_emailed_at: days_ago(20), is_active: true) end) inactive_users_ids = @@ -1779,7 +2088,7 @@ defmodule Pleroma.UserTest do users = Enum.map(1..total, fn _ -> - insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false) + insert(:user, last_digest_emailed_at: days_ago(20), is_active: true) end) {inactive, active} = Enum.split(users, trunc(total / 2)) @@ -1812,7 +2121,7 @@ defmodule Pleroma.UserTest do users = Enum.map(1..total, fn _ -> - insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false) + insert(:user, last_digest_emailed_at: days_ago(20), is_active: true) end) [sender | recipients] = users @@ -1850,39 +2159,6 @@ defmodule Pleroma.UserTest do end end - describe "toggle_confirmation/1" do - test "if user is confirmed" do - user = insert(:user, confirmation_pending: false) - {:ok, user} = User.toggle_confirmation(user) - - assert user.confirmation_pending - assert user.confirmation_token - end - - test "if user is unconfirmed" do - user = insert(:user, confirmation_pending: true, confirmation_token: "some token") - {:ok, user} = User.toggle_confirmation(user) - - refute user.confirmation_pending - refute user.confirmation_token - end - end - - describe "ensure_keys_present" do - test "it creates keys for a user and stores them in info" do - user = insert(:user) - refute is_binary(user.keys) - {:ok, user} = User.ensure_keys_present(user) - assert is_binary(user.keys) - end - - test "it doesn't create keys if there already are some" do - user = insert(:user, keys: "xxx") - {:ok, user} = User.ensure_keys_present(user) - assert user.keys == "xxx" - end - end - describe "get_ap_ids_by_nicknames" do test "it returns a list of AP ids for a given set of nicknames" do user = insert(:user) @@ -1900,7 +2176,7 @@ defmodule Pleroma.UserTest do user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed") user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2") insert(:user, local: true) - insert(:user, local: false, deactivated: true) + insert(:user, local: false, is_active: false) {:ok, user1: user1, user2: user2} end @@ -1960,13 +2236,33 @@ defmodule Pleroma.UserTest do assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id) end + + test "removes report notifs when user isn't superuser any more" do + report_activity = insert(:report_activity) + user = insert(:user, is_moderator: true, is_admin: true) + {:ok, _} = Notification.create_notifications(report_activity) + + assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user) + + {:ok, user} = user |> User.admin_api_update(%{is_moderator: false}) + # is still superuser because still admin + assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user) + + {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false}) + # is still superuser because still moderator + assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user) + + {:ok, user} = user |> User.admin_api_update(%{is_moderator: false}) + # is not a superuser any more + assert [] = Notification.for_user(user) + end end describe "following/followers synchronization" do setup do: clear_config([:instance, :external_user_synchronization]) test "updates the counters normally on following/getting a follow when disabled" do - Pleroma.Config.put([:instance, :external_user_synchronization], false) + clear_config([:instance, :external_user_synchronization], false) user = insert(:user) other_user = @@ -1980,15 +2276,14 @@ defmodule Pleroma.UserTest do assert other_user.following_count == 0 assert other_user.follower_count == 0 - {:ok, user} = Pleroma.User.follow(user, other_user) - other_user = Pleroma.User.get_by_id(other_user.id) + {:ok, user, other_user} = Pleroma.User.follow(user, other_user) assert user.following_count == 1 assert other_user.follower_count == 1 end - test "syncronizes the counters with the remote instance for the followed when enabled" do - Pleroma.Config.put([:instance, :external_user_synchronization], false) + test "synchronizes the counters with the remote instance for the followed when enabled" do + clear_config([:instance, :external_user_synchronization], false) user = insert(:user) @@ -2003,15 +2298,14 @@ defmodule Pleroma.UserTest do assert other_user.following_count == 0 assert other_user.follower_count == 0 - Pleroma.Config.put([:instance, :external_user_synchronization], true) - {:ok, _user} = User.follow(user, other_user) - other_user = User.get_by_id(other_user.id) + clear_config([:instance, :external_user_synchronization], true) + {:ok, _user, other_user} = User.follow(user, other_user) assert other_user.follower_count == 437 end - test "syncronizes the counters with the remote instance for the follower when enabled" do - Pleroma.Config.put([:instance, :external_user_synchronization], false) + test "synchronizes the counters with the remote instance for the follower when enabled" do + clear_config([:instance, :external_user_synchronization], false) user = insert(:user) @@ -2026,8 +2320,8 @@ defmodule Pleroma.UserTest do assert other_user.following_count == 0 assert other_user.follower_count == 0 - Pleroma.Config.put([:instance, :external_user_synchronization], true) - {:ok, other_user} = User.follow(other_user, user) + clear_config([:instance, :external_user_synchronization], true) + {:ok, other_user, _user} = User.follow(other_user, user) assert other_user.following_count == 152 end @@ -2038,11 +2332,40 @@ defmodule Pleroma.UserTest do [user: insert(:user)] end - test "blank email returns error", %{user: user} do + test "blank email returns error if we require an email on registration", %{user: user} do + orig_account_activation_required = + Pleroma.Config.get([:instance, :account_activation_required]) + + Pleroma.Config.put([:instance, :account_activation_required], true) + + on_exit(fn -> + Pleroma.Config.put( + [:instance, :account_activation_required], + orig_account_activation_required + ) + end) + assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "") assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil) end + test "blank email should be fine if we do not require an email on registration", %{user: user} do + orig_account_activation_required = + Pleroma.Config.get([:instance, :account_activation_required]) + + Pleroma.Config.put([:instance, :account_activation_required], false) + + on_exit(fn -> + Pleroma.Config.put( + [:instance, :account_activation_required], + orig_account_activation_required + ) + end) + + assert {:ok, %User{email: nil}} = User.change_email(user, "") + assert {:ok, %User{email: nil}} = User.change_email(user, nil) + end + test "non unique email returns error", %{user: user} do %{email: email} = insert(:user) @@ -2058,6 +2381,25 @@ defmodule Pleroma.UserTest do test "changes email", %{user: user} do assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party") end + + test "adds email", %{user: user} do + orig_account_activation_required = + Pleroma.Config.get([:instance, :account_activation_required]) + + Pleroma.Config.put([:instance, :account_activation_required], false) + + on_exit(fn -> + Pleroma.Config.put( + [:instance, :account_activation_required], + orig_account_activation_required + ) + end) + + assert {:ok, _} = User.change_email(user, "") + Pleroma.Config.put([:instance, :account_activation_required], true) + + assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party") + end end describe "get_cached_by_nickname_or_id" do @@ -2073,43 +2415,43 @@ defmodule Pleroma.UserTest do test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{ remote_user: remote_user } do - Pleroma.Config.put([:instance, :limit_to_local_content], false) + clear_config([:instance, :limit_to_local_content], false) assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id) - Pleroma.Config.put([:instance, :limit_to_local_content], true) + clear_config([:instance, :limit_to_local_content], true) assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id) - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) + clear_config([:instance, :limit_to_local_content], :unauthenticated) assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id) end test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated", %{remote_user: remote_user} do - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) + clear_config([:instance, :limit_to_local_content], :unauthenticated) assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname) end test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated", %{remote_user: remote_user, local_user: local_user} do - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) + clear_config([:instance, :limit_to_local_content], :unauthenticated) assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user) end test "disallows getting remote users by nickname when :limit_to_local_content is set to true", %{remote_user: remote_user} do - Pleroma.Config.put([:instance, :limit_to_local_content], true) + clear_config([:instance, :limit_to_local_content], true) assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname) end test "allows getting local users by nickname no matter what :limit_to_local_content is set to", %{local_user: local_user} do - Pleroma.Config.put([:instance, :limit_to_local_content], false) + clear_config([:instance, :limit_to_local_content], false) assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) - Pleroma.Config.put([:instance, :limit_to_local_content], true) + clear_config([:instance, :limit_to_local_content], true) assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) + clear_config([:instance, :limit_to_local_content], :unauthenticated) assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname) end end @@ -2128,6 +2470,36 @@ defmodule Pleroma.UserTest do end end + describe "local_nickname/1" do + test "returns nickname without host" do + assert User.local_nickname("@mentioned") == "mentioned" + assert User.local_nickname("a_local_nickname") == "a_local_nickname" + assert User.local_nickname("nickname@host.com") == "nickname" + end + end + + describe "full_nickname/1" do + test "returns fully qualified nickname for local and remote users" do + local_user = + insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user") + + remote_user = insert(:user, nickname: "remote@host.com", local: false) + + assert User.full_nickname(local_user) == "local_user@somehost.com" + assert User.full_nickname(remote_user) == "remote@host.com" + end + + test "strips leading @ from mentions" do + assert User.full_nickname("@mentioned") == "mentioned" + assert User.full_nickname("@nickname@host.com") == "nickname@host.com" + end + + test "does not modify nicknames" do + assert User.full_nickname("nickname") == "nickname" + assert User.full_nickname("nickname@host.com") == "nickname@host.com" + end + end + test "avatar fallback" do user = insert(:user) assert User.avatar_url(user) =~ "/images/avi.png" @@ -2139,4 +2511,242 @@ defmodule Pleroma.UserTest do assert User.avatar_url(user, no_default: true) == nil end + + test "get_host/1" do + user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain") + assert User.get_host(user) == "lain.com" + end + + test "update_last_active_at/1" do + user = insert(:user) + assert is_nil(user.last_active_at) + + test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + + assert {:ok, user} = User.update_last_active_at(user) + + assert user.last_active_at >= test_started_at + assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) + + last_active_at = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(-:timer.hours(24), :millisecond) + |> NaiveDateTime.truncate(:second) + + assert {:ok, user} = + user + |> cast(%{last_active_at: last_active_at}, [:last_active_at]) + |> User.update_and_set_cache() + + assert user.last_active_at == last_active_at + assert {:ok, user} = User.update_last_active_at(user) + assert user.last_active_at >= test_started_at + assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) + end + + test "active_user_count/1" do + insert(:user) + insert(:user, %{local: false}) + insert(:user, %{last_active_at: NaiveDateTime.utc_now()}) + insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)}) + insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)}) + insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)}) + insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)}) + + assert User.active_user_count() == 2 + assert User.active_user_count(180) == 3 + assert User.active_user_count(365) == 4 + assert User.active_user_count(1000) == 5 + end + + describe "pins" do + setup do + user = insert(:user) + + [user: user, object_id: object_id_from_created_activity(user)] + end + + test "unique pins", %{user: user, object_id: object_id} do + assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} = + User.add_pinned_object_id(user, object_id) + + assert Enum.count(pins) == 1 + + assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} = + User.add_pinned_object_id(updated_user, object_id) + + assert pinned_at1 == pinned_at2 + + assert Enum.count(pins) == 1 + end + + test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do + clear_config([:instance, :max_pinned_statuses], 1) + {:ok, updated} = User.add_pinned_object_id(user, object_id) + + object_id2 = object_id_from_created_activity(user) + + {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2) + assert Keyword.has_key?(errors, :pinned_objects) + end + + test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do + assert {:ok, updated} = User.add_pinned_object_id(user, object_id) + + {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id) + assert after_remove.pinned_objects == %{} + end + end + + defp object_id_from_created_activity(user) do + %{id: id} = insert(:note_activity, user: user) + %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id) + object_id + end + + describe "add_alias/2" do + test "should add alias for another user" do + user = insert(:user) + user2 = insert(:user) + + assert {:ok, user_updated} = user |> User.add_alias(user2) + + assert user_updated.also_known_as |> length() == 1 + assert user2.ap_id in user_updated.also_known_as + end + + test "should add multiple aliases" do + user = insert(:user) + user2 = insert(:user) + user3 = insert(:user) + + assert {:ok, user} = user |> User.add_alias(user2) + assert {:ok, user_updated} = user |> User.add_alias(user3) + + assert user_updated.also_known_as |> length() == 2 + assert user2.ap_id in user_updated.also_known_as + assert user3.ap_id in user_updated.also_known_as + end + + test "should not add duplicate aliases" do + user = insert(:user) + user2 = insert(:user) + + assert {:ok, user} = user |> User.add_alias(user2) + + assert {:ok, user_updated} = user |> User.add_alias(user2) + + assert user_updated.also_known_as |> length() == 1 + assert user2.ap_id in user_updated.also_known_as + end + end + + describe "alias_users/1" do + test "should get aliases for a user" do + user = insert(:user) + user2 = insert(:user, also_known_as: [user.ap_id]) + + aliases = user2 |> User.alias_users() + + assert aliases |> length() == 1 + + alias_user = aliases |> Enum.at(0) + + assert alias_user.ap_id == user.ap_id + end + end + + describe "delete_alias/2" do + test "should delete existing alias" do + user = insert(:user) + user2 = insert(:user, also_known_as: [user.ap_id]) + + assert {:ok, user_updated} = user2 |> User.delete_alias(user) + + assert user_updated.also_known_as == [] + end + + test "should report error on non-existing alias" do + user = insert(:user) + user2 = insert(:user) + user3 = insert(:user, also_known_as: [user.ap_id]) + + assert {:error, :no_such_alias} = user3 |> User.delete_alias(user2) + + user3_updated = User.get_cached_by_ap_id(user3.ap_id) + + assert user3_updated.also_known_as |> length() == 1 + assert user.ap_id in user3_updated.also_known_as + end + end + + describe "follow_hashtag/2" do + test "should follow a hashtag" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 1 + assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + end + + test "should not follow a hashtag twice" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 1 + assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + end + + test "can follow multiple hashtags" do + user = insert(:user) + hashtag = insert(:hashtag) + other_hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + assert {:ok, _} = user |> User.follow_hashtag(other_hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 2 + assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + assert other_hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) + end + end + + describe "unfollow_hashtag/2" do + test "should unfollow a hashtag" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 0 + end + + test "should not error when trying to unfollow a hashtag twice" do + user = insert(:user) + hashtag = insert(:hashtag) + + assert {:ok, _} = user |> User.follow_hashtag(hashtag) + assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) + assert {:ok, _} = user |> User.unfollow_hashtag(hashtag) + + user = User.get_cached_by_ap_id(user.ap_id) + + assert user.followed_hashtags |> Enum.count() == 0 + end + end end