6de2455917
- Added GLOBAL_MARKETS_TITLE to all translation files - Updated footer with 12 markets (4 active + 8 upcoming) - Translated market section to: zh-cn, zh-tw, ja, ko, th, vi, id, ms, hi - Built and deployed to production - CloudFront invalidation: I3RTMXVFDJXWLG3SYX208OP1CC
103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
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)
|
|
}
|