mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-06-03 20:13:00 +00:00
cleanup
This commit is contained in:
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
@@ -14,12 +15,20 @@ type Config struct {
|
||||
DatabaseURL string
|
||||
DatabaseDirectURL string
|
||||
NeonAuthURL string
|
||||
AuthJWTSecret string
|
||||
JobRunnerKey string
|
||||
EmailFrom string
|
||||
SMSFrom string
|
||||
StripeSecretKey string
|
||||
StripeWebhookKey string
|
||||
StripePriceIDs map[string]string
|
||||
SMTPHost string
|
||||
SMTPPort string
|
||||
SMTPUsername string
|
||||
SMTPPassword string
|
||||
PaddleEnvironment string
|
||||
PaddleAPIKey string
|
||||
PaddleWebhookKey string
|
||||
PaddlePriceMatrix map[string]map[string]string
|
||||
UmamiAPIURL string
|
||||
UmamiAPIKey string
|
||||
DemoMode bool
|
||||
}
|
||||
|
||||
func Load() (Config, error) {
|
||||
@@ -31,28 +40,141 @@ func Load() (Config, error) {
|
||||
DatabaseURL: strings.TrimSpace(os.Getenv("BOOKRA_DATABASE_URL")),
|
||||
DatabaseDirectURL: strings.TrimSpace(os.Getenv("BOOKRA_DATABASE_DIRECT_URL")),
|
||||
NeonAuthURL: strings.TrimSpace(os.Getenv("BOOKRA_NEON_AUTH_URL")),
|
||||
AuthJWTSecret: strings.TrimSpace(os.Getenv("BOOKRA_AUTH_JWT_SECRET")),
|
||||
JobRunnerKey: strings.TrimSpace(os.Getenv("BOOKRA_JOB_RUNNER_KEY")),
|
||||
EmailFrom: valueOrDefault("BOOKRA_EMAIL_FROM", "noreply@bookra.dev"),
|
||||
SMSFrom: valueOrDefault("BOOKRA_SMS_FROM", "Bookra"),
|
||||
StripeSecretKey: strings.TrimSpace(os.Getenv("BOOKRA_STRIPE_SECRET_KEY")),
|
||||
StripeWebhookKey: strings.TrimSpace(os.Getenv("BOOKRA_STRIPE_WEBHOOK_SECRET")),
|
||||
StripePriceIDs: map[string]string{
|
||||
"starter": strings.TrimSpace(os.Getenv("BOOKRA_STRIPE_STARTER_PRICE_ID")),
|
||||
"growth": strings.TrimSpace(os.Getenv("BOOKRA_STRIPE_GROWTH_PRICE_ID")),
|
||||
"multi-location": strings.TrimSpace(os.Getenv("BOOKRA_STRIPE_MULTI_LOCATION_PRICE_ID")),
|
||||
},
|
||||
SMTPHost: strings.TrimSpace(os.Getenv("BOOKRA_SMTP_HOST")),
|
||||
SMTPPort: valueOrDefault("BOOKRA_SMTP_PORT", "587"),
|
||||
SMTPUsername: strings.TrimSpace(os.Getenv("BOOKRA_SMTP_USERNAME")),
|
||||
SMTPPassword: strings.TrimSpace(os.Getenv("BOOKRA_SMTP_PASSWORD")),
|
||||
PaddleEnvironment: normalizePaddleEnvironment(os.Getenv("BOOKRA_PADDLE_ENV")),
|
||||
PaddleAPIKey: strings.TrimSpace(os.Getenv("BOOKRA_PADDLE_API_KEY")),
|
||||
PaddleWebhookKey: strings.TrimSpace(os.Getenv("BOOKRA_PADDLE_WEBHOOK_SECRET")),
|
||||
PaddlePriceMatrix: paddlePriceMatrixFromEnv(),
|
||||
UmamiAPIURL: strings.TrimSpace(os.Getenv("BOOKRA_UMAMI_API_URL")),
|
||||
UmamiAPIKey: strings.TrimSpace(os.Getenv("BOOKRA_UMAMI_API_KEY")),
|
||||
DemoMode: boolFromEnv("BOOKRA_DEMO_MODE", false),
|
||||
}
|
||||
|
||||
if cfg.FrontendURL == "" {
|
||||
return Config{}, errors.New("BOOKRA_FRONTEND_URL is required")
|
||||
}
|
||||
if err := cfg.validateRuntimeRequirements(); err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (cfg Config) validateRuntimeRequirements() error {
|
||||
if cfg.Environment == "development" || cfg.Environment == "test" {
|
||||
return nil
|
||||
}
|
||||
|
||||
missing := make([]string, 0, 3)
|
||||
if cfg.DatabaseURL == "" {
|
||||
missing = append(missing, "BOOKRA_DATABASE_URL")
|
||||
}
|
||||
if cfg.NeonAuthURL == "" {
|
||||
missing = append(missing, "BOOKRA_NEON_AUTH_URL")
|
||||
}
|
||||
if cfg.JobRunnerKey == "" {
|
||||
missing = append(missing, "BOOKRA_JOB_RUNNER_KEY")
|
||||
}
|
||||
if cfg.SMTPHost == "" {
|
||||
missing = append(missing, "BOOKRA_SMTP_HOST")
|
||||
}
|
||||
if cfg.PaddleAPIKey == "" {
|
||||
missing = append(missing, "BOOKRA_PADDLE_API_KEY")
|
||||
}
|
||||
if cfg.PaddleWebhookKey == "" {
|
||||
missing = append(missing, "BOOKRA_PADDLE_WEBHOOK_SECRET")
|
||||
}
|
||||
for _, planCode := range []string{"starter", "pro", "business"} {
|
||||
if cfg.PaddlePriceMatrix[planCode]["czk"] == "" || cfg.PaddlePriceMatrix[planCode]["usd"] == "" {
|
||||
envPlan := strings.ToUpper(strings.ReplaceAll(planCode, "-", "_"))
|
||||
missing = append(missing, "BOOKRA_PADDLE_"+envPlan+"_CZK_PRICE_ID")
|
||||
missing = append(missing, "BOOKRA_PADDLE_"+envPlan+"_USD_PRICE_ID")
|
||||
}
|
||||
}
|
||||
if len(missing) > 0 {
|
||||
return fmt.Errorf("%s required when BOOKRA_APP_ENV=%s", strings.Join(uniqueStrings(missing), ", "), cfg.Environment)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg Config) PaddleConfigured() bool {
|
||||
return strings.TrimSpace(cfg.PaddleAPIKey) != ""
|
||||
}
|
||||
|
||||
func (cfg Config) PaddleWebhookConfigured() bool {
|
||||
return strings.TrimSpace(cfg.PaddleWebhookKey) != ""
|
||||
}
|
||||
|
||||
func (cfg Config) PaddleCheckoutConfigured(planCode string) bool {
|
||||
planCode = normalizePlanCode(planCode)
|
||||
return cfg.PaddleConfigured() && cfg.PaddleWebhookConfigured() && cfg.PaddlePriceMatrix[planCode]["czk"] != "" && cfg.PaddlePriceMatrix[planCode]["usd"] != ""
|
||||
}
|
||||
|
||||
func paddlePriceMatrixFromEnv() map[string]map[string]string {
|
||||
matrix := map[string]map[string]string{
|
||||
"starter": {},
|
||||
"pro": {},
|
||||
"business": {},
|
||||
}
|
||||
for _, planCode := range []string{"starter", "pro", "business"} {
|
||||
envPlan := strings.ToUpper(strings.ReplaceAll(planCode, "-", "_"))
|
||||
matrix[planCode]["czk"] = strings.TrimSpace(os.Getenv("BOOKRA_PADDLE_" + envPlan + "_CZK_PRICE_ID"))
|
||||
matrix[planCode]["usd"] = strings.TrimSpace(os.Getenv("BOOKRA_PADDLE_" + envPlan + "_USD_PRICE_ID"))
|
||||
}
|
||||
return matrix
|
||||
}
|
||||
|
||||
func normalizePaddleEnvironment(value string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||
case "live", "production":
|
||||
return "live"
|
||||
default:
|
||||
return "sandbox"
|
||||
}
|
||||
}
|
||||
|
||||
func normalizePlanCode(planCode string) string {
|
||||
switch strings.TrimSpace(planCode) {
|
||||
case "growth":
|
||||
return "pro"
|
||||
case "multi-location":
|
||||
return "business"
|
||||
default:
|
||||
return strings.TrimSpace(planCode)
|
||||
}
|
||||
}
|
||||
|
||||
func valueOrDefault(key string, fallback string) string {
|
||||
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
|
||||
return value
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func boolFromEnv(key string, fallback bool) bool {
|
||||
value := strings.TrimSpace(os.Getenv(key))
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
value = strings.ToLower(value)
|
||||
return value == "true" || value == "1" || value == "yes" || value == "on"
|
||||
}
|
||||
|
||||
func uniqueStrings(values []string) []string {
|
||||
seen := map[string]struct{}{}
|
||||
out := make([]string, 0, len(values))
|
||||
for _, value := range values {
|
||||
if _, ok := seen[value]; ok {
|
||||
continue
|
||||
}
|
||||
seen[value] = struct{}{}
|
||||
out = append(out, value)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user