298 lines
8.6 KiB
Elixir
298 lines
8.6 KiB
Elixir
defmodule ShootingEventPhx.Domain.Settings do
|
|
@moduledoc false
|
|
import Ecto.Query
|
|
alias ShootingEventPhx.Repo
|
|
alias ShootingEventPhx.Domain.AppSetting
|
|
|
|
@setting_view_proof_in_view "view_proof_in_view"
|
|
@setting_live_active_view "live_active_view"
|
|
@setting_live_show_group_live "live_show_group_live"
|
|
@setting_live_group_display_mode "live_group_display_mode"
|
|
@setting_live_group_fixed_code "live_group_fixed_code"
|
|
@setting_live_show_prelim_tie "live_show_prelim_tie"
|
|
@setting_live_show_prelim_overall "live_show_prelim_overall"
|
|
@setting_live_show_final_groups "live_show_final_groups"
|
|
@setting_live_final_display_mode "live_final_display_mode"
|
|
@setting_live_final_fixed_group "live_final_fixed_group"
|
|
@setting_live_show_final_tie "live_show_final_tie"
|
|
@setting_live_show_podium "live_show_podium"
|
|
@setting_live_rotation_interval "live_rotation_interval_sec"
|
|
@setting_live_rotation_players "live_rotation_player_count"
|
|
|
|
@allowed_live_views MapSet.new([
|
|
"group_live",
|
|
"prelim_tie",
|
|
"prelim_overall",
|
|
"final_groups",
|
|
"final_tie",
|
|
"podium"
|
|
])
|
|
|
|
def default_live_mode do
|
|
%{
|
|
"activeView" => "group_live",
|
|
"showGroupLive" => true,
|
|
"groupDisplayMode" => "rotate",
|
|
"groupFixedCode" => "",
|
|
"showPrelimTie" => true,
|
|
"showPrelimOverall" => true,
|
|
"showFinalGroups" => true,
|
|
"finalDisplayMode" => "rotate",
|
|
"finalFixedGroup" => 1,
|
|
"showFinalTie" => true,
|
|
"showPodium" => true,
|
|
"rotationIntervalSec" => 5,
|
|
"rotationPlayerCount" => 12
|
|
}
|
|
end
|
|
|
|
def read_settings do
|
|
all =
|
|
Repo.all(from s in AppSetting, select: {s.key, s.value})
|
|
|> Map.new()
|
|
|
|
live = default_live_mode()
|
|
|
|
live =
|
|
live
|
|
|> Map.put("showGroupLive", setting_bool(Map.get(all, @setting_live_show_group_live, "1")))
|
|
|> Map.put(
|
|
"activeView",
|
|
normalize_live_active_view(
|
|
Map.get(all, @setting_live_active_view, live["activeView"]),
|
|
live["activeView"]
|
|
)
|
|
)
|
|
|> Map.put(
|
|
"groupDisplayMode",
|
|
normalize_display_mode(
|
|
Map.get(all, @setting_live_group_display_mode, live["groupDisplayMode"]),
|
|
live["groupDisplayMode"]
|
|
)
|
|
)
|
|
|> Map.put(
|
|
"groupFixedCode",
|
|
String.upcase(String.trim(Map.get(all, @setting_live_group_fixed_code, "")))
|
|
)
|
|
|> Map.put("showPrelimTie", setting_bool(Map.get(all, @setting_live_show_prelim_tie, "1")))
|
|
|> Map.put(
|
|
"showPrelimOverall",
|
|
setting_bool(Map.get(all, @setting_live_show_prelim_overall, "1"))
|
|
)
|
|
|> Map.put(
|
|
"showFinalGroups",
|
|
setting_bool(Map.get(all, @setting_live_show_final_groups, "1"))
|
|
)
|
|
|> Map.put(
|
|
"finalDisplayMode",
|
|
normalize_display_mode(
|
|
Map.get(all, @setting_live_final_display_mode, live["finalDisplayMode"]),
|
|
live["finalDisplayMode"]
|
|
)
|
|
)
|
|
|> Map.put(
|
|
"finalFixedGroup",
|
|
normalize_final_fixed_group(Map.get(all, @setting_live_final_fixed_group, "1"), 1)
|
|
)
|
|
|> Map.put("showFinalTie", setting_bool(Map.get(all, @setting_live_show_final_tie, "1")))
|
|
|> Map.put("showPodium", setting_bool(Map.get(all, @setting_live_show_podium, "1")))
|
|
|> Map.put(
|
|
"rotationIntervalSec",
|
|
normalize_rotation_interval(Map.get(all, @setting_live_rotation_interval, "5"), 5)
|
|
)
|
|
|> Map.put(
|
|
"rotationPlayerCount",
|
|
normalize_rotation_player_count(Map.get(all, @setting_live_rotation_players, "12"), 12)
|
|
)
|
|
|
|
%{
|
|
"viewProofInView" => setting_bool(Map.get(all, @setting_view_proof_in_view, "0")),
|
|
"liveMode" => live
|
|
}
|
|
end
|
|
|
|
def update_settings(%{} = req) do
|
|
has_update =
|
|
Map.has_key?(req, "viewProofInView") or
|
|
Map.has_key?(req, :viewProofInView) or
|
|
Map.has_key?(req, "liveMode") or
|
|
Map.has_key?(req, :liveMode)
|
|
|
|
if not has_update do
|
|
{:error, "at least one settings field is required"}
|
|
else
|
|
Repo.transaction(fn ->
|
|
req
|
|
|> get_value("viewProofInView")
|
|
|> maybe_upsert(@setting_view_proof_in_view)
|
|
|
|
live_patch = get_value(req, "liveMode")
|
|
if is_map(live_patch), do: persist_live_patch(live_patch)
|
|
end)
|
|
|> case do
|
|
{:ok, _} -> :ok
|
|
{:error, %Ecto.ConstraintError{} = e} -> {:error, Exception.message(e)}
|
|
{:error, reason} when is_binary(reason) -> {:error, reason}
|
|
{:error, reason} -> {:error, inspect(reason)}
|
|
end
|
|
end
|
|
end
|
|
|
|
defp persist_live_patch(patch) do
|
|
patch
|
|
|> get_value("activeView")
|
|
|> maybe_upsert(@setting_live_active_view, fn v ->
|
|
normalize_live_active_view(v, "group_live")
|
|
end)
|
|
|
|
patch
|
|
|> get_value("showGroupLive")
|
|
|> maybe_upsert(@setting_live_show_group_live)
|
|
|
|
patch
|
|
|> get_value("groupDisplayMode")
|
|
|> maybe_upsert(@setting_live_group_display_mode, fn v ->
|
|
normalize_display_mode(v, "rotate")
|
|
end)
|
|
|
|
patch
|
|
|> get_value("groupFixedCode")
|
|
|> maybe_upsert(@setting_live_group_fixed_code, fn v ->
|
|
v |> to_string() |> String.trim() |> String.upcase()
|
|
end)
|
|
|
|
patch
|
|
|> get_value("showPrelimTie")
|
|
|> maybe_upsert(@setting_live_show_prelim_tie)
|
|
|
|
patch
|
|
|> get_value("showPrelimOverall")
|
|
|> maybe_upsert(@setting_live_show_prelim_overall)
|
|
|
|
patch
|
|
|> get_value("showFinalGroups")
|
|
|> maybe_upsert(@setting_live_show_final_groups)
|
|
|
|
patch
|
|
|> get_value("finalDisplayMode")
|
|
|> maybe_upsert(@setting_live_final_display_mode, fn v ->
|
|
normalize_display_mode(v, "rotate")
|
|
end)
|
|
|
|
patch
|
|
|> get_value("finalFixedGroup")
|
|
|> maybe_upsert(@setting_live_final_fixed_group, fn v -> normalize_final_fixed_group(v, 1) end)
|
|
|
|
patch
|
|
|> get_value("showFinalTie")
|
|
|> maybe_upsert(@setting_live_show_final_tie)
|
|
|
|
patch
|
|
|> get_value("showPodium")
|
|
|> maybe_upsert(@setting_live_show_podium)
|
|
|
|
patch
|
|
|> get_value("rotationIntervalSec")
|
|
|> maybe_upsert(@setting_live_rotation_interval, fn v -> normalize_rotation_interval(v, 5) end)
|
|
|
|
patch
|
|
|> get_value("rotationPlayerCount")
|
|
|> maybe_upsert(@setting_live_rotation_players, fn v ->
|
|
normalize_rotation_player_count(v, 12)
|
|
end)
|
|
end
|
|
|
|
defp maybe_upsert(nil, _key), do: :ok
|
|
|
|
defp maybe_upsert(value, key) do
|
|
normalized = setting_string(value)
|
|
|
|
Repo.insert!(
|
|
%AppSetting{key: key, value: normalized},
|
|
on_conflict: [set: [value: normalized, updated_at: DateTime.utc_now()]],
|
|
conflict_target: :key
|
|
)
|
|
end
|
|
|
|
defp maybe_upsert(nil, _key, _fun), do: :ok
|
|
|
|
defp maybe_upsert(value, key, normalize_fun) do
|
|
normalized = value |> normalize_fun.() |> setting_string()
|
|
maybe_upsert(normalized, key)
|
|
end
|
|
|
|
defp get_value(map, key) when is_map(map) do
|
|
cond do
|
|
Map.has_key?(map, key) -> Map.get(map, key)
|
|
Map.has_key?(map, String.to_atom(key)) -> Map.get(map, String.to_atom(key))
|
|
true -> nil
|
|
end
|
|
end
|
|
|
|
defp setting_bool(value) do
|
|
case value |> to_string() |> String.trim() |> String.downcase() do
|
|
"1" -> true
|
|
"true" -> true
|
|
"yes" -> true
|
|
"on" -> true
|
|
_ -> false
|
|
end
|
|
end
|
|
|
|
defp setting_string(v) when is_boolean(v), do: if(v, do: "1", else: "0")
|
|
defp setting_string(v) when is_integer(v), do: Integer.to_string(v)
|
|
defp setting_string(v), do: v |> to_string()
|
|
|
|
defp normalize_display_mode(value, fallback) do
|
|
case value |> to_string() |> String.trim() |> String.downcase() do
|
|
"fixed" -> "fixed"
|
|
"rotate" -> "rotate"
|
|
_ -> if(String.downcase(to_string(fallback)) == "fixed", do: "fixed", else: "rotate")
|
|
end
|
|
end
|
|
|
|
defp normalize_final_fixed_group(value, fallback) do
|
|
parsed =
|
|
case Integer.parse(to_string(value)) do
|
|
{v, _} -> v
|
|
_ -> fallback
|
|
end
|
|
|
|
if parsed == 2, do: 2, else: 1
|
|
end
|
|
|
|
defp normalize_rotation_interval(value, fallback) do
|
|
parsed =
|
|
case Integer.parse(to_string(value)) do
|
|
{v, _} -> v
|
|
_ -> fallback
|
|
end
|
|
|
|
parsed |> max(3) |> min(30)
|
|
end
|
|
|
|
defp normalize_rotation_player_count(value, fallback) do
|
|
parsed =
|
|
case Integer.parse(to_string(value)) do
|
|
{v, _} -> v
|
|
_ -> fallback
|
|
end
|
|
|
|
parsed |> max(3) |> min(40)
|
|
end
|
|
|
|
defp normalize_live_active_view(value, fallback) do
|
|
normalized =
|
|
value
|
|
|> to_string()
|
|
|> String.trim()
|
|
|> String.downcase()
|
|
|
|
cond do
|
|
MapSet.member?(@allowed_live_views, normalized) -> normalized
|
|
MapSet.member?(@allowed_live_views, to_string(fallback)) -> fallback
|
|
true -> "group_live"
|
|
end
|
|
end
|
|
end
|