f62b94af44
Co-authored-by: Copilot <copilot@github.com>
309 lines
9.2 KiB
Go
309 lines
9.2 KiB
Go
package config
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Config enthält alle Anwendungskonfigurationen
|
|
type Config struct {
|
|
// Server Konfiguration
|
|
ServerPort string
|
|
|
|
// Database Konfiguration
|
|
DatabaseURL string
|
|
DatabaseType string
|
|
|
|
// Logging Konfiguration
|
|
DebugMode bool
|
|
LogLevel string
|
|
|
|
// Environment
|
|
Environment string
|
|
|
|
DevTesting string // "yes" or "no", used to determine if we are in a test environment
|
|
|
|
// Frontend URLs for CORS
|
|
FrontendURL string // Frontend URL for CORS configuration
|
|
|
|
// PDF Templates
|
|
TemplatesDir string // Directory where PDF templates are stored
|
|
ExportTempDir string // Directory for temporary PDF exports
|
|
|
|
// Mail Configuration
|
|
MailHost string // SMTP server host
|
|
MailPort int // SMTP server port
|
|
MailUsername string // SMTP username
|
|
MailPassword string // SMTP password
|
|
MailFrom string // Default sender email address
|
|
}
|
|
|
|
// Cfg ist die globale Konfigurationsvariable
|
|
// Sie wird beim Programmstart automatisch geladen
|
|
var Cfg *Config
|
|
|
|
// init lädt die Konfiguration einmal beim Programmstart
|
|
func init() {
|
|
Cfg = LoadConfig()
|
|
}
|
|
|
|
// defaultConfig gibt die Standard-Konfiguration zurück
|
|
func defaultConfig() *Config {
|
|
return &Config{
|
|
ServerPort: "8180",
|
|
DatabaseURL: "",
|
|
DatabaseType: "mysql",
|
|
DebugMode: false,
|
|
LogLevel: "INFO",
|
|
Environment: "production",
|
|
DevTesting: "no", // Default to "no", can be overridden in tests
|
|
FrontendURL: "http://localhost:5173", // Default frontend URL for development
|
|
TemplatesDir: "./templates", // Default templates directory
|
|
ExportTempDir: "./xporttemp", // Default export temp directory
|
|
MailHost: "", // No default, must be configured
|
|
MailPort: 465, // Default SMTP SSL port
|
|
MailUsername: "", // No default, must be configured
|
|
MailPassword: "", // No default, must be configured
|
|
MailFrom: "", // No default, must be configured
|
|
}
|
|
}
|
|
|
|
// LoadConfig lädt die Konfiguration aus Umgebungsvariablen
|
|
func LoadConfig() *Config {
|
|
// Lade .env-Datei falls vorhanden
|
|
loadEnvFile()
|
|
|
|
config := defaultConfig()
|
|
|
|
// Debug: Zeige geladene Umgebungsvariablen
|
|
fmt.Printf("DEBUG LoadConfig - ENVIRONMENT aus ENV: '%s'\n", os.Getenv("ENVIRONMENT"))
|
|
fmt.Printf("DEBUG LoadConfig - TESTING aus ENV: '%s'\n", os.Getenv("DEVTESTING"))
|
|
fmt.Printf("DEBUG LoadConfig - DATABASE_TYPE aus ENV: '%s'\n", os.Getenv("DATABASE_TYPE"))
|
|
|
|
// Server Port
|
|
if port := os.Getenv("API_PORT"); port != "" {
|
|
config.ServerPort = port
|
|
}
|
|
if port := os.Getenv("SERVER_PORT"); port != "" {
|
|
config.ServerPort = port
|
|
}
|
|
|
|
// Database
|
|
if dbURL := os.Getenv("DATABASE_URL"); dbURL != "" {
|
|
config.DatabaseURL = dbURL
|
|
} else {
|
|
host := os.Getenv("DB_HOST")
|
|
port := os.Getenv("DB_PORT")
|
|
user := os.Getenv("DB_USER")
|
|
password := os.Getenv("DB_PASSWORD")
|
|
dbName := os.Getenv("DB_NAME")
|
|
if composed := buildDatabaseURL(host, port, user, password, dbName); composed != "" {
|
|
config.DatabaseURL = composed
|
|
}
|
|
}
|
|
if dbType := os.Getenv("DATABASE_TYPE"); dbType != "" {
|
|
config.DatabaseType = strings.ToLower(dbType)
|
|
}
|
|
|
|
// Debug Mode
|
|
if debug := os.Getenv("DEBUG"); debug != "" {
|
|
config.DebugMode = strings.ToLower(debug) == "true" || debug == "1"
|
|
}
|
|
|
|
// Log Level
|
|
if logLevel := os.Getenv("LOG_LEVEL"); logLevel != "" {
|
|
config.LogLevel = strings.ToUpper(logLevel)
|
|
}
|
|
|
|
// Environment
|
|
if env := os.Getenv("ENVIRONMENT"); env != "" {
|
|
config.Environment = strings.ToLower(env)
|
|
}
|
|
if env := os.Getenv("GO_ENV"); env != "" {
|
|
config.Environment = strings.ToLower(env)
|
|
}
|
|
|
|
// Automatisch Debug-Modus für Development-Environment aktivieren
|
|
if config.Environment == "development" || config.Environment == "dev" {
|
|
config.DebugMode = true
|
|
if config.LogLevel == "INFO" {
|
|
config.LogLevel = "DEBUG"
|
|
}
|
|
}
|
|
// Testing in Development
|
|
if testing := os.Getenv("DEVTESTING"); testing != "" {
|
|
config.DevTesting = strings.ToLower(testing)
|
|
fmt.Printf("DEBUG LoadConfig - DEVTESTING gefunden: '%s' -> DevTesting: '%s'\n", testing, config.DevTesting)
|
|
} else {
|
|
config.DevTesting = "no" // Default to "no"
|
|
fmt.Printf("DEBUG LoadConfig - DEVTESTING nicht gefunden, setze DevTesting auf 'no'\n")
|
|
}
|
|
|
|
// Frontend URL
|
|
if frontendURL := os.Getenv("BASE_URL"); frontendURL != "" {
|
|
config.FrontendURL = frontendURL
|
|
}
|
|
|
|
// Templates Directory
|
|
if templatesDir := os.Getenv("TEMPLATES_DIR"); templatesDir != "" {
|
|
config.TemplatesDir = templatesDir
|
|
}
|
|
|
|
// Export Temp Directory
|
|
if exportTempDir := os.Getenv("EXPORT_TEMP_DIR"); exportTempDir != "" {
|
|
config.ExportTempDir = exportTempDir
|
|
}
|
|
|
|
// Mail Configuration
|
|
if mailHost := os.Getenv("MAIL_HOST"); mailHost != "" {
|
|
config.MailHost = mailHost
|
|
}
|
|
if mailPort := os.Getenv("MAIL_PORT"); mailPort != "" {
|
|
if port, err := strconv.Atoi(mailPort); err == nil {
|
|
config.MailPort = port
|
|
}
|
|
}
|
|
if mailUsername := os.Getenv("MAIL_USERNAME"); mailUsername != "" {
|
|
config.MailUsername = mailUsername
|
|
}
|
|
if mailPassword := os.Getenv("MAIL_PASSWORD"); mailPassword != "" {
|
|
config.MailPassword = mailPassword
|
|
}
|
|
if mailFrom := os.Getenv("MAIL_FROM"); mailFrom != "" {
|
|
config.MailFrom = mailFrom
|
|
} else if config.MailUsername != "" {
|
|
// Fallback: Verwende Username als From-Adresse
|
|
config.MailFrom = config.MailUsername
|
|
}
|
|
|
|
fmt.Printf("DEBUG LoadConfig - Finale Config: Environment='%s', DevTesting='%s', DatabaseType='%s'\n Complete: %v\n",
|
|
config.Environment, config.DevTesting, config.DatabaseType, config)
|
|
|
|
return config
|
|
}
|
|
|
|
// loadEnvFile lädt eine .env-Datei falls vorhanden
|
|
func loadEnvFile() {
|
|
envFiles := []string{".env", ".env.local"}
|
|
configFile := os.Getenv("CONFIG_FILE")
|
|
if configFile != "" {
|
|
envFiles = append(envFiles, configFile)
|
|
}
|
|
|
|
for _, envFile := range envFiles {
|
|
if _, err := os.Stat(envFile); err == nil {
|
|
fmt.Printf("DEBUG loadEnvFile - Lade .env-Datei: %s\n", envFile)
|
|
loadEnvFileContent(envFile)
|
|
} else {
|
|
fmt.Printf("DEBUG loadEnvFile - .env-Datei nicht gefunden: %s\n", envFile)
|
|
}
|
|
}
|
|
}
|
|
|
|
// loadEnvFileContent lädt den Inhalt einer .env-Datei
|
|
func loadEnvFileContent(filename string) {
|
|
fmt.Printf("DEBUG loadEnvFileContent - Öffne Datei: %s\n", filename)
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
fmt.Printf("DEBUG loadEnvFileContent - Fehler beim Öffnen von %s: %v\n", filename, err)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
lineNum := 0
|
|
for scanner.Scan() {
|
|
lineNum++
|
|
line := strings.TrimSpace(scanner.Text())
|
|
|
|
// Überspringe leere Zeilen und Kommentare
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
|
|
// Teile die Zeile in Key=Value auf
|
|
parts := strings.SplitN(line, "=", 2)
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
|
|
key := strings.TrimSpace(parts[0])
|
|
value := strings.TrimSpace(parts[1])
|
|
|
|
// Behandle Kommentare am Ende der Zeile (nur wenn nicht in Anführungszeichen)
|
|
if !strings.HasPrefix(value, `"`) && !strings.HasPrefix(value, `'`) {
|
|
// Suche nach Kommentar am Ende der Zeile
|
|
if commentPos := strings.Index(value, "#"); commentPos > 0 {
|
|
// Entferne Kommentar und Leerzeichen davor
|
|
value = strings.TrimSpace(value[:commentPos])
|
|
}
|
|
}
|
|
|
|
// Entferne Anführungszeichen falls vorhanden
|
|
value = strings.Trim(value, `"'`)
|
|
|
|
fmt.Printf("DEBUG loadEnvFileContent - Zeile %d: %s='%s' (nach Kommentar-Behandlung)\n", lineNum, key, value)
|
|
|
|
// Setze die Umgebungsvariable nur, wenn sie noch nicht gesetzt ist
|
|
if os.Getenv(key) == "" {
|
|
os.Setenv(key, value)
|
|
fmt.Printf("DEBUG loadEnvFileContent - Setze ENV %s='%s'\n", key, value)
|
|
} else {
|
|
fmt.Printf("DEBUG loadEnvFileContent - ENV %s bereits gesetzt, überspringe\n", key)
|
|
}
|
|
}
|
|
fmt.Printf("DEBUG loadEnvFileContent - Datei %s vollständig verarbeitet (%d Zeilen)\n", filename, lineNum)
|
|
}
|
|
|
|
// buildDatabaseURL composes a MySQL/MariaDB DSN from individual connection parts.
|
|
// Returns an empty string if host, user, or dbName is missing.
|
|
func buildDatabaseURL(host, port, user, password, dbName string) string {
|
|
if host == "" || user == "" || dbName == "" {
|
|
return ""
|
|
}
|
|
if port == "" {
|
|
port = "3306"
|
|
}
|
|
return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
|
user, password, host, port, dbName)
|
|
}
|
|
|
|
// IsDevelopment prüft, ob die Anwendung im Development-Modus läuft
|
|
func (c *Config) IsDevelopment() bool {
|
|
return c.Environment == "development" || c.Environment == "dev"
|
|
}
|
|
|
|
// IsProduction prüft, ob die Anwendung im Production-Modus läuft
|
|
func (c *Config) IsProduction() bool {
|
|
return c.Environment == "production" || c.Environment == "prod"
|
|
}
|
|
|
|
// GetServerAddress gibt die vollständige Server-Adresse zurück
|
|
func (c *Config) GetServerAddress() string {
|
|
return ":" + c.ServerPort
|
|
}
|
|
|
|
// GetBoolEnv ist eine Hilfsfunktion zum Laden von Boolean-Umgebungsvariablen
|
|
func GetBoolEnv(key string, defaultValue bool) bool {
|
|
if value := os.Getenv(key); value != "" {
|
|
if parsed, err := strconv.ParseBool(value); err == nil {
|
|
return parsed
|
|
}
|
|
return strings.ToLower(value) == "true" || value == "1"
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
// GetIntEnv ist eine Hilfsfunktion zum Laden von Integer-Umgebungsvariablen
|
|
func GetIntEnv(key string, defaultValue int) int {
|
|
if value := os.Getenv(key); value != "" {
|
|
if parsed, err := strconv.Atoi(value); err == nil {
|
|
return parsed
|
|
}
|
|
}
|
|
return defaultValue
|
|
}
|