160 lines
5.2 KiB
Elixir
160 lines
5.2 KiB
Elixir
defmodule Mv.Membership do
|
|
@moduledoc """
|
|
Ash Domain for membership management.
|
|
|
|
## Resources
|
|
- `Member` - Club members with personal information and custom field values
|
|
- `CustomFieldValue` - Dynamic custom field values attached to members
|
|
- `CustomField` - Schema definitions for custom fields
|
|
- `Setting` - Global application settings (singleton)
|
|
|
|
## Public API
|
|
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`, etc.
|
|
- Settings management: `get_settings/0`, `update_settings/2`
|
|
|
|
## Admin Interface
|
|
The domain is configured with AshAdmin for management UI.
|
|
"""
|
|
use Ash.Domain,
|
|
extensions: [AshAdmin.Domain, AshPhoenix]
|
|
|
|
admin do
|
|
show? true
|
|
end
|
|
|
|
resources do
|
|
resource Mv.Membership.Member do
|
|
define :create_member, action: :create_member
|
|
define :list_members, action: :read
|
|
define :update_member, action: :update_member
|
|
define :destroy_member, action: :destroy
|
|
end
|
|
|
|
resource Mv.Membership.CustomFieldValue do
|
|
define :create_custom_field_value, action: :create
|
|
define :list_custom_field_values, action: :read
|
|
define :update_custom_field_value, action: :update
|
|
define :destroy_custom_field_value, action: :destroy
|
|
end
|
|
|
|
resource Mv.Membership.CustomField do
|
|
define :create_custom_field, action: :create
|
|
define :list_custom_fields, action: :read
|
|
define :update_custom_field, action: :update
|
|
define :destroy_custom_field, action: :destroy_with_values
|
|
define :prepare_custom_field_deletion, action: :prepare_deletion, args: [:id]
|
|
end
|
|
|
|
resource Mv.Membership.Setting do
|
|
# Note: create action exists but is not exposed via code interface
|
|
# It's only used internally as fallback in get_settings/0
|
|
# Settings should be created via seed script
|
|
define :update_settings, action: :update
|
|
define :update_member_field_visibility, action: :update_member_field_visibility
|
|
end
|
|
end
|
|
|
|
# Singleton pattern: Get the single settings record
|
|
@doc """
|
|
Gets the global settings.
|
|
|
|
Settings should normally be created via the seed script (`priv/repo/seeds.exs`).
|
|
If no settings exist, this function will create them as a fallback using the
|
|
`ASSOCIATION_NAME` environment variable or "Club Name" as default.
|
|
|
|
## Returns
|
|
|
|
- `{:ok, settings}` - The settings record
|
|
- `{:ok, nil}` - No settings exist (should not happen if seeds were run)
|
|
- `{:error, error}` - Error reading settings
|
|
|
|
## Examples
|
|
|
|
iex> {:ok, settings} = Mv.Membership.get_settings()
|
|
iex> settings.club_name
|
|
"My Club"
|
|
|
|
"""
|
|
def get_settings do
|
|
# Try to get the first (and only) settings record
|
|
case Ash.read_one(Mv.Membership.Setting, domain: __MODULE__) do
|
|
{:ok, nil} ->
|
|
# No settings exist - create as fallback (should normally be created via seed script)
|
|
default_club_name = System.get_env("ASSOCIATION_NAME") || "Club Name"
|
|
|
|
Mv.Membership.Setting
|
|
|> Ash.Changeset.for_create(:create, %{club_name: default_club_name})
|
|
|> Ash.create!(domain: __MODULE__)
|
|
|> then(fn settings -> {:ok, settings} end)
|
|
|
|
{:ok, settings} ->
|
|
{:ok, settings}
|
|
|
|
{:error, error} ->
|
|
{:error, error}
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Updates the global settings.
|
|
|
|
## Parameters
|
|
|
|
- `settings` - The settings record to update
|
|
- `attrs` - A map of attributes to update (e.g., `%{club_name: "New Name"}`)
|
|
|
|
## Returns
|
|
|
|
- `{:ok, updated_settings}` - Successfully updated settings
|
|
- `{:error, error}` - Validation or update error
|
|
|
|
## Examples
|
|
|
|
iex> {:ok, settings} = Mv.Membership.get_settings()
|
|
iex> {:ok, updated} = Mv.Membership.update_settings(settings, %{club_name: "New Club"})
|
|
iex> updated.club_name
|
|
"New Club"
|
|
|
|
"""
|
|
def update_settings(settings, attrs) do
|
|
settings
|
|
|> Ash.Changeset.for_update(:update, attrs)
|
|
|> Ash.update(domain: __MODULE__)
|
|
end
|
|
|
|
@doc """
|
|
Updates the member field visibility configuration.
|
|
|
|
This is a specialized action for updating only the member field visibility settings.
|
|
It validates that all keys are valid member fields and all values are booleans.
|
|
|
|
## Parameters
|
|
|
|
- `settings` - The settings record to update
|
|
- `visibility_config` - A map of member field names (atoms) to boolean visibility values
|
|
(e.g., `%{street: false, house_number: false}`)
|
|
|
|
## Returns
|
|
|
|
- `{:ok, updated_settings}` - Successfully updated settings
|
|
- `{:error, error}` - Validation or update error
|
|
|
|
## Examples
|
|
|
|
iex> {:ok, settings} = Mv.Membership.get_settings()
|
|
iex> {:ok, updated} = Mv.Membership.update_member_field_visibility(settings, %{street: false, house_number: false})
|
|
iex> updated.member_field_visibility
|
|
%{street: false, house_number: false}
|
|
|
|
"""
|
|
def update_member_field_visibility(settings, visibility_config) do
|
|
settings
|
|
|> Ash.Changeset.for_update(:update_member_field_visibility, %{
|
|
member_field_visibility: visibility_config
|
|
})
|
|
|> Ash.update(domain: __MODULE__)
|
|
end
|
|
end
|