- Migrations: vereinfacht_contact_id on members, vereinfacht_* on settings - Mv.Config: Vereinfacht ENV/Settings helpers, vereinfacht_configured?, contact_view_url - Setting: vereinfacht_api_url, api_key, club_id
239 lines
6.6 KiB
Elixir
239 lines
6.6 KiB
Elixir
defmodule Mv.Config do
|
|
@moduledoc """
|
|
Configuration helper functions for the application.
|
|
|
|
Provides centralized access to configuration values to avoid
|
|
magic strings/atoms scattered throughout the codebase.
|
|
"""
|
|
|
|
@doc """
|
|
Returns whether SQL sandbox mode is enabled.
|
|
|
|
SQL sandbox mode is typically enabled in test environments
|
|
to allow concurrent database access in tests.
|
|
|
|
## Returns
|
|
|
|
- `true` if SQL sandbox is enabled
|
|
- `false` otherwise
|
|
"""
|
|
@spec sql_sandbox?() :: boolean()
|
|
def sql_sandbox? do
|
|
Application.get_env(:mv, :sql_sandbox, false)
|
|
end
|
|
|
|
@doc """
|
|
Returns the maximum file size for CSV imports in bytes.
|
|
|
|
Reads the `max_file_size_mb` value from the CSV import configuration
|
|
and converts it to bytes.
|
|
|
|
## Returns
|
|
|
|
- Maximum file size in bytes (default: 10_485_760 bytes = 10 MB)
|
|
|
|
## Examples
|
|
|
|
iex> Mv.Config.csv_import_max_file_size_bytes()
|
|
10_485_760
|
|
"""
|
|
@spec csv_import_max_file_size_bytes() :: non_neg_integer()
|
|
def csv_import_max_file_size_bytes do
|
|
max_file_size_mb = get_csv_import_config(:max_file_size_mb, 10)
|
|
max_file_size_mb * 1024 * 1024
|
|
end
|
|
|
|
@doc """
|
|
Returns the maximum number of rows allowed in CSV imports.
|
|
|
|
Reads the `max_rows` value from the CSV import configuration.
|
|
|
|
## Returns
|
|
|
|
- Maximum number of rows (default: 1000)
|
|
|
|
## Examples
|
|
|
|
iex> Mv.Config.csv_import_max_rows()
|
|
1000
|
|
"""
|
|
@spec csv_import_max_rows() :: pos_integer()
|
|
def csv_import_max_rows do
|
|
get_csv_import_config(:max_rows, 1000)
|
|
end
|
|
|
|
@doc """
|
|
Returns the maximum file size for CSV imports in megabytes.
|
|
|
|
Reads the `max_file_size_mb` value from the CSV import configuration.
|
|
|
|
## Returns
|
|
|
|
- Maximum file size in megabytes (default: 10)
|
|
|
|
## Examples
|
|
|
|
iex> Mv.Config.csv_import_max_file_size_mb()
|
|
10
|
|
"""
|
|
@spec csv_import_max_file_size_mb() :: pos_integer()
|
|
def csv_import_max_file_size_mb do
|
|
get_csv_import_config(:max_file_size_mb, 10)
|
|
end
|
|
|
|
# Helper function to get CSV import config values
|
|
defp get_csv_import_config(key, default) do
|
|
Application.get_env(:mv, :csv_import, [])
|
|
|> Keyword.get(key, default)
|
|
|> parse_and_validate_integer(default)
|
|
end
|
|
|
|
# Parses and validates integer configuration values.
|
|
#
|
|
# Accepts:
|
|
# - Integer values (passed through)
|
|
# - String integers (e.g., "1000") - parsed to integer
|
|
# - Invalid values (e.g., "abc", nil) - falls back to default
|
|
#
|
|
# Always clamps the result to a minimum of 1 to ensure positive values.
|
|
#
|
|
# Note: We don't log warnings for unparseable values because:
|
|
# - These functions may be called frequently (e.g., on every request)
|
|
# - Logging would create excessive log spam
|
|
# - The fallback to default provides a safe behavior
|
|
# - Configuration errors should be caught during deployment/testing
|
|
defp parse_and_validate_integer(value, _default) when is_integer(value) do
|
|
max(1, value)
|
|
end
|
|
|
|
defp parse_and_validate_integer(value, default) when is_binary(value) do
|
|
case Integer.parse(value) do
|
|
{int, _remainder} -> max(1, int)
|
|
:error -> default
|
|
end
|
|
end
|
|
|
|
defp parse_and_validate_integer(_value, default) do
|
|
default
|
|
end
|
|
|
|
@doc """
|
|
Returns the maximum number of rows allowed in PDF exports.
|
|
|
|
Reads the `row_limit` value from the PDF export configuration.
|
|
|
|
## Returns
|
|
|
|
- Maximum number of rows (default: 5000)
|
|
|
|
## Examples
|
|
|
|
iex> Mv.Config.pdf_export_row_limit()
|
|
5000
|
|
"""
|
|
@spec pdf_export_row_limit() :: pos_integer()
|
|
def pdf_export_row_limit do
|
|
get_pdf_export_config(:row_limit, 5000)
|
|
end
|
|
|
|
# Helper function to get PDF export config values
|
|
defp get_pdf_export_config(key, default) do
|
|
Application.get_env(:mv, :pdf_export, [])
|
|
|> Keyword.get(key, default)
|
|
|> parse_and_validate_integer(default)
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Vereinfacht accounting software integration
|
|
# ENV variables take priority; fallback to Settings from database.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@doc """
|
|
Returns the Vereinfacht API base URL.
|
|
|
|
Reads from `VEREINFACHT_API_URL` env first, then from Settings.
|
|
"""
|
|
@spec vereinfacht_api_url() :: String.t() | nil
|
|
def vereinfacht_api_url do
|
|
env_or_setting("VEREINFACHT_API_URL", :vereinfacht_api_url)
|
|
end
|
|
|
|
@doc """
|
|
Returns the Vereinfacht API key (Bearer token).
|
|
|
|
Reads from `VEREINFACHT_API_KEY` env first, then from Settings.
|
|
"""
|
|
@spec vereinfacht_api_key() :: String.t() | nil
|
|
def vereinfacht_api_key do
|
|
env_or_setting("VEREINFACHT_API_KEY", :vereinfacht_api_key)
|
|
end
|
|
|
|
@doc """
|
|
Returns the Vereinfacht club ID for multi-tenancy.
|
|
|
|
Reads from `VEREINFACHT_CLUB_ID` env first, then from Settings.
|
|
"""
|
|
@spec vereinfacht_club_id() :: String.t() | nil
|
|
def vereinfacht_club_id do
|
|
env_or_setting("VEREINFACHT_CLUB_ID", :vereinfacht_club_id)
|
|
end
|
|
|
|
@doc """
|
|
Returns true if Vereinfacht is fully configured (URL, API key, and club ID all set).
|
|
"""
|
|
@spec vereinfacht_configured?() :: boolean()
|
|
def vereinfacht_configured? do
|
|
present?(vereinfacht_api_url()) and present?(vereinfacht_api_key()) and
|
|
present?(vereinfacht_club_id())
|
|
end
|
|
|
|
@doc """
|
|
Returns true if any Vereinfacht ENV variable is set (used to gray out Settings UI).
|
|
"""
|
|
@spec vereinfacht_env_configured?() :: boolean()
|
|
def vereinfacht_env_configured? do
|
|
System.get_env("VEREINFACHT_API_URL") != nil or
|
|
System.get_env("VEREINFACHT_API_KEY") != nil or
|
|
System.get_env("VEREINFACHT_CLUB_ID") != nil
|
|
end
|
|
|
|
defp env_or_setting(env_key, setting_key) do
|
|
case System.get_env(env_key) do
|
|
nil -> get_vereinfacht_from_settings(setting_key)
|
|
value -> trim_nil(value)
|
|
end
|
|
end
|
|
|
|
defp get_vereinfacht_from_settings(key) do
|
|
case Mv.Membership.get_settings() do
|
|
{:ok, settings} -> settings |> Map.get(key) |> trim_nil()
|
|
{:error, _} -> nil
|
|
end
|
|
end
|
|
|
|
defp trim_nil(nil), do: nil
|
|
|
|
defp trim_nil(s) when is_binary(s) do
|
|
t = String.trim(s)
|
|
if t == "", do: nil, else: t
|
|
end
|
|
|
|
@doc """
|
|
Returns the URL to view a finance contact (e.g. in Vereinfacht frontend or API).
|
|
|
|
Uses the configured API base URL and appends /finance-contacts/{id}.
|
|
Can be extended later with a dedicated frontend URL setting.
|
|
"""
|
|
@spec vereinfacht_contact_view_url(String.t()) :: String.t() | nil
|
|
def vereinfacht_contact_view_url(contact_id) when is_binary(contact_id) do
|
|
base = vereinfacht_api_url()
|
|
|
|
if present?(base),
|
|
do: base |> String.trim_trailing("/") |> then(&"#{&1}/finance-contacts/#{contact_id}"),
|
|
else: nil
|
|
end
|
|
|
|
defp present?(nil), do: false
|
|
defp present?(s) when is_binary(s), do: String.trim(s) != ""
|
|
defp present?(_), do: false
|
|
end
|