Added more settings methods; Hooked up initial settings runner to app boot
This commit is contained in:
parent
97f899e11d
commit
970f12792a
6 changed files with 107 additions and 6 deletions
1
.iex.exs
1
.iex.exs
|
|
@ -11,6 +11,7 @@ alias Pinchflat.Tasks
|
||||||
alias Pinchflat.Media
|
alias Pinchflat.Media
|
||||||
alias Pinchflat.Profiles
|
alias Pinchflat.Profiles
|
||||||
alias Pinchflat.Sources
|
alias Pinchflat.Sources
|
||||||
|
alias Pinchflat.Settings
|
||||||
|
|
||||||
alias Pinchflat.MediaClient.{SourceDetails, MediaDownloader}
|
alias Pinchflat.MediaClient.{SourceDetails, MediaDownloader}
|
||||||
alias Pinchflat.Metadata.{Zipper, ThumbnailFetcher}
|
alias Pinchflat.Metadata.{Zipper, ThumbnailFetcher}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ defmodule Pinchflat.Application do
|
||||||
children = [
|
children = [
|
||||||
PinchflatWeb.Telemetry,
|
PinchflatWeb.Telemetry,
|
||||||
Pinchflat.Repo,
|
Pinchflat.Repo,
|
||||||
|
# {Task, &run_startup_tasks/0},
|
||||||
|
Pinchflat.StartupTasks,
|
||||||
{Oban, Application.fetch_env!(:pinchflat, Oban)},
|
{Oban, Application.fetch_env!(:pinchflat, Oban)},
|
||||||
{DNSCluster, query: Application.get_env(:pinchflat, :dns_cluster_query) || :ignore},
|
{DNSCluster, query: Application.get_env(:pinchflat, :dns_cluster_query) || :ignore},
|
||||||
{Phoenix.PubSub, name: Pinchflat.PubSub},
|
{Phoenix.PubSub, name: Pinchflat.PubSub},
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ defmodule Pinchflat.Settings do
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Creates or updates a setting, returning the parsed value.
|
Creates or updates a setting, returning the parsed value.
|
||||||
Raises if an unsupported datatype is used.
|
Raises if an unsupported datatype is used. Optionally allows
|
||||||
|
specifying the datatype.
|
||||||
|
|
||||||
Returns value in type of `Ecto.Enum.mappings(Setting, :datatype)`
|
Returns value in type of `Ecto.Enum.mappings(Setting, :datatype)`
|
||||||
"""
|
"""
|
||||||
|
|
@ -46,6 +47,24 @@ defmodule Pinchflat.Settings do
|
||||||
|> read_setting()
|
|> read_setting()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Attempts to find a setting by name or creates a setting with value
|
||||||
|
if one doesn't exist, returning the parsed value. Optionally allows
|
||||||
|
specifying the datatype.
|
||||||
|
|
||||||
|
Returns value in type of `Ecto.Enum.mappings(Setting, :datatype)`
|
||||||
|
"""
|
||||||
|
def fetch!(name, value) do
|
||||||
|
fetch!(name, value, infer_datatype(value))
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch!(name, value, datatype) do
|
||||||
|
case Repo.get_by(Setting, name: to_string(name)) do
|
||||||
|
nil -> create_setting!(name, value, datatype)
|
||||||
|
setting -> read_setting(setting)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp change_setting(setting, attrs) do
|
defp change_setting(setting, attrs) do
|
||||||
Setting.changeset(setting, attrs)
|
Setting.changeset(setting, attrs)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
36
lib/pinchflat/startup_tasks.ex
Normal file
36
lib/pinchflat/startup_tasks.ex
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
defmodule Pinchflat.StartupTasks do
|
||||||
|
@moduledoc """
|
||||||
|
This module is responsible for running startup tasks on app boot.
|
||||||
|
|
||||||
|
It's a GenServer because that plays REALLY nicely with the existing
|
||||||
|
Phoenix supervision tree.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# restart: :temporary means that this process will never be restarted (ie: will run once and then die)
|
||||||
|
use GenServer, restart: :temporary
|
||||||
|
|
||||||
|
alias Pinchflat.Settings
|
||||||
|
|
||||||
|
def start_link(opts \\ []) do
|
||||||
|
GenServer.start_link(__MODULE__, %{}, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Runs application startup tasks.
|
||||||
|
|
||||||
|
Any code defined here will run every time the application starts. You must
|
||||||
|
make sure that the code is idempotent and safe to run multiple times.
|
||||||
|
|
||||||
|
This is a good place to set up default settings, create initial records, stuff like that
|
||||||
|
"""
|
||||||
|
@impl true
|
||||||
|
def init(state) do
|
||||||
|
apply_default_settings()
|
||||||
|
|
||||||
|
{:ok, state}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp apply_default_settings do
|
||||||
|
Settings.fetch!(:onboarding, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -4,25 +4,32 @@ defmodule Pinchflat.SettingsTest do
|
||||||
alias Pinchflat.Settings
|
alias Pinchflat.Settings
|
||||||
alias Pinchflat.Settings.Setting
|
alias Pinchflat.Settings.Setting
|
||||||
|
|
||||||
|
# NOTE: We're treating some of these tests differently
|
||||||
|
# than in other modules because certain settings
|
||||||
|
# are always created on app boot (including in the test env),
|
||||||
|
# so we can't treat these like a clean slate.
|
||||||
|
|
||||||
describe "list_settings/0" do
|
describe "list_settings/0" do
|
||||||
test "returns all settings" do
|
test "returns all settings" do
|
||||||
Settings.set!("foo", "bar")
|
Settings.set!("foo", "bar")
|
||||||
assert [_] = Settings.list_settings()
|
results = Settings.list_settings()
|
||||||
|
|
||||||
|
assert Enum.all?(results, fn setting -> match?(%Setting{}, setting) end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "set/2" do
|
describe "set/2" do
|
||||||
test "creates a new setting if one does not exist" do
|
test "creates a new setting if one does not exist" do
|
||||||
assert Repo.aggregate(Setting, :count, :id) == 0
|
original = Repo.aggregate(Setting, :count, :id)
|
||||||
Settings.set!("foo", "bar")
|
Settings.set!("foo", "bar")
|
||||||
assert Repo.aggregate(Setting, :count, :id) == 1
|
assert Repo.aggregate(Setting, :count, :id) == original + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
test "updates an existing setting if one exists" do
|
test "updates an existing setting if one exists" do
|
||||||
Settings.set!("foo", "bar")
|
Settings.set!("foo", "bar")
|
||||||
assert Repo.aggregate(Setting, :count, :id) == 1
|
original = Repo.aggregate(Setting, :count, :id)
|
||||||
Settings.set!("foo", "baz")
|
Settings.set!("foo", "baz")
|
||||||
assert Repo.aggregate(Setting, :count, :id) == 1
|
assert Repo.aggregate(Setting, :count, :id) == original
|
||||||
assert Settings.get!("foo") == "baz"
|
assert Settings.get!("foo") == "baz"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -78,4 +85,24 @@ defmodule Pinchflat.SettingsTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "fetch/2" do
|
||||||
|
test "creates a setting if one doesn't exist" do
|
||||||
|
original = Repo.aggregate(Setting, :count, :id)
|
||||||
|
assert Settings.fetch!("foo", "bar") == "bar"
|
||||||
|
assert Repo.aggregate(Setting, :count, :id) == original + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns an existing setting if one does exist" do
|
||||||
|
Settings.set!("foo", "bar")
|
||||||
|
|
||||||
|
assert Settings.fetch!("foo", "baz") == "bar"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "fetch/3" do
|
||||||
|
test "allows manual specification of datatype" do
|
||||||
|
assert Settings.fetch!("foo", "true", :boolean) == true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
16
test/pinchflat/startup_tasks_test.exs
Normal file
16
test/pinchflat/startup_tasks_test.exs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
defmodule Pinchflat.StartupTasksTest do
|
||||||
|
use Pinchflat.DataCase
|
||||||
|
|
||||||
|
alias Pinchflat.Settings
|
||||||
|
|
||||||
|
# Since this runs on app boot (even in the test env),
|
||||||
|
# any actions in the `init/1` function will already have
|
||||||
|
# run. So we can only test the side effects of those actions,
|
||||||
|
# rather than the actions themselves.
|
||||||
|
|
||||||
|
describe "apply_default_settings" do
|
||||||
|
test "sets default settings" do
|
||||||
|
assert Settings.get!(:onboarding) == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue