mirror of
https://github.com/danbee/chess
synced 2025-03-04 08:39:06 +00:00
Add profile page to update name and email
* Also add ability to change password
This commit is contained in:
parent
344619ac4f
commit
bc5c6c4f04
@ -23,12 +23,26 @@ defmodule Chess.Store.User do
|
|||||||
@doc false
|
@doc false
|
||||||
def changeset(struct, params \\ %{}) do
|
def changeset(struct, params \\ %{}) do
|
||||||
struct
|
struct
|
||||||
|> cast(params, required_attrs())
|
|> cast(params, registration_attrs())
|
||||||
|> validate_required(required_attrs())
|
|> validate_required(registration_attrs())
|
||||||
|> unique_constraint(:email)
|
|> unique_constraint(:email)
|
||||||
|> hash_password()
|
|> hash_password()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def profile_changeset(struct, params \\ %{}) do
|
||||||
|
struct
|
||||||
|
|> cast(params, profile_attrs())
|
||||||
|
|> validate_required(profile_attrs())
|
||||||
|
|> unique_constraint(:email)
|
||||||
|
end
|
||||||
|
|
||||||
|
def password_changeset(struct, params \\ %{}) do
|
||||||
|
struct
|
||||||
|
|> cast(params, [:password])
|
||||||
|
|> validate_required([:password])
|
||||||
|
|> hash_password()
|
||||||
|
end
|
||||||
|
|
||||||
def opponents(user) do
|
def opponents(user) do
|
||||||
from user in "users",
|
from user in "users",
|
||||||
where: user.id != ^user.id,
|
where: user.id != ^user.id,
|
||||||
@ -45,5 +59,6 @@ defmodule Chess.Store.User do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp required_attrs, do: ~w[name email password]a
|
defp registration_attrs, do: ~w[name email password]a
|
||||||
|
defp profile_attrs, do: ~w{name email}a
|
||||||
end
|
end
|
||||||
|
|||||||
29
lib/chess_web/controllers/password_controller.ex
Normal file
29
lib/chess_web/controllers/password_controller.ex
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
defmodule ChessWeb.PasswordController do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
use ChessWeb, :controller
|
||||||
|
|
||||||
|
import Chess.Auth, only: [current_user: 1]
|
||||||
|
|
||||||
|
alias Chess.Store.User
|
||||||
|
|
||||||
|
def edit(conn, _params) do
|
||||||
|
changeset = User.changeset(current_user(conn), %{})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> render("edit.html", changeset: changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(conn, %{"user" => user}) do
|
||||||
|
changeset = User.password_changeset(current_user(conn), user)
|
||||||
|
|
||||||
|
case Repo.update(changeset) do
|
||||||
|
{:ok, _user} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, gettext("Password updated successfully."))
|
||||||
|
|> redirect(to: page_path(conn, :index))
|
||||||
|
{:error, changeset} ->
|
||||||
|
render(conn, "edit.html", changeset: changeset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
29
lib/chess_web/controllers/profile_controller.ex
Normal file
29
lib/chess_web/controllers/profile_controller.ex
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
defmodule ChessWeb.ProfileController do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
use ChessWeb, :controller
|
||||||
|
|
||||||
|
import Chess.Auth, only: [current_user: 1]
|
||||||
|
|
||||||
|
alias Chess.Store.User
|
||||||
|
|
||||||
|
def edit(conn, _params) do
|
||||||
|
changeset = User.changeset(current_user(conn), %{})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> render("edit.html", changeset: changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(conn, %{"user" => user}) do
|
||||||
|
changeset = User.profile_changeset(current_user(conn), user)
|
||||||
|
|
||||||
|
case Repo.update(changeset) do
|
||||||
|
{:ok, _user} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, gettext("Profile updated successfully."))
|
||||||
|
|> redirect(to: page_path(conn, :index))
|
||||||
|
{:error, changeset} ->
|
||||||
|
render(conn, "edit.html", changeset: changeset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -40,6 +40,10 @@ defmodule ChessWeb.Router do
|
|||||||
|
|
||||||
resources "/games", GameController,
|
resources "/games", GameController,
|
||||||
only: [:index, :new, :create, :show, :delete]
|
only: [:index, :new, :create, :show, :delete]
|
||||||
|
resources "/profile", ProfileController,
|
||||||
|
only: [:edit, :update], singleton: true
|
||||||
|
resources "/password", PasswordController,
|
||||||
|
only: [:edit, :update], singleton: true
|
||||||
end
|
end
|
||||||
|
|
||||||
# Other scopes may use custom stacks.
|
# Other scopes may use custom stacks.
|
||||||
|
|||||||
@ -18,7 +18,8 @@
|
|||||||
|
|
||||||
<nav class="user-nav" role="user">
|
<nav class="user-nav" role="user">
|
||||||
<%= if current_user(@conn) do %>
|
<%= if current_user(@conn) do %>
|
||||||
<%= current_user(@conn).name %> (<%= current_user(@conn).email %>)
|
<%= link(current_user(@conn).name, to: profile_path(@conn, :edit)) %>
|
||||||
|
(<%= current_user(@conn).email %>)
|
||||||
|
|
|
|
||||||
<%= link gettext("Log out"),
|
<%= link gettext("Log out"),
|
||||||
to: session_path(@conn, :delete),
|
to: session_path(@conn, :delete),
|
||||||
|
|||||||
22
lib/chess_web/templates/password/edit.html.eex
Normal file
22
lib/chess_web/templates/password/edit.html.eex
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<div class="form">
|
||||||
|
<h2><%= gettext "Password" %></h2>
|
||||||
|
|
||||||
|
<%= form_for @changeset, password_path(@conn, :update), [class: "update-password"], fn f -> %>
|
||||||
|
<%= if @changeset.action do %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p>
|
||||||
|
<%= gettext "Oops, something went wrong! Please check the errors below." %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-field">
|
||||||
|
<%= input f, :password, as: :password %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<%= submit gettext("Update Password"), class: "btn btn-primary" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
28
lib/chess_web/templates/profile/edit.html.eex
Normal file
28
lib/chess_web/templates/profile/edit.html.eex
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<div class="form">
|
||||||
|
<h2><%= gettext "Profile" %></h2>
|
||||||
|
|
||||||
|
<%= form_for @changeset, profile_path(@conn, :update), [class: "update-profile"], fn f -> %>
|
||||||
|
<%= if @changeset.action do %>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p>
|
||||||
|
<%= gettext "Oops, something went wrong! Please check the errors below." %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-field">
|
||||||
|
<%= input f, :name %>
|
||||||
|
</div>
|
||||||
|
<div class="form-field">
|
||||||
|
<%= input f, :email, as: :email %>
|
||||||
|
</div>
|
||||||
|
<div class="form-field">
|
||||||
|
<%= link gettext("Change password"), to: password_path(@conn, :edit) %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<%= submit gettext("Update Profile"), class: "btn btn-primary" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
3
lib/chess_web/views/password_view.ex
Normal file
3
lib/chess_web/views/password_view.ex
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
defmodule ChessWeb.PasswordView do
|
||||||
|
use ChessWeb, :view
|
||||||
|
end
|
||||||
3
lib/chess_web/views/profile_view.ex
Normal file
3
lib/chess_web/views/profile_view.ex
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
defmodule ChessWeb.ProfileView do
|
||||||
|
use ChessWeb, :view
|
||||||
|
end
|
||||||
48
test/features/password_test.exs
Normal file
48
test/features/password_test.exs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
defmodule Chess.Features.PasswordTest do
|
||||||
|
use ChessWeb.FeatureCase
|
||||||
|
|
||||||
|
import Wallaby.Query
|
||||||
|
import Chess.Factory
|
||||||
|
|
||||||
|
import Chess.AuthenticationHelpers
|
||||||
|
|
||||||
|
test "user can change their password", %{session: session} do
|
||||||
|
user = insert(:user, %{
|
||||||
|
name: "Link",
|
||||||
|
email: "link@hyrule.com",
|
||||||
|
password: "ilovezelda"
|
||||||
|
})
|
||||||
|
|
||||||
|
session
|
||||||
|
|> login(user.email, "ilovezelda")
|
||||||
|
|
||||||
|
session
|
||||||
|
|> click(link(user.name))
|
||||||
|
|> click(link("Change password"))
|
||||||
|
|> fill_in(text_field("Password"), with: "ganonsucks")
|
||||||
|
|> click(button("Update Password"))
|
||||||
|
|
||||||
|
assert session |> has_text?("Password updated successfully")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "password cannot be blank", %{session: session} do
|
||||||
|
user = insert(:user, %{
|
||||||
|
name: "Link",
|
||||||
|
email: "link@hyrule.com",
|
||||||
|
password: "ilovezelda"
|
||||||
|
})
|
||||||
|
|
||||||
|
session
|
||||||
|
|> login(user.email, "ilovezelda")
|
||||||
|
|
||||||
|
session
|
||||||
|
|> click(link(user.name))
|
||||||
|
|> click(link("Change password"))
|
||||||
|
|> click(button("Update Password"))
|
||||||
|
|
||||||
|
session
|
||||||
|
|> assert_has(
|
||||||
|
css("[data-role='password-error']", text: "can't be blank")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
68
test/features/profile_test.exs
Normal file
68
test/features/profile_test.exs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
defmodule Chess.Features.ProfileTest do
|
||||||
|
use ChessWeb.FeatureCase
|
||||||
|
|
||||||
|
import Wallaby.Query
|
||||||
|
import Chess.Factory
|
||||||
|
|
||||||
|
import Chess.AuthenticationHelpers
|
||||||
|
|
||||||
|
test "user can update their details", %{session: session} do
|
||||||
|
user = insert(:user, %{
|
||||||
|
name: "Link",
|
||||||
|
email: "link@hyrule.com",
|
||||||
|
password: "ilovezelda"
|
||||||
|
})
|
||||||
|
|
||||||
|
session
|
||||||
|
|> login(user.email, "ilovezelda")
|
||||||
|
|
||||||
|
session
|
||||||
|
|> click(link(user.name))
|
||||||
|
|> fill_in(text_field("Name"), with: "Not Zelda")
|
||||||
|
|> click(button("Update Profile"))
|
||||||
|
|
||||||
|
assert session |> has_text?("Not Zelda")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "name cannot be blank", %{session: session} do
|
||||||
|
user = insert(:user, %{
|
||||||
|
name: "Link",
|
||||||
|
email: "link@hyrule.com",
|
||||||
|
password: "ilovezelda"
|
||||||
|
})
|
||||||
|
|
||||||
|
session
|
||||||
|
|> login(user.email, "ilovezelda")
|
||||||
|
|
||||||
|
session
|
||||||
|
|> click(link(user.name))
|
||||||
|
|> fill_in(text_field("Name"), with: "")
|
||||||
|
|> click(button("Update Profile"))
|
||||||
|
|
||||||
|
session
|
||||||
|
|> assert_has(
|
||||||
|
css("[data-role='name-error']", text: "can't be blank")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "email cannot be blank", %{session: session} do
|
||||||
|
user = insert(:user, %{
|
||||||
|
name: "Link",
|
||||||
|
email: "link@hyrule.com",
|
||||||
|
password: "ilovezelda"
|
||||||
|
})
|
||||||
|
|
||||||
|
session
|
||||||
|
|> login(user.email, "ilovezelda")
|
||||||
|
|
||||||
|
session
|
||||||
|
|> click(link(user.name))
|
||||||
|
|> fill_in(text_field("Email"), with: "")
|
||||||
|
|> click(button("Update Profile"))
|
||||||
|
|
||||||
|
session
|
||||||
|
|> assert_has(
|
||||||
|
css("[data-role='email-error']", text: "can't be blank")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user