WIP: member property validation closes #49 #71
8 changed files with 150 additions and 7 deletions
|
|
@ -13,6 +13,9 @@ defmodule Mv.Membership.Email do
|
||||||
max_length: @max_length
|
max_length: @max_length
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def cast_input("", _), do: {:ok, nil}
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def cast_input(value, _) when is_binary(value) do
|
def cast_input(value, _) when is_binary(value) do
|
||||||
value = String.trim(value)
|
value = String.trim(value)
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ defmodule Mv.Membership do
|
||||||
end
|
end
|
||||||
|
|
||||||
resource Mv.Membership.Property do
|
resource Mv.Membership.Property do
|
||||||
define :create_property, action: :create
|
define :create_property, action: :create_property
|
||||||
define :list_property, action: :read
|
define :list_property, action: :read
|
||||||
define :update_property, action: :update
|
define :update_property, action: :update_property
|
||||||
define :destroy_property, action: :destroy
|
define :destroy_property, action: :destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
28
lib/membership/phone_number.ex
Normal file
28
lib/membership/phone_number.ex
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
defmodule Mv.Membership.PhoneNumber do
|
||||||
|
@match_pattern ~S/^\+?\d{5,16}$/
|
||||||
|
@match_regex Regex.compile!(@match_pattern)
|
||||||
|
|
||||||
|
use Ash.Type.NewType,
|
||||||
|
subtype_of: :string,
|
||||||
|
constraints: [
|
||||||
|
match: @match_pattern,
|
||||||
|
trim?: true
|
||||||
|
]
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def cast_input("", _), do: {:ok, nil}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def cast_input(value, _) when is_binary(value) do
|
||||||
|
value = String.trim(value)
|
||||||
|
|
||||||
|
if Regex.match?(@match_regex, value) do
|
||||||
|
{:ok, value}
|
||||||
|
else
|
||||||
|
:error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def cast_input(_, _), do: :error
|
||||||
|
end
|
||||||
|
|
@ -9,14 +9,28 @@ defmodule Mv.Membership.Property do
|
||||||
end
|
end
|
||||||
|
|
||||||
actions do
|
actions do
|
||||||
defaults [:create, :read, :update, :destroy]
|
defaults [:read, :destroy]
|
||||||
default_accept [:value, :member_id, :property_type_id]
|
default_accept [:value, :member_id, :property_type_id]
|
||||||
|
|
||||||
|
create :create_property do
|
||||||
|
primary? true
|
||||||
|
load [:property_type]
|
||||||
|
end
|
||||||
|
|
||||||
|
update :update_property do
|
||||||
|
primary? true
|
||||||
|
require_atomic? false
|
||||||
|
load [:property_type]
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
attributes do
|
attributes do
|
||||||
uuid_primary_key :id
|
uuid_primary_key :id
|
||||||
|
|
||||||
attribute :value, :union,
|
attribute :value, :union,
|
||||||
|
allow_nil?: true,
|
||||||
constraints: [
|
constraints: [
|
||||||
storage: :type_and_value,
|
storage: :type_and_value,
|
||||||
types: [
|
types: [
|
||||||
|
|
@ -24,7 +38,8 @@ defmodule Mv.Membership.Property do
|
||||||
date: [type: :date],
|
date: [type: :date],
|
||||||
integer: [type: :integer],
|
integer: [type: :integer],
|
||||||
string: [type: :string],
|
string: [type: :string],
|
||||||
email: [type: Mv.Membership.Email]
|
email: [type: Mv.Membership.Email],
|
||||||
|
phone: [type: Mv.Membership.PhoneNumber]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
@ -38,4 +53,15 @@ defmodule Mv.Membership.Property do
|
||||||
calculations do
|
calculations do
|
||||||
calculate :value_to_string, :string, expr(value[:value] <> "")
|
calculate :value_to_string, :string, expr(value[:value] <> "")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
aggregates do
|
||||||
|
first :property_type_required,
|
||||||
|
:property_type,
|
||||||
|
:required
|
||||||
|
end
|
||||||
|
|
||||||
|
validations do
|
||||||
|
validate {Mv.Membership.Validations.ValidateProperty, attribute: :value}
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ defmodule Mv.Membership.PropertyType do
|
||||||
attribute :name, :string, allow_nil?: false, public?: true
|
attribute :name, :string, allow_nil?: false, public?: true
|
||||||
|
|
||||||
attribute :value_type, :atom,
|
attribute :value_type, :atom,
|
||||||
constraints: [one_of: [:string, :integer, :boolean, :date, :email]],
|
constraints: [one_of: [:string, :integer, :boolean, :date, :email, :phone]],
|
||||||
allow_nil?: false,
|
allow_nil?: false,
|
||||||
description: "Definies the datatype `Property.value` is interpreted as"
|
description: "Definies the datatype `Property.value` is interpreted as"
|
||||||
|
|
||||||
|
|
|
||||||
27
lib/membership/validate_property.ex
Normal file
27
lib/membership/validate_property.ex
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
defmodule Mv.Membership.Validations.ValidateProperty do
|
||||||
|
use Ash.Resource.Validation
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def init(opts) do
|
||||||
|
if is_atom(opts[:value]) do
|
||||||
|
{:ok, opts}
|
||||||
|
else
|
||||||
|
{:error, "attribute must be an atom!"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def validate(changeset, _opts, _context) do
|
||||||
|
changeset = Ash.Changeset.load(changeset, [:property_type])
|
||||||
|
property_type = changeset.data.property_type
|
||||||
|
IO.inspect(property_type)
|
||||||
|
required? = property_type.required
|
||||||
|
union_value = Ash.Changeset.get_attribute(changeset, :value)
|
||||||
|
|
||||||
|
if required? and union_value in [nil, ""] do
|
||||||
|
{:error, field: :value, message: "is required"}
|
||||||
|
else
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -72,7 +72,10 @@ defmodule MvWeb.MemberLive.FormComponent do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("validate", %{"member" => member_params}, socket) do
|
def handle_event("validate", %{"member" => member_params}, socket) do
|
||||||
{:noreply, assign(socket, form: AshPhoenix.Form.validate(socket.assigns.form, member_params))}
|
#IO.inspect(socket.assigns.form, label: "BEFORE_VALIDATION!!!")
|
||||||
|
form = AshPhoenix.Form.validate(socket.assigns.form, member_params)
|
||||||
|
#IO.inspect(form, label: "AFTER_VALIDATION!!!")
|
||||||
|
{:noreply, assign(socket, form: form)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_event("save", %{"member" => member_params}, socket) do
|
def handle_event("save", %{"member" => member_params}, socket) do
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ for attrs <- [
|
||||||
value_type: :boolean,
|
value_type: :boolean,
|
||||||
description: "Status des Mitgliedsbeitrages des Mitglieds",
|
description: "Status des Mitgliedsbeitrages des Mitglieds",
|
||||||
immutable: true,
|
immutable: true,
|
||||||
required: true
|
required: false
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
name: "Email",
|
name: "Email",
|
||||||
|
|
@ -40,6 +40,62 @@ for attrs <- [
|
||||||
description: "Email-Adresse des Mitglieds",
|
description: "Email-Adresse des Mitglieds",
|
||||||
immutable: true,
|
immutable: true,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
name: "Telefonnummer",
|
||||||
|
value_type: :phone,
|
||||||
|
description: "Telefonnummer des Mitglieds",
|
||||||
|
immutable: true,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
name: "Eintrittsdatum",
|
||||||
|
value_type: :date,
|
||||||
|
description: "Eintrittsdatum des Mitglieds",
|
||||||
|
immutable: true,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
name: "Austrittsdatum",
|
||||||
|
value_type: :date,
|
||||||
|
description: "Austrittsdatum des Mitglieds",
|
||||||
|
immutable: true,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
name: "Notiz",
|
||||||
|
value_type: :string,
|
||||||
|
description: "Notiz",
|
||||||
|
immutable: true,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
name: "Stadt",
|
||||||
|
value_type: :string,
|
||||||
|
description: "Stadt",
|
||||||
|
immutable: true,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
name: "Straße",
|
||||||
|
value_type: :string,
|
||||||
|
description: "Straße",
|
||||||
|
immutable: true,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
name: "Hausnummer",
|
||||||
|
value_type: :integer,
|
||||||
|
description: "Hausnummer",
|
||||||
|
immutable: true,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
name: "PLZ",
|
||||||
|
value_type: :string,
|
||||||
|
description: "PLZ",
|
||||||
|
immutable: true,
|
||||||
|
required: false
|
||||||
}
|
}
|
||||||
] do
|
] do
|
||||||
Membership.create_property_type!(
|
Membership.create_property_type!(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue