fix: Allow optional email values in custom fields
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Moritz 2025-11-13 18:39:21 +01:00
parent e9290b7156
commit 2b3c94d3b2
Signed by: moritz
GPG key ID: 1020A035E5DD0824
3 changed files with 42 additions and 6 deletions

View file

@ -8,10 +8,11 @@ defmodule Mv.Membership.Email do
addresses according to a standard regex pattern.
## Validation Rules
- Minimum length: 5 characters
- **Optional**: `nil` and empty strings are allowed (custom fields are optional)
- Minimum length: 5 characters (for non-empty values)
- Maximum length: 254 characters (RFC 5321 maximum)
- Pattern: Standard email format (username@domain.tld)
- Automatic trimming of leading/trailing whitespace
- Automatic trimming of leading/trailing whitespace (empty strings become `nil`)
## Usage
This type is used in the CustomFieldValue union type for custom fields with
@ -46,11 +47,18 @@ defmodule Mv.Membership.Email do
max_length: @max_length
]
@impl true
def cast_input(nil, _), do: {:ok, nil}
@impl true
def cast_input(value, _) when is_binary(value) do
value = String.trim(value)
cond do
# Empty string after trim becomes nil (optional field)
value == "" ->
{:ok, nil}
String.length(value) < @min_length ->
:error

View file

@ -1,7 +1,7 @@
defmodule Mv.Membership.CustomFieldValidationTest do
@moduledoc """
Tests for CustomField validation constraints.
Tests cover:
- Name length validation (max 100 characters)
- Name trimming
@ -203,4 +203,3 @@ defmodule Mv.Membership.CustomFieldValidationTest do
end
end
end

View file

@ -1,7 +1,7 @@
defmodule Mv.Membership.CustomFieldValueValidationTest do
@moduledoc """
Tests for CustomFieldValue validation constraints.
Tests cover:
- String value length validation (max 10,000 characters)
- String value trimming
@ -184,6 +184,36 @@ defmodule Mv.Membership.CustomFieldValueValidationTest do
end
describe "email value validation" do
test "accepts nil value (optional field)", %{member: member, email_field: email_field} do
assert {:ok, custom_field_value} =
CustomFieldValue
|> Ash.Changeset.for_create(:create, %{
member_id: member.id,
custom_field_id: email_field.id,
value: %{"_union_type" => "email", "_union_value" => nil}
})
|> Ash.create()
assert custom_field_value.value.value == nil
end
test "accepts empty string (becomes nil after trim)", %{
member: member,
email_field: email_field
} do
assert {:ok, custom_field_value} =
CustomFieldValue
|> Ash.Changeset.for_create(:create, %{
member_id: member.id,
custom_field_id: email_field.id,
value: %{"_union_type" => "email", "_union_value" => ""}
})
|> Ash.create()
# Empty string after trim should become nil
assert custom_field_value.value.value == nil
end
test "accepts valid email", %{member: member, email_field: email_field} do
assert {:ok, custom_field_value} =
CustomFieldValue
@ -273,4 +303,3 @@ defmodule Mv.Membership.CustomFieldValueValidationTest do
end
end
end