feat: Kunden-Seite zeigt API-Keys beim Aufklappen

- Klick auf Kundenzeile klappt Key-Panel auf
- Zeigt Agent + Read-only Keys mit Permission-Badge
- Key teilweise maskiert, Kopier-Button vorhanden
- Backend: GET /api/v1/customers/{id}/apikeys
- DB: ListCustomerAPIKeys() nach customer_id gefiltert
This commit is contained in:
cynfo3000
2026-03-10 00:06:16 +01:00
parent fba824da8b
commit 5cc3476479
5 changed files with 168 additions and 15 deletions
+15
View File
@@ -58,6 +58,21 @@ func (h *Handler) createAPIKey(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusCreated, apiKey)
}
// GET /api/v1/customers/{id}/apikeys
func (h *Handler) listCustomerAPIKeys(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
writeError(w, http.StatusBadRequest, "Ungueltige ID")
return
}
keys, err := h.db.ListCustomerAPIKeys(id)
if err != nil {
writeError(w, http.StatusInternalServerError, "Laden fehlgeschlagen")
return
}
writeJSON(w, http.StatusOK, keys)
}
// DELETE /api/v1/apikeys/{id}
func (h *Handler) deleteAPIKey(w http.ResponseWriter, r *http.Request) {
idStr := r.PathValue("id")
+1
View File
@@ -59,6 +59,7 @@ func (h *Handler) SetupRoutes(mux *http.ServeMux, hub *ws.Hub) {
mux.HandleFunc("GET /api/v1/apikeys", h.listAPIKeys)
mux.HandleFunc("POST /api/v1/apikeys", h.createAPIKey)
mux.HandleFunc("DELETE /api/v1/apikeys/{id}", h.deleteAPIKey)
mux.HandleFunc("GET /api/v1/customers/{id}/apikeys", h.listCustomerAPIKeys)
// System Settings
mux.HandleFunc("GET /api/v1/settings", h.getSettings)
+32
View File
@@ -1259,6 +1259,38 @@ func (d *Database) UpdateAPIKeyLastUsed(key string) {
d.db.Exec("UPDATE api_keys SET last_used = NOW() WHERE key = $1", key)
}
func (d *Database) ListCustomerAPIKeys(customerID int) ([]APIKey, error) {
rows, err := d.db.Query(
"SELECT id, name, key, permissions, customer_id, created_at, last_used FROM api_keys WHERE customer_id = $1 ORDER BY permissions, created_at",
customerID,
)
if err != nil {
return nil, err
}
defer rows.Close()
var keys []APIKey
for rows.Next() {
var k APIKey
var lastUsed sql.NullTime
var custID sql.NullInt64
if err := rows.Scan(&k.ID, &k.Name, &k.Key, &k.Permissions, &custID, &k.CreatedAt, &lastUsed); err != nil {
return nil, err
}
if lastUsed.Valid {
k.LastUsed = &lastUsed.Time
}
if custID.Valid {
id := int(custID.Int64)
k.CustomerID = &id
}
keys = append(keys, k)
}
if keys == nil {
keys = []APIKey{}
}
return keys, rows.Err()
}
// MigrateConfigAPIKeys migriert API-Keys aus der Config in die DB (einmalig)
// --- Audit Log ---