chessh/lib/schema/player.ex
2022-12-19 01:39:10 -07:00

82 lines
2.1 KiB
Elixir

defmodule Chessh.Player do
use Ecto.Schema
import Ecto.Changeset
@derive {Inspect, except: [:password]}
schema "players" do
field(:username, :string)
field(:password, :string, virtual: true)
field(:hashed_password, :string)
timestamps()
end
def registration_changeset(user, attrs, opts \\ []) do
user
|> cast(attrs, [:username, :password])
|> validate_username()
|> validate_password(opts)
end
def password_changeset(user, attrs, opts \\ []) do
user
|> cast(attrs, [:password])
|> validate_confirmation(:password, message: "does not match password")
|> validate_password(opts)
end
def valid_password?(%Chessh.Player{hashed_password: hashed_password}, password)
when is_binary(hashed_password) and byte_size(password) > 0 do
Bcrypt.verify_pass(password, hashed_password)
end
def valid_password?(_, _) do
Bcrypt.no_user_verify()
false
end
def validate_current_password(changeset, password) do
if valid_password?(changeset.data, password) do
changeset
else
add_error(changeset, :current_password, "is not valid")
end
end
defp validate_username(changeset) do
changeset
|> validate_required([:username])
|> validate_length(:username, min: 2, max: 12)
|> validate_format(:username, ~r/^[a-zA-Z0-9_\-]*$/,
message: "only letters, numbers, underscores, and hyphens allowed"
)
|> unique_constraint(:username)
|> lowercase(:username)
end
defp validate_password(changeset, opts) do
changeset
|> validate_required([:password])
|> validate_length(:password, min: 8, max: 80)
|> maybe_hash_password(opts)
end
defp maybe_hash_password(changeset, opts) do
hash_password? = Keyword.get(opts, :hash_password, true)
password = get_change(changeset, :password)
if hash_password? && password && changeset.valid? do
changeset
|> put_change(:hashed_password, Bcrypt.hash_pwd_salt(password))
|> delete_change(:password)
else
changeset
end
end
defp lowercase(changeset, field) do
Map.update!(changeset, field, &String.downcase/1)
end
end