refactor: email validations
This commit is contained in:
parent
7522724945
commit
2693f67d33
2 changed files with 27 additions and 51 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
defmodule Mv.Membership.Member.Validations.EmailNotUsedByOtherUser do
|
||||
@moduledoc """
|
||||
Validates that the member's email is not already used by another user
|
||||
(unless that user is linked to this member).
|
||||
|
||||
This prevents email conflicts when syncing between users and members.
|
||||
Validates that the member's email is not already used by another user.
|
||||
Allows syncing with linked user (excludes linked user from check).
|
||||
"""
|
||||
use Ash.Resource.Validation
|
||||
|
||||
|
|
@ -11,49 +9,39 @@ defmodule Mv.Membership.Member.Validations.EmailNotUsedByOtherUser do
|
|||
def validate(changeset, _opts, _context) do
|
||||
case Ash.Changeset.fetch_change(changeset, :email) do
|
||||
{:ok, new_email} ->
|
||||
check_email_not_used_by_other_user(changeset, new_email)
|
||||
linked_user_id = get_linked_user_id(changeset.data)
|
||||
check_email_uniqueness(new_email, linked_user_id)
|
||||
|
||||
:error ->
|
||||
# Email not being changed
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp check_email_not_used_by_other_user(changeset, new_email) do
|
||||
# Load the user relationship to check if this member is linked to a user
|
||||
member_with_user =
|
||||
case Ash.load(changeset.data, :user) do
|
||||
{:ok, loaded} -> loaded
|
||||
{:error, _} -> changeset.data
|
||||
end
|
||||
|
||||
linked_user_id = if member_with_user.user, do: member_with_user.user.id, else: nil
|
||||
|
||||
# Check if any user has this email (case-insensitive)
|
||||
# Exclude the user linked to this member (if any)
|
||||
defp check_email_uniqueness(new_email, exclude_user_id) do
|
||||
query =
|
||||
Mv.Accounts.User
|
||||
|> Ash.Query.filter(email == ^new_email)
|
||||
|> then(fn q ->
|
||||
if linked_user_id do
|
||||
Ash.Query.filter(q, id != ^linked_user_id)
|
||||
else
|
||||
q
|
||||
end
|
||||
end)
|
||||
|> maybe_exclude_id(exclude_user_id)
|
||||
|
||||
case Ash.read(query) do
|
||||
{:ok, []} ->
|
||||
# No conflicting user found
|
||||
:ok
|
||||
|
||||
{:ok, users} when is_list(users) and length(users) > 0 ->
|
||||
# Email is already used by another user
|
||||
{:ok, _} ->
|
||||
{:error, field: :email, message: "is already used by another user", value: new_email}
|
||||
|
||||
{:error, _} ->
|
||||
# Error reading users - 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)
|
||||
|
||||
defp get_linked_user_id(member_data) do
|
||||
case Ash.load(member_data, :user) do
|
||||
{:ok, %{user: %{id: id}}} -> id
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue