Current section
Files
Jump to
Current section
Files
web/controllers/user_controller.ex
defmodule Shield.UserController do
use Shield.Web, :controller
alias Shield.Policy.User.ChangePassword, as: ChangePasswordPolicy
alias Shield.Policy.User.Confirm, as: ConfirmPolicy
alias Shield.Policy.User.Login, as: LoginPolicy
alias Shield.Policy.User.Logout, as: LogoutPolicy
alias Shield.Policy.User.RecoverPassword, as: RecoverPasswordPolicy
alias Shield.Policy.User.Register, as: RegisterPolicy
alias Shield.Policy.User.ResetPassword, as: ResetPasswordPolicy
@renderer Application.get_env(:authable, :renderer)
@views Application.get_env(:shield, :views)
@hooks Application.get_env(:shield, :hooks)
plug :scrub_params, "user" when action in [:register, :login]
plug Authable.Plug.Authenticate, [scopes: ~w(read)] when action in [:me]
plug Authable.Plug.Authenticate, [scopes: ~w(read write)] when action in [:logout]
plug Authable.Plug.Authenticate, [scopes: ~w(session read write)] when action in [:change_password]
plug Authable.Plug.UnauthorizedOnly when action in [:register, :login, :confirm, :recover_password, :reset_password]
plug Shield.Arm.Confirmable, [enabled: Application.get_env(:shield, :confirmable)] when action in [:me, :change_password]
# GET /users/me
def me(conn, _) do
conn
|> put_status(:ok)
|> render(@views[:user], "show.json", user: conn.assigns[:current_user])
end
# GET /users/confirm
def confirm(conn, %{"confirmation_token" => _} = user_params) do
case ConfirmPolicy.process(user_params) do
{:ok, res} ->
conn
|> @hooks.after_user_confirm_success({user_params, res})
|> @renderer.render(:ok, res)
{:error, {http_status_code, %Ecto.Changeset{} = errors} = res} ->
conn
|> @hooks.after_user_confirm_failure({user_params, res})
|> put_status(http_status_code)
|> render(@views[:changeset], "error.json", changeset: errors)
{:error, {http_status_code, errors} = res} ->
conn
|> @hooks.after_user_confirm_failure({user_params, res})
|> @renderer.render(http_status_code, %{errors: errors})
end
end
def confirm(conn, _) do
@renderer.render(conn, :unprocessable_entity, %{errors:
%{details: "Missing confirmation_token data!"}})
end
# POST /users/recover-password
def recover_password(conn, %{"user" => %{"email" => _} = user_params}) do
case RecoverPasswordPolicy.process(user_params) do
{:ok, %{"user" => user, "token" => token} = res} ->
conn
|> @hooks.after_user_recover_password_success({user_params, res})
|> assign(:current_user, user)
|> fetch_session
|> put_session(:session_token, token.value)
|> configure_session(renew: true)
|> put_status(:created)
|> render(@views[:user], "show.json", user: user)
{:error, {http_status_code, %Ecto.Changeset{} = errors} = res} ->
conn
|> @hooks.after_user_recover_password_failure({user_params, res})
|> put_status(http_status_code)
|> render(@views[:changeset], "error.json", changeset: errors)
{:error, {http_status_code, errors} = res} ->
conn
|> @hooks.after_user_recover_password_failure({user_params, res})
|> @renderer.render(http_status_code, %{errors: errors})
end
end
def recover_password(conn, _) do
@renderer.render(conn, :unprocessable_entity, %{errors:
%{details: "Missing email data!"}})
end
# POST /users/register
def register(conn, %{"user" => %{"email" => _, "password" => _} = user_params} = params) do
conn = @hooks.before_user_register(conn, params)
case RegisterPolicy.process(user_params) do
{:ok, %{"user" => user} = res} ->
conn
|> @hooks.after_user_register_success({user_params, res})
|> put_status(:created)
|> render(@views[:user], "show.json", user: user)
{:error, {http_status_code, %Ecto.Changeset{} = errors} = res} ->
conn
|> @hooks.after_user_login_failure({user_params, res})
|> put_status(http_status_code)
|> render(@views[:changeset], "error.json", changeset: errors)
{:error, {http_status_code, errors} = res} ->
conn
|> @hooks.after_user_register_failure({user_params, res})
|> @renderer.render(http_status_code, %{errors: errors})
end
end
def register(conn, _) do
@renderer.render(conn, :unprocessable_entity, %{errors:
%{details: "Missing email or password data!"}})
end
# POST /users/login
def login(conn, %{"user" => %{"email" => email, "password" => password} = user_params} = params) when is_binary(password) and is_binary(email) do
conn = @hooks.before_user_login(conn, params)
case LoginPolicy.process(user_params) do
{:ok, %{"user" => user, "token" => token} = res} ->
conn
|> @hooks.after_user_login_success({user_params, res})
|> assign(:current_user, user)
|> fetch_session
|> put_session(:session_token, token.value)
|> configure_session(renew: true)
|> put_status(:created)
|> render(@views[:user], "show.json", user: user)
{:error, {http_status_code, %Ecto.Changeset{} = errors} = res} ->
conn
|> @hooks.after_user_login_failure({user_params, res})
|> put_status(http_status_code)
|> render(@views[:changeset], "error.json", changeset: errors)
{:error, {http_status_code, errors} = res} ->
conn
|> @hooks.after_user_login_failure({user_params, res})
|> @renderer.render(http_status_code, %{errors: errors})
end
end
def login(conn, _) do
@renderer.render(conn, :unprocessable_entity, %{errors:
%{details: "Missing email or password data!"}})
end
# DELETE /users/logout
def logout(conn, _) do
token_value = get_session(fetch_session(conn), :session_token)
LogoutPolicy.process(%{"token_value" => token_value})
conn
|> fetch_session()
|> configure_session(drop: true)
|> send_resp(:no_content, "")
end
# POST /users/reset-password
def reset_password(conn, %{"user" => %{"password" => _, "reset_token" => _} = user_params}) do
case ResetPasswordPolicy.process(user_params) do
{:ok, res} ->
conn
|> @hooks.after_user_reset_password_success({user_params, res})
|> @renderer.render(:ok, %{messages: "Password updated!"})
{:error, {http_status_code, %Ecto.Changeset{} = errors} = res} ->
conn
|> @hooks.after_user_reset_password_failure({user_params, res})
|> put_status(http_status_code)
|> render(@views[:changeset], "error.json", changeset: errors)
{:error, {http_status_code, errors} = res} ->
conn
|> @hooks.after_user_reset_password_failure({user_params, res})
|> @renderer.render(http_status_code, %{errors: errors})
end
end
def reset_password(conn, _) do
@renderer.render(conn, :unprocessable_entity, %{errors:
%{details: "Missing password or reset_token data!"}})
end
# POST /users/change-password
def change_password(conn, %{"user" => %{"password" => _, "old_password" => _} = user_params}) do
params_with_user = Map.put(user_params, "user", conn.assigns[:current_user])
case ChangePasswordPolicy.process(params_with_user) do
{:ok, res} ->
conn
|> @hooks.after_user_change_password_success({user_params, res})
|> @renderer.render(:ok, %{messages: "Password updated!"})
{:error, {http_status_code, %Ecto.Changeset{} = errors} = res} ->
conn
|> @hooks.after_user_change_password_failure({user_params, res})
|> put_status(http_status_code)
|> render(@views[:changeset], "error.json", changeset: errors)
{:error, {http_status_code, errors} = res} ->
conn
|> @hooks.after_user_change_password_failure({user_params, res})
|> @renderer.render(http_status_code, %{errors: errors})
end
end
def change_password(conn, _) do
@renderer.render(conn, :unprocessable_entity, %{errors:
%{details: "Missing password or old_password data!"}})
end
end