feat: add ability to override the UI configuration with environment variables

This commit is contained in:
Elias Schneider
2025-02-12 14:20:52 +01:00
parent 2d78349b38
commit 4e858420e9
5 changed files with 65 additions and 21 deletions

View File

@@ -25,6 +25,7 @@ type EnvConfigSchema struct {
Host string `env:"HOST"`
MaxMindLicenseKey string `env:"MAXMIND_LICENSE_KEY"`
GeoLiteDBPath string `env:"GEOLITE_DB_PATH"`
UiConfigDisabled bool `env:"PUBLIC_UI_CONFIG_DISABLED"`
}
var EnvConfig = &EnvConfigSchema{
@@ -38,6 +39,7 @@ var EnvConfig = &EnvConfigSchema{
Host: "0.0.0.0",
MaxMindLicenseKey: "",
GeoLiteDBPath: "data/GeoLite2-City.mmdb",
UiConfigDisabled: false,
}
func init() {

View File

@@ -184,3 +184,10 @@ func (e *OidcAccessDeniedError) Error() string {
}
func (e *OidcAccessDeniedError) HttpStatusCode() int { return http.StatusForbidden }
type UiConfigDisabledError struct{}
func (e *UiConfigDisabledError) Error() string {
return "The configuration can't be changed since the UI configuration is disabled"
}
func (e *UiConfigDisabledError) HttpStatusCode() int { return http.StatusForbidden }

View File

@@ -188,12 +188,15 @@ var defaultDbConfig = model.AppConfig{
}
func (s *AppConfigService) UpdateAppConfig(input dto.AppConfigUpdateDto) ([]model.AppConfigVariable, error) {
var savedConfigVariables []model.AppConfigVariable
if common.EnvConfig.UiConfigDisabled {
return nil, &common.UiConfigDisabledError{}
}
tx := s.db.Begin()
rt := reflect.ValueOf(input).Type()
rv := reflect.ValueOf(input)
var savedConfigVariables []model.AppConfigVariable
for i := 0; i < rt.NumField(); i++ {
field := rt.Field(i)
key := field.Tag.Get("json")
@@ -254,9 +257,13 @@ func (s *AppConfigService) ListAppConfig(showAll bool) ([]model.AppConfigVariabl
return nil, err
}
// Set the value to the default value if it is empty
for i := range configuration {
if configuration[i].Value == "" && configuration[i].DefaultValue != "" {
if common.EnvConfig.UiConfigDisabled {
// Set the value to the environment variable if the UI config is disabled
configuration[i].Value = s.getConfigVariableFromEnvironmentVariable(configuration[i].Key, configuration[i].DefaultValue)
} else if configuration[i].Value == "" && configuration[i].DefaultValue != "" {
// Set the value to the default value if it is empty
configuration[i].Value = configuration[i].DefaultValue
}
}
@@ -355,12 +362,25 @@ func (s *AppConfigService) LoadDbConfigFromDb() error {
return err
}
if storedConfigVar.Value == "" && storedConfigVar.DefaultValue != "" {
if common.EnvConfig.UiConfigDisabled {
storedConfigVar.Value = s.getConfigVariableFromEnvironmentVariable(currentConfigVar.Key, storedConfigVar.DefaultValue)
} else if storedConfigVar.Value == "" && storedConfigVar.DefaultValue != "" {
storedConfigVar.Value = storedConfigVar.DefaultValue
}
dbConfigField.Set(reflect.ValueOf(storedConfigVar))
}
return nil
}
func (s *AppConfigService) getConfigVariableFromEnvironmentVariable(key, fallbackValue string) string {
environmentVariableName := utils.CamelCaseToScreamingSnakeCase(key)
if value, exists := os.LookupEnv(environmentVariableName); exists {
return value
}
return fallbackValue
}

View File

@@ -5,6 +5,8 @@ import (
"fmt"
"math/big"
"net/url"
"regexp"
"strings"
"unicode"
)
@@ -62,3 +64,12 @@ func CamelCaseToSnakeCase(s string) string {
}
return string(result)
}
func CamelCaseToScreamingSnakeCase(s string) string {
// Insert underscores before uppercase letters (except the first one)
re := regexp.MustCompile(`([a-z0-9])([A-Z])`)
snake := re.ReplaceAllString(s, `${1}_${2}`)
// Convert to uppercase
return strings.ToUpper(snake)
}

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { env } from '$env/dynamic/public';
import CollapsibleCard from '$lib/components/collapsible-card.svelte';
import AppConfigService from '$lib/services/app-config-service';
import appConfigStore from '$lib/stores/application-configuration-store';
@@ -13,6 +14,7 @@
let { data } = $props();
let appConfig = $state(data.appConfig);
const uiConfigDisabled = env.PUBLIC_UI_CONFIG_DISABLED === 'true';
const appConfigService = new AppConfigService();
async function updateAppConfig(updatedAppConfig: Partial<AllAppConfig>) {
@@ -55,26 +57,28 @@
<title>Application Configuration</title>
</svelte:head>
<CollapsibleCard id="application-configuration-general" title="General" defaultExpanded>
<AppConfigGeneralForm {appConfig} callback={updateAppConfig} />
</CollapsibleCard>
<fieldset class="flex flex-col gap-5" disabled={uiConfigDisabled}>
<CollapsibleCard id="application-configuration-general" title="General" defaultExpanded>
<AppConfigGeneralForm {appConfig} callback={updateAppConfig} />
</CollapsibleCard>
<CollapsibleCard
id="application-configuration-email"
title="Email"
description="Enable email notifications to alert users when a login is detected from a new device or
<CollapsibleCard
id="application-configuration-email"
title="Email"
description="Enable email notifications to alert users when a login is detected from a new device or
location."
>
<AppConfigEmailForm {appConfig} callback={updateAppConfig} />
</CollapsibleCard>
>
<AppConfigEmailForm {appConfig} callback={updateAppConfig} />
</CollapsibleCard>
<CollapsibleCard
id="application-configuration-ldap"
title="LDAP"
description="Configure LDAP settings to sync users and groups from an LDAP server."
>
<AppConfigLdapForm {appConfig} callback={updateAppConfig} />
</CollapsibleCard>
<CollapsibleCard
id="application-configuration-ldap"
title="LDAP"
description="Configure LDAP settings to sync users and groups from an LDAP server."
>
<AppConfigLdapForm {appConfig} callback={updateAppConfig} />
</CollapsibleCard>
</fieldset>
<CollapsibleCard id="application-configuration-images" title="Images">
<UpdateApplicationImages callback={updateImages} />