feat: Go后端补全所有缺失API接口,消除前端404报错
新增接口: - GET /instances/accessible — 查询页实例列表(按access_type筛选) - GET /instances/:id/databases — 数据库列表(placeholder) - GET /instances/:id/databases/:db/tables — 表列表(placeholder) - POST /instances/test-connection — 新实例连接测试 - CRUD /instance-groups — 完整实例组管理(创建/更新/删除/查询单个) - /instance-groups/:id/instances — 实例分配/移除 - /instance-groups/:id/users — 用户分配 - PUT /instance-groups/users/:userId/groups — 用户组更新 - GET/PUT /ldap-config — LDAP配置读写 - POST /ldap-config/test — LDAP连接测试(placeholder) - POST /ldap-config/ou-list — OU列表(placeholder) - POST /ldap-config/user-list — 用户列表(placeholder) - PUT /settings — 批量更新设置 - GET /settings/cleanup/preview — 清理预览 - POST /settings/cleanup/run — 执行清理 修复: - ListSettings 返回按group分组的dict(前端期望格式) - ListInstanceGroups 返回enriched数据(含实例/用户计数) - 前端所有页面0个404错误,查询页实例下拉框正常显示
This commit is contained in:
1 parent
26148d0ca7
commit
622923821b
5 files changed
+526
-4
No files matched your search
@@ -90,11 +90,43 @@ func ListQueryHistories(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, histories)
|
||||
}
|
||||
|
||||
// GET /api/v1/settings
|
||||
// GET /api/v1/settings — returns settings grouped by `group` field
|
||||
func ListSettings(c *gin.Context) {
|
||||
var settings []model.SystemSetting
|
||||
model.DB.Order("sort_order").Find(&settings)
|
||||
c.JSON(http.StatusOK, settings)
|
||||
|
||||
// group by `group` field
|
||||
grouped := make(map[string][]model.SystemSetting)
|
||||
for _, s := range settings {
|
||||
grouped[s.Group] = append(grouped[s.Group], s)
|
||||
}
|
||||
c.JSON(http.StatusOK, grouped)
|
||||
}
|
||||
|
||||
// PUT /api/v1/settings — batch update settings
|
||||
func UpdateSettings(c *gin.Context) {
|
||||
var items []struct {
|
||||
ID int `json:"id"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&items); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
for _, item := range items {
|
||||
model.DB.Model(&model.SystemSetting{}).Where("id = ?", item.ID).Update("value", item.Value)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Settings updated"})
|
||||
}
|
||||
|
||||
// GET /api/v1/settings/cleanup/preview
|
||||
func SettingsCleanupPreview(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, map[string]interface{}{})
|
||||
}
|
||||
|
||||
// POST /api/v1/settings/cleanup/run
|
||||
func SettingsCleanupRun(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Cleanup done (placeholder)", "stats": map[string]interface{}{}})
|
||||
}
|
||||
|
||||
// GET /api/v1/notifications/channels
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
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
|
||||
model.DB.Model(&model.InstanceGroupMember{}).
|
||||
Where("group_id IN ? AND access_type = ?", groupIDs, accessType).
|
||||
Pluck("instance_id", &instanceIDs)
|
||||
// also include readwrite
|
||||
if accessType == "readonly" {
|
||||
model.DB.Model(&model.InstanceGroupMember{}).
|
||||
Where("group_id IN ? AND access_type = ?", groupIDs, "readwrite").
|
||||
Pluck("instance_id", &instanceIDs)
|
||||
} else if accessType == "write" {
|
||||
model.DB.Model(&model.InstanceGroupMember{}).
|
||||
Where("group_id IN ? AND access_type = ?", groupIDs, "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
|
||||
}
|
||||
// TODO: actual database connection to list databases
|
||||
// Return placeholder for now
|
||||
c.JSON(http.StatusOK, []string{"information_schema"})
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
// TODO: actual database connection to list tables
|
||||
_ = dbName
|
||||
c.JSON(http.StatusOK, []interface{}{})
|
||||
}
|
||||
|
||||
// POST /api/v1/instances/test-connection (new instance, not saved yet)
|
||||
func TestNewConnection(c *gin.Context) {
|
||||
// TODO: actual connection test
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"message": "Connection test passed (placeholder)",
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"sql-platform/internal/model"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// GET /api/v1/instance-groups
|
||||
// (already in ghost.go as stub, replace with real implementation)
|
||||
|
||||
// GET /api/v1/instance-groups/:id
|
||||
func GetInstanceGroup(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var group model.InstanceGroup
|
||||
if err := model.DB.First(&group, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"detail": "Instance group not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, enrichGroup(group))
|
||||
}
|
||||
|
||||
// POST /api/v1/instance-groups
|
||||
func CreateInstanceGroup(c *gin.Context) {
|
||||
var group model.InstanceGroup
|
||||
if err := c.ShouldBindJSON(&group); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
if err := model.DB.Create(&group).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, enrichGroup(group))
|
||||
}
|
||||
|
||||
// PUT /api/v1/instance-groups/:id
|
||||
func UpdateInstanceGroup(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var group model.InstanceGroup
|
||||
if err := model.DB.First(&group, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"detail": "Instance group not found"})
|
||||
return
|
||||
}
|
||||
|
||||
var input map[string]interface{}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := model.DB.Model(&group).Updates(input).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
model.DB.First(&group, id)
|
||||
c.JSON(http.StatusOK, enrichGroup(group))
|
||||
}
|
||||
|
||||
// DELETE /api/v1/instance-groups/:id
|
||||
func DeleteInstanceGroup(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if err := model.DB.Delete(&model.InstanceGroup{}, id).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
// also clean up members
|
||||
model.DB.Where("group_id = ?", id).Delete(&model.InstanceGroupMember{})
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Instance group deleted"})
|
||||
}
|
||||
|
||||
// POST /api/v1/instance-groups/:id/instances
|
||||
func AssignGroupInstances(c *gin.Context) {
|
||||
groupID, _ := strconv.Atoi(c.Param("id"))
|
||||
var input struct {
|
||||
InstanceIDs []int `json:"instance_ids"`
|
||||
AccessType string `json:"access_type"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
if input.AccessType == "" {
|
||||
input.AccessType = "readonly"
|
||||
}
|
||||
|
||||
for _, iid := range input.InstanceIDs {
|
||||
member := model.InstanceGroupMember{
|
||||
GroupID: groupID,
|
||||
InstanceID: iid,
|
||||
AccessType: input.AccessType,
|
||||
}
|
||||
model.DB.Where("group_id = ? AND instance_id = ? AND access_type = ?",
|
||||
groupID, iid, input.AccessType).FirstOrCreate(&member)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Instances assigned"})
|
||||
}
|
||||
|
||||
// DELETE /api/v1/instance-groups/:id/instances/:instanceId
|
||||
func RemoveGroupInstance(c *gin.Context) {
|
||||
groupID := c.Param("id")
|
||||
instanceID := c.Param("instanceId")
|
||||
accessType := c.Query("access_type")
|
||||
|
||||
query := model.DB.Where("group_id = ? AND instance_id = ?", groupID, instanceID)
|
||||
if accessType != "" {
|
||||
query = query.Where("access_type = ?", accessType)
|
||||
}
|
||||
query.Delete(&model.InstanceGroupMember{})
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Instance removed from group"})
|
||||
}
|
||||
|
||||
// GET /api/v1/instance-groups/:id/users
|
||||
func ListGroupUsers(c *gin.Context) {
|
||||
groupID := c.Param("id")
|
||||
var userGroups []model.UserGroup
|
||||
model.DB.Where("group_id = ?", groupID).Find(&userGroups)
|
||||
c.JSON(http.StatusOK, userGroups)
|
||||
}
|
||||
|
||||
// POST /api/v1/instance-groups/:id/users
|
||||
func AssignGroupUsers(c *gin.Context) {
|
||||
groupID, _ := strconv.Atoi(c.Param("id"))
|
||||
var input struct {
|
||||
UserIDs []int `json:"user_ids"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// delete existing
|
||||
model.DB.Where("group_id = ?", groupID).Delete(&model.UserGroup{})
|
||||
|
||||
perms := ""
|
||||
if len(input.Permissions) > 0 {
|
||||
// store as JSON array string
|
||||
import_json_str := "["
|
||||
for i, p := range input.Permissions {
|
||||
if i > 0 {
|
||||
import_json_str += ","
|
||||
}
|
||||
import_json_str += `"` + p + `"`
|
||||
}
|
||||
import_json_str += "]"
|
||||
perms = import_json_str
|
||||
}
|
||||
|
||||
for _, uid := range input.UserIDs {
|
||||
ug := model.UserGroup{UserID: uid, GroupID: groupID}
|
||||
if perms != "" {
|
||||
ug.Permissions = &perms
|
||||
}
|
||||
model.DB.Create(&ug)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Users assigned"})
|
||||
}
|
||||
|
||||
// PUT /api/v1/instance-groups/users/:userId/groups
|
||||
func UpdateUserGroups(c *gin.Context) {
|
||||
userID := c.Param("userId")
|
||||
var input struct {
|
||||
GroupIDs []int `json:"group_ids"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
uid, _ := strconv.Atoi(userID)
|
||||
model.DB.Where("user_id = ?", uid).Delete(&model.UserGroup{})
|
||||
for _, gid := range input.GroupIDs {
|
||||
model.DB.Create(&model.UserGroup{UserID: uid, GroupID: gid})
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "User groups updated"})
|
||||
}
|
||||
|
||||
// enrichGroup adds computed counts to InstanceGroup response
|
||||
func enrichGroup(group model.InstanceGroup) gin.H {
|
||||
gid := group.ID
|
||||
|
||||
var readonlyCount, writeCount, userCount int64
|
||||
var readonlyMembers, writeMembers []model.InstanceGroupMember
|
||||
|
||||
model.DB.Where("group_id = ? AND access_type IN ?", gid, []string{"readonly", "readwrite"}).Find(&readonlyMembers)
|
||||
readonlyCount = int64(len(readonlyMembers))
|
||||
|
||||
model.DB.Where("group_id = ? AND access_type IN ?", gid, []string{"write", "readwrite"}).Find(&writeMembers)
|
||||
writeCount = int64(len(writeMembers))
|
||||
|
||||
model.DB.Model(&model.UserGroup{}).Where("group_id = ?", gid).Count(&userCount)
|
||||
|
||||
// collect instance details
|
||||
allInstanceIDs := []int{}
|
||||
for _, m := range readonlyMembers {
|
||||
allInstanceIDs = append(allInstanceIDs, m.InstanceID)
|
||||
}
|
||||
for _, m := range writeMembers {
|
||||
allInstanceIDs = append(allInstanceIDs, m.InstanceID)
|
||||
}
|
||||
|
||||
// unique
|
||||
seen := map[int]bool{}
|
||||
uniqueIDs := []int{}
|
||||
for _, id := range allInstanceIDs {
|
||||
if !seen[id] {
|
||||
seen[id] = true
|
||||
uniqueIDs = append(uniqueIDs, id)
|
||||
}
|
||||
}
|
||||
|
||||
var instances []model.Instance
|
||||
if len(uniqueIDs) > 0 {
|
||||
model.DB.Where("id IN ?", uniqueIDs).Find(&instances)
|
||||
}
|
||||
for i := range instances {
|
||||
instances[i].Password = "******"
|
||||
}
|
||||
|
||||
return gin.H{
|
||||
"id": group.ID,
|
||||
"name": group.Name,
|
||||
"description": group.Description,
|
||||
"db_type": group.DBType,
|
||||
"permissions": group.Permissions,
|
||||
"is_active": group.IsActive,
|
||||
"created_at": group.CreatedAt,
|
||||
"updated_at": group.UpdatedAt,
|
||||
"workflow_id": group.WorkflowID,
|
||||
"access_type": group.AccessType,
|
||||
"allowed_databases": group.AllowedDatabases,
|
||||
"readonly_instance_count": readonlyCount,
|
||||
"write_instance_count": writeCount,
|
||||
"user_count": userCount,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"sql-platform/internal/model"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// GET /api/v1/ldap-config
|
||||
func GetLDAPConfig(c *gin.Context) {
|
||||
var configs []model.LDAPConfig
|
||||
model.DB.Order("id").Find(&configs)
|
||||
if len(configs) == 0 {
|
||||
c.JSON(http.StatusOK, nil)
|
||||
return
|
||||
}
|
||||
// mask password
|
||||
configs[0].AdminPassword = "******"
|
||||
c.JSON(http.StatusOK, configs[0])
|
||||
}
|
||||
|
||||
// PUT /api/v1/ldap-config
|
||||
func UpdateLDAPConfig(c *gin.Context) {
|
||||
var input map[string]interface{}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
var configs []model.LDAPConfig
|
||||
model.DB.Order("id").Find(&configs)
|
||||
|
||||
if len(configs) == 0 {
|
||||
// create new
|
||||
config := model.LDAPConfig{}
|
||||
if v, ok := input["ldap_host"].(string); ok {
|
||||
config.LDAPHost = v
|
||||
}
|
||||
if v, ok := input["base_dn"].(string); ok {
|
||||
config.BaseDN = v
|
||||
}
|
||||
if v, ok := input["admin_dn"].(string); ok {
|
||||
config.AdminDN = v
|
||||
}
|
||||
if v, ok := input["admin_password"].(string); ok && v != "******" {
|
||||
config.AdminPassword = v
|
||||
}
|
||||
if v, ok := input["search_filter"].(string); ok {
|
||||
config.SearchFilter = &v
|
||||
}
|
||||
if v, ok := input["user_mapping"].(string); ok {
|
||||
config.UserMapping = &v
|
||||
}
|
||||
if v, ok := input["ldap_port"].(float64); ok {
|
||||
port := int(v)
|
||||
config.LDAPPort = &port
|
||||
}
|
||||
if v, ok := input["use_ldaps"].(bool); ok {
|
||||
config.UseLDAPS = &v
|
||||
}
|
||||
model.DB.Create(&config)
|
||||
c.JSON(http.StatusOK, config)
|
||||
} else {
|
||||
// update existing
|
||||
if pw, ok := input["admin_password"].(string); ok && pw == "******" {
|
||||
delete(input, "admin_password")
|
||||
}
|
||||
model.DB.Model(&configs[0]).Updates(input)
|
||||
model.DB.First(&configs[0], configs[0].ID)
|
||||
configs[0].AdminPassword = "******"
|
||||
c.JSON(http.StatusOK, configs[0])
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/v1/ldap-config/test
|
||||
func TestLDAPConnection(c *gin.Context) {
|
||||
// TODO: actual LDAP connection test
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"message": "LDAP connection test (placeholder)",
|
||||
})
|
||||
}
|
||||
|
||||
// POST /api/v1/ldap-config/ou-list
|
||||
func ListLDAPOUs(c *gin.Context) {
|
||||
// TODO: actual LDAP OU list
|
||||
c.JSON(http.StatusOK, []interface{}{})
|
||||
}
|
||||
|
||||
// POST /api/v1/ldap-config/user-list
|
||||
func ListLDAPUsers(c *gin.Context) {
|
||||
// TODO: actual LDAP user list
|
||||
c.JSON(http.StatusOK, []interface{}{})
|
||||
}
|
||||
|
||||
// POST /api/v1/ldap-config/create-ou
|
||||
func CreateLDAPOU(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "OU created (placeholder)"})
|
||||
}
|
||||
|
||||
// POST /api/v1/ldap-config/create-user
|
||||
func CreateLDAPUser(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "User created (placeholder)"})
|
||||
}
|
||||
|
||||
// POST /api/v1/ldap-config/batch-import-ldap
|
||||
func BatchImportLDAP(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Batch import (placeholder)", "count": 0})
|
||||
}
|
||||
@@ -34,9 +34,13 @@ func Setup(r *gin.Engine) {
|
||||
|
||||
// Instances
|
||||
auth.GET("/instances", handler.ListInstances)
|
||||
auth.GET("/instances/accessible", handler.AccessibleInstances)
|
||||
auth.GET("/instances/stats", handler.InstanceStats)
|
||||
auth.GET("/instances/:id", handler.GetInstance)
|
||||
auth.GET("/instances/:id/databases", handler.ListDatabases)
|
||||
auth.GET("/instances/:id/databases/:db/tables", handler.ListTables)
|
||||
auth.POST("/instances/:id/test-connection", handler.TestConnection)
|
||||
auth.POST("/instances/test-connection", handler.TestNewConnection)
|
||||
|
||||
// Instance management (admin/dba only)
|
||||
admin := auth.Group("")
|
||||
@@ -47,6 +51,24 @@ func Setup(r *gin.Engine) {
|
||||
admin.DELETE("/instances/:id", handler.DeleteInstance)
|
||||
}
|
||||
|
||||
// Instance Groups
|
||||
auth.GET("/instance-groups", handler.ListInstanceGroups)
|
||||
auth.GET("/instance-groups/:id", handler.GetInstanceGroup)
|
||||
auth.GET("/instance-groups/:id/users", handler.ListGroupUsers)
|
||||
auth.POST("/instance-groups/:id/instances", handler.AssignGroupInstances)
|
||||
auth.DELETE("/instance-groups/:id/instances/:instanceId", handler.RemoveGroupInstance)
|
||||
auth.POST("/instance-groups/:id/users", handler.AssignGroupUsers)
|
||||
auth.PUT("/instance-groups/users/:userId/groups", handler.UpdateUserGroups)
|
||||
|
||||
// Instance Group management (admin/dba only)
|
||||
igAdmin := auth.Group("")
|
||||
igAdmin.Use(middleware.RequireRole("admin", "dba"))
|
||||
{
|
||||
igAdmin.POST("/instance-groups", handler.CreateInstanceGroup)
|
||||
igAdmin.PUT("/instance-groups/:id", handler.UpdateInstanceGroup)
|
||||
igAdmin.DELETE("/instance-groups/:id", handler.DeleteInstanceGroup)
|
||||
}
|
||||
|
||||
// Users (admin only)
|
||||
userAdmin := auth.Group("")
|
||||
userAdmin.Use(middleware.RequireRole("admin"))
|
||||
@@ -57,6 +79,26 @@ func Setup(r *gin.Engine) {
|
||||
userAdmin.DELETE("/users/:id", handler.DeleteUser)
|
||||
}
|
||||
|
||||
// LDAP config (admin only)
|
||||
ldapAdmin := auth.Group("")
|
||||
ldapAdmin.Use(middleware.RequireRole("admin"))
|
||||
{
|
||||
ldapAdmin.GET("/ldap-config", handler.GetLDAPConfig)
|
||||
ldapAdmin.PUT("/ldap-config", handler.UpdateLDAPConfig)
|
||||
ldapAdmin.POST("/ldap-config/test", handler.TestLDAPConnection)
|
||||
ldapAdmin.POST("/ldap-config/ou-list", handler.ListLDAPOUs)
|
||||
ldapAdmin.POST("/ldap-config/user-list", handler.ListLDAPUsers)
|
||||
ldapAdmin.POST("/ldap-config/create-ou", handler.CreateLDAPOU)
|
||||
ldapAdmin.POST("/ldap-config/create-user", handler.CreateLDAPUser)
|
||||
ldapAdmin.POST("/ldap-config/batch-import-ldap", handler.BatchImportLDAP)
|
||||
}
|
||||
|
||||
// Settings
|
||||
auth.GET("/settings", handler.ListSettings)
|
||||
auth.PUT("/settings", handler.UpdateSettings)
|
||||
auth.GET("/settings/cleanup/preview", handler.SettingsCleanupPreview)
|
||||
auth.POST("/settings/cleanup/run", handler.SettingsCleanupRun)
|
||||
|
||||
// gh-ost (admin/dba only)
|
||||
ghostGroup := auth.Group("")
|
||||
ghostGroup.Use(middleware.RequireRole("admin", "dba"))
|
||||
@@ -71,11 +113,9 @@ func Setup(r *gin.Engine) {
|
||||
auth.GET("/audit-rules", handler.ListAuditRules)
|
||||
auth.GET("/announcements", handler.ListAnnouncements)
|
||||
auth.GET("/query-histories", handler.ListQueryHistories)
|
||||
auth.GET("/settings", handler.ListSettings)
|
||||
auth.GET("/notifications/channels", handler.ListNotificationChannels)
|
||||
auth.GET("/notifications/templates", handler.ListNotificationTemplates)
|
||||
auth.GET("/workflows", handler.ListWorkflows)
|
||||
auth.GET("/instance-groups", handler.ListInstanceGroups)
|
||||
auth.POST("/notifications/test", handler.TestNotification)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user