final
This commit is contained in:
@@ -3,33 +3,275 @@ package main
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (a *App) readSettings() (AppSettings, error) {
|
||||
var raw string
|
||||
err := a.db.QueryRow(`SELECT value FROM app_settings WHERE key = 'view_proof_in_view'`).Scan(&raw)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return AppSettings{ViewProofInView: false}, nil
|
||||
}
|
||||
return AppSettings{}, fmt.Errorf("read app setting view_proof_in_view: %w", err)
|
||||
const (
|
||||
settingViewProofInView = "view_proof_in_view"
|
||||
settingLiveActiveView = "live_active_view"
|
||||
settingLiveShowGroupLive = "live_show_group_live"
|
||||
settingLiveGroupDisplayMode = "live_group_display_mode"
|
||||
settingLiveGroupFixedCode = "live_group_fixed_code"
|
||||
settingLiveShowPrelimTie = "live_show_prelim_tie"
|
||||
settingLiveShowPrelimOverall = "live_show_prelim_overall"
|
||||
settingLiveShowFinalGroups = "live_show_final_groups"
|
||||
settingLiveFinalDisplayMode = "live_final_display_mode"
|
||||
settingLiveFinalFixedGroup = "live_final_fixed_group"
|
||||
settingLiveShowFinalTie = "live_show_final_tie"
|
||||
settingLiveShowPodium = "live_show_podium"
|
||||
settingLiveRotationInterval = "live_rotation_interval_sec"
|
||||
settingLiveRotationPlayers = "live_rotation_player_count"
|
||||
)
|
||||
|
||||
func defaultLiveModeSettings() LiveModeSettings {
|
||||
return LiveModeSettings{
|
||||
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,
|
||||
}
|
||||
return AppSettings{ViewProofInView: settingBool(raw)}, nil
|
||||
}
|
||||
|
||||
func (a *App) updateViewProofInView(enabled bool) error {
|
||||
_, err := a.db.Exec(`
|
||||
INSERT INTO app_settings(key, value, updated_at)
|
||||
VALUES('view_proof_in_view', ?, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = CURRENT_TIMESTAMP
|
||||
`, settingString(enabled))
|
||||
func (a *App) readSettings() (AppSettings, error) {
|
||||
live := defaultLiveModeSettings()
|
||||
|
||||
viewProofRaw, err := a.readSettingValue(settingViewProofInView)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update app setting view_proof_in_view: %w", err)
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingViewProofInView, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveShowGroupLive); err == nil {
|
||||
live.ShowGroupLive = settingBool(raw)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveShowGroupLive, err)
|
||||
}
|
||||
if raw, err := a.readSettingValue(settingLiveActiveView); err == nil {
|
||||
live.ActiveView = normalizeLiveActiveView(raw, live.ActiveView)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveActiveView, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveGroupDisplayMode); err == nil {
|
||||
live.GroupDisplayMode = normalizeLiveDisplayMode(raw, live.GroupDisplayMode)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveGroupDisplayMode, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveGroupFixedCode); err == nil {
|
||||
live.GroupFixedCode = strings.ToUpper(strings.TrimSpace(raw))
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveGroupFixedCode, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveShowPrelimTie); err == nil {
|
||||
live.ShowPrelimTie = settingBool(raw)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveShowPrelimTie, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveShowPrelimOverall); err == nil {
|
||||
live.ShowPrelimOverall = settingBool(raw)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveShowPrelimOverall, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveShowFinalGroups); err == nil {
|
||||
live.ShowFinalGroups = settingBool(raw)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveShowFinalGroups, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveFinalDisplayMode); err == nil {
|
||||
live.FinalDisplayMode = normalizeLiveDisplayMode(raw, live.FinalDisplayMode)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveFinalDisplayMode, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveFinalFixedGroup); err == nil {
|
||||
live.FinalFixedGroup = normalizeLiveFinalFixedGroup(raw, live.FinalFixedGroup)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveFinalFixedGroup, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveShowFinalTie); err == nil {
|
||||
live.ShowFinalTie = settingBool(raw)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveShowFinalTie, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveShowPodium); err == nil {
|
||||
live.ShowPodium = settingBool(raw)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveShowPodium, err)
|
||||
}
|
||||
|
||||
if raw, err := a.readSettingValue(settingLiveRotationInterval); err == nil {
|
||||
live.RotationIntervalSec = normalizeRotationInterval(raw, live.RotationIntervalSec)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveRotationInterval, err)
|
||||
}
|
||||
if raw, err := a.readSettingValue(settingLiveRotationPlayers); err == nil {
|
||||
live.RotationPlayerCount = normalizeRotationPlayerCount(raw, live.RotationPlayerCount)
|
||||
} else {
|
||||
return AppSettings{}, fmt.Errorf("read app setting %s: %w", settingLiveRotationPlayers, err)
|
||||
}
|
||||
|
||||
return AppSettings{
|
||||
ViewProofInView: settingBool(viewProofRaw),
|
||||
LiveMode: live,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *App) updateSettings(req AdminSettingsUpdateRequest) error {
|
||||
tx, err := a.db.Begin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("begin settings transaction: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
hasUpdate := false
|
||||
|
||||
if req.ViewProofInView != nil {
|
||||
hasUpdate = true
|
||||
if err := upsertSetting(tx, settingViewProofInView, settingString(*req.ViewProofInView)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if req.LiveMode != nil {
|
||||
patch := req.LiveMode
|
||||
if patch.ActiveView != nil {
|
||||
hasUpdate = true
|
||||
value := normalizeLiveActiveView(*patch.ActiveView, "group_live")
|
||||
if err := upsertSetting(tx, settingLiveActiveView, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.ShowGroupLive != nil {
|
||||
hasUpdate = true
|
||||
if err := upsertSetting(tx, settingLiveShowGroupLive, settingString(*patch.ShowGroupLive)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.GroupDisplayMode != nil {
|
||||
hasUpdate = true
|
||||
value := normalizeLiveDisplayMode(*patch.GroupDisplayMode, "rotate")
|
||||
if err := upsertSetting(tx, settingLiveGroupDisplayMode, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.GroupFixedCode != nil {
|
||||
hasUpdate = true
|
||||
value := strings.ToUpper(strings.TrimSpace(*patch.GroupFixedCode))
|
||||
if err := upsertSetting(tx, settingLiveGroupFixedCode, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.ShowPrelimTie != nil {
|
||||
hasUpdate = true
|
||||
if err := upsertSetting(tx, settingLiveShowPrelimTie, settingString(*patch.ShowPrelimTie)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.ShowPrelimOverall != nil {
|
||||
hasUpdate = true
|
||||
if err := upsertSetting(tx, settingLiveShowPrelimOverall, settingString(*patch.ShowPrelimOverall)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.ShowFinalGroups != nil {
|
||||
hasUpdate = true
|
||||
if err := upsertSetting(tx, settingLiveShowFinalGroups, settingString(*patch.ShowFinalGroups)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.FinalDisplayMode != nil {
|
||||
hasUpdate = true
|
||||
value := normalizeLiveDisplayMode(*patch.FinalDisplayMode, "rotate")
|
||||
if err := upsertSetting(tx, settingLiveFinalDisplayMode, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.FinalFixedGroup != nil {
|
||||
hasUpdate = true
|
||||
value := normalizeLiveFinalFixedGroupInt(*patch.FinalFixedGroup)
|
||||
if err := upsertSetting(tx, settingLiveFinalFixedGroup, strconv.Itoa(value)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.ShowFinalTie != nil {
|
||||
hasUpdate = true
|
||||
if err := upsertSetting(tx, settingLiveShowFinalTie, settingString(*patch.ShowFinalTie)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.ShowPodium != nil {
|
||||
hasUpdate = true
|
||||
if err := upsertSetting(tx, settingLiveShowPodium, settingString(*patch.ShowPodium)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.RotationIntervalSec != nil {
|
||||
hasUpdate = true
|
||||
value := normalizeRotationIntervalInt(*patch.RotationIntervalSec)
|
||||
if err := upsertSetting(tx, settingLiveRotationInterval, strconv.Itoa(value)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if patch.RotationPlayerCount != nil {
|
||||
hasUpdate = true
|
||||
value := normalizeRotationPlayerCountInt(*patch.RotationPlayerCount)
|
||||
if err := upsertSetting(tx, settingLiveRotationPlayers, strconv.Itoa(value)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !hasUpdate {
|
||||
return fmt.Errorf("no settings to update")
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("commit settings transaction: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func upsertSetting(tx *sql.Tx, key string, value string) error {
|
||||
_, err := tx.Exec(`
|
||||
INSERT INTO app_settings(key, value, updated_at)
|
||||
VALUES(?, ?, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = CURRENT_TIMESTAMP
|
||||
`, key, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("update app setting %s: %w", key, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) readSettingValue(key string) (string, error) {
|
||||
var raw string
|
||||
err := a.db.QueryRow(`SELECT value FROM app_settings WHERE key = ?`, key).Scan(&raw)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func settingBool(value string) bool {
|
||||
switch strings.TrimSpace(strings.ToLower(value)) {
|
||||
case "1", "true", "yes", "on":
|
||||
@@ -45,3 +287,80 @@ func settingString(value bool) string {
|
||||
}
|
||||
return "0"
|
||||
}
|
||||
|
||||
func normalizeLiveDisplayMode(value string, fallback string) string {
|
||||
normalized := strings.TrimSpace(strings.ToLower(value))
|
||||
if normalized == "fixed" {
|
||||
return "fixed"
|
||||
}
|
||||
if normalized == "rotate" {
|
||||
return "rotate"
|
||||
}
|
||||
if strings.TrimSpace(strings.ToLower(fallback)) == "fixed" {
|
||||
return "fixed"
|
||||
}
|
||||
return "rotate"
|
||||
}
|
||||
|
||||
func normalizeLiveFinalFixedGroup(value string, fallback int) int {
|
||||
parsed, err := strconv.Atoi(strings.TrimSpace(value))
|
||||
if err != nil {
|
||||
return normalizeLiveFinalFixedGroupInt(fallback)
|
||||
}
|
||||
return normalizeLiveFinalFixedGroupInt(parsed)
|
||||
}
|
||||
|
||||
func normalizeLiveFinalFixedGroupInt(value int) int {
|
||||
if value == 2 {
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func normalizeRotationInterval(raw string, fallback int) int {
|
||||
parsed, err := strconv.Atoi(strings.TrimSpace(raw))
|
||||
if err != nil {
|
||||
return normalizeRotationIntervalInt(fallback)
|
||||
}
|
||||
return normalizeRotationIntervalInt(parsed)
|
||||
}
|
||||
|
||||
func normalizeRotationIntervalInt(value int) int {
|
||||
if value < 3 {
|
||||
return 3
|
||||
}
|
||||
if value > 30 {
|
||||
return 30
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func normalizeRotationPlayerCount(raw string, fallback int) int {
|
||||
parsed, err := strconv.Atoi(strings.TrimSpace(raw))
|
||||
if err != nil {
|
||||
return normalizeRotationPlayerCountInt(fallback)
|
||||
}
|
||||
return normalizeRotationPlayerCountInt(parsed)
|
||||
}
|
||||
|
||||
func normalizeRotationPlayerCountInt(value int) int {
|
||||
if value < 3 {
|
||||
return 3
|
||||
}
|
||||
if value > 40 {
|
||||
return 40
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func normalizeLiveActiveView(value string, fallback string) string {
|
||||
switch strings.TrimSpace(strings.ToLower(value)) {
|
||||
case "group_live", "prelim_tie", "prelim_overall", "final_groups", "final_tie", "podium":
|
||||
return strings.TrimSpace(strings.ToLower(value))
|
||||
default:
|
||||
if strings.TrimSpace(strings.ToLower(fallback)) != "" {
|
||||
return strings.TrimSpace(strings.ToLower(fallback))
|
||||
}
|
||||
return "group_live"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user