package api import ( "crypto/rand" "encoding/hex" "encoding/json" "fmt" "log" "net/http" "strconv" "github.com/cynfo/rmm-backend/db" ) // generateCustomerAPIKey erstellt automatisch einen Read-only Key fuer einen Kunden func generateCustomerAPIKey(database *db.Database, customerID int, number, name string) (*db.APIKey, error) { b := make([]byte, 16) if _, err := rand.Read(b); err != nil { return nil, err } key := hex.EncodeToString(b) keyName := fmt.Sprintf("Read-only — %s %s", number, name) return database.CreateAPIKey(keyName, key, "read", &customerID) } // GET /api/v1/customers func (h *Handler) listCustomers(w http.ResponseWriter, r *http.Request) { customers, err := h.db.GetCustomers() if err != nil { writeError(w, http.StatusInternalServerError, "Fehler beim Laden") return } writeJSON(w, http.StatusOK, customers) } // POST /api/v1/customers func (h *Handler) createCustomer(w http.ResponseWriter, r *http.Request) { var req struct { Number string `json:"number"` Name string `json:"name"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Number == "" || req.Name == "" { writeError(w, http.StatusBadRequest, "number und name sind erforderlich") return } c, err := h.db.CreateCustomer(req.Number, req.Name) if err != nil { writeError(w, http.StatusInternalServerError, "Kunde anlegen fehlgeschlagen") return } // Automatisch einen Read-only API-Key fuer den neuen Kunden erstellen apiKey, keyErr := generateCustomerAPIKey(h.db, c.ID, req.Number, req.Name) if keyErr != nil { log.Printf("Auto-API-Key fuer Kunde %s fehlgeschlagen: %v", req.Number, keyErr) } h.auditLog(r, "customer.create", "customer", req.Number, req.Name, "") resp := map[string]interface{}{ "customer": c, } if apiKey != nil { resp["api_key"] = apiKey } writeJSON(w, http.StatusCreated, resp) } // GET /api/v1/customers/{id} func (h *Handler) getCustomer(w http.ResponseWriter, r *http.Request) { id, err := strconv.Atoi(r.PathValue("id")) if err != nil { writeError(w, http.StatusBadRequest, "Ungueltige ID") return } c, err := h.db.GetCustomer(id) if err != nil { writeError(w, http.StatusInternalServerError, "Fehler beim Laden") return } if c == nil { writeError(w, http.StatusNotFound, "Kunde nicht gefunden") return } writeJSON(w, http.StatusOK, c) } // PUT /api/v1/customers/{id} func (h *Handler) updateCustomer(w http.ResponseWriter, r *http.Request) { id, err := strconv.Atoi(r.PathValue("id")) if err != nil { writeError(w, http.StatusBadRequest, "Ungueltige ID") return } var req struct { Number string `json:"number"` Name string `json:"name"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Number == "" || req.Name == "" { writeError(w, http.StatusBadRequest, "number und name sind erforderlich") return } if err := h.db.UpdateCustomer(id, req.Number, req.Name); err != nil { writeError(w, http.StatusInternalServerError, "Aktualisierung fehlgeschlagen") return } writeJSON(w, http.StatusOK, map[string]string{"message": "Kunde aktualisiert"}) } // DELETE /api/v1/customers/{id} func (h *Handler) deleteCustomer(w http.ResponseWriter, r *http.Request) { id, err := strconv.Atoi(r.PathValue("id")) if err != nil { writeError(w, http.StatusBadRequest, "Ungueltige ID") return } deleted, err := h.db.DeleteCustomer(id) if err != nil { writeError(w, http.StatusInternalServerError, "Loeschen fehlgeschlagen") return } if !deleted { writeError(w, http.StatusNotFound, "Kunde nicht gefunden") return } h.auditLog(r, "customer.delete", "customer", strconv.Itoa(id), "", "") writeJSON(w, http.StatusOK, map[string]string{"message": "Kunde geloescht"}) } // GET /api/v1/customers/{id}/agents func (h *Handler) getCustomerAgents(w http.ResponseWriter, r *http.Request) { id, err := strconv.Atoi(r.PathValue("id")) if err != nil { writeError(w, http.StatusBadRequest, "Ungueltige ID") return } agents, err := h.db.GetAgentsByCustomer(id) if err != nil { writeError(w, http.StatusInternalServerError, "Fehler beim Laden") return } writeJSON(w, http.StatusOK, agents) } // PUT /api/v1/agents/{id}/customer func (h *Handler) assignAgentCustomer(w http.ResponseWriter, r *http.Request) { agentID := r.PathValue("id") var req struct { CustomerID int `json:"customer_id"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.CustomerID == 0 { writeError(w, http.StatusBadRequest, "customer_id erforderlich") return } if err := h.db.AssignAgentCustomer(agentID, req.CustomerID); err != nil { writeError(w, http.StatusInternalServerError, "Zuordnung fehlgeschlagen") return } writeJSON(w, http.StatusOK, map[string]string{"message": "Agent zugeordnet"}) } // DELETE /api/v1/agents/{id}/customer func (h *Handler) unassignAgentCustomer(w http.ResponseWriter, r *http.Request) { agentID := r.PathValue("id") if err := h.db.UnassignAgentCustomer(agentID); err != nil { writeError(w, http.StatusInternalServerError, "Zuordnung entfernen fehlgeschlagen") return } writeJSON(w, http.StatusOK, map[string]string{"message": "Zuordnung entfernt"}) }