package handlers import ( "database/sql" "encoding/json" "net/http" "time" ) type SettingsHandler struct { DB *sql.DB } func NewSettingsHandler(db *sql.DB) *SettingsHandler { return &SettingsHandler{DB: db} } // Init creates the settings table if it does not exist. func (h *SettingsHandler) Init() error { _, err := h.DB.Exec(` CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at TIMESTAMPTZ NOT NULL ) `) return err } func (h *SettingsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: h.get(w, r) case http.MethodPut: h.put(w, r) default: writeError(w, http.StatusMethodNotAllowed, "method not allowed") } } func (h *SettingsHandler) get(w http.ResponseWriter, r *http.Request) { rows, err := h.DB.QueryContext(r.Context(), `SELECT key, value FROM settings ORDER BY key`) if err != nil { writeError(w, http.StatusInternalServerError, "internal error") return } defer rows.Close() result := make(map[string]string) for rows.Next() { var key, value string if err := rows.Scan(&key, &value); err != nil { writeError(w, http.StatusInternalServerError, "internal error") return } result[key] = value } if err := rows.Err(); err != nil { writeError(w, http.StatusInternalServerError, "internal error") return } writeJSON(w, http.StatusOK, result) } func (h *SettingsHandler) put(w http.ResponseWriter, r *http.Request) { var body map[string]string if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } if len(body) == 0 { writeError(w, http.StatusBadRequest, "body must contain at least one key") return } tx, err := h.DB.BeginTx(r.Context(), nil) if err != nil { writeError(w, http.StatusInternalServerError, "internal error") return } defer tx.Rollback() now := time.Now() for k, v := range body { _, err := tx.ExecContext(r.Context(), `INSERT INTO settings (key, value, updated_at) VALUES ($1, $2, $3) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = EXCLUDED.updated_at`, k, v, now) if err != nil { writeError(w, http.StatusInternalServerError, "internal error") return } } if err := tx.Commit(); err != nil { writeError(w, http.StatusInternalServerError, "internal error") return } writeJSON(w, http.StatusOK, body) }