diff --git a/lib/graphql/error.ex b/lib/graphql/error.ex index ddcf0df1d..ae6af7e09 100644 --- a/lib/graphql/error.ex +++ b/lib/graphql/error.ex @@ -110,6 +110,7 @@ defmodule Mobilizon.GraphQL.Error do defp metadata(:not_found), do: {404, dgettext("errors", "Resource not found")} defp metadata(:user_not_found), do: {404, dgettext("errors", "User not found")} + defp metadata(:user_pending), do: {404, dgettext("errors", "User pending")} defp metadata(:post_not_found), do: {404, dgettext("errors", "Post not found")} defp metadata(:event_not_found), do: {404, dgettext("errors", "Event not found")} defp metadata(:group_not_found), do: {404, dgettext("errors", "Group not found")} diff --git a/lib/graphql/resolvers/user.ex b/lib/graphql/resolvers/user.ex index 29503c3a5..fb044ad18 100644 --- a/lib/graphql/resolvers/user.ex +++ b/lib/graphql/resolvers/user.ex @@ -86,6 +86,9 @@ defmodule Mobilizon.GraphQL.Resolvers.User do {:error, :user_not_found} -> {:error, :user_not_found} + {:error, :user_pending} -> + {:error, :user_pending} + {:error, :disabled_user} -> {:error, dgettext("errors", "This user has been disabled")} @@ -158,6 +161,13 @@ defmodule Mobilizon.GraphQL.Resolvers.User do user_agent = Map.get(context, :user_agent, "") now = DateTime.utc_now() + role = + if Config.instance_registrations_moderation?() do + :pending + else + :user + end + with {:ok, email} <- lowercase_domain(email), :registration_ok <- check_registration_config(email, moderation), :not_deny_listed <- check_registration_denylist(email), @@ -165,7 +175,12 @@ defmodule Mobilizon.GraphQL.Resolvers.User do {:spam, AntiSpam.service().check_user(email, current_ip, user_agent)}, {:ok, %User{} = user} <- args - |> Map.merge(%{email: email, current_sign_in_ip: current_ip, current_sign_in_at: now}) + |> Map.merge(%{ + email: email, + current_sign_in_ip: current_ip, + current_sign_in_at: now, + role: role + }) |> Users.register() do Email.User.send_confirmation_email(user, Map.get(args, :locale, "en")) {:ok, user} @@ -361,6 +376,9 @@ defmodule Mobilizon.GraphQL.Resolvers.User do # TODO : implement rate limits for this endpoint {:error, dgettext("errors", "No user with this email was found")} + {:error, :user_pending} -> + {:error, dgettext("errors", "User is pending")} + {:error, :email_too_soon} -> {:error, dgettext( diff --git a/lib/mobilizon/users/users.ex b/lib/mobilizon/users/users.ex index fe9e9ef87..c512c094e 100644 --- a/lib/mobilizon/users/users.ex +++ b/lib/mobilizon/users/users.ex @@ -82,7 +82,7 @@ defmodule Mobilizon.Users do Gets an user by its email. """ @spec get_user_by_email(String.t(), Keyword.t()) :: - {:ok, User.t()} | {:error, :user_not_found} + {:ok, User.t()} | {:error, :user_not_found} | {:error, :user_pending} def get_user_by_email(email, options \\ []) do activated = Keyword.get(options, :activated, nil) unconfirmed = Keyword.get(options, :unconfirmed, true) diff --git a/lib/service/auth/authenticator.ex b/lib/service/auth/authenticator.ex index fea00568d..28407d16d 100644 --- a/lib/service/auth/authenticator.ex +++ b/lib/service/auth/authenticator.ex @@ -92,12 +92,16 @@ defmodule Mobilizon.Service.Auth.Authenticator do end end - @spec fetch_user(String.t()) :: User.t() | {:error, :user_not_found} + @spec fetch_user(String.t()) :: User.t() | {:error, :user_not_found} | {:error, :pending} def fetch_user(nil), do: {:error, :user_not_found} def fetch_user(email) when not is_nil(email) do with {:ok, %User{} = user} <- Users.get_user_by_email(email, activated: true) do - user + if user.role == :pending do + {:error, :user_pending} + else + user + end end end end diff --git a/lib/service/auth/mobilizon_authenticator.ex b/lib/service/auth/mobilizon_authenticator.ex index cc2e5aa58..872206fec 100644 --- a/lib/service/auth/mobilizon_authenticator.ex +++ b/lib/service/auth/mobilizon_authenticator.ex @@ -28,6 +28,9 @@ defmodule Mobilizon.Service.Auth.MobilizonAuthenticator do {:user, {:error, :user_not_found}} -> {:error, :user_not_found} + {:user, {:error, :user_pending}} -> + {:error, :user_pending} + {:acceptable_password, false} -> {:error, :bad_password} diff --git a/test/graphql/resolvers/user_test.exs b/test/graphql/resolvers/user_test.exs index 8e468c88d..a15809b08 100644 --- a/test/graphql/resolvers/user_test.exs +++ b/test/graphql/resolvers/user_test.exs @@ -397,6 +397,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do assert res["data"]["createUser"]["locale"] == @user_creation.locale {:ok, user} = Users.get_user_by_email(@user_creation.email) + assert user.role == :user assert_email_sent(to: user.email) end @@ -480,6 +481,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do {:ok, user} = Users.get_user_by_email(@user_creation.email) assert user.moderation == @user_creation_with_moderation.moderation + assert user.role == :pending Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_moderation], false) @@ -1040,6 +1042,32 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do assert hd(res["errors"])["message"] == "User not found" end + + test "test login_user/3 with pending user", %{conn: conn} do + {:ok, %User{} = user} = + Users.register(%{ + email: "toto@tata.tld", + password: "p4ssw0rd", + moderation: @moderation_empty + }) + + {:ok, %User{} = _user} = + Users.update_user(user, %{ + "confirmed_at" => DateTime.utc_now() |> DateTime.truncate(:second), + "confirmation_sent_at" => nil, + "confirmation_token" => nil, + "role" => :pending + }) + + res = + conn + |> AbsintheHelpers.graphql_query( + query: @login_mutation, + variables: %{email: user.email, password: user.password} + ) + + assert hd(res["errors"])["message"] == "User pending" + end end describe "Resolver: Refresh a token" do