package handler import ( "net/http" "sql-platform/internal/middleware" "sql-platform/internal/model" "github.com/gin-gonic/gin" ) // GET /api/v1/instances/accessible?access_type=readonly|write func AccessibleInstances(c *gin.Context) { userID, _, role := middleware.GetCurrentUser(c) accessType := c.DefaultQuery("access_type", "readonly") var instances []model.Instance if role == "admin" || role == "dba" { // admin/dba see all instances, filter by access_mode if needed query := model.DB.Order("id") if accessType == "readonly" { query = query.Where("access_mode IN ?", []string{"readwrite", "readonly"}) } else { query = query.Where("access_mode IN ?", []string{"readwrite", "write"}) } query.Find(&instances) } else { // developer/auditor: only instances in their groups var groupIDs []int model.DB.Model(&model.UserGroup{}).Where("user_id = ?", userID).Pluck("group_id", &groupIDs) if len(groupIDs) == 0 { c.JSON(http.StatusOK, []model.Instance{}) return } var instanceIDs []int // Query for the requested access_type OR readwrite (readwrite grants both) model.DB.Model(&model.InstanceGroupMember{}). Where("group_id IN ? AND (access_type = ? OR access_type = ?)", groupIDs, accessType, "readwrite"). Pluck("instance_id", &instanceIDs) if len(instanceIDs) == 0 { c.JSON(http.StatusOK, []model.Instance{}) return } model.DB.Where("id IN ?", instanceIDs).Order("id").Find(&instances) } // mask passwords for i := range instances { instances[i].Password = "******" } c.JSON(http.StatusOK, instances) } // GET /api/v1/instances/:id/databases func ListDatabases(c *gin.Context) { id := c.Param("id") var instance model.Instance if err := model.DB.First(&instance, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"detail": "Instance not found"}) return } databases, err := listDatabases(&instance) if err != nil { c.JSON(http.StatusOK, []string{}) return } if databases == nil { databases = []string{} } c.JSON(http.StatusOK, databases) } // GET /api/v1/instances/:id/databases/:db/tables func ListTables(c *gin.Context) { id := c.Param("id") dbName := c.Param("db") var instance model.Instance if err := model.DB.First(&instance, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"detail": "Instance not found"}) return } tables, err := listTables(&instance, dbName) if err != nil { c.JSON(http.StatusOK, []interface{}{}) return } if tables == nil { tables = []map[string]interface{}{} } c.JSON(http.StatusOK, tables) } // POST /api/v1/instances/test-connection (new instance, not saved yet) func TestNewConnection(c *gin.Context) { var req struct { DBType string `json:"db_type"` Host string `json:"host"` Port int `json:"port"` Username string `json:"username"` Password string `json:"password"` Database string `json:"database"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"detail": "Invalid request"}) return } instance := &model.Instance{ DBType: req.DBType, Host: req.Host, Port: req.Port, Username: req.Username, Password: req.Password, } if req.Database != "" { instance.Database = &req.Database } success, message := testDBConnection(instance) if success { c.JSON(http.StatusOK, gin.H{"success": true, "message": message}) } else { c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": message}) } }