Features: - User registration and authentication with email/password - Admin login with username-based authentication (separate from regular users) - Review system for contractors to rate clients - Star rating system with review forms - Client identification with private data protection - Contractor registration with document verification - Admin dashboard for review management - Contact form (demo, non-functional) - Responsive navigation with DaisyUI components - Docker Compose setup for production deployment - PostgreSQL database with Ecto migrations - High Vis color scheme (dark background with safety orange/green) Admin credentials: username: admin, password: admin123 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
337 lines
6.4 KiB
Elixir
337 lines
6.4 KiB
Elixir
defmodule MyFirstElixirVibeCode.Accounts do
|
|
@moduledoc """
|
|
The Accounts context.
|
|
"""
|
|
|
|
import Ecto.Query, warn: false
|
|
alias MyFirstElixirVibeCode.Repo
|
|
|
|
alias MyFirstElixirVibeCode.Accounts.Client
|
|
|
|
@doc """
|
|
Returns the list of clients.
|
|
|
|
## Examples
|
|
|
|
iex> list_clients()
|
|
[%Client{}, ...]
|
|
|
|
"""
|
|
def list_clients do
|
|
Repo.all(Client)
|
|
end
|
|
|
|
@doc """
|
|
Gets a single client.
|
|
|
|
Raises `Ecto.NoResultsError` if the Client does not exist.
|
|
|
|
## Examples
|
|
|
|
iex> get_client!(123)
|
|
%Client{}
|
|
|
|
iex> get_client!(456)
|
|
** (Ecto.NoResultsError)
|
|
|
|
"""
|
|
def get_client!(id), do: Repo.get!(Client, id)
|
|
|
|
@doc """
|
|
Creates a client.
|
|
|
|
## Examples
|
|
|
|
iex> create_client(%{field: value})
|
|
{:ok, %Client{}}
|
|
|
|
iex> create_client(%{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def create_client(attrs) do
|
|
%Client{}
|
|
|> Client.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
@doc """
|
|
Updates a client.
|
|
|
|
## Examples
|
|
|
|
iex> update_client(client, %{field: new_value})
|
|
{:ok, %Client{}}
|
|
|
|
iex> update_client(client, %{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def update_client(%Client{} = client, attrs) do
|
|
client
|
|
|> Client.changeset(attrs)
|
|
|> Repo.update()
|
|
end
|
|
|
|
@doc """
|
|
Deletes a client.
|
|
|
|
## Examples
|
|
|
|
iex> delete_client(client)
|
|
{:ok, %Client{}}
|
|
|
|
iex> delete_client(client)
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def delete_client(%Client{} = client) do
|
|
Repo.delete(client)
|
|
end
|
|
|
|
@doc """
|
|
Returns an `%Ecto.Changeset{}` for tracking client changes.
|
|
|
|
## Examples
|
|
|
|
iex> change_client(client)
|
|
%Ecto.Changeset{data: %Client{}}
|
|
|
|
"""
|
|
def change_client(%Client{} = client, attrs \\ %{}) do
|
|
Client.changeset(client, attrs)
|
|
end
|
|
|
|
alias MyFirstElixirVibeCode.Accounts.Contractor
|
|
|
|
@doc """
|
|
Returns the list of contractors.
|
|
|
|
## Examples
|
|
|
|
iex> list_contractors()
|
|
[%Contractor{}, ...]
|
|
|
|
"""
|
|
def list_contractors do
|
|
Repo.all(Contractor)
|
|
end
|
|
|
|
@doc """
|
|
Gets a single contractor.
|
|
|
|
Raises `Ecto.NoResultsError` if the Contractor does not exist.
|
|
|
|
## Examples
|
|
|
|
iex> get_contractor!(123)
|
|
%Contractor{}
|
|
|
|
iex> get_contractor!(456)
|
|
** (Ecto.NoResultsError)
|
|
|
|
"""
|
|
def get_contractor!(id), do: Repo.get!(Contractor, id)
|
|
|
|
@doc """
|
|
Creates a contractor.
|
|
|
|
## Examples
|
|
|
|
iex> create_contractor(%{field: value})
|
|
{:ok, %Contractor{}}
|
|
|
|
iex> create_contractor(%{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def create_contractor(attrs) do
|
|
%Contractor{}
|
|
|> Contractor.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
@doc """
|
|
Updates a contractor.
|
|
|
|
## Examples
|
|
|
|
iex> update_contractor(contractor, %{field: new_value})
|
|
{:ok, %Contractor{}}
|
|
|
|
iex> update_contractor(contractor, %{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def update_contractor(%Contractor{} = contractor, attrs) do
|
|
contractor
|
|
|> Contractor.changeset(attrs)
|
|
|> Repo.update()
|
|
end
|
|
|
|
@doc """
|
|
Deletes a contractor.
|
|
|
|
## Examples
|
|
|
|
iex> delete_contractor(contractor)
|
|
{:ok, %Contractor{}}
|
|
|
|
iex> delete_contractor(contractor)
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def delete_contractor(%Contractor{} = contractor) do
|
|
Repo.delete(contractor)
|
|
end
|
|
|
|
@doc """
|
|
Returns an `%Ecto.Changeset{}` for tracking contractor changes.
|
|
|
|
## Examples
|
|
|
|
iex> change_contractor(contractor)
|
|
%Ecto.Changeset{data: %Contractor{}}
|
|
|
|
"""
|
|
def change_contractor(%Contractor{} = contractor, attrs \\ %{}) do
|
|
Contractor.changeset(contractor, attrs)
|
|
end
|
|
|
|
@doc """
|
|
Registers a new contractor with required documents.
|
|
|
|
## Examples
|
|
|
|
iex> register_contractor(%{field: value})
|
|
{:ok, %Contractor{}}
|
|
|
|
iex> register_contractor(%{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def register_contractor(attrs) do
|
|
%Contractor{}
|
|
|> Contractor.registration_changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
@doc """
|
|
Returns an `%Ecto.Changeset{}` for tracking contractor registration changes.
|
|
|
|
## Examples
|
|
|
|
iex> change_contractor_registration(contractor)
|
|
%Ecto.Changeset{data: %Contractor{}}
|
|
|
|
"""
|
|
def change_contractor_registration(%Contractor{} = contractor, attrs \\ %{}) do
|
|
Contractor.registration_changeset(contractor, attrs)
|
|
end
|
|
|
|
alias MyFirstElixirVibeCode.Accounts.User
|
|
|
|
@doc """
|
|
Returns the list of users.
|
|
"""
|
|
def list_users do
|
|
Repo.all(User)
|
|
end
|
|
|
|
@doc """
|
|
Gets a single user.
|
|
|
|
Raises `Ecto.NoResultsError` if the User does not exist.
|
|
"""
|
|
def get_user!(id), do: Repo.get!(User, id)
|
|
|
|
@doc """
|
|
Gets a user by email.
|
|
"""
|
|
def get_user_by_email(email) when is_binary(email) do
|
|
Repo.get_by(User, email: email)
|
|
end
|
|
|
|
@doc """
|
|
Gets a user by email and password.
|
|
"""
|
|
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)
|
|
if User.valid_password?(user, password), do: user
|
|
end
|
|
|
|
@doc """
|
|
Gets a user by username and password (for admin login).
|
|
"""
|
|
def get_user_by_username_and_password(username, password)
|
|
when is_binary(username) and is_binary(password) do
|
|
user = Repo.get_by(User, username: username)
|
|
if user && user.is_admin && User.valid_password?(user, password), do: user
|
|
end
|
|
|
|
@doc """
|
|
Creates a user.
|
|
|
|
## Examples
|
|
|
|
iex> create_user(%{field: value})
|
|
{:ok, %User{}}
|
|
|
|
iex> create_user(%{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def create_user(attrs \\ %{}) do
|
|
%User{}
|
|
|> User.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
@doc """
|
|
Updates a user.
|
|
|
|
## Examples
|
|
|
|
iex> update_user(user, %{field: new_value})
|
|
{:ok, %User{}}
|
|
|
|
iex> update_user(user, %{field: bad_value})
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def update_user(%User{} = user, attrs) do
|
|
user
|
|
|> User.changeset(attrs)
|
|
|> Repo.update()
|
|
end
|
|
|
|
@doc """
|
|
Deletes a user.
|
|
|
|
## Examples
|
|
|
|
iex> delete_user(user)
|
|
{:ok, %User{}}
|
|
|
|
iex> delete_user(user)
|
|
{:error, %Ecto.Changeset{}}
|
|
|
|
"""
|
|
def delete_user(%User{} = user) do
|
|
Repo.delete(user)
|
|
end
|
|
|
|
@doc """
|
|
Returns an `%Ecto.Changeset{}` for tracking user changes.
|
|
|
|
## Examples
|
|
|
|
iex> change_user(user)
|
|
%Ecto.Changeset{data: %User{}}
|
|
|
|
"""
|
|
def change_user(%User{} = user, attrs \\ %{}) do
|
|
User.changeset(user, attrs)
|
|
end
|
|
end
|