144 lines
5.5 KiB
Go
144 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type config struct {
|
|
Port string
|
|
WebDir string
|
|
AppBaseURL string
|
|
MCPResourceURL string
|
|
CorsOrigins []string
|
|
DatabaseURL string
|
|
MinIOEndpoint string
|
|
MinIOBucket string
|
|
MinIOAccessKey string
|
|
MinIOSecretKey string
|
|
AssetEncryptionEnabled bool
|
|
AuthDisabled bool
|
|
KeycloakIssuer string
|
|
KeycloakIssuerInternal string
|
|
KeycloakAudience string
|
|
StripeSecretKey string
|
|
StripeAPIBaseURL string
|
|
StripeWebhookSecret string
|
|
StripeWebhookTolerance time.Duration
|
|
StripeAllowedPriceIDs []string
|
|
StripeCheckoutSuccessURL string
|
|
StripeCheckoutCancelURL string
|
|
BillingEventRetentionDays int
|
|
EntitlementHistoryRetentionDays int
|
|
EducationalRecordRetentionDays int
|
|
DefaultTrialDays int
|
|
DefaultFreeDays int
|
|
KeycloakThemeDeployEnabled bool
|
|
NotificationProvider string
|
|
SendGridAPIKey string
|
|
SendGridFromEmail string
|
|
SendGridAPIBaseURL string
|
|
ShutdownTimeout time.Duration
|
|
}
|
|
|
|
func loadConfig() config {
|
|
return config{
|
|
Port: getEnv("PORT", "8080"),
|
|
WebDir: strings.TrimSpace(getEnv("WEB_DIR", "")),
|
|
AppBaseURL: strings.TrimRight(getEnv("APP_BASE_URL", "http://localhost:5173"), "/"),
|
|
MCPResourceURL: strings.TrimRight(getEnv("MCP_RESOURCE_URL", "http://localhost:8080/api/mcp"), "/"),
|
|
CorsOrigins: parseList(getEnv("CORS_ALLOWED_ORIGINS", "*")),
|
|
DatabaseURL: getEnv("DATABASE_URL", "postgres://cms:cms@postgres:5432/cms?sslmode=disable"),
|
|
MinIOEndpoint: getEnv("MINIO_ENDPOINT", ""),
|
|
MinIOBucket: getEnv("MINIO_BUCKET", ""),
|
|
MinIOAccessKey: getEnv("MINIO_ACCESS_KEY", ""),
|
|
MinIOSecretKey: getEnv("MINIO_SECRET_KEY", ""),
|
|
AssetEncryptionEnabled: getEnvBool("ASSET_ENCRYPTION_ENABLED", false),
|
|
AuthDisabled: getEnvBool("AUTH_DISABLED", false),
|
|
KeycloakIssuer: getEnv("KEYCLOAK_ISSUER", "http://localhost:8081/realms/cms"),
|
|
KeycloakIssuerInternal: getEnv("KEYCLOAK_ISSUER_INTERNAL", "http://keycloak:8080/realms/cms"),
|
|
KeycloakAudience: getEnv("KEYCLOAK_AUDIENCE", "cms-backend"),
|
|
StripeSecretKey: getEnv("STRIPE_SECRET_KEY", ""),
|
|
StripeAPIBaseURL: getEnv("STRIPE_API_BASE_URL", "https://api.stripe.com"),
|
|
StripeWebhookSecret: getEnv("STRIPE_WEBHOOK_SECRET", ""),
|
|
StripeWebhookTolerance: time.Duration(getEnvInt("STRIPE_WEBHOOK_TOLERANCE_SECONDS", 300)) * time.Second,
|
|
StripeAllowedPriceIDs: parseOptionalList(getEnv("STRIPE_ALLOWED_PRICE_IDS", "")),
|
|
StripeCheckoutSuccessURL: getEnv("STRIPE_CHECKOUT_SUCCESS_URL", "http://localhost:5173/learn/billing?checkout=success"),
|
|
StripeCheckoutCancelURL: getEnv("STRIPE_CHECKOUT_CANCEL_URL", "http://localhost:5173/learn/billing?checkout=cancel"),
|
|
BillingEventRetentionDays: getEnvInt("BILLING_EVENT_RETENTION_DAYS", 365),
|
|
EntitlementHistoryRetentionDays: getEnvInt("ENTITLEMENT_HISTORY_RETENTION_DAYS", 730),
|
|
EducationalRecordRetentionDays: getEnvInt("EDUCATIONAL_RECORD_RETENTION_DAYS", 2555),
|
|
DefaultTrialDays: getEnvInt("DEFAULT_TRIAL_DAYS", 14),
|
|
DefaultFreeDays: getEnvInt("DEFAULT_FREE_ACCESS_DAYS", 3650),
|
|
KeycloakThemeDeployEnabled: getEnvBool("KEYCLOAK_THEME_DEPLOY_ENABLED", true),
|
|
NotificationProvider: strings.ToLower(getEnv("NOTIFICATION_PROVIDER", "noop")),
|
|
SendGridAPIKey: getEnv("SENDGRID_API_KEY", ""),
|
|
SendGridFromEmail: getEnv("SENDGRID_FROM_EMAIL", ""),
|
|
SendGridAPIBaseURL: getEnv("SENDGRID_API_BASE_URL", "https://api.sendgrid.com"),
|
|
ShutdownTimeout: time.Duration(getEnvInt("SHUTDOWN_TIMEOUT_SECONDS", 10)) * time.Second,
|
|
}
|
|
}
|
|
|
|
func getEnv(key, fallback string) string {
|
|
value, ok := os.LookupEnv(key)
|
|
if !ok || strings.TrimSpace(value) == "" {
|
|
return fallback
|
|
}
|
|
return value
|
|
}
|
|
|
|
func getEnvInt(key string, fallback int) int {
|
|
raw := strings.TrimSpace(getEnv(key, ""))
|
|
if raw == "" {
|
|
return fallback
|
|
}
|
|
value, err := strconv.Atoi(raw)
|
|
if err != nil {
|
|
return fallback
|
|
}
|
|
return value
|
|
}
|
|
|
|
func getEnvBool(key string, fallback bool) bool {
|
|
raw := strings.TrimSpace(strings.ToLower(getEnv(key, "")))
|
|
if raw == "" {
|
|
return fallback
|
|
}
|
|
return raw == "1" || raw == "true" || raw == "yes" || raw == "on"
|
|
}
|
|
|
|
func parseList(raw string) []string {
|
|
if strings.TrimSpace(raw) == "" {
|
|
return []string{"*"}
|
|
}
|
|
parts := strings.Split(raw, ",")
|
|
out := make([]string, 0, len(parts))
|
|
for _, part := range parts {
|
|
item := strings.TrimSpace(part)
|
|
if item != "" {
|
|
out = append(out, item)
|
|
}
|
|
}
|
|
if len(out) == 0 {
|
|
return []string{"*"}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func parseOptionalList(raw string) []string {
|
|
if strings.TrimSpace(raw) == "" {
|
|
return []string{}
|
|
}
|
|
parts := strings.Split(raw, ",")
|
|
out := make([]string, 0, len(parts))
|
|
for _, part := range parts {
|
|
item := strings.TrimSpace(part)
|
|
if item != "" {
|
|
out = append(out, item)
|
|
}
|
|
}
|
|
return out
|
|
}
|