feat: calculate member.email from user.email

This commit is contained in:
Moritz 2025-08-05 16:51:39 +02:00
parent 0be9bb7cea
commit b7f0060358
Signed by: moritz
GPG key ID: 1020A035E5DD0824
5 changed files with 300 additions and 10 deletions

View file

@ -18,7 +18,7 @@ defmodule Mv.Membership.Member do
accept [
:first_name,
:last_name,
:email,
:member_email,
:birth_date,
:paid,
:phone_number,
@ -42,7 +42,7 @@ defmodule Mv.Membership.Member do
accept [
:first_name,
:last_name,
:email,
:member_email,
:birth_date,
:paid,
:phone_number,
@ -65,7 +65,6 @@ defmodule Mv.Membership.Member do
# 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 compare(:birth_date, less_than_or_equal_to: &Date.utc_today/0),
@ -92,21 +91,21 @@ defmodule Mv.Membership.Member do
where: [present(:postal_code)],
message: "must consist of 5 digits"
# Email validation with EctoCommons.EmailValidator
# Email validation with EctoCommons.EmailValidator (only for member_email)
validate fn changeset, _ ->
email = Ash.Changeset.get_attribute(changeset, :email)
member_email = Ash.Changeset.get_attribute(changeset, :member_email)
changeset2 =
{%{}, %{email: :string}}
|> Ecto.Changeset.cast(%{email: email}, [:email])
|> Ecto.Changeset.cast(%{email: member_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"}
{:error, field: :member_email, message: "is not a valid email"}
end
end
end, where: [present(:member_email)]
end
attributes do
@ -122,8 +121,9 @@ defmodule Mv.Membership.Member do
constraints min_length: 1
end
attribute :email, :string do
allow_nil? false
# Internal email field for members without users
attribute :member_email, :string do
allow_nil? true
constraints min_length: 5, max_length: 254
end
@ -170,5 +170,11 @@ defmodule Mv.Membership.Member do
relationships do
has_many :properties, Mv.Membership.Property
has_one :user, Mv.Accounts.User
end
calculations do
calculate :email, :string, Mv.Membership.MemberEmailCalculation
end
end

View file

@ -0,0 +1,19 @@
defmodule Mv.Membership.MemberEmailCalculation do
use Ash.Resource.Calculation
@impl true
def load(_query, _opts, _context) do
# We need member_email and user.email
[:member_email, user: [:email]]
end
@impl true
def calculate(records, _opts, _context) do
Enum.map(records, fn record ->
case record.user do
%{email: user_email} when is_binary(user_email) -> user_email
_ -> record.member_email
end
end)
end
end