Files
bookhoard/internal/handlers/system_settings.go
T
john-okeefe 330df97cfd Add timezone backend support (handlers, utilities, user context)
- Add FormatInTimezone and FormatTimestamptzInTimezone helpers
  in templates/utils.go for timezone-aware time display
- Add Timezone field to templates.User struct
- Pass user timezone from DB to template context in helpers.go
- Add timezone update handling in auth.go UpdateProfile with
  validation via time.LoadLocation
- Add UpdateTimezoneSettings handler in system_settings.go for
  admin system-wide default timezone using UpdateSystemSetting
2026-04-27 21:30:53 -04:00

136 lines
4.4 KiB
Go

package handlers
import (
"bookhoard/internal/database"
"errors"
"net/http"
"strconv"
"time"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v5"
)
type SystemSettingsHandler struct {
db *database.Queries
}
func NewSystemSettingsHandler(db *database.Queries) *SystemSettingsHandler {
return &SystemSettingsHandler{
db: db,
}
}
type UpdateScanSettingsRequest struct {
ScanPollIntervalSeconds int32 `json:"scan_poll_interval_seconds" validate:"required,min=1,max=3600"`
AutoScanEnabled bool `json:"auto_scan_enabled"`
}
type ScanSettingsResponse struct {
ScanPollIntervalSeconds int32 `json:"scan_poll_interval_seconds"`
AutoScanEnabled bool `json:"auto_scan_enabled"`
Message string `json:"message,omitempty"`
}
type UpdateTimezoneSettingsRequest struct {
DefaultTimezone string `json:"default_timezone" validate:"required"`
}
func (h *SystemSettingsHandler) UpdateTimezoneSettings(c *echo.Context) error {
var req UpdateTimezoneSettingsRequest
if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request"})
}
if _, err := time.LoadLocation(req.DefaultTimezone); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid timezone"})
}
err := h.db.UpdateSystemSetting(c.Request().Context(), database.UpdateSystemSettingParams{
SettingKey: "default_timezone",
SettingValue: req.DefaultTimezone,
})
if err != nil {
return err
}
return c.JSON(http.StatusOK, map[string]string{"message": "Timezone updated"})
}
func (h *SystemSettingsHandler) UpdateScanSettings(c *echo.Context) error {
var req UpdateScanSettingsRequest
if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
}
if err := c.Validate(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
}
scanFrequencyValue := strconv.FormatInt(int64(req.ScanPollIntervalSeconds), 10)
autoScanValue := strconv.FormatBool(req.AutoScanEnabled)
err := h.db.UpdateSystemSetting(c.Request().Context(), database.UpdateSystemSettingParams{
SettingKey: "scan_poll_interval_seconds",
SettingValue: scanFrequencyValue,
})
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return c.JSON(http.StatusNotFound, map[string]string{"error": "system setting not found"})
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
err = h.db.UpdateSystemSetting(c.Request().Context(), database.UpdateSystemSettingParams{
SettingKey: "auto_scan_enabled",
SettingValue: autoScanValue,
})
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return c.JSON(http.StatusNotFound, map[string]string{"error": "system setting not found"})
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
return c.JSON(http.StatusOK, ScanSettingsResponse{
ScanPollIntervalSeconds: req.ScanPollIntervalSeconds,
AutoScanEnabled: req.AutoScanEnabled,
Message: "scan settings updated successfully",
})
}
func (h *SystemSettingsHandler) GetScanSettings(c *echo.Context) error {
scanFrequencySetting, err := h.db.GetSystemSetting(c.Request().Context(), "scan_poll_interval_seconds")
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return c.JSON(http.StatusOK, ScanSettingsResponse{
ScanPollIntervalSeconds: 60,
AutoScanEnabled: true,
})
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
autoScanSetting, err := h.db.GetSystemSetting(c.Request().Context(), "auto_scan_enabled")
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return c.JSON(http.StatusOK, ScanSettingsResponse{
ScanPollIntervalSeconds: 60,
AutoScanEnabled: true,
})
}
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
scanFrequency, err := strconv.ParseInt(scanFrequencySetting, 10, 32)
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "invalid scan frequency setting"})
}
autoScanEnabled, err := strconv.ParseBool(autoScanSetting)
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "invalid auto scan setting"})
}
return c.JSON(http.StatusOK, ScanSettingsResponse{
ScanPollIntervalSeconds: int32(scanFrequency),
AutoScanEnabled: autoScanEnabled,
})
}