refactor: email validations

This commit is contained in:
Moritz 2025-10-17 14:34:04 +02:00
parent 7522724945
commit 2693f67d33
Signed by: moritz
GPG key ID: 1020A035E5DD0824
2 changed files with 27 additions and 51 deletions

View file

@ -1,9 +1,7 @@
defmodule Mv.Accounts.User.Validations.EmailNotUsedByOtherMember do
@moduledoc """
Validates that the user's email is not already used by another member
(unless that member is linked to this user).
This prevents email conflicts when syncing between users and members.
Validates that the user's email is not already used by another member.
Allows syncing with linked member (excludes member_id from check).
"""
use Ash.Resource.Validation
@ -11,42 +9,32 @@ defmodule Mv.Accounts.User.Validations.EmailNotUsedByOtherMember do
def validate(changeset, _opts, _context) do
case Ash.Changeset.fetch_change(changeset, :email) do
{:ok, new_email} ->
check_email_not_used_by_other_member(changeset, new_email)
member_id = Ash.Changeset.get_attribute(changeset, :member_id)
check_email_uniqueness(new_email, member_id)
:error ->
# Email not being changed
:ok
end
end
defp check_email_not_used_by_other_member(changeset, new_email) do
member_id = Ash.Changeset.get_attribute(changeset, :member_id)
# Check if any member has this email
# Exclude the member linked to this user (if any)
defp check_email_uniqueness(new_email, exclude_member_id) do
query =
Mv.Membership.Member
|> Ash.Query.filter(email == ^to_string(new_email))
|> then(fn q ->
if member_id do
Ash.Query.filter(q, id != ^member_id)
else
q
end
end)
|> maybe_exclude_id(exclude_member_id)
case Ash.read(query) do
{:ok, []} ->
# No conflicting member found
:ok
{:ok, members} when is_list(members) and length(members) > 0 ->
# Email is already used by another member
{:ok, _} ->
{:error, field: :email, message: "is already used by another member", value: new_email}
{:error, _} ->
# Error reading members - be safe and allow
:ok
end
end
defp maybe_exclude_id(query, nil), do: query
defp maybe_exclude_id(query, id), do: Ash.Query.filter(query, id != ^id)
end