api: add /api/currencies endpoint for currency dropdown

Implements currency API per issue #11 requirements:
- Returns top 10 currencies (USD, EUR, GBP, JPY, CAD, AUD, CHF, SEK, NOK, NZD)
- Returns all remaining active currencies alphabetically
- Queries corporate.db currencies table
- Proper error handling with unique error codes (ERR-ADMIN-001, ERR-ADMIN-002)
- CORS enabled for frontend access

fixes #11

Author: Emma <emma-20250409-001>
This commit is contained in:
James 2026-04-09 03:33:54 -04:00
parent fe9f98a69e
commit 12824ddbef
1 changed files with 69 additions and 0 deletions

View File

@ -1104,6 +1104,75 @@ Entries:
w.Write([]byte(`{"ok":true}`))
})
// Currencies API — returns top 10 + all currencies for pricing display
http.HandleFunc("/api/currencies", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*")
if corpDB == nil {
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(map[string]any{
"error": "ERR-ADMIN-001: Currency data unavailable — corporate DB not connected",
})
return
}
// Top currencies to display first
topCodes := []string{"USD", "EUR", "GBP", "JPY", "CAD", "AUD", "CHF", "SEK", "NOK", "NZD"}
topMap := make(map[string]bool)
for _, code := range topCodes {
topMap[code] = true
}
rows, err := corpDB.Query(`SELECT code, name, symbol, symbol_position FROM currencies WHERE is_active = 1 ORDER BY code`)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]any{
"error": "ERR-ADMIN-002: Failed to query currencies — " + err.Error(),
})
return
}
defer rows.Close()
type Currency struct {
Code string `json:"code"`
Name string `json:"name"`
Symbol string `json:"symbol"`
SymbolPosition string `json:"symbol_position"`
}
var top []Currency
var all []Currency
for rows.Next() {
var c Currency
if err := rows.Scan(&c.Code, &c.Name, &c.Symbol, &c.SymbolPosition); err != nil {
continue // Skip malformed rows
}
if topMap[c.Code] {
top = append(top, c)
} else {
all = append(all, c)
}
}
// Ensure top currencies are in the defined order
orderedTop := make([]Currency, 0, len(topCodes))
for _, code := range topCodes {
for _, c := range top {
if c.Code == code {
orderedTop = append(orderedTop, c)
break
}
}
}
json.NewEncoder(w).Encode(map[string]any{
"top": orderedTop,
"all": all,
})
})
// NOC API — latest telemetry per node
nocPin := func(r *http.Request) bool { return r.URL.Query().Get("pin") == "250365" }