feat(app): wire settings registry into startup and admin routes
Construct the SettingsRegistry at boot, load it, and thread it through
every consumer so the configurable values take effect and stay cached.
cmd/server/main.go:
- Build the registry from the Queries handle and Load() it right after
schema init; a load failure logs and continues (getters fall back to
compiled defaults, so startup is never blocked).
- Wire the registry into the package-level password validator
(SetDefaultPasswordSettings) and call SetSettings on every handler/
service that reads tunables: AuthHandler, DeviceAuthMiddleware,
OPDSHandler, SidecarHandler, SystemSettingsHandler,
AnnotationService, ConversionService.
- Source the restart-time values from the registry: login lockout
(max attempts + duration) feeds NewLoginAttemptTracker, and the new
NewSyncQueueProcessorWithConfig / NewWorkerWithConfig take the sync
queue and worker pool configs.
router.go:
- Config gains a Settings *database.SettingsRegistry field.
- The global auth rate limiter now reads RequestsPerMinute from
registry.AuthRateLimit() (env stays as the enabled/disabled switch
and as the fallback if the registry is unset).
admin_library.go:
- The HTMX scan-settings save endpoint reloads the registry after
writing so the change is visible without a page reload.
- Add PUT /admin/settings/tunable: a small HTMX endpoint that calls
SystemSettingsHandler.ApplySetting and returns a colored status
snippet ("Saved" or "Saved — restart required") for the admin UI's
per-row forms.
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"bookhoard/internal/database"
|
||||
"bookhoard/internal/handlers"
|
||||
"bookhoard/templates"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -406,6 +407,11 @@ func registerAdminSettingsRoutes(cfg *Config, frontendProtected *echo.Group) {
|
||||
SettingValue: strconv.Itoa(interval),
|
||||
})
|
||||
|
||||
// Refresh the registry cache so the change is visible immediately.
|
||||
if cfg.Settings != nil {
|
||||
cfg.Settings.Reload(ctx)
|
||||
}
|
||||
|
||||
scanSettings := templates.ScanSettingsData{
|
||||
AutoScanEnabled: autoScan,
|
||||
ScanPollIntervalSeconds: interval,
|
||||
@@ -414,4 +420,28 @@ func registerAdminSettingsRoutes(cfg *Config, frontendProtected *echo.Group) {
|
||||
_ = templates.ScanSettingsSection(scanSettings).Render(ctx, &buf)
|
||||
return c.HTML(http.StatusOK, buf.String())
|
||||
})
|
||||
|
||||
// HTMX endpoint for saving a single tunable setting. Returns a small HTML
|
||||
// status snippet rendered into the row's status span.
|
||||
g.PUT("/admin/settings/tunable", func(c *echo.Context) error {
|
||||
ctx := c.Request().Context()
|
||||
key := c.FormValue("key")
|
||||
value := c.FormValue("value")
|
||||
|
||||
if cfg.SystemSettingsHandler == nil {
|
||||
return c.HTML(http.StatusServiceUnavailable, `<span style="color: var(--status-danger);">settings unavailable</span>`)
|
||||
}
|
||||
resp, err := cfg.SystemSettingsHandler.ApplySetting(ctx, key, value)
|
||||
if err != nil {
|
||||
return c.HTML(http.StatusBadRequest, fmt.Sprintf(`<span style="color: var(--status-danger);">%s</span>`, err.Error()))
|
||||
}
|
||||
|
||||
color := "var(--status-success)"
|
||||
msg := "Saved"
|
||||
if resp.ReloadRequired {
|
||||
color = "var(--status-warning)"
|
||||
msg = "Saved — restart required"
|
||||
}
|
||||
return c.HTML(http.StatusOK, fmt.Sprintf(`<span style="color: %s;">%s</span>`, color, msg))
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user