feat(connections): wire full CRUD endpoints for AD connections
- Add Create/Update/Delete handlers on ConnectionsHandler backed by the existing ConnectionRepository (soft-delete preserves audit history). - Register List/Get/Create/Update/Delete/Test routes on /ad-connections so the resource is no longer stubbed out.
This commit is contained in:
@@ -5,11 +5,11 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/logging"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/models"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/repository"
|
||||
"github.com/Grace-Solutions/OrchestrAD/internal/services"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// ConnectionsHandler handles AD connection API endpoints
|
||||
@@ -107,6 +107,64 @@ func (h *ConnectionsHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
WriteJSON(w, http.StatusOK, connectionToResponse(conn))
|
||||
}
|
||||
|
||||
// Create handles POST /api/v1/ad-connections
|
||||
func (h *ConnectionsHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||
var req ConnectionRequest
|
||||
if err := DecodeJSON(r, &req); err != nil {
|
||||
WriteError(w, http.StatusBadRequest, ErrCodeBadRequest, "Invalid request body")
|
||||
return
|
||||
}
|
||||
if req.Name == "" || req.Hosts == "" || req.RootDN == "" {
|
||||
WriteError(w, http.StatusBadRequest, ErrCodeValidation, "name, hosts and rootDn are required")
|
||||
return
|
||||
}
|
||||
conn := requestToConnection(&req, nil)
|
||||
if err := h.repo.Create(conn); err != nil {
|
||||
h.logger.Error("ConnectionsHandler", "Create failed: %v", err)
|
||||
WriteError(w, http.StatusInternalServerError, ErrCodeInternalError, "Failed to create connection")
|
||||
return
|
||||
}
|
||||
WriteJSON(w, http.StatusCreated, connectionToResponse(conn))
|
||||
}
|
||||
|
||||
// Update handles PUT /api/v1/ad-connections/{id}
|
||||
func (h *ConnectionsHandler) Update(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
existing, err := h.repo.GetByID(id)
|
||||
if err != nil {
|
||||
h.logger.Error("ConnectionsHandler", "GetByID failed: %v", err)
|
||||
WriteError(w, http.StatusInternalServerError, ErrCodeInternalError, "Failed to load connection")
|
||||
return
|
||||
}
|
||||
if existing == nil {
|
||||
WriteError(w, http.StatusNotFound, ErrCodeNotFound, "Connection not found")
|
||||
return
|
||||
}
|
||||
var req ConnectionRequest
|
||||
if err := DecodeJSON(r, &req); err != nil {
|
||||
WriteError(w, http.StatusBadRequest, ErrCodeBadRequest, "Invalid request body")
|
||||
return
|
||||
}
|
||||
conn := requestToConnection(&req, existing)
|
||||
if err := h.repo.Update(conn); err != nil {
|
||||
h.logger.Error("ConnectionsHandler", "Update failed: %v", err)
|
||||
WriteError(w, http.StatusInternalServerError, ErrCodeInternalError, "Failed to update connection")
|
||||
return
|
||||
}
|
||||
WriteJSON(w, http.StatusOK, connectionToResponse(conn))
|
||||
}
|
||||
|
||||
// Delete handles DELETE /api/v1/ad-connections/{id}
|
||||
func (h *ConnectionsHandler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
if err := h.repo.SoftDelete(id); err != nil {
|
||||
h.logger.Error("ConnectionsHandler", "Delete failed: %v", err)
|
||||
WriteError(w, http.StatusInternalServerError, ErrCodeInternalError, "Failed to delete connection")
|
||||
return
|
||||
}
|
||||
WriteJSON(w, http.StatusOK, map[string]bool{"deleted": true})
|
||||
}
|
||||
|
||||
// Test handles POST /api/v1/ad-connections/{id}/test
|
||||
func (h *ConnectionsHandler) Test(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
@@ -133,6 +191,29 @@ func (h *ConnectionsHandler) Test(w http.ResponseWriter, r *http.Request) {
|
||||
WriteJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
func requestToConnection(req *ConnectionRequest, existing *models.ADConnection) *models.ADConnection {
|
||||
conn := &models.ADConnection{}
|
||||
if existing != nil {
|
||||
*conn = *existing
|
||||
}
|
||||
conn.Name = req.Name
|
||||
conn.Description = req.Description
|
||||
conn.IsEnabled = req.IsEnabled
|
||||
conn.Hosts = req.Hosts
|
||||
conn.Port = req.Port
|
||||
conn.UseTLS = req.UseTLS
|
||||
conn.UseStartTLS = req.UseStartTLS
|
||||
conn.AllowInvalidCerts = req.AllowInvalidCerts
|
||||
conn.RootDN = req.RootDN
|
||||
conn.BindDN = req.BindDN
|
||||
conn.CredentialID = req.CredentialID
|
||||
conn.DefaultSearchScope = req.DefaultSearchScope
|
||||
conn.TimeoutSeconds = req.TimeoutSeconds
|
||||
conn.PagingEnabled = req.PagingEnabled
|
||||
conn.PageSize = req.PageSize
|
||||
return conn
|
||||
}
|
||||
|
||||
func connectionToResponse(c *models.ADConnection) ConnectionResponse {
|
||||
resp := ConnectionResponse{
|
||||
ID: c.ID,
|
||||
|
||||
@@ -126,14 +126,14 @@ func (s *Server) setupRoutes() {
|
||||
})
|
||||
|
||||
// AD Connections
|
||||
connectionsHandler := api.NewConnectionsHandler(s.deps.ConnRepo, s.deps.ConnService, s.logger)
|
||||
r.Route("/ad-connections", func(r chi.Router) {
|
||||
r.Get("/", s.handleNotImplemented)
|
||||
r.Post("/", s.handleNotImplemented)
|
||||
r.Get("/{id}", s.handleNotImplemented)
|
||||
r.Put("/{id}", s.handleNotImplemented)
|
||||
r.Delete("/{id}", s.handleNotImplemented)
|
||||
r.Post("/test", s.handleNotImplemented)
|
||||
r.Post("/{id}/test", s.handleNotImplemented)
|
||||
r.Get("/", connectionsHandler.List)
|
||||
r.Post("/", connectionsHandler.Create)
|
||||
r.Get("/{id}", connectionsHandler.Get)
|
||||
r.Put("/{id}", connectionsHandler.Update)
|
||||
r.Delete("/{id}", connectionsHandler.Delete)
|
||||
r.Post("/{id}/test", connectionsHandler.Test)
|
||||
r.Post("/{id}/query-preview", s.handleNotImplemented)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user