1
0
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:
Daniel Barber 2018-08-11 13:10:18 -04:00
parent 344619ac4f
commit bc5c6c4f04
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
11 changed files with 254 additions and 4 deletions

View File

@ -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

View 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

View 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

View File

@ -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.

View File

@ -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),

View 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>

View 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>

View File

@ -0,0 +1,3 @@
defmodule ChessWeb.PasswordView do
use ChessWeb, :view
end

View File

@ -0,0 +1,3 @@
defmodule ChessWeb.ProfileView do
use ChessWeb, :view
end

View 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

View 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