diff --git a/cmd/server/main.go b/cmd/server/main.go index 540b25b..eb5b02c 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -73,6 +73,10 @@ func main() { configRepo := config.NewRepository(dbCon) configService := config.NewService(configRepo) + if err := configService.EnsureDefaults(); err != nil { + panic(fmt.Errorf("failed to ensure config defaults: %w", err)) + } + fileRepo := file.NewRepository(dbCon) fileService := file.NewService(fileRepo, "./uploads") fileHandler := file.NewHandler(fileService, configService) diff --git a/internal/config/defaults.go b/internal/config/defaults.go index a6ede89..054b5bf 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -1,13 +1,19 @@ package config +import "strconv" + const ( - KeyUploadMaxFileSizeBytes = "upload.max_file_size_bytes" - KeyUploadMultiMaxFiles = "upload.multi.max_files" - KeyUploadMaxHours = "upload.max_hours" - KeyRateLimitLoginPerMinute = "ratelimit.login.per_minute" - KeyRateLimitApiPerMinute = "ratelimit.api.per_minute" - KeyRateLimitApiBurst = "ratelimit.api.burst" - KeyRateLimitLoginBurst = "ratelimit.login.burst" + KeyUploadMaxFileSizeBytes = "upload.max_file_size_bytes" + KeyUploadMultiMaxFiles = "upload.multi.max_files" + KeyUploadMaxHours = "upload.max_hours" + KeyRateLimitLoginPerMinute = "ratelimit.login.per_minute" + KeyRateLimitApiPerMinute = "ratelimit.api.per_minute" + KeyRateLimitApiBurst = "ratelimit.api.burst" + KeyRateLimitLoginBurst = "ratelimit.login.burst" + + KeyUseNtfy = "use_ntfy" + KeyNtfyUrl = "ntfy.url" + KeyNtfyTopic = "ntfy.topic" ) // Defaults (used when DB does not have an override) @@ -20,4 +26,27 @@ const ( DefaultRateLimitLoginBurst = 10 DefaultRateLimitApiPerMinute = 60 DefaultRateLimitApiBurst = 30 + + DefaultUseNtfy = 0 + DefaultNtfyUrl = "" + DefaultNtfyTopic = "" ) + +// DefaultKeyValues returns a map of config keys to their default string values, for use when initializing the database. +// Code duplication be dammed +func DefaultKeyValues() map[string]string { + return map[string]string{ + KeyUploadMaxFileSizeBytes: strconv.FormatInt(DefaultUploadMaxFileSizeBytes, 10), + KeyUploadMultiMaxFiles: strconv.Itoa(DefaultUploadMultiMaxFiles), + KeyUploadMaxHours: strconv.Itoa(DefaultUploadMaxHours), + + KeyRateLimitLoginPerMinute: strconv.Itoa(DefaultRateLimitLoginPerMinute), + KeyRateLimitLoginBurst: strconv.Itoa(DefaultRateLimitLoginBurst), + KeyRateLimitApiPerMinute: strconv.Itoa(DefaultRateLimitApiPerMinute), + KeyRateLimitApiBurst: strconv.Itoa(DefaultRateLimitApiBurst), + + KeyUseNtfy: strconv.Itoa(DefaultUseNtfy), + KeyNtfyUrl: DefaultNtfyUrl, + KeyNtfyTopic: DefaultNtfyTopic, + } +} diff --git a/internal/config/repository.go b/internal/config/repository.go index 4f5cfb1..3a790ab 100644 --- a/internal/config/repository.go +++ b/internal/config/repository.go @@ -1,6 +1,10 @@ package config -import "gorm.io/gorm" +import ( + "errors" + + "gorm.io/gorm" +) type Repository struct { db *gorm.DB @@ -37,3 +41,15 @@ func (r *Repository) List() ([]ConfigEntry, error) { } return entries, nil } + +func (r *Repository) CreateIfMissing(key, value string) error { + var e ConfigEntry + err := r.db.First(&e, "key = ?", key).Error + if err == nil { + return nil + } + if errors.Is(err, gorm.ErrRecordNotFound) { + return r.db.Create(&ConfigEntry{Key: key, Value: value}).Error + } + return err +} diff --git a/internal/config/service.go b/internal/config/service.go index 60f7515..20b3856 100644 --- a/internal/config/service.go +++ b/internal/config/service.go @@ -22,6 +22,15 @@ func NewService(r *Repository) *Service { return &Service{repo: r, cache: make(map[string]string)} } +func (s *Service) EnsureDefaults() error { + for k, v := range DefaultKeyValues() { + if err := s.repo.CreateIfMissing(k, v); err != nil { + return err + } + } + return nil +} + func (s *Service) List() ([]ConfigEntry, error) { entries, err := s.repo.List() if err != nil { diff --git a/internal/web/config.go b/internal/web/config.go index afed66d..fb2285a 100644 --- a/internal/web/config.go +++ b/internal/web/config.go @@ -20,6 +20,10 @@ type ConfigPageData struct { RateLimitLoginBurst int RateLimitApiPerMinute int RateLimitApiBurst int + + NtfyUse bool + NtfyUrl string + NtfyTopic string } // ConfigPage renders a modular admin config screen. @@ -28,14 +32,17 @@ func (h *Handler) ConfigPage(c *gin.Context) { maxBytes := cfg.GetInt64Default(config.KeyUploadMaxFileSizeBytes, config.DefaultUploadMaxFileSizeBytes) data := ConfigPageData{ - Success: c.Query("saved") == "1", - UploadMaxFileSizeMB: maxBytes / (1024 * 1024), - UploadMultiMaxFiles: cfg.GetIntDefault(config.KeyUploadMultiMaxFiles, config.DefaultUploadMultiMaxFiles), - UploadMaxHours: cfg.GetIntDefault(config.KeyUploadMaxHours, config.DefaultUploadMaxHours), + Success: c.Query("saved") == "1", + UploadMaxFileSizeMB: maxBytes / (1024 * 1024), + UploadMultiMaxFiles: cfg.GetIntDefault(config.KeyUploadMultiMaxFiles, config.DefaultUploadMultiMaxFiles), + UploadMaxHours: cfg.GetIntDefault(config.KeyUploadMaxHours, config.DefaultUploadMaxHours), RateLimitLoginPerMinute: cfg.GetIntDefault(config.KeyRateLimitLoginPerMinute, config.DefaultRateLimitLoginPerMinute), RateLimitLoginBurst: cfg.GetIntDefault(config.KeyRateLimitLoginBurst, config.DefaultRateLimitLoginBurst), RateLimitApiPerMinute: cfg.GetIntDefault(config.KeyRateLimitApiPerMinute, config.DefaultRateLimitApiPerMinute), RateLimitApiBurst: cfg.GetIntDefault(config.KeyRateLimitApiBurst, config.DefaultRateLimitApiBurst), + NtfyUse: cfg.GetIntDefault(config.KeyUseNtfy, 0) != 0, + NtfyUrl: cfg.GetStringDefault(config.KeyNtfyUrl, config.DefaultNtfyUrl), + NtfyTopic: cfg.GetStringDefault(config.KeyNtfyTopic, config.DefaultNtfyTopic), } c.HTML(http.StatusOK, "config.html", data) @@ -113,6 +120,14 @@ func (h *Handler) ConfigSave(c *gin.Context) { return } + useNTFY, err := strconv.ParseBool(c.PostForm("ntfy_use")) + if err != nil { + h.renderConfigError(c, "invalid ntfy use value") + return + } + ntfyUrl := c.PostForm("ntfy_url") + ntfyTopic := c.PostForm("ntfy_topic") + // Persist. if err := cfg.SetString(config.KeyUploadMaxFileSizeBytes, strconv.FormatInt(maxMB*1024*1024, 10)); err != nil { h.renderConfigError(c, err.Error()) @@ -132,16 +147,25 @@ func (h *Handler) ConfigSave(c *gin.Context) { _ = cfg.SetString(config.KeyRateLimitApiPerMinute, strconv.Itoa(apiPerMin)) _ = cfg.SetString(config.KeyRateLimitApiBurst, strconv.Itoa(apiBurst)) + // shitty ah fix + actualBool := 0 + if useNTFY { + actualBool = 1 + } + _ = cfg.SetString(config.KeyUseNtfy, strconv.Itoa(actualBool)) + _ = cfg.SetString(config.KeyNtfyUrl, ntfyUrl) + _ = cfg.SetString(config.KeyNtfyTopic, ntfyTopic) + c.Redirect(http.StatusFound, "/config?saved=1") } func (h *Handler) renderConfigError(c *gin.Context, msg string) { maxBytes := h.configService.GetInt64Default(config.KeyUploadMaxFileSizeBytes, config.DefaultUploadMaxFileSizeBytes) data := ConfigPageData{ - Error: msg, - UploadMaxFileSizeMB: maxBytes / (1024 * 1024), - UploadMultiMaxFiles: h.configService.GetIntDefault(config.KeyUploadMultiMaxFiles, config.DefaultUploadMultiMaxFiles), - UploadMaxHours: h.configService.GetIntDefault(config.KeyUploadMaxHours, config.DefaultUploadMaxHours), + Error: msg, + UploadMaxFileSizeMB: maxBytes / (1024 * 1024), + UploadMultiMaxFiles: h.configService.GetIntDefault(config.KeyUploadMultiMaxFiles, config.DefaultUploadMultiMaxFiles), + UploadMaxHours: h.configService.GetIntDefault(config.KeyUploadMaxHours, config.DefaultUploadMaxHours), RateLimitLoginPerMinute: h.configService.GetIntDefault(config.KeyRateLimitLoginPerMinute, config.DefaultRateLimitLoginPerMinute), RateLimitLoginBurst: h.configService.GetIntDefault(config.KeyRateLimitLoginBurst, config.DefaultRateLimitLoginBurst), RateLimitApiPerMinute: h.configService.GetIntDefault(config.KeyRateLimitApiPerMinute, config.DefaultRateLimitApiPerMinute), diff --git a/internal/web/handler.go b/internal/web/handler.go index fff7c52..4b2544d 100644 --- a/internal/web/handler.go +++ b/internal/web/handler.go @@ -19,6 +19,7 @@ type ConfigService interface { GetIntDefault(key string, def int) int GetInt64Default(key string, def int64) int64 SetString(key, value string) error + GetStringDefault(key string, value string) string } func NewHandler(fileService *file.Service, cfg ConfigService) *Handler { diff --git a/templates/config.html b/templates/config.html index f59bdf0..cfe49f5 100644 --- a/templates/config.html +++ b/templates/config.html @@ -207,6 +207,26 @@ +