CustomField policies: actor required, no system-actor fallback, error handling

- list_required_custom_fields: require actor (two clauses, no default)
- Member validation: use context.actor only, differentiate Forbidden vs transient errors
- stream_custom_fields: log + send flash on error instead of returning []
- GlobalSettingsLive: handle_info for custom_fields_load_error, put_flash
- Seeds: use Membership.update_member with actor, format
This commit is contained in:
Moritz 2026-01-29 15:30:07 +01:00 committed by moritz
parent c9431caabe
commit 5a2f035ecc
5 changed files with 67 additions and 19 deletions

View file

@ -14,7 +14,7 @@ defmodule Mv.Membership do
The domain exposes these main actions:
- Member CRUD: `create_member/1`, `list_members/0`, `update_member/2`, `destroy_member/1`
- Custom field value management: `create_custom_field_value/1`, `list_custom_field_values/0`, etc.
- Custom field management: `create_custom_field/1`, `list_custom_fields/0`, `list_required_custom_fields/0`, etc.
- Custom field management: `create_custom_field/1`, `list_custom_fields/0`, `list_required_custom_fields/1`, etc.
- Settings management: `get_settings/0`, `update_settings/2`, `update_member_field_visibility/2`, `update_single_member_field_visibility/3`
- Group management: `create_group/1`, `list_groups/0`, `update_group/2`, `destroy_group/1`
- Member-group associations: `create_member_group/1`, `list_member_groups/0`, `destroy_member_group/1`
@ -156,7 +156,7 @@ defmodule Mv.Membership do
This is an optimized version that filters at the database level instead of
loading all custom fields and filtering in memory. Requires an actor for
authorization (CustomField read policy).
authorization (CustomField read policy). Callers must pass `actor:`; no default.
## Options
@ -166,22 +166,26 @@ defmodule Mv.Membership do
## Returns
- `{:ok, required_custom_fields}` - List of required custom fields
- `{:error, error}` - Error reading custom fields (e.g. Forbidden when no actor)
- `{:error, :missing_actor}` - When actor is nil (caller must pass actor)
- `{:error, error}` - Error reading custom fields (e.g. Forbidden)
## Examples
iex> {:ok, required_fields} = Mv.Membership.list_required_custom_fields(actor: actor)
iex> Enum.all?(required_fields, & &1.required)
true
"""
def list_required_custom_fields(opts \\ []) do
actor = Keyword.get(opts, :actor)
iex> Mv.Membership.list_required_custom_fields(actor: nil)
{:error, :missing_actor}
"""
def list_required_custom_fields(actor: actor) when not is_nil(actor) do
Mv.Membership.CustomField
|> Ash.Query.filter(expr(required == true))
|> Ash.read(domain: __MODULE__, actor: actor)
end
def list_required_custom_fields(actor: nil), do: {:error, :missing_actor}
@doc """
Updates the member field visibility configuration.