refactor: merge internal/sync into internal/garmin, regroup api files and routes
Garmin auth/sync routes move under /api/garmin/*; sync.Service becomes garmin.Sync with garmin.SyncConfig/ClientConfig; applog becomes internal/log; the test mock moves into the garmin package as MockClient (breaking the test-only import cycle the merge created); stale test URLs and type names updated to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
88
backend/internal/api/config.go
Normal file
88
backend/internal/api/config.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"geniusrun/backend/internal/config"
|
||||
)
|
||||
|
||||
// EnvVar is one read-only environment-configuration entry, already
|
||||
// display-safe (masking happens in config.Config.DisplayEnv).
|
||||
type EnvVar struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type configEntry struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
Default string `json:"default"`
|
||||
Overridden bool `json:"overridden"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// configView assembles the GET/PUT response: registry defaults overlaid
|
||||
// with DB overrides, plus the env snapshot.
|
||||
func (s *Server) configView(r *http.Request) (map[string]any, error) {
|
||||
overrides, err := s.DB.ConfigValues(r.Context())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
registry := config.AppRegistry()
|
||||
app := make([]configEntry, 0, len(registry))
|
||||
for _, k := range registry {
|
||||
value, overridden := overrides[k.Key]
|
||||
if !overridden {
|
||||
value = k.Default
|
||||
}
|
||||
app = append(app, configEntry{
|
||||
Key: k.Key, Value: value, Default: k.Default,
|
||||
Overridden: overridden, Description: k.Description,
|
||||
})
|
||||
}
|
||||
envVars := s.EnvVars
|
||||
if envVars == nil {
|
||||
envVars = []EnvVar{}
|
||||
}
|
||||
return map[string]any{"application": app, "environment": envVars}, nil
|
||||
}
|
||||
|
||||
func (s *Server) handleGetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
resp, err := s.configView(r)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, resp)
|
||||
}
|
||||
|
||||
// handlePutConfig updates application configuration. Cold: saved values
|
||||
// take effect on the next backend restart; the response is just the
|
||||
// refreshed view, same shape as GET.
|
||||
func (s *Server) handlePutConfig(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
|
||||
}
|
||||
// Validate every pair before writing anything -- all-or-nothing.
|
||||
for key, value := range body {
|
||||
if err := config.ValidateAppValue(key, value); err != nil {
|
||||
writeError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
for key, value := range body {
|
||||
if err := s.DB.SetConfigValue(r.Context(), key, value); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
resp, err := s.configView(r)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, resp)
|
||||
}
|
||||
Reference in New Issue
Block a user