Member fields

This commit is contained in:
Moritz 2025-06-11 22:14:42 +02:00
parent 2e50e01e7f
commit abfc94473f
Signed by: moritz
GPG key ID: 1020A035E5DD0824
9 changed files with 540 additions and 11 deletions

View file

@ -14,6 +14,23 @@ defmodule Mv.Membership.Member do
create :create_member do
primary? true
argument :properties, {:array, :map}
accept [
:first_name,
:last_name,
:email,
:birth_date,
:paid,
:phone_number,
:join_date,
:exit_date,
:notes,
:city,
:street,
:house_number,
:postal_code
]
change manage_relationship(:properties, type: :create)
end
@ -21,12 +38,176 @@ defmodule Mv.Membership.Member do
primary? true
require_atomic? false
argument :properties, {:array, :map}
accept [
:first_name,
:last_name,
:email,
:birth_date,
:paid,
:phone_number,
:join_date,
:exit_date,
:notes,
:city,
:street,
:house_number,
:postal_code
]
change manage_relationship(:properties, on_match: :update, on_no_match: :create)
end
end
attributes do
uuid_v7_primary_key :id
attribute :first_name, :string do
allow_nil? false
constraints min_length: 1
end
attribute :last_name, :string do
allow_nil? false
constraints min_length: 1
end
attribute :email, :string do
allow_nil? false
constraints min_length: 5, max_length: 254
end
attribute :birth_date, :date do
allow_nil? true
end
attribute :paid, :boolean do
allow_nil? true
end
attribute :phone_number, :string do
allow_nil? true
end
attribute :join_date, :date do
allow_nil? true
end
attribute :exit_date, :date do
allow_nil? true
end
attribute :notes, :string do
allow_nil? true
end
attribute :city, :string do
allow_nil? true
end
attribute :street, :string do
allow_nil? true
end
attribute :house_number, :string do
allow_nil? true
end
attribute :postal_code, :string do
allow_nil? true
end
end
validations do
# Required fields are covered by allow_nil? false
# First name and last name must not be empty
validate present(:first_name)
validate present(:last_name)
validate present(:email)
# Birth date not in the future
validate fn changeset, _ ->
birth_date = Ash.Changeset.get_attribute(changeset, :birth_date)
if birth_date && Date.compare(birth_date, Date.utc_today()) == :gt do
{:error, field: :birth_date, message: "cannot be in the future"}
else
:ok
end
end
# Join date not in the future
validate fn changeset, _ ->
join_date = Ash.Changeset.get_attribute(changeset, :join_date)
if join_date && Date.compare(join_date, Date.utc_today()) == :gt do
{:error, field: :join_date, message: "cannot be in the future"}
else
:ok
end
end
# Exit date not before join date
validate fn changeset, _ ->
join_date = Ash.Changeset.get_attribute(changeset, :join_date)
exit_date = Ash.Changeset.get_attribute(changeset, :exit_date)
if join_date && exit_date && Date.compare(exit_date, join_date) == :lt do
{:error, field: :exit_date, message: "cannot be before join date"}
else
:ok
end
end
# Phone number format (only if set)
validate fn changeset, _ ->
phone = Ash.Changeset.get_attribute(changeset, :phone_number)
if phone && !Regex.match?(~r/^\+?[0-9\- ]{6,20}$/, phone) do
{:error, field: :phone_number, message: "is not a valid phone number"}
else
:ok
end
end
# Postal code format (only if set)
validate fn changeset, _ ->
postal_code = Ash.Changeset.get_attribute(changeset, :postal_code)
if postal_code && !Regex.match?(~r/^\d{5}$/, postal_code) do
{:error, field: :postal_code, message: "must consist of 5 digits"}
else
:ok
end
end
# paid must be boolean if set
validate fn changeset, _ ->
paid = Ash.Changeset.get_attribute(changeset, :paid)
if not is_nil(paid) and not is_boolean(paid) do
{:error, field: :paid, message: "must be true or false"}
else
:ok
end
end
# Email validation with EctoCommons.EmailValidator
validate fn changeset, _ ->
email = Ash.Changeset.get_attribute(changeset, :email)
changeset2 =
{%{}, %{email: :string}}
|> Ecto.Changeset.cast(%{email: email}, [:email])
|> EctoCommons.EmailValidator.validate_email(:email, checks: [:html_input, :pow])
if changeset2.valid? do
:ok
else
{:error, field: :email, message: "is not a valid email"}
end
end
end
relationships do