user settings updated to lv and lv tests created. all tests working
This commit is contained in:
parent
24502e2667
commit
ef7b8e0bb8
26 changed files with 389 additions and 288 deletions
|
@ -172,10 +172,10 @@ defmodule Bones73k.Accounts do
|
|||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def apply_user_email(user, password, attrs) do
|
||||
def apply_user_email(user, %{"current_password" => curr_pw} = attrs) do
|
||||
user
|
||||
|> User.email_changeset(attrs)
|
||||
|> User.validate_current_password(password)
|
||||
|> User.validate_current_password(curr_pw)
|
||||
|> Ecto.Changeset.apply_action(:update)
|
||||
end
|
||||
|
||||
|
@ -247,11 +247,11 @@ defmodule Bones73k.Accounts do
|
|||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_user_password(user, password, attrs) do
|
||||
def update_user_password(user, %{"current_password" => curr_pw} = attrs) do
|
||||
changeset =
|
||||
user
|
||||
|> User.password_changeset(attrs)
|
||||
|> User.validate_current_password(password)
|
||||
|> User.validate_current_password(curr_pw)
|
||||
|
||||
Ecto.Multi.new()
|
||||
|> Ecto.Multi.update(:user, changeset)
|
||||
|
|
|
@ -35,10 +35,6 @@ defmodule Bones73kWeb.UserAuth do
|
|||
|> put_session(:user_token, token)
|
||||
|> put_session(:live_socket_id, "users_sessions:#{Base.url_encode64(token)}")
|
||||
|> maybe_write_remember_me_cookie(token, params)
|
||||
|> put_flash(
|
||||
:info,
|
||||
raw("Welcome back, #{user.email} — you were logged in successfuly.")
|
||||
)
|
||||
|> redirect(to: get_session(conn, :user_return_to) || signed_in_path(conn))
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule Bones73kWeb.UserSessionController do
|
||||
use Bones73kWeb, :controller
|
||||
|
||||
alias Phoenix.HTML
|
||||
alias Bones73k.Accounts
|
||||
alias Bones73k.Accounts.User
|
||||
alias Bones73kWeb.UserAuth
|
||||
|
@ -11,7 +12,12 @@ defmodule Bones73kWeb.UserSessionController do
|
|||
|
||||
def create(conn, %{"user" => %{"email" => email, "password" => password} = user_params}) do
|
||||
if user = Accounts.get_user_by_email_and_password(email, password) do
|
||||
UserAuth.log_in_user(conn, user, user_params)
|
||||
conn
|
||||
|> put_flash(
|
||||
:info,
|
||||
HTML.raw("Welcome back, #{user.email} — you were logged in successfuly.")
|
||||
)
|
||||
|> UserAuth.log_in_user(user, user_params)
|
||||
else
|
||||
render(conn, "new.html", error_message: "Invalid email or password")
|
||||
end
|
||||
|
|
|
@ -2,36 +2,6 @@ defmodule Bones73kWeb.UserSettingsController do
|
|||
use Bones73kWeb, :controller
|
||||
|
||||
alias Bones73k.Accounts
|
||||
alias Bones73kWeb.UserAuth
|
||||
|
||||
plug(:assign_email_and_password_changesets)
|
||||
|
||||
def edit(conn, _params) do
|
||||
render(conn, "edit.html")
|
||||
end
|
||||
|
||||
def update_email(conn, %{"current_password" => password, "user" => user_params}) do
|
||||
user = conn.assigns.current_user
|
||||
|
||||
case Accounts.apply_user_email(user, password, user_params) do
|
||||
{:ok, applied_user} ->
|
||||
Accounts.deliver_update_email_instructions(
|
||||
applied_user,
|
||||
user.email,
|
||||
&Routes.user_settings_url(conn, :confirm_email, &1)
|
||||
)
|
||||
|
||||
conn
|
||||
|> put_flash(
|
||||
:info,
|
||||
"A link to confirm your email change has been sent to the new address."
|
||||
)
|
||||
|> redirect(to: Routes.user_settings_path(conn, :edit))
|
||||
|
||||
{:error, changeset} ->
|
||||
render(conn, "edit.html", email_changeset: changeset)
|
||||
end
|
||||
end
|
||||
|
||||
def confirm_email(conn, %{"token" => token}) do
|
||||
case Accounts.update_user_email(conn.assigns.current_user, token) do
|
||||
|
@ -46,27 +16,4 @@ defmodule Bones73kWeb.UserSettingsController do
|
|||
|> redirect(to: Routes.user_settings_path(conn, :edit))
|
||||
end
|
||||
end
|
||||
|
||||
def update_password(conn, %{"current_password" => password, "user" => user_params}) do
|
||||
user = conn.assigns.current_user
|
||||
|
||||
case Accounts.update_user_password(user, password, user_params) do
|
||||
{:ok, user} ->
|
||||
conn
|
||||
|> put_flash(:info, "Password updated successfully.")
|
||||
|> put_session(:user_return_to, Routes.user_settings_path(conn, :edit))
|
||||
|> UserAuth.log_in_user(user)
|
||||
|
||||
{:error, changeset} ->
|
||||
render(conn, "edit.html", password_changeset: changeset)
|
||||
end
|
||||
end
|
||||
|
||||
defp assign_email_and_password_changesets(conn, _opts) do
|
||||
user = conn.assigns.current_user
|
||||
|
||||
conn
|
||||
|> assign(:email_changeset, Accounts.change_user_email(user))
|
||||
|> assign(:password_changeset, Accounts.change_user_password(user))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,12 +4,6 @@ defmodule Bones73kWeb.UserLive.Registration do
|
|||
alias Bones73k.Accounts
|
||||
alias Bones73k.Accounts.User
|
||||
|
||||
@messages [
|
||||
success: "Welcome! New accout created.",
|
||||
info:
|
||||
"Some features may be unavailable until you confirm your email. Check your inbox for instructions."
|
||||
]
|
||||
|
||||
@impl true
|
||||
def mount(_params, session, socket) do
|
||||
socket
|
||||
|
@ -25,7 +19,11 @@ defmodule Bones73kWeb.UserLive.Registration do
|
|||
%{
|
||||
user_id: nil,
|
||||
user_return_to: Map.get(session, "user_return_to", "/"),
|
||||
messages: @messages
|
||||
messages: [
|
||||
success: "Welcome! Your new account has been created, and you've been logged in.",
|
||||
info:
|
||||
"Some features may be unavailable until you confirm your email address. Check your inbox for instructions."
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ defmodule Bones73kWeb.UserLive.ResetPassword do
|
|||
{:ok, _} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:success, "Password reset successfully.")
|
||||
|> put_flash(:info, "Password reset successfully.")
|
||||
|> redirect(to: Routes.user_session_path(socket, :new))}
|
||||
|
||||
{:error, changeset} ->
|
||||
|
|
39
lib/bones73k_web/live/user/settings.ex
Normal file
39
lib/bones73k_web/live/user/settings.ex
Normal file
|
@ -0,0 +1,39 @@
|
|||
defmodule Bones73kWeb.UserLive.Settings do
|
||||
use Bones73kWeb, :live_view
|
||||
|
||||
alias Bones73k.Accounts.User
|
||||
|
||||
@impl true
|
||||
def mount(_params, session, socket) do
|
||||
socket
|
||||
|> assign_defaults(session)
|
||||
|> alert_email_verified?()
|
||||
|> live_okreply()
|
||||
end
|
||||
|
||||
defp alert_email_verified?(socket) do
|
||||
case socket.assigns.current_user do
|
||||
%{confirmed_at: nil} ->
|
||||
put_flash(socket, :warning, [
|
||||
"Your email hasn't been confirmed, some areas may be restricted. Shall we ",
|
||||
link("resend the verification email?",
|
||||
to: Routes.user_confirmation_path(socket, :new),
|
||||
class: "alert-link"
|
||||
)
|
||||
])
|
||||
|
||||
_ ->
|
||||
socket
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:put_flash_message, {flash_type, msg}}, socket) do
|
||||
socket |> put_flash(flash_type, msg) |> live_noreply()
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({:clear_flash_message, flash_type}, socket) do
|
||||
socket |> clear_flash(flash_type) |> live_noreply()
|
||||
end
|
||||
end
|
9
lib/bones73k_web/live/user/settings.html.leex
Normal file
9
lib/bones73k_web/live/user/settings.html.leex
Normal file
|
@ -0,0 +1,9 @@
|
|||
<h3 class="mb-3">
|
||||
<%= icon_div @socket, "bi-sliders", [class: "icon baseline"] %>
|
||||
User Settings
|
||||
</h3>
|
||||
|
||||
<div class="row">
|
||||
<%= live_component @socket, Bones73kWeb.UserLive.Settings.Email, id: "email-#{@current_user.id}", current_user: @current_user %>
|
||||
<%= live_component @socket, Bones73kWeb.UserLive.Settings.Password, id: "password-#{@current_user.id}", current_user: @current_user %>
|
||||
</div>
|
62
lib/bones73k_web/live/user/settings/email.ex
Normal file
62
lib/bones73k_web/live/user/settings/email.ex
Normal file
|
@ -0,0 +1,62 @@
|
|||
defmodule Bones73kWeb.UserLive.Settings.Email do
|
||||
use Bones73kWeb, :live_component
|
||||
|
||||
alias Bones73k.Accounts
|
||||
alias Bones73k.Accounts.User
|
||||
|
||||
@impl true
|
||||
def update(%{current_user: user} = assigns, socket) do
|
||||
socket
|
||||
|> assign(id: assigns.id)
|
||||
|> assign(current_user: user)
|
||||
|> assign(changeset: get_changeset(user))
|
||||
|> live_okreply()
|
||||
end
|
||||
|
||||
defp get_changeset(user, user_params \\ %{}) do
|
||||
Accounts.change_user_email(user, user_params)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("validate", %{"user" => user_params}, socket) do
|
||||
cs = get_changeset(socket.assigns.current_user, user_params)
|
||||
{:noreply, assign(socket, changeset: %{cs | action: :update})}
|
||||
end
|
||||
|
||||
# user_settings_path GET /users/settings/confirm_email/:token Bones73kWeb.UserSettingsController :confirm_email
|
||||
|
||||
@impl true
|
||||
def handle_event("save", %{"user" => user_params}, socket) do
|
||||
case Accounts.apply_user_email(socket.assigns.current_user, user_params) do
|
||||
{:ok, applied_user} ->
|
||||
Accounts.deliver_update_email_instructions(
|
||||
applied_user,
|
||||
socket.assigns.current_user.email,
|
||||
&Routes.user_settings_url(socket, :confirm_email, &1)
|
||||
)
|
||||
|
||||
send(self(), {:clear_flash_message, :error})
|
||||
|
||||
send(
|
||||
self(),
|
||||
{:put_flash_message,
|
||||
{:info, "A link to confirm your e-mail change has been sent to the new address."}}
|
||||
)
|
||||
|
||||
socket
|
||||
|> assign(changeset: get_changeset(socket.assigns.current_user))
|
||||
|> live_noreply()
|
||||
|
||||
{:error, cs} ->
|
||||
cu = socket.assigns.current_user
|
||||
cpw = user_params["current_password"]
|
||||
valid_password? = User.valid_password?(cu, cpw)
|
||||
msg = (valid_password? && "Could not reset email.") || "Invalid current password."
|
||||
send(self(), {:put_flash_message, {:error, msg}})
|
||||
|
||||
socket
|
||||
|> assign(changeset: cs)
|
||||
|> live_noreply()
|
||||
end
|
||||
end
|
||||
end
|
51
lib/bones73k_web/live/user/settings/email.html.leex
Normal file
51
lib/bones73k_web/live/user/settings/email.html.leex
Normal file
|
@ -0,0 +1,51 @@
|
|||
<div id="<%= @id %>" class="col-sm-9 col-md-7 col-lg-5 col-xl-4 mt-1">
|
||||
|
||||
<h4>Change email</h4>
|
||||
|
||||
<%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, phx_target: @myself], fn f -> %>
|
||||
|
||||
<div class="mb-3" phx-feedback-for="<%= input_id(f, :email) %>">
|
||||
<%= label f, :email, class: "form-label" %>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text">
|
||||
<%= icon_div @socket, "bi-at", [class: "icon fs-5"] %>
|
||||
</span>
|
||||
<%= email_input f, :email,
|
||||
value: input_value(f, :email),
|
||||
class: input_class(f, :email, "form-control"),
|
||||
placeholder: "e.g., babka@73k.us",
|
||||
maxlength: User.max_email,
|
||||
phx_debounce: "600",
|
||||
aria_describedby: error_id(f, :email)
|
||||
%>
|
||||
<%= error_tag f, :email %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-3" phx-feedback-for="<%= input_id(f, :current_password) %>">
|
||||
<%= label f, :current_password, class: "form-label" %>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">
|
||||
<%= icon_div @socket, "bi-lock", [class: "icon fs-5"] %>
|
||||
</span>
|
||||
<%= password_input f, :current_password,
|
||||
class: "form-control",
|
||||
required: true,
|
||||
aria_describedby: error_id(f, :current_password)
|
||||
%>
|
||||
<%= error_tag f, :current_password %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= submit "Change email",
|
||||
disabled: !@changeset.valid? || input_value(f, :current_password) == "",
|
||||
class: "btn btn-primary",
|
||||
phx_disable_with: "Saving..."
|
||||
%>
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
|
||||
</div>
|
57
lib/bones73k_web/live/user/settings/password.ex
Normal file
57
lib/bones73k_web/live/user/settings/password.ex
Normal file
|
@ -0,0 +1,57 @@
|
|||
defmodule Bones73kWeb.UserLive.Settings.Password do
|
||||
use Bones73kWeb, :live_component
|
||||
|
||||
alias Bones73k.Accounts
|
||||
alias Bones73k.Accounts.User
|
||||
|
||||
@impl true
|
||||
def update(%{current_user: user} = assigns, socket) do
|
||||
socket
|
||||
|> assign(id: assigns.id)
|
||||
|> assign(current_user: user)
|
||||
|> assign(changeset: get_changeset(user))
|
||||
|> assign(login_params: init_login_params(socket))
|
||||
|> assign(trigger_submit: false)
|
||||
|> live_okreply()
|
||||
end
|
||||
|
||||
defp get_changeset(user, user_params \\ %{}) do
|
||||
Accounts.change_user_password(user, user_params)
|
||||
end
|
||||
|
||||
defp init_login_params(socket) do
|
||||
%{
|
||||
user_id: nil,
|
||||
user_return_to: Routes.user_settings_path(socket, :edit),
|
||||
messages: [info: "Password updated successfully."]
|
||||
}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("validate", %{"user" => user_params}, socket) do
|
||||
cs = get_changeset(socket.assigns.current_user, user_params)
|
||||
{:noreply, assign(socket, changeset: %{cs | action: :update})}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("save", %{"user" => user_params}, socket) do
|
||||
case Accounts.update_user_password(socket.assigns.current_user, user_params) do
|
||||
{:ok, user} ->
|
||||
socket
|
||||
|> assign(login_params: %{socket.assigns.login_params | user_id: user.id})
|
||||
|> assign(trigger_submit: true)
|
||||
|> live_noreply()
|
||||
|
||||
{:error, cs} ->
|
||||
cu = socket.assigns.current_user
|
||||
cpw = user_params["current_password"]
|
||||
valid_password? = User.valid_password?(cu, cpw)
|
||||
msg = (valid_password? && "Could not change password.") || "Invalid current password."
|
||||
send(self(), {:put_flash_message, {:error, msg}})
|
||||
|
||||
socket
|
||||
|> assign(changeset: cs)
|
||||
|> live_noreply()
|
||||
end
|
||||
end
|
||||
end
|
76
lib/bones73k_web/live/user/settings/password.html.leex
Normal file
76
lib/bones73k_web/live/user/settings/password.html.leex
Normal file
|
@ -0,0 +1,76 @@
|
|||
<div id="<%= @id %>" class="col-sm-9 col-md-7 col-lg-5 col-xl-4 mt-1">
|
||||
|
||||
<h4>Change password</h4>
|
||||
|
||||
<%= form_for @changeset, "#", [phx_change: :validate, phx_submit: :save, phx_target: @myself], fn f -> %>
|
||||
|
||||
<div class="mb-3" phx-feedback-for="<%= input_id(f, :password) %>">
|
||||
<%= label f, :password, "New password", class: "form-label" %>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text">
|
||||
<%= icon_div @socket, "bi-key", [class: "icon fs-5"] %>
|
||||
</span>
|
||||
<%= password_input f, :password,
|
||||
value: input_value(f, :password),
|
||||
class: input_class(f, :password, "form-control"),
|
||||
maxlength: User.max_password,
|
||||
phx_debounce: "600",
|
||||
aria_describedby: error_id(f, :password)
|
||||
%>
|
||||
<%= error_tag f, :password %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3" phx-feedback-for="<%= input_id(f, :password_confirmation) %>">
|
||||
<%= label f, :password_confirmation, "Confirm new password", class: "form-label" %>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text">
|
||||
<%= icon_div @socket, "bi-key-fill", [class: "icon fs-5"] %>
|
||||
</span>
|
||||
<%= password_input f, :password_confirmation,
|
||||
value: input_value(f, :password_confirmation),
|
||||
class: input_class(f, :password_confirmation, "form-control"),
|
||||
maxlength: User.max_password,
|
||||
aria_describedby: error_id(f, :password_confirmation)
|
||||
%>
|
||||
<%= error_tag f, :password_confirmation %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3" phx-feedback-for="<%= input_id(f, :current_password) %>">
|
||||
<%= label f, :current_password, class: "form-label" %>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">
|
||||
<%= icon_div @socket, "bi-lock", [class: "icon fs-5"] %>
|
||||
</span>
|
||||
<%= password_input f, :current_password,
|
||||
class: "form-control",
|
||||
required: true,
|
||||
aria_describedby: error_id(f, :current_password)
|
||||
%>
|
||||
<%= error_tag f, :current_password %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= submit "Change password",
|
||||
disabled: !@changeset.valid? || input_value(f, :current_password) == "",
|
||||
class: "btn btn-primary",
|
||||
phx_disable_with: "Saving..."
|
||||
%>
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
|
||||
<%# hidden form for initial login after registration %>
|
||||
<%= form_for :user, Routes.user_session_path(@socket, :create), [phx_trigger_action: @trigger_submit, id: "settings_pw_change_trigger"], fn f -> %>
|
||||
<%= hidden_input f, :params_token, value: Phoenix.Token.encrypt(Bones73kWeb.Endpoint, "login_params", @login_params) %>
|
||||
<% end %>
|
||||
|
||||
<%# hidden form to submit user for relogin after password change %>
|
||||
<%#= form_for :user_login, Routes.user_session_path(@socket, :create), [phx_trigger_action: @trigger_submit], fn f -> %>
|
||||
<%#= hidden_input f, :login_params_token, value: Phoenix.Token.encrypt(Bones73kWeb.Endpoint, "login_params", @login_params) %>
|
||||
<%#= hidden_input f, :remember_me, value: false %>
|
||||
<%# end %>
|
||||
|
||||
</div>
|
|
@ -72,13 +72,9 @@ defmodule Bones73kWeb.Router do
|
|||
pipe_through([:browser, :require_authenticated_user])
|
||||
|
||||
# # liveview user settings
|
||||
# live "/users/settings", UserLive.Settings, :edit
|
||||
live "/users/settings", UserLive.Settings, :edit
|
||||
|
||||
# original user routes from phx.gen.auth
|
||||
# TODO:
|
||||
get("/users/settings", UserSettingsController, :edit)
|
||||
put("/users/settings/update_password", UserSettingsController, :update_password)
|
||||
put("/users/settings/update_email", UserSettingsController, :update_email)
|
||||
get("/users/settings/confirm_email/:token", UserSettingsController, :confirm_email)
|
||||
end
|
||||
|
||||
|
@ -86,7 +82,6 @@ defmodule Bones73kWeb.Router do
|
|||
pipe_through([:browser])
|
||||
|
||||
delete("/users/log_out", UserSessionController, :delete)
|
||||
# TODO: understanding/testing force_logout?
|
||||
get("/users/force_logout", UserSessionController, :force_logout)
|
||||
get("/users/confirm", UserConfirmationController, :new)
|
||||
post("/users/confirm", UserConfirmationController, :create)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<%# phoenix flash alerts: %>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-11 col-lg-9 col-xl-8 ">
|
||||
<div class="col-md-12 col-lg-10 col-xl-9 ">
|
||||
<%= for {kind, color} <- alert_kinds() do %>
|
||||
<%= if flash_content = get_flash(@conn, kind) do %>
|
||||
<div class="alert alert-<%= color %> alert-dismissible fade show" role="alert">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<%# liveview flash alerts: %>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-11 col-lg-9 col-xl-8 ">
|
||||
<div class="col-md-12 col-lg-10 col-xl-9 ">
|
||||
<%= for {kind, color} <- alert_kinds() do %>
|
||||
<%= if flash_content = live_flash(@flash, kind) do %>
|
||||
<div class="alert alert-<%= color %> alert-dismissible fade show" role="alert" id="lv-alert-<%= kind %>" phx-hook="AlertRemover" data-key="<%= kind %>">
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
<h1>Settings</h1>
|
||||
|
||||
<h3>Change email</h3>
|
||||
|
||||
<%= form_for @email_changeset, Routes.user_settings_path(@conn, :update_email), fn f -> %>
|
||||
<%= if @email_changeset.action do %>
|
||||
<div class="alert alert-danger">
|
||||
<p>Oops, something went wrong! Please check the errors below.</p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= label f, :email %>
|
||||
<%= email_input f, :email, required: true %>
|
||||
<%= error_tag f, :email %>
|
||||
|
||||
<%= label f, :current_password, for: "current_password_for_email" %>
|
||||
<%= password_input f, :current_password, required: true, name: "current_password", id: "current_password_for_email" %>
|
||||
<%= error_tag f, :current_password %>
|
||||
|
||||
<div>
|
||||
<%= submit "Change email" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<h3>Change password</h3>
|
||||
|
||||
<%= form_for @password_changeset, Routes.user_settings_path(@conn, :update_password), fn f -> %>
|
||||
<%= if @password_changeset.action do %>
|
||||
<div class="alert alert-danger">
|
||||
<p>Oops, something went wrong! Please check the errors below.</p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= label f, :password, "New password" %>
|
||||
<%= password_input f, :password, required: true %>
|
||||
<%= error_tag f, :password %>
|
||||
|
||||
<%= label f, :password_confirmation, "Confirm new password" %>
|
||||
<%= password_input f, :password_confirmation, required: true %>
|
||||
<%= error_tag f, :password_confirmation %>
|
||||
|
||||
<%= label f, :current_password, for: "current_password_for_password" %>
|
||||
<%= password_input f, :current_password, required: true, name: "current_password", id: "current_password_for_password" %>
|
||||
<%= error_tag f, :current_password %>
|
||||
|
||||
<div>
|
||||
<%= submit "Change password" %>
|
||||
</div>
|
||||
<% end %>
|
|
@ -1,3 +0,0 @@
|
|||
defmodule Bones73kWeb.UserSettingsView do
|
||||
use Bones73kWeb, :view
|
||||
end
|
|
@ -58,19 +58,19 @@ defmodule Bones73k.AccountsTest do
|
|||
end
|
||||
|
||||
test "validates email and password when given" do
|
||||
{:error, changeset} = Accounts.register_user(%{email: "not valid", password: "not valid"})
|
||||
|
||||
assert %{
|
||||
email: ["must have the @ sign and no spaces"],
|
||||
password: ["should be at least 12 character(s)"]
|
||||
} = errors_on(changeset)
|
||||
{:error, changeset} = Accounts.register_user(%{email: "not valid", password: "2shrt"})
|
||||
pw_err = "should be at least #{User.min_password()} character(s)"
|
||||
assert "must be a valid email address" in errors_on(changeset).email
|
||||
assert pw_err in errors_on(changeset).password
|
||||
end
|
||||
|
||||
test "validates maximum values for email and password for security" do
|
||||
too_long = String.duplicate("db", 100)
|
||||
too_long = "#{String.duplicate("db", 300)}@example.com"
|
||||
{:error, changeset} = Accounts.register_user(%{email: too_long, password: too_long})
|
||||
assert "should be at most 160 character(s)" in errors_on(changeset).email
|
||||
assert "should be at most 80 character(s)" in errors_on(changeset).password
|
||||
em_err = "should be at most #{User.max_email()} character(s)"
|
||||
pw_err = "should be at most #{User.max_password()} character(s)"
|
||||
assert em_err in errors_on(changeset).email
|
||||
assert pw_err in errors_on(changeset).password
|
||||
end
|
||||
|
||||
test "validates email uniqueness" do
|
||||
|
@ -92,16 +92,22 @@ defmodule Bones73k.AccountsTest do
|
|||
assert is_nil(user.password)
|
||||
assert user.role == :user
|
||||
end
|
||||
end
|
||||
|
||||
describe "register_admin/1" do
|
||||
test "registers users with a hashed password and sets role to :admin" do
|
||||
test "registers different role :manager and sets role to :manager" do
|
||||
email = unique_user_email()
|
||||
{:ok, user} = Accounts.register_admin(%{email: email, password: valid_user_password()})
|
||||
attrs = %{email: email, role: :manager, password: valid_user_password()}
|
||||
{:ok, user} = Accounts.register_user(attrs)
|
||||
assert user.email == email
|
||||
assert is_binary(user.hashed_password)
|
||||
assert is_nil(user.confirmed_at)
|
||||
assert is_nil(user.password)
|
||||
assert user.role == :manager
|
||||
end
|
||||
|
||||
test "registers different role :admin and sets role to :admin" do
|
||||
email = unique_user_email()
|
||||
attrs = %{email: email, role: :admin, password: valid_user_password()}
|
||||
{:ok, user} = Accounts.register_user(attrs)
|
||||
assert user.role == :admin
|
||||
end
|
||||
end
|
||||
|
@ -109,7 +115,7 @@ defmodule Bones73k.AccountsTest do
|
|||
describe "change_user_registration/2" do
|
||||
test "returns a changeset" do
|
||||
assert %Ecto.Changeset{} = changeset = Accounts.change_user_registration(%User{})
|
||||
assert changeset.required == [:password, :email]
|
||||
assert changeset.required == [:password, :email, :role]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -126,45 +132,42 @@ defmodule Bones73k.AccountsTest do
|
|||
end
|
||||
|
||||
test "requires email to change", %{user: user} do
|
||||
{:error, changeset} = Accounts.apply_user_email(user, valid_user_password(), %{})
|
||||
attrs = %{"current_password" => valid_user_password()}
|
||||
{:error, changeset} = Accounts.apply_user_email(user, attrs)
|
||||
assert %{email: ["did not change"]} = errors_on(changeset)
|
||||
end
|
||||
|
||||
test "validates email", %{user: user} do
|
||||
{:error, changeset} =
|
||||
Accounts.apply_user_email(user, valid_user_password(), %{email: "not valid"})
|
||||
|
||||
assert %{email: ["must have the @ sign and no spaces"]} = errors_on(changeset)
|
||||
attrs = %{"current_password" => valid_user_password(), "email" => "not valid"}
|
||||
{:error, changeset} = Accounts.apply_user_email(user, attrs)
|
||||
assert %{email: ["must be a valid email address"]} = errors_on(changeset)
|
||||
end
|
||||
|
||||
test "validates maximum value for email for security", %{user: user} do
|
||||
too_long = String.duplicate("db", 100)
|
||||
|
||||
{:error, changeset} =
|
||||
Accounts.apply_user_email(user, valid_user_password(), %{email: too_long})
|
||||
|
||||
assert "should be at most 160 character(s)" in errors_on(changeset).email
|
||||
too_long = "#{String.duplicate("db", 300)}@example.com"
|
||||
attrs = %{"current_password" => valid_user_password(), "email" => too_long}
|
||||
{:error, changeset} = Accounts.apply_user_email(user, attrs)
|
||||
em_err = "should be at most #{User.max_email()} character(s)"
|
||||
assert em_err in errors_on(changeset).email
|
||||
end
|
||||
|
||||
test "validates email uniqueness", %{user: user} do
|
||||
%{email: email} = user_fixture()
|
||||
|
||||
{:error, changeset} =
|
||||
Accounts.apply_user_email(user, valid_user_password(), %{email: email})
|
||||
|
||||
attrs = %{"current_password" => valid_user_password(), "email" => email}
|
||||
{:error, changeset} = Accounts.apply_user_email(user, attrs)
|
||||
assert "has already been taken" in errors_on(changeset).email
|
||||
end
|
||||
|
||||
test "validates current password", %{user: user} do
|
||||
{:error, changeset} =
|
||||
Accounts.apply_user_email(user, "invalid", %{email: unique_user_email()})
|
||||
|
||||
attrs = %{"current_password" => "invalid", "email" => unique_user_email()}
|
||||
{:error, changeset} = Accounts.apply_user_email(user, attrs)
|
||||
assert %{current_password: ["is not valid"]} = errors_on(changeset)
|
||||
end
|
||||
|
||||
test "applies the email without persisting it", %{user: user} do
|
||||
email = unique_user_email()
|
||||
{:ok, user} = Accounts.apply_user_email(user, valid_user_password(), %{email: email})
|
||||
attrs = %{"current_password" => valid_user_password(), "email" => email}
|
||||
{:ok, user} = Accounts.apply_user_email(user, attrs)
|
||||
assert user.email == email
|
||||
assert Accounts.get_user!(user.id).email != email
|
||||
end
|
||||
|
@ -245,52 +248,47 @@ defmodule Bones73k.AccountsTest do
|
|||
end
|
||||
|
||||
test "validates password", %{user: user} do
|
||||
{:error, changeset} =
|
||||
Accounts.update_user_password(user, valid_user_password(), %{
|
||||
password: "not valid",
|
||||
password_confirmation: "another"
|
||||
})
|
||||
attrs = %{
|
||||
"current_password" => valid_user_password(),
|
||||
"password" => "2shrt",
|
||||
"password_confirmation" => "another"
|
||||
}
|
||||
|
||||
assert %{
|
||||
password: ["should be at least 12 character(s)"],
|
||||
password_confirmation: ["does not match password"]
|
||||
} = errors_on(changeset)
|
||||
{:error, changeset} = Accounts.update_user_password(user, attrs)
|
||||
pw_err = "should be at least #{User.min_password()} character(s)"
|
||||
conf_err = "does not match password"
|
||||
assert pw_err in errors_on(changeset).password
|
||||
assert conf_err in errors_on(changeset).password_confirmation
|
||||
end
|
||||
|
||||
test "validates maximum values for password for security", %{user: user} do
|
||||
too_long = String.duplicate("db", 100)
|
||||
attrs = %{
|
||||
"current_password" => valid_user_password(),
|
||||
"password" => String.duplicate("db", 100)
|
||||
}
|
||||
|
||||
{:error, changeset} =
|
||||
Accounts.update_user_password(user, valid_user_password(), %{password: too_long})
|
||||
|
||||
assert "should be at most 80 character(s)" in errors_on(changeset).password
|
||||
{:error, changeset} = Accounts.update_user_password(user, attrs)
|
||||
pw_err = "should be at most #{User.max_password()} character(s)"
|
||||
assert pw_err in errors_on(changeset).password
|
||||
end
|
||||
|
||||
test "validates current password", %{user: user} do
|
||||
{:error, changeset} =
|
||||
Accounts.update_user_password(user, "invalid", %{password: valid_user_password()})
|
||||
|
||||
attrs = %{"current_password" => "invalid", "password" => valid_user_password()}
|
||||
{:error, changeset} = Accounts.update_user_password(user, attrs)
|
||||
assert %{current_password: ["is not valid"]} = errors_on(changeset)
|
||||
end
|
||||
|
||||
test "updates the password", %{user: user} do
|
||||
{:ok, user} =
|
||||
Accounts.update_user_password(user, valid_user_password(), %{
|
||||
password: "new valid password"
|
||||
})
|
||||
|
||||
attrs = %{"current_password" => valid_user_password(), "password" => "new valid password"}
|
||||
{:ok, user} = Accounts.update_user_password(user, attrs)
|
||||
assert is_nil(user.password)
|
||||
assert Accounts.get_user_by_email_and_password(user.email, "new valid password")
|
||||
end
|
||||
|
||||
test "deletes all tokens for the given user", %{user: user} do
|
||||
_ = Accounts.generate_user_session_token(user)
|
||||
|
||||
{:ok, _} =
|
||||
Accounts.update_user_password(user, valid_user_password(), %{
|
||||
password: "new valid password"
|
||||
})
|
||||
|
||||
attrs = %{"current_password" => valid_user_password(), "password" => "new valid password"}
|
||||
{:ok, _} = Accounts.update_user_password(user, attrs)
|
||||
refute Repo.get_by(UserToken, user_id: user.id)
|
||||
end
|
||||
end
|
||||
|
@ -456,14 +454,13 @@ defmodule Bones73k.AccountsTest do
|
|||
test "validates password", %{user: user} do
|
||||
{:error, changeset} =
|
||||
Accounts.reset_user_password(user, %{
|
||||
password: "not valid",
|
||||
password: "2shrt",
|
||||
password_confirmation: "another"
|
||||
})
|
||||
|
||||
assert %{
|
||||
password: ["should be at least 12 character(s)"],
|
||||
password_confirmation: ["does not match password"]
|
||||
} = errors_on(changeset)
|
||||
pw_err = "should be at least #{User.min_password()} character(s)"
|
||||
assert pw_err in errors_on(changeset).password
|
||||
assert "does not match password" in errors_on(changeset).password_confirmation
|
||||
end
|
||||
|
||||
test "validates maximum values for password for security", %{user: user} do
|
||||
|
|
|
@ -13,7 +13,8 @@ defmodule Bones73kWeb.UserRegistrationControllerTest do
|
|||
end
|
||||
|
||||
test "redirects if already logged in", %{conn: conn} do
|
||||
conn = conn |> log_in_user(user_fixture()) |> get(Routes.user_registration_path(conn, :new))
|
||||
to = Routes.user_registration_path(conn, :new)
|
||||
conn = conn |> log_in_user(user_fixture()) |> get(to)
|
||||
assert redirected_to(conn) == "/"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,6 +15,12 @@ defmodule Bones73kWeb.UserResetPasswordControllerTest do
|
|||
response = html_response(conn, 200)
|
||||
assert response =~ "Forgot your password?\n </h3>"
|
||||
end
|
||||
|
||||
test "redirects if already logged in", %{conn: conn} do
|
||||
to = Routes.user_reset_password_path(conn, :new)
|
||||
conn = conn |> log_in_user(user_fixture()) |> get(to)
|
||||
assert redirected_to(conn) == "/"
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST /users/reset_password" do
|
||||
|
|
|
@ -10,7 +10,7 @@ defmodule Bones73kWeb.UserSettingsControllerTest do
|
|||
test "renders settings page", %{conn: conn} do
|
||||
conn = get(conn, Routes.user_settings_path(conn, :edit))
|
||||
response = html_response(conn, 200)
|
||||
assert response =~ "<h1>Settings</h1>"
|
||||
assert response =~ "User Settings\n</h3>"
|
||||
end
|
||||
|
||||
test "redirects if user is not logged in" do
|
||||
|
@ -20,71 +20,6 @@ defmodule Bones73kWeb.UserSettingsControllerTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "PUT /users/settings/update_password" do
|
||||
test "updates the user password and resets tokens", %{conn: conn, user: user} do
|
||||
new_password_conn =
|
||||
put(conn, Routes.user_settings_path(conn, :update_password), %{
|
||||
"current_password" => valid_user_password(),
|
||||
"user" => %{
|
||||
"password" => "new valid password",
|
||||
"password_confirmation" => "new valid password"
|
||||
}
|
||||
})
|
||||
|
||||
assert redirected_to(new_password_conn) == Routes.user_settings_path(conn, :edit)
|
||||
assert get_session(new_password_conn, :user_token) != get_session(conn, :user_token)
|
||||
assert get_flash(new_password_conn, :info) =~ "Password updated successfully"
|
||||
assert Accounts.get_user_by_email_and_password(user.email, "new valid password")
|
||||
end
|
||||
|
||||
test "does not update password on invalid data", %{conn: conn} do
|
||||
old_password_conn =
|
||||
put(conn, Routes.user_settings_path(conn, :update_password), %{
|
||||
"current_password" => "invalid",
|
||||
"user" => %{
|
||||
"password" => "too short",
|
||||
"password_confirmation" => "does not match"
|
||||
}
|
||||
})
|
||||
|
||||
response = html_response(old_password_conn, 200)
|
||||
assert response =~ "<h1>Settings</h1>"
|
||||
assert response =~ "should be at least 12 character(s)"
|
||||
assert response =~ "does not match password"
|
||||
assert response =~ "is not valid"
|
||||
|
||||
assert get_session(old_password_conn, :user_token) == get_session(conn, :user_token)
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT /users/settings/update_email" do
|
||||
@tag :capture_log
|
||||
test "updates the user email", %{conn: conn, user: user} do
|
||||
conn =
|
||||
put(conn, Routes.user_settings_path(conn, :update_email), %{
|
||||
"current_password" => valid_user_password(),
|
||||
"user" => %{"email" => unique_user_email()}
|
||||
})
|
||||
|
||||
assert redirected_to(conn) == Routes.user_settings_path(conn, :edit)
|
||||
assert get_flash(conn, :info) =~ "A link to confirm your email"
|
||||
assert Accounts.get_user_by_email(user.email)
|
||||
end
|
||||
|
||||
test "does not update email on invalid data", %{conn: conn} do
|
||||
conn =
|
||||
put(conn, Routes.user_settings_path(conn, :update_email), %{
|
||||
"current_password" => "invalid",
|
||||
"user" => %{"email" => "with spaces"}
|
||||
})
|
||||
|
||||
response = html_response(conn, 200)
|
||||
assert response =~ "<h1>Settings</h1>"
|
||||
assert response =~ "must have the @ sign and no spaces"
|
||||
assert response =~ "is not valid"
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /users/settings/confirm_email/:token" do
|
||||
setup %{user: user} do
|
||||
email = unique_user_email()
|
||||
|
|
|
@ -52,9 +52,6 @@ defmodule Bones73kWeb.AdminDashboardLiveTest do
|
|||
assert "/" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert "/users/log_in" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert html_response(conn, 200) =~
|
||||
"You were logged out. Please login again to continue using our application."
|
||||
end
|
||||
|
|
|
@ -4,12 +4,6 @@ defmodule Bones73kWeb.PageLiveTest do
|
|||
import Phoenix.LiveViewTest
|
||||
import Bones73k.AccountsFixtures
|
||||
|
||||
test "disconnected and connected render without authentication should redirect to login page",
|
||||
%{conn: conn} do
|
||||
# If we don't previously log in we will be redirected to the login page
|
||||
assert {:error, {:redirect, %{to: "/users/log_in"}}} = live(conn, "/")
|
||||
end
|
||||
|
||||
test "disconnected and connected render with authentication should redirect to index page", %{
|
||||
conn: conn
|
||||
} do
|
||||
|
@ -44,9 +38,6 @@ defmodule Bones73kWeb.PageLiveTest do
|
|||
assert "/" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert "/users/log_in" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert html_response(conn, 200) =~
|
||||
"You were logged out. Please login again to continue using our application."
|
||||
end
|
||||
|
|
|
@ -188,16 +188,13 @@ defmodule Bones73kWeb.PropertyLiveTest do
|
|||
assert_receive {:DOWN, ^ref, _, _, _}
|
||||
refute Process.alive?(index_live.pid)
|
||||
|
||||
# Assert our liveview was redirected, following first to /users/force_logout, then to "/", and then to "/users/log_in"
|
||||
# Assert our liveview was redirected, following first to /users/force_logout, then to "/"
|
||||
assert_redirect(index_live, "/users/force_logout")
|
||||
|
||||
conn = get(conn, "/users/force_logout")
|
||||
assert "/" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert "/users/log_in" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert html_response(conn, 200) =~
|
||||
"You were logged out. Please login again to continue using our application."
|
||||
end
|
||||
|
@ -338,9 +335,6 @@ defmodule Bones73kWeb.PropertyLiveTest do
|
|||
assert "/" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert "/users/log_in" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert html_response(conn, 200) =~
|
||||
"You were logged out. Please login again to continue using our application."
|
||||
end
|
||||
|
|
|
@ -6,8 +6,7 @@ defmodule Bones73kWeb.UserLive.ResetPasswordTest do
|
|||
|
||||
alias Bones73k.Repo
|
||||
alias Bones73k.Accounts
|
||||
alias Bones73k.Accounts.User
|
||||
alias Bones73k.Accounts.UserToken
|
||||
alias Bones73k.Accounts.{User, UserToken}
|
||||
|
||||
setup %{conn: conn} do
|
||||
user = user_fixture()
|
||||
|
@ -46,7 +45,7 @@ defmodule Bones73kWeb.UserLive.ResetPasswordTest do
|
|||
|
||||
# Confirm redirected
|
||||
flash = assert_redirected(view, Routes.user_session_path(conn, :new))
|
||||
assert flash["success"] == "Password reset successfully."
|
||||
assert flash["info"] == "Password reset successfully."
|
||||
|
||||
# Confirm password was updated
|
||||
assert Accounts.get_user_by_email_and_password(user.email, new_pw)
|
||||
|
|
|
@ -54,9 +54,6 @@ defmodule Bones73kWeb.UserDashboardLiveTest do
|
|||
assert "/" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert "/users/log_in" = redir_path = redirected_to(conn, 302)
|
||||
conn = get(recycle(conn), redir_path)
|
||||
|
||||
assert html_response(conn, 200) =~
|
||||
"You were logged out. Please login again to continue using our application."
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue