BOC v1.0: RS256 auth, Ledger integration, Prometheus metrics, CI/CD, backup
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// SettingsHandler manages system configuration
|
||||
type SettingsHandler struct {
|
||||
mu sync.RWMutex
|
||||
settings map[string]interface{}
|
||||
path string
|
||||
}
|
||||
|
||||
func NewSettingsHandler() *SettingsHandler {
|
||||
h := &SettingsHandler{
|
||||
settings: make(map[string]interface{}),
|
||||
path: "/app/config/system.json",
|
||||
}
|
||||
h.load()
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) load() {
|
||||
data, err := os.ReadFile(h.path)
|
||||
if err != nil {
|
||||
// Use defaults
|
||||
h.settings = h.defaultSettings()
|
||||
return
|
||||
}
|
||||
json.Unmarshal(data, &h.settings)
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) save() error {
|
||||
data, err := json.MarshalIndent(h.settings, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(h.path, data, 0644)
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) defaultSettings() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"appearance": map[string]interface{}{
|
||||
"theme": "light",
|
||||
"density": "comfortable",
|
||||
"sidebar_width": 240,
|
||||
"animations": true,
|
||||
},
|
||||
"dashboard": map[string]interface{}{
|
||||
"greeting_enabled": true,
|
||||
"kpi_refresh": 300,
|
||||
"activity_max": 10,
|
||||
},
|
||||
"notifications": map[string]interface{}{
|
||||
"in_app": true,
|
||||
"email": false,
|
||||
"slack": false,
|
||||
},
|
||||
"advanced": map[string]interface{}{
|
||||
"api_rate_limit": 1000,
|
||||
"cache_ttl": 300,
|
||||
"log_level": "info",
|
||||
"export_max_rows": 10000,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetSettings returns all settings
|
||||
func (h *SettingsHandler) GetSettings(w http.ResponseWriter, r *http.Request) {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(h.settings)
|
||||
}
|
||||
|
||||
// UpdateSettings updates settings
|
||||
func (h *SettingsHandler) UpdateSettings(w http.ResponseWriter, r *http.Request) {
|
||||
var updates map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&updates); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
// Merge updates
|
||||
for key, value := range updates {
|
||||
h.settings[key] = value
|
||||
}
|
||||
|
||||
if err := h.save(); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to save settings")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(h.settings)
|
||||
}
|
||||
|
||||
// GetModuleConfig returns module configuration
|
||||
func (h *SettingsHandler) GetModuleConfig(w http.ResponseWriter, r *http.Request) {
|
||||
module := r.URL.Query().Get("module")
|
||||
if module == "" {
|
||||
writeError(w, http.StatusBadRequest, "module required")
|
||||
return
|
||||
}
|
||||
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
|
||||
modules, ok := h.settings["modules"].(map[string]interface{})
|
||||
if !ok {
|
||||
writeError(w, http.StatusNotFound, "modules not configured")
|
||||
return
|
||||
}
|
||||
|
||||
config, ok := modules[module]
|
||||
if !ok {
|
||||
writeError(w, http.StatusNotFound, "module not found")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(config)
|
||||
}
|
||||
|
||||
// ToggleModule enables/disables a module
|
||||
func (h *SettingsHandler) ToggleModule(w http.ResponseWriter, r *http.Request) {
|
||||
module := r.URL.Query().Get("module")
|
||||
if module == "" {
|
||||
writeError(w, http.StatusBadRequest, "module required")
|
||||
return
|
||||
}
|
||||
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
modules, ok := h.settings["modules"].(map[string]interface{})
|
||||
if !ok {
|
||||
modules = make(map[string]interface{})
|
||||
h.settings["modules"] = modules
|
||||
}
|
||||
|
||||
config, ok := modules[module].(map[string]interface{})
|
||||
if !ok {
|
||||
config = map[string]interface{}{"enabled": false}
|
||||
}
|
||||
|
||||
// Toggle enabled state
|
||||
if enabled, ok := config["enabled"].(bool); ok {
|
||||
config["enabled"] = !enabled
|
||||
} else {
|
||||
config["enabled"] = true
|
||||
}
|
||||
modules[module] = config
|
||||
|
||||
if err := h.save(); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to save")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(config)
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
h.GetSettings(w, r)
|
||||
case http.MethodPut:
|
||||
h.UpdateSettings(w, r)
|
||||
default:
|
||||
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user