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:
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user