package handlers // Methods on AdminHandler, mirrors admin provider config pattern. import ( "net/http" "github.com/gin-gonic/gin" "switchboard-core/models" ) // ListGlobalConnections returns all global-scope connections. func (h *AdminHandler) ListGlobalConnections(c *gin.Context) { conns, err := h.stores.Connections.ListGlobal(c.Request.Context()) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list connections"}) return } c.JSON(http.StatusOK, gin.H{"data": maskConnectionSecrets(conns)}) } // CreateGlobalConnection creates a global-scope connection. func (h *AdminHandler) CreateGlobalConnection(c *gin.Context) { var req struct { Type string `json:"type" binding:"required"` PackageID string `json:"package_id" binding:"required"` Name string `json:"name" binding:"required"` Config models.JSONMap `json:"config"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } ch := &ConnectionHandler{stores: h.stores, vault: h.vault} secretFields := ch.lookupSecretFields(c, req.PackageID, req.Type) encConfig := ch.encryptSecrets(req.Config, secretFields, models.ScopeGlobal, "") conn := &models.ExtConnection{ Type: req.Type, PackageID: req.PackageID, Scope: models.ScopeGlobal, OwnerID: "", Name: req.Name, Config: encConfig, IsActive: true, } if err := h.stores.Connections.Create(c.Request.Context(), conn); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create connection"}) return } c.JSON(http.StatusCreated, gin.H{ "id": conn.ID, "type": conn.Type, "name": conn.Name, }) } // UpdateGlobalConnection updates a global-scope connection. func (h *AdminHandler) UpdateGlobalConnection(c *gin.Context) { id := c.Param("id") existing, err := h.stores.Connections.GetByID(c.Request.Context(), id) if err != nil || existing.Scope != models.ScopeGlobal { c.JSON(http.StatusNotFound, gin.H{"error": "connection not found"}) return } var req struct { Name *string `json:"name,omitempty"` Config models.JSONMap `json:"config,omitempty"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } patch := models.ExtConnectionPatch{Name: req.Name} if req.Config != nil { ch := &ConnectionHandler{stores: h.stores, vault: h.vault} secretFields := ch.lookupSecretFields(c, existing.PackageID, existing.Type) patch.Config = ch.encryptSecrets(req.Config, secretFields, models.ScopeGlobal, "") } if err := h.stores.Connections.Update(c.Request.Context(), id, patch); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update connection"}) return } c.JSON(http.StatusOK, gin.H{"message": "connection updated"}) } // DeleteGlobalConnection deletes a global-scope connection. func (h *AdminHandler) DeleteGlobalConnection(c *gin.Context) { id := c.Param("id") n, err := h.stores.Connections.DeleteByIDAndScope(c.Request.Context(), id, models.ScopeGlobal, "") if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete connection"}) return } if n == 0 { c.JSON(http.StatusNotFound, gin.H{"error": "connection not found"}) return } c.JSON(http.StatusOK, gin.H{"message": "connection deleted"}) }