Add username as login option
This commit is contained in:
parent
f540a6bb4d
commit
e82c9c0bd4
7 changed files with 67 additions and 33 deletions
|
@ -48,9 +48,15 @@ defmodule ChoreTracker.Accounts do
|
|||
nil
|
||||
|
||||
"""
|
||||
def get_user_by_email_and_password(email, password)
|
||||
when is_binary(email) and is_binary(password) do
|
||||
user = Repo.get_by(User, email: email)
|
||||
def get_user_by_login_and_password(login, password)
|
||||
when is_binary(login) and is_binary(password) do
|
||||
user =
|
||||
if String.contains?(login, "@") do
|
||||
Repo.get_by(User, email: login)
|
||||
else
|
||||
Repo.get_by(User, username: login)
|
||||
end
|
||||
|
||||
if User.valid_password?(user, password), do: user
|
||||
end
|
||||
|
||||
|
@ -84,7 +90,7 @@ defmodule ChoreTracker.Accounts do
|
|||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def register_user(attrs, opts) do
|
||||
def register_user(attrs, opts \\ []) do
|
||||
%User{}
|
||||
|> User.registration_changeset(attrs, opts)
|
||||
|> Repo.insert()
|
||||
|
|
|
@ -3,6 +3,7 @@ defmodule ChoreTracker.Accounts.User do
|
|||
import Ecto.Changeset
|
||||
|
||||
schema "users" do
|
||||
field :username, :string
|
||||
field :email, :string
|
||||
field :password, :string, virtual: true, redact: true
|
||||
field :hashed_password, :string, redact: true
|
||||
|
@ -38,11 +39,23 @@ defmodule ChoreTracker.Accounts.User do
|
|||
"""
|
||||
def registration_changeset(user, attrs, opts \\ []) do
|
||||
user
|
||||
|> cast(attrs, [:email, :password, :display_name])
|
||||
|> cast(attrs, [:username, :display_name, :email, :password])
|
||||
|> validate_username()
|
||||
|> validate_email(opts)
|
||||
|> validate_password(opts)
|
||||
end
|
||||
|
||||
defp validate_username(changeset) do
|
||||
changeset
|
||||
|> validate_required([:username])
|
||||
|> validate_length(:username, min: 3, max: 30)
|
||||
|> validate_format(:username, ~r/^[a-zA-Z0-9_]+$/,
|
||||
message: "username can only include letters, numbers and underscores"
|
||||
)
|
||||
|> unsafe_validate_unique(:username, ChoreTracker.Repo)
|
||||
|> unique_constraint(:username)
|
||||
end
|
||||
|
||||
defp validate_email(changeset, opts) do
|
||||
changeset
|
||||
|> validate_required([:email])
|
||||
|
|
|
@ -19,9 +19,10 @@ defmodule ChoreTrackerWeb.UserSessionController do
|
|||
end
|
||||
|
||||
defp create(conn, %{"user" => user_params}, info) do
|
||||
%{"email" => email, "password" => password} = user_params
|
||||
%{"password" => password} = user_params
|
||||
login = user_params["login"] || user_params["username"] || user_params["email"]
|
||||
|
||||
if user = Accounts.get_user_by_email_and_password(email, password) do
|
||||
if user = Accounts.get_user_by_login_and_password(login, password) do
|
||||
conn
|
||||
|> put_flash(:info, info)
|
||||
|> UserAuth.log_in_user(user, user_params)
|
||||
|
@ -29,7 +30,7 @@ defmodule ChoreTrackerWeb.UserSessionController do
|
|||
# In order to prevent user enumeration attacks, don't disclose whether the email is registered.
|
||||
conn
|
||||
|> put_flash(:error, "Invalid email or password")
|
||||
|> put_flash(:email, String.slice(email, 0, 160))
|
||||
|> put_flash(:login, String.slice(login, 0, 160))
|
||||
|> redirect(to: ~p"/users/log_in")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ defmodule ChoreTrackerWeb.UserLoginLive do
|
|||
</.header>
|
||||
|
||||
<.simple_form for={@form} id="login_form" action={~p"/users/log_in"} phx-update="ignore">
|
||||
<.input field={@form[:email]} type="email" label="Email" required />
|
||||
<.input field={@form[:login]} label="Username or email" required />
|
||||
<.input field={@form[:password]} type="password" label="Password" required />
|
||||
|
||||
<:actions>
|
||||
|
|
|
@ -31,6 +31,8 @@ defmodule ChoreTrackerWeb.UserRegistrationLive do
|
|||
Oops, something went wrong! Please check the errors below.
|
||||
</.error>
|
||||
|
||||
<.input field={@form[:username]} label="Username" required />
|
||||
<.input field={@form[:display_name]} label="Display name" required />
|
||||
<.input field={@form[:email]} type="email" label="Email" required />
|
||||
<.input field={@form[:password]} type="password" label="Password" required />
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ defmodule ChoreTracker.Repo.Migrations.CreateUsersAuthTables do
|
|||
execute "CREATE EXTENSION IF NOT EXISTS citext", ""
|
||||
|
||||
create table(:users) do
|
||||
add :username, :citext, null: false
|
||||
add :email, :citext, null: false
|
||||
add :hashed_password, :string, null: false
|
||||
add :confirmed_at, :utc_datetime
|
||||
|
@ -13,6 +14,7 @@ defmodule ChoreTracker.Repo.Migrations.CreateUsersAuthTables do
|
|||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
||||
create unique_index(:users, [:username])
|
||||
create unique_index(:users, [:email])
|
||||
|
||||
create table(:users_tokens) do
|
||||
|
|
|
@ -10,35 +10,38 @@
|
|||
# We recommend using the bang functions (`insert!`, `update!`
|
||||
# and so on) as they will fail if something goes wrong.
|
||||
|
||||
admin_password = "secret"
|
||||
|
||||
{:ok, admin} =
|
||||
ondrej =
|
||||
ChoreTracker.Accounts.register_user(
|
||||
%{
|
||||
username: "ondrej",
|
||||
email: "ondrej@jednota.party",
|
||||
password: admin_password,
|
||||
password: "secret",
|
||||
display_name: "Ondřej"
|
||||
},
|
||||
disable_password_validation: true
|
||||
)
|
||||
|
||||
ChoreTracker.Accounts.register_user(
|
||||
matej =
|
||||
ChoreTracker.Accounts.register_user(
|
||||
%{
|
||||
username: "matej",
|
||||
email: "matej@jednota.party",
|
||||
password: "secret",
|
||||
display_name: "Matěj"
|
||||
},
|
||||
disable_password_validation: true
|
||||
)
|
||||
)
|
||||
|
||||
ChoreTracker.Accounts.register_user(
|
||||
valentyna =
|
||||
ChoreTracker.Accounts.register_user(
|
||||
%{
|
||||
username: "valentyna",
|
||||
email: "valentyna@jednota.party",
|
||||
password: "secret",
|
||||
display_name: "Valentýna"
|
||||
},
|
||||
disable_password_validation: true
|
||||
)
|
||||
)
|
||||
|
||||
ChoreTracker.Chores.create_chore(%{
|
||||
name: "Uklidit kuchyň",
|
||||
|
@ -50,7 +53,12 @@ ChoreTracker.Chores.create_chore(%{
|
|||
- Umýt lednici
|
||||
- Vytřít podlahu
|
||||
""",
|
||||
starts_at: Date.utc_today()
|
||||
starts_at: Date.utc_today(),
|
||||
assignees: [
|
||||
ondrej,
|
||||
matej,
|
||||
valentyna
|
||||
]
|
||||
})
|
||||
|
||||
ChoreTracker.Chores.create_chore(%{
|
||||
|
@ -62,7 +70,9 @@ ChoreTracker.Chores.create_chore(%{
|
|||
- Vyluxovat
|
||||
- Vytřít podlahu
|
||||
""",
|
||||
starts_at: Date.utc_today()
|
||||
starts_at: Date.utc_today(),
|
||||
assignees: [
|
||||
ondrej,
|
||||
matej
|
||||
]
|
||||
})
|
||||
|
||||
IO.puts(["✓ Admin user created\n", " login: ", admin.email, "\n password: ", admin_password])
|
||||
|
|
Loading…
Reference in a new issue