Skip to content

Commit

Permalink
Add user registration schemas and update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pawelsierant committed Feb 28, 2024
1 parent febb9e5 commit da7311a
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule BuildelWeb.UserRegistrationController do
use BuildelWeb, :controller
use BuildelWeb.Validator
use OpenApiSpex.ControllerSpecs

alias Buildel.Accounts
alias Buildel.Accounts.User
Expand All @@ -9,16 +9,28 @@ defmodule BuildelWeb.UserRegistrationController do

action_fallback(BuildelWeb.FallbackController)

defparams :create do
required(:user, :map) do
required(:email, :string, format: :email)
required(:password, :string, min: 12)
end
end
plug OpenApiSpex.Plug.CastAndValidate,
json_render_error_v2: true,
render_error: BuildelWeb.ErrorRendererPlug

tags ["user"]

operation :create,
summary: "Create user forgot password request",
parameters: [],
request_body:
{"user", "application/json", BuildelWeb.Schemas.Users.CreateRegistrationRequest},
responses: [
created: {"user", "application/json", BuildelWeb.Schemas.Users.ShowResponse},
unprocessable_entity:
{"unprocessable entity", "application/json",
BuildelWeb.Schemas.Errors.UnprocessableEntity}
]

def create(conn, _params) do
%{user: user_params} = conn.body_params

def create(conn, params) do
with {:ok, %{user: user_params}} <- validate(:create, params),
{:ok, %User{} = user} <- Accounts.register_user(user_params),
with {:ok, %User{} = user} <- Accounts.register_user(user_params),
{:ok, _} =
Accounts.deliver_user_confirmation_instructions(
user,
Expand All @@ -35,7 +47,16 @@ defmodule BuildelWeb.UserRegistrationController do
|> render(:show, user: user)
else
{:error, %Ecto.Changeset{action: :insert}} ->
{:error, changeset_error(global: "email has already been taken")}
{:error,
%Ecto.Changeset{
action: :validate,
errors:
%{global: "email has already been taken"}
|> Enum.map(fn {key, value} -> {key, {value, []}} end)
|> Enum.into(%{}),
changes: %{},
types: %{}
}}

e ->
e
Expand Down
4 changes: 4 additions & 0 deletions apps/api/lib/buildel_web/error_renderer_plug.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ defmodule BuildelWeb.ErrorRendererPlug do
|> send_resp(422, json)
end

defp add_error(errors, [], error) do
Map.update(errors, :global, [to_string(error)], &(&1 ++ [to_string(error)]))
end

defp add_error(errors, [path], error) do
Map.update(errors, path, [to_string(error)], &(&1 ++ [to_string(error)]))
end
Expand Down
46 changes: 42 additions & 4 deletions apps/api/lib/buildel_web/schemas/users.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule BuildelWeb.Schemas.Users do
title: "User",
type: :object,
properties: %{
id: %Schema{type: :integer, description: "User ID"},
id: %Schema{type: :integer, description: "User ID"}
},
required: [:id]
})
Expand Down Expand Up @@ -36,7 +36,11 @@ defmodule BuildelWeb.Schemas.Users do
properties: %{
current_password: %Schema{type: :string, description: "Current password", minLength: 12},
password: %Schema{type: :string, description: "New password", minLength: 12},
password_confirmation: %Schema{type: :string, description: "New password confirmation", minLength: 12}
password_confirmation: %Schema{
type: :string,
description: "New password confirmation",
minLength: 12
}
},
required: [:current_password, :password, :password_confirmation]
})
Expand All @@ -49,7 +53,12 @@ defmodule BuildelWeb.Schemas.Users do
title: "UserCreateForgotPasswordRequest",
type: :object,
properties: %{
email: %Schema{type: :string, description: "User email", pattern: ~r/@/},
email: %Schema{
type: :string,
description: "User email",
pattern: ~r/^[^\s]+@[^\s]+$/,
example: "[email protected]"
}
},
required: [:email]
})
Expand All @@ -64,9 +73,38 @@ defmodule BuildelWeb.Schemas.Users do
properties: %{
token: %Schema{type: :string, description: "Token"},
password: %Schema{type: :string, description: "New password", minLength: 12},
password_confirmation: %Schema{type: :string, description: "New password confirmation", minLength: 12},
password_confirmation: %Schema{
type: :string,
description: "New password confirmation",
minLength: 12
}
},
required: [:token, :password, :password_confirmation]
})
end

defmodule CreateRegistrationRequest do
require OpenApiSpex

OpenApiSpex.schema(%{
title: "UserCreateRegistrationRequest",
type: :object,
properties: %{
user: %Schema{
type: :object,
properties: %{
email: %Schema{
type: :string,
description: "Email",
pattern: ~r/^[^\s]+@[^\s]+$/,
example: "[email protected]"
},
password: %Schema{type: :string, description: "Password", minLength: 12}
},
required: [:email, :password]
}
},
required: [:user]
})
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@ defmodule BuildelWeb.UserRegistrationControllerTest do

import Buildel.AccountsFixtures

setup %{conn: conn} do
{:ok,
conn:
put_req_header(conn, "accept", "application/json")
|> put_req_header("content-type", "application/json")}
end

describe "POST /api/users/register" do
@tag :capture_log
test "creates account and logs the user in", %{conn: conn} do
test "creates account and logs the user in", %{conn: conn, api_spec: api_spec} do
email = unique_user_email()

conn =
post(conn, ~p"/api/users/register", %{
"user" => valid_user_attributes(email: email)
})

response = json_response(conn, 201)
assert_schema(response, "UserShowResponse", api_spec)

assert get_session(conn, :user_token)
conn = get(conn, ~p"/api/users/me")
json_response(conn, 200)
Expand All @@ -27,8 +37,8 @@ defmodule BuildelWeb.UserRegistrationControllerTest do
assert json_response(conn, 422) == %{
"errors" => %{
"user" => %{
"email" => ["has invalid format"],
"password" => ["should be at least 12 character(s)"]
"email" => ["Invalid format. Expected ~r/^[^\\s]+@[^\\s]+$/"],
"password" => ["String length is smaller than minLength: 12"]
}
}
}
Expand All @@ -47,9 +57,13 @@ defmodule BuildelWeb.UserRegistrationControllerTest do
json_response(conn, 200)

conn =
post(conn, ~p"/api/users/register", %{
"user" => valid_user_attributes(email: email)
})
post(
build_conn() |> put_req_header("content-type", "application/json"),
~p"/api/users/register",
%{
"user" => valid_user_attributes(email: email)
}
)

assert json_response(conn, 422) == %{
"errors" => %{
Expand Down

0 comments on commit da7311a

Please sign in to comment.