feat: add join form settings
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Simon 2026-03-10 14:29:49 +01:00
parent b7a83d9298
commit fa738aae88
Signed by: simon
GPG key ID: 40E7A58C4AA1EDB2
12 changed files with 846 additions and 54 deletions

View file

@ -15,6 +15,12 @@ defmodule Mv.Membership.Setting do
(e.g., `%{"first_name" => true, "last_name" => true}`). Email is always required; other fields default to optional.
- `include_joining_cycle` - Whether to include the joining cycle in membership fee generation (default: true)
- `default_membership_fee_type_id` - Default membership fee type for new members (optional)
- `join_form_enabled` - Whether the public /join page is active (default: false)
- `join_form_field_ids` - Ordered list of field IDs shown on the join form. Each entry is
either a member field name string (e.g. "email") or a custom field UUID. Email is always
included and always required; normalization enforces this automatically.
- `join_form_field_required` - Map of field ID => required boolean for the join form.
Email is always forced to true.
## Singleton Pattern
This resource uses a singleton pattern - there should only be one settings record.
@ -86,8 +92,13 @@ defmodule Mv.Membership.Setting do
:oidc_client_secret,
:oidc_admin_group_name,
:oidc_groups_claim,
:oidc_only
:oidc_only,
:join_form_enabled,
:join_form_field_ids,
:join_form_field_required
]
change Mv.Membership.Setting.Changes.NormalizeJoinFormSettings
end
update :update do
@ -110,8 +121,13 @@ defmodule Mv.Membership.Setting do
:oidc_client_secret,
:oidc_admin_group_name,
:oidc_groups_claim,
:oidc_only
:oidc_only,
:join_form_enabled,
:join_form_field_ids,
:join_form_field_required
]
change Mv.Membership.Setting.Changes.NormalizeJoinFormSettings
end
update :update_member_field_visibility do
@ -232,6 +248,39 @@ defmodule Mv.Membership.Setting do
end,
on: [:create, :update]
# Validate join_form_field_ids: each entry must be a known member field name
# or a UUID-format string (custom field ID). Normalization (NormalizeJoinFormSettings
# change) runs before validations, so email is already present when this runs.
validate fn changeset, _context ->
field_ids = Ash.Changeset.get_attribute(changeset, :join_form_field_ids)
if is_list(field_ids) and field_ids != [] do
valid_member_fields =
Mv.Constants.member_fields() |> Enum.map(&Atom.to_string/1)
uuid_pattern =
~r/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
invalid_ids =
Enum.reject(field_ids, fn id ->
is_binary(id) and
(id in valid_member_fields or Regex.match?(uuid_pattern, id))
end)
if Enum.empty?(invalid_ids) do
:ok
else
{:error,
field: :join_form_field_ids,
message:
"Invalid field identifiers: #{inspect(invalid_ids)}. Use member field names or custom field UUIDs."}
end
else
:ok
end
end,
on: [:create, :update]
# Validate default_membership_fee_type_id exists if set
validate fn changeset, context ->
fee_type_id =
@ -382,6 +431,29 @@ defmodule Mv.Membership.Setting do
description "When true and OIDC is configured, sign-in shows only OIDC (password login hidden)"
end
# Join form (Beitrittsformular) settings
attribute :join_form_enabled, :boolean do
allow_nil? false
default false
public? true
description "When true, the public /join page is active and new members can submit a request."
end
attribute :join_form_field_ids, {:array, :string} do
allow_nil? true
public? true
description "Ordered list of field IDs shown on the join form. Each entry is a member field name (e.g. 'email') or a custom field UUID. Email is always present after normalization."
end
attribute :join_form_field_required, :map do
allow_nil? true
public? true
description "Map of field ID => required boolean for the join form. Email is always true after normalization."
end
timestamps()
end