Packages
phoenix_kit
1.2.7
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit/settings.ex
defmodule PhoenixKit.Settings do
@moduledoc """
The Settings context for system configuration management.
This module provides functions for managing system-wide settings in PhoenixKit.
Settings are stored in the database and can be updated through the admin panel.
## Core Functions
### Settings Management
- `get_setting/1` - Get a setting value by key
- `get_setting/2` - Get a setting value with default fallback
- `update_setting/2` - Update or create a setting
- `list_all_settings/0` - Get all settings as a map
### Default Settings
The system includes three core settings:
- `time_zone`: System timezone offset
- `date_format`: Date display format
- `time_format`: Time display format
## Usage Examples
# Get a setting with default
timezone = PhoenixKit.Settings.get_setting("time_zone", "0")
# Update a setting
{:ok, setting} = PhoenixKit.Settings.update_setting("time_zone", "+1")
# Get all settings as a map
settings = PhoenixKit.Settings.list_all_settings()
# => %{"time_zone" => "0", "date_format" => "Y-m-d", "time_format" => "H:i"}
## Configuration
The context uses PhoenixKit's configured repository and respects table prefixes
set during installation.
"""
import Ecto.Query, warn: false
import Ecto.Changeset, only: [add_error: 3]
alias PhoenixKit.Settings.Setting
alias PhoenixKit.Settings.Setting.SettingsForm
alias PhoenixKit.Utils.Date, as: UtilsDate
# Gets the configured repository for database operations.
# Uses PhoenixKit.RepoHelper to get the configured repo with proper prefix support.
defp repo do
PhoenixKit.RepoHelper.repo()
end
@doc """
Gets a setting value by key.
Returns the setting value as a string, or nil if not found.
## Examples
iex> PhoenixKit.Settings.get_setting("time_zone")
"0"
iex> PhoenixKit.Settings.get_setting("non_existent")
nil
"""
def get_setting(key) when is_binary(key) do
setting_record = repo().get_by(Setting, key: key)
case setting_record do
%Setting{value: value} -> value
nil -> nil
end
end
@doc """
Gets a setting value by key with a default fallback.
Returns the setting value as a string, or the default if not found.
## Examples
iex> PhoenixKit.Settings.get_setting("time_zone", "0")
"0"
iex> PhoenixKit.Settings.get_setting("non_existent", "default")
"default"
"""
def get_setting(key, default) when is_binary(key) do
get_setting(key) || default
end
@doc """
Updates or creates a setting with the given key and value.
If the setting exists, updates its value and timestamp.
If the setting doesn't exist, creates a new one.
Returns `{:ok, setting}` on success, `{:error, changeset}` on failure.
## Examples
iex> PhoenixKit.Settings.update_setting("time_zone", "+1")
{:ok, %Setting{key: "time_zone", value: "+1"}}
iex> PhoenixKit.Settings.update_setting("", "invalid")
{:error, %Ecto.Changeset{}}
"""
def update_setting(key, value) when is_binary(key) and is_binary(value) do
case repo().get_by(Setting, key: key) do
%Setting{} = setting ->
setting
|> Setting.update_changeset(%{value: value})
|> repo().update()
nil ->
%Setting{}
|> Setting.changeset(%{key: key, value: value})
|> repo().insert()
end
end
@doc """
Lists all settings as a map with keys as setting names and values as setting values.
Returns a map where keys are setting names and values are setting values.
Useful for loading all settings at once for forms or configuration.
## Examples
iex> PhoenixKit.Settings.list_all_settings()
%{
"time_zone" => "0",
"date_format" => "Y-m-d",
"time_format" => "H:i"
}
"""
def list_all_settings do
Setting
|> select([s], {s.key, s.value})
|> repo().all()
|> Map.new()
end
@doc """
Gets all settings with their full details (including timestamps).
Returns a list of Setting structs. Useful for admin interfaces
that need to show when settings were created/updated.
## Examples
iex> PhoenixKit.Settings.list_settings()
[
%Setting{key: "time_zone", value: "0", date_added: ~U[2024-01-01 00:00:00.000000Z]},
%Setting{key: "date_format", value: "Y-m-d", date_added: ~U[2024-01-01 00:00:00.000000Z]}
]
"""
def list_settings do
Setting
|> order_by([s], s.key)
|> repo().all()
end
@doc """
Gets the available options for each setting type.
Returns a map with setting keys and their available options as {label, value} tuples.
Used to populate dropdown menus in the admin interface.
## Examples
iex> PhoenixKit.Settings.get_setting_options()
%{
"time_zone" => [{"UTC-12", "-12"}, {"UTC+0 (GMT)", "0"}, {"UTC+8", "8"}],
"date_format" => [{"YYYY-MM-DD", "Y-m-d"}, {"MM/DD/YYYY", "m/d/Y"}],
"time_format" => [{"24 Hour (15:30)", "H:i"}, {"12 Hour (3:30 PM)", "h:i A"}]
}
"""
def get_setting_options do
%{
"time_zone" => [
{"UTC-12 (Baker Island)", "-12"},
{"UTC-11 (American Samoa)", "-11"},
{"UTC-10 (Hawaii)", "-10"},
{"UTC-9 (Alaska)", "-9"},
{"UTC-8 (Pacific Time)", "-8"},
{"UTC-7 (Mountain Time)", "-7"},
{"UTC-6 (Central Time)", "-6"},
{"UTC-5 (Eastern Time)", "-5"},
{"UTC-4 (Atlantic Time)", "-4"},
{"UTC-3 (Argentina)", "-3"},
{"UTC-2 (Mid-Atlantic)", "-2"},
{"UTC-1 (Cape Verde)", "-1"},
{"UTC+0 (GMT/London)", "0"},
{"UTC+1 (Central Europe)", "1"},
{"UTC+2 (Eastern Europe)", "2"},
{"UTC+3 (Moscow)", "3"},
{"UTC+4 (Dubai)", "4"},
{"UTC+5 (Pakistan)", "5"},
{"UTC+6 (Bangladesh)", "6"},
{"UTC+7 (Thailand)", "7"},
{"UTC+8 (China/Singapore)", "8"},
{"UTC+9 (Japan/Korea)", "9"},
{"UTC+10 (Australia East)", "10"},
{"UTC+11 (Solomon Islands)", "11"},
{"UTC+12 (New Zealand)", "12"}
],
"date_format" => UtilsDate.get_date_format_options(),
"time_format" => UtilsDate.get_time_format_options()
}
end
@doc """
Gets default values for all settings.
Returns a map with setting keys and their default values.
These defaults match the ones defined in the V03 migration.
## Examples
iex> PhoenixKit.Settings.get_defaults()
%{
"time_zone" => "0",
"date_format" => "Y-m-d",
"time_format" => "H:i"
}
"""
def get_defaults do
%{
"project_title" => "PhoenixKit",
"time_zone" => "0",
"date_format" => "Y-m-d",
"time_format" => "H:i"
}
end
@doc """
Gets the display label for a timezone value.
## Examples
iex> PhoenixKit.Settings.get_timezone_label("0", get_setting_options())
"UTC+0 (GMT/London)"
"""
def get_timezone_label(value, setting_options) do
case Enum.find(setting_options["time_zone"], fn {_label, val} -> val == value end) do
{label, _value} -> label
nil -> "UTC#{if value != "0", do: value, else: ""}"
end
end
@doc """
Gets the display label for a setting option value.
## Examples
iex> options = [{"YYYY-MM-DD", "Y-m-d"}, {"MM/DD/YYYY", "m/d/Y"}]
iex> PhoenixKit.Settings.get_option_label("Y-m-d", options)
"YYYY-MM-DD"
"""
def get_option_label(value, options) do
case Enum.find(options, fn {_label, val} -> val == value end) do
{label, _value} -> label
nil -> value
end
end
@doc """
Gets a boolean setting value by key with a default fallback.
Converts string values "true"/"false" to actual boolean values.
Returns the default if the setting is not found or has an invalid value.
## Examples
iex> PhoenixKit.Settings.get_boolean_setting("feature_enabled", false)
false
iex> PhoenixKit.Settings.get_boolean_setting("feature_enabled", true)
true
"""
def get_boolean_setting(key, default \\ false) when is_binary(key) and is_boolean(default) do
raw_value = get_setting(key)
case raw_value do
"true" -> true
"false" -> false
nil -> default
_ -> default
end
end
@doc """
Gets an integer setting value by key, with fallback to default.
Converts the stored string value to an integer. If the setting doesn't exist
or cannot be converted to an integer, returns the default value.
## Examples
iex> PhoenixKit.Settings.get_integer_setting("max_items", 10)
10
iex> PhoenixKit.Settings.get_integer_setting("existing_number", 5)
25 # if "25" is stored in database
"""
def get_integer_setting(key, default \\ 0) when is_binary(key) and is_integer(default) do
raw_value = get_setting(key)
case raw_value do
nil ->
default
value when is_binary(value) ->
case Integer.parse(value) do
{integer_value, _} -> integer_value
:error -> default
end
_ ->
default
end
end
@doc """
Updates or creates a boolean setting with the given key and boolean value.
Converts boolean values to "true"/"false" strings for storage.
If the setting exists, updates its value and timestamp.
If the setting doesn't exist, creates a new one.
Returns `{:ok, setting}` on success, `{:error, changeset}` on failure.
## Examples
iex> PhoenixKit.Settings.update_boolean_setting("feature_enabled", true)
{:ok, %Setting{key: "feature_enabled", value: "true"}}
iex> PhoenixKit.Settings.update_boolean_setting("feature_enabled", false)
{:ok, %Setting{key: "feature_enabled", value: "false"}}
"""
def update_boolean_setting(key, boolean_value)
when is_binary(key) and is_boolean(boolean_value) do
string_value = if boolean_value, do: "true", else: "false"
update_setting(key, string_value)
end
@doc """
Updates or creates a setting with module association.
Similar to update_setting/2 but allows specifying which module the setting belongs to.
Useful for organizing feature-specific settings.
## Examples
iex> PhoenixKit.Settings.update_setting_with_module("codes_enabled", "true", "referral_codes")
{:ok, %Setting{key: "codes_enabled", value: "true", module: "referral_codes"}}
"""
def update_setting_with_module(key, value, module) when is_binary(key) and is_binary(value) do
existing_setting = repo().get_by(Setting, key: key)
case existing_setting do
%Setting{} = setting ->
setting
|> Setting.update_changeset(%{value: value, module: module})
|> repo().update()
nil ->
%Setting{}
|> Setting.changeset(%{key: key, value: value, module: module})
|> repo().insert()
end
end
@doc """
Updates or creates a boolean setting with module association.
Combines boolean handling with module organization.
## Examples
iex> PhoenixKit.Settings.update_boolean_setting_with_module("feature_enabled", true, "referral_codes")
{:ok, %Setting{key: "feature_enabled", value: "true", module: "referral_codes"}}
"""
def update_boolean_setting_with_module(key, boolean_value, module)
when is_binary(key) and is_boolean(boolean_value) and is_binary(module) do
string_value = if boolean_value, do: "true", else: "false"
update_setting_with_module(key, string_value, module)
end
## Settings Form Functions
@doc """
Creates a changeset for settings form validation.
Takes a map of settings and returns a changeset that can be used in Phoenix forms.
This function handles the conversion from string keys to atoms and creates the proper
embedded schema structure for form validation.
## Examples
iex> settings = %{"project_title" => "My App", "time_zone" => "0"}
iex> PhoenixKit.Settings.change_settings(settings)
%Ecto.Changeset{data: %SettingsForm{}, valid?: true}
iex> PhoenixKit.Settings.change_settings(%{})
%Ecto.Changeset{data: %SettingsForm{}, valid?: false}
"""
def change_settings(settings \\ %{}) do
# Convert string keys to atoms for the embedded schema
attrs = atomize_keys(settings)
# Create the form struct with current values
form_data = struct(SettingsForm, attrs)
# Create changeset without validation action
SettingsForm.changeset(form_data, attrs)
end
@doc """
Validates settings parameters and returns a changeset.
Similar to change_settings/1 but sets the action to :validate to trigger
error display in forms.
## Examples
iex> settings = %{"project_title" => "", "time_zone" => "invalid"}
iex> changeset = PhoenixKit.Settings.validate_settings(settings)
iex> changeset.action
:validate
iex> changeset.valid?
false
"""
def validate_settings(settings) do
settings
|> change_settings()
|> Map.put(:action, :validate)
end
@doc """
Updates multiple settings at once using form parameters.
Takes a map of settings parameters, validates them, and if valid, updates
all settings in the database. This is typically used from the settings form
in the admin panel.
Returns `{:ok, updated_settings_map}` on success or `{:error, changeset}` on failure.
## Examples
iex> params = %{"project_title" => "My App", "time_zone" => "+1"}
iex> PhoenixKit.Settings.update_settings(params)
{:ok, %{"project_title" => "My App", "time_zone" => "+1"}}
iex> PhoenixKit.Settings.update_settings(%{"time_zone" => "invalid"})
{:error, %Ecto.Changeset{}}
"""
def update_settings(settings_params) do
changeset = validate_settings(settings_params)
if changeset.valid? do
case update_all_settings_from_changeset(changeset) do
{:ok, updated_settings} -> {:ok, updated_settings}
{:error, errors} -> {:error, add_error(changeset, :base, errors)}
end
else
{:error, changeset}
end
end
# Private helper to convert string keys to atoms for changeset
defp atomize_keys(map) when is_map(map) do
Map.new(map, fn {k, v} -> {String.to_atom(k), v} end)
end
# Private helper to update all settings from a valid changeset
defp update_all_settings_from_changeset(changeset) do
# Extract the changes from the changeset
settings_to_update =
changeset.changes
|> Map.new(fn {k, v} -> {Atom.to_string(k), v} end)
# Update each setting in the database
updated_settings =
Enum.reduce(settings_to_update, %{}, fn {key, value}, acc ->
case update_setting(key, value) do
{:ok, _setting} -> Map.put(acc, key, value)
{:error, _changeset} -> acc
end
end)
# Check if all settings were updated successfully
if map_size(updated_settings) == map_size(settings_to_update) do
{:ok, updated_settings}
else
{:error, "Some settings failed to update"}
end
end
end