mirror of
https://github.com/pocket-id/pocket-id.git
synced 2025-12-18 17:23:26 +03:00
feat: add ability to override the UI configuration with environment variables
This commit is contained in:
@@ -25,6 +25,7 @@ type EnvConfigSchema struct {
|
|||||||
Host string `env:"HOST"`
|
Host string `env:"HOST"`
|
||||||
MaxMindLicenseKey string `env:"MAXMIND_LICENSE_KEY"`
|
MaxMindLicenseKey string `env:"MAXMIND_LICENSE_KEY"`
|
||||||
GeoLiteDBPath string `env:"GEOLITE_DB_PATH"`
|
GeoLiteDBPath string `env:"GEOLITE_DB_PATH"`
|
||||||
|
UiConfigDisabled bool `env:"PUBLIC_UI_CONFIG_DISABLED"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var EnvConfig = &EnvConfigSchema{
|
var EnvConfig = &EnvConfigSchema{
|
||||||
@@ -38,6 +39,7 @@ var EnvConfig = &EnvConfigSchema{
|
|||||||
Host: "0.0.0.0",
|
Host: "0.0.0.0",
|
||||||
MaxMindLicenseKey: "",
|
MaxMindLicenseKey: "",
|
||||||
GeoLiteDBPath: "data/GeoLite2-City.mmdb",
|
GeoLiteDBPath: "data/GeoLite2-City.mmdb",
|
||||||
|
UiConfigDisabled: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -184,3 +184,10 @@ func (e *OidcAccessDeniedError) Error() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *OidcAccessDeniedError) HttpStatusCode() int { return http.StatusForbidden }
|
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 }
|
||||||
|
|||||||
@@ -188,12 +188,15 @@ var defaultDbConfig = model.AppConfig{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *AppConfigService) UpdateAppConfig(input dto.AppConfigUpdateDto) ([]model.AppConfigVariable, error) {
|
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()
|
tx := s.db.Begin()
|
||||||
rt := reflect.ValueOf(input).Type()
|
rt := reflect.ValueOf(input).Type()
|
||||||
rv := reflect.ValueOf(input)
|
rv := reflect.ValueOf(input)
|
||||||
|
|
||||||
|
var savedConfigVariables []model.AppConfigVariable
|
||||||
for i := 0; i < rt.NumField(); i++ {
|
for i := 0; i < rt.NumField(); i++ {
|
||||||
field := rt.Field(i)
|
field := rt.Field(i)
|
||||||
key := field.Tag.Get("json")
|
key := field.Tag.Get("json")
|
||||||
@@ -254,9 +257,13 @@ func (s *AppConfigService) ListAppConfig(showAll bool) ([]model.AppConfigVariabl
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the value to the default value if it is empty
|
|
||||||
for i := range configuration {
|
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
|
configuration[i].Value = configuration[i].DefaultValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,12 +362,25 @@ func (s *AppConfigService) LoadDbConfigFromDb() error {
|
|||||||
return err
|
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
|
storedConfigVar.Value = storedConfigVar.DefaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
dbConfigField.Set(reflect.ValueOf(storedConfigVar))
|
dbConfigField.Set(reflect.ValueOf(storedConfigVar))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,3 +64,12 @@ func CamelCaseToSnakeCase(s string) string {
|
|||||||
}
|
}
|
||||||
return string(result)
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { env } from '$env/dynamic/public';
|
||||||
import CollapsibleCard from '$lib/components/collapsible-card.svelte';
|
import CollapsibleCard from '$lib/components/collapsible-card.svelte';
|
||||||
import AppConfigService from '$lib/services/app-config-service';
|
import AppConfigService from '$lib/services/app-config-service';
|
||||||
import appConfigStore from '$lib/stores/application-configuration-store';
|
import appConfigStore from '$lib/stores/application-configuration-store';
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
let { data } = $props();
|
let { data } = $props();
|
||||||
let appConfig = $state(data.appConfig);
|
let appConfig = $state(data.appConfig);
|
||||||
|
|
||||||
|
const uiConfigDisabled = env.PUBLIC_UI_CONFIG_DISABLED === 'true';
|
||||||
const appConfigService = new AppConfigService();
|
const appConfigService = new AppConfigService();
|
||||||
|
|
||||||
async function updateAppConfig(updatedAppConfig: Partial<AllAppConfig>) {
|
async function updateAppConfig(updatedAppConfig: Partial<AllAppConfig>) {
|
||||||
@@ -55,6 +57,7 @@
|
|||||||
<title>Application Configuration</title>
|
<title>Application Configuration</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
<fieldset class="flex flex-col gap-5" disabled={uiConfigDisabled}>
|
||||||
<CollapsibleCard id="application-configuration-general" title="General" defaultExpanded>
|
<CollapsibleCard id="application-configuration-general" title="General" defaultExpanded>
|
||||||
<AppConfigGeneralForm {appConfig} callback={updateAppConfig} />
|
<AppConfigGeneralForm {appConfig} callback={updateAppConfig} />
|
||||||
</CollapsibleCard>
|
</CollapsibleCard>
|
||||||
@@ -75,6 +78,7 @@
|
|||||||
>
|
>
|
||||||
<AppConfigLdapForm {appConfig} callback={updateAppConfig} />
|
<AppConfigLdapForm {appConfig} callback={updateAppConfig} />
|
||||||
</CollapsibleCard>
|
</CollapsibleCard>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<CollapsibleCard id="application-configuration-images" title="Images">
|
<CollapsibleCard id="application-configuration-images" title="Images">
|
||||||
<UpdateApplicationImages callback={updateImages} />
|
<UpdateApplicationImages callback={updateImages} />
|
||||||
|
|||||||
Reference in New Issue
Block a user