- app.go 将查询条件从字符串拼接改为占位符参数绑定 - config.go 将查询条件从字符串拼接改为占位符参数绑定 - user.go 将查询条件从字符串拼接改为占位符参数绑定 - 移除 app.go 中重复的条件构建逻辑 - 对 group_id、enabled 等参数增加类型校验与错误处理
364 lines
10 KiB
Go
364 lines
10 KiB
Go
package handler
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"kenaito-conf/server/internal/dao"
|
|
"kenaito-conf/server/internal/middleware"
|
|
"kenaito-conf/server/internal/model"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type AppHandler struct{}
|
|
|
|
func NewAppHandler() *AppHandler {
|
|
return &AppHandler{}
|
|
}
|
|
|
|
type AppListRequest struct {
|
|
PageNo int `form:"pageNo" binding:"required"`
|
|
PageSize int `form:"pageSize" binding:"required"`
|
|
AppType string `form:"appType"`
|
|
Name string `form:"name"`
|
|
Code string `form:"code"`
|
|
GroupId string `form:"groupId"`
|
|
}
|
|
|
|
func (h *AppHandler) List(c *gin.Context) {
|
|
var req AppListRequest
|
|
if err := c.ShouldBindQuery(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, model.WrapperResponse{Code: 400, Msg: "参数错误"})
|
|
return
|
|
}
|
|
|
|
userInfo := middleware.GetUserInfo(c)
|
|
|
|
conditions := []string{"enabled = 1"}
|
|
args := make([]interface{}, 0, 6)
|
|
|
|
if !userInfo.IsSuperAdmin() {
|
|
userId, _ := strconv.Atoi(userInfo.Id)
|
|
userIdStr := strconv.Itoa(userId)
|
|
|
|
if userInfo.IsGroupAdmin() && userInfo.GroupId != nil {
|
|
// 组管理员:本组应用 + 自己是负责人的应用
|
|
conditions = append(conditions, "(group_id = ? OR FIND_IN_SET(?, owner_ids) > 0)")
|
|
args = append(args, *userInfo.GroupId, userIdStr)
|
|
} else {
|
|
// 普通用户:自己是负责人的应用
|
|
conditions = append(conditions, "FIND_IN_SET(?, owner_ids) > 0")
|
|
args = append(args, userIdStr)
|
|
}
|
|
}
|
|
if req.AppType != "" {
|
|
conditions = append(conditions, "service_id = ?")
|
|
args = append(args, req.AppType)
|
|
}
|
|
if req.Name != "" {
|
|
conditions = append(conditions, "name LIKE ?")
|
|
args = append(args, "%"+req.Name+"%")
|
|
}
|
|
if req.Code != "" {
|
|
conditions = append(conditions, "code LIKE ?")
|
|
args = append(args, "%"+req.Code+"%")
|
|
}
|
|
if req.GroupId != "" {
|
|
groupId, err := strconv.Atoi(req.GroupId)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, model.WrapperResponse{Code: 400, Msg: "参数错误"})
|
|
return
|
|
}
|
|
conditions = append(conditions, "group_id = ?")
|
|
args = append(args, groupId)
|
|
}
|
|
|
|
whereClause := strings.Join(conditions, " AND ")
|
|
|
|
var apps []model.Application
|
|
total, _ := dao.Engine.Where(whereClause, args...).Count(&model.Application{})
|
|
dao.Engine.Where(whereClause, args...).Limit(req.PageSize, (req.PageNo-1)*req.PageSize).Find(&apps)
|
|
|
|
// load group names - batch query to avoid N+1
|
|
groupIds := make(map[int]bool)
|
|
for _, app := range apps {
|
|
if app.GroupId != nil {
|
|
groupIds[*app.GroupId] = true
|
|
}
|
|
}
|
|
groupMap := make(map[int]string)
|
|
if len(groupIds) > 0 {
|
|
ids := make([]int, 0, len(groupIds))
|
|
for gid := range groupIds {
|
|
ids = append(ids, gid)
|
|
}
|
|
var groups []model.BusinessGroup
|
|
dao.Engine.In("id", ids).Find(&groups)
|
|
for _, g := range groups {
|
|
groupMap[g.Id] = g.Name
|
|
}
|
|
}
|
|
for i := range apps {
|
|
if apps[i].GroupId != nil {
|
|
apps[i].GroupName = groupMap[*apps[i].GroupId]
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, model.PageResult{PageNo: req.PageNo, PageSize: req.PageSize, Total: total, Data: apps})
|
|
}
|
|
|
|
func (h *AppHandler) GetById(c *gin.Context) {
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
var app model.Application
|
|
has, _ := dao.Engine.ID(id).Get(&app)
|
|
if !has {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 404, Msg: "应用不存在"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: app})
|
|
}
|
|
|
|
type AddAppRequest struct {
|
|
Id int `json:"id"`
|
|
GroupId *int `json:"groupId"`
|
|
Name string `json:"name" binding:"required"`
|
|
Code string `json:"code" binding:"required"`
|
|
ServiceId string `json:"serviceId"`
|
|
OwnerIds []int `json:"ownerIds"`
|
|
Remarks string `json:"remarks"`
|
|
}
|
|
|
|
func (h *AppHandler) Add(c *gin.Context) {
|
|
var req AddAppRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, model.WrapperResponse{Code: 400, Msg: "参数错误"})
|
|
return
|
|
}
|
|
|
|
userInfo := middleware.GetUserInfo(c)
|
|
|
|
// check if code exists
|
|
var existing model.Application
|
|
if has, _ := dao.Engine.Where("code = ?", req.Code).Get(&existing); has {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 1002, Msg: "应用已存在"})
|
|
return
|
|
}
|
|
|
|
// 处理负责人:如果未指定,默认为当前用户
|
|
ownerIds := req.OwnerIds
|
|
if len(ownerIds) == 0 {
|
|
uid, _ := strconv.Atoi(userInfo.Id)
|
|
ownerIds = []int{uid}
|
|
}
|
|
|
|
// 验证所有用户ID都存在
|
|
var users []model.User
|
|
if err := dao.Engine.In("id", ownerIds).Find(&users); err != nil || len(users) != len(ownerIds) {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 400, Msg: "部分负责人不存在"})
|
|
return
|
|
}
|
|
|
|
// 构建逗号分隔的用户名和ID字符串
|
|
ownerNames := make([]string, 0, len(users))
|
|
ownerIdStrs := make([]string, 0, len(users))
|
|
for _, u := range users {
|
|
ownerNames = append(ownerNames, u.Name)
|
|
ownerIdStrs = append(ownerIdStrs, strconv.Itoa(u.Id))
|
|
}
|
|
|
|
app := model.Application{
|
|
GroupId: req.GroupId,
|
|
Name: req.Name,
|
|
Code: req.Code,
|
|
ServiceId: req.ServiceId,
|
|
OwnerIds: strings.Join(ownerIdStrs, ","),
|
|
OwnerNames: strings.Join(ownerNames, ","),
|
|
Remarks: req.Remarks,
|
|
Enabled: true,
|
|
CreatedAt: func() *time.Time { t := time.Now(); return &t }(),
|
|
CreatedBy: userInfo.Name,
|
|
}
|
|
|
|
dao.Engine.Insert(&app)
|
|
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: true})
|
|
}
|
|
|
|
func (h *AppHandler) Update(c *gin.Context) {
|
|
var req AddAppRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, model.WrapperResponse{Code: 400, Msg: "参数错误"})
|
|
return
|
|
}
|
|
|
|
if req.Id == 0 {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 400, Msg: "id参数缺失"})
|
|
return
|
|
}
|
|
|
|
var app model.Application
|
|
has, _ := dao.Engine.ID(req.Id).Get(&app)
|
|
if !has {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 404, Msg: "应用不存在"})
|
|
return
|
|
}
|
|
|
|
userInfo := middleware.GetUserInfo(c)
|
|
|
|
app.Name = req.Name
|
|
app.ServiceId = req.ServiceId
|
|
app.Remarks = req.Remarks
|
|
|
|
// 更新负责人
|
|
if len(req.OwnerIds) > 0 {
|
|
// 验证所有用户ID都存在
|
|
var users []model.User
|
|
if err := dao.Engine.In("id", req.OwnerIds).Find(&users); err != nil || len(users) != len(req.OwnerIds) {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 400, Msg: "部分负责人不存在"})
|
|
return
|
|
}
|
|
|
|
// 构建逗号分隔的用户名和ID字符串
|
|
ownerNames := make([]string, 0, len(users))
|
|
ownerIdStrs := make([]string, 0, len(users))
|
|
for _, u := range users {
|
|
ownerNames = append(ownerNames, u.Name)
|
|
ownerIdStrs = append(ownerIdStrs, strconv.Itoa(u.Id))
|
|
}
|
|
app.OwnerIds = strings.Join(ownerIdStrs, ",")
|
|
app.OwnerNames = strings.Join(ownerNames, ",")
|
|
}
|
|
|
|
app.UpdatedBy = userInfo.Name
|
|
now := time.Now()
|
|
app.UpdatedAt = &now
|
|
|
|
dao.Engine.ID(app.Id).Cols("name", "service_id", "remarks", "owner_ids", "owner_names", "updated_by", "updated_at").Update(&app)
|
|
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: true})
|
|
}
|
|
|
|
func (h *AppHandler) Delete(c *gin.Context) {
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
userInfo := middleware.GetUserInfo(c)
|
|
|
|
if !userInfo.IsSuperAdmin() {
|
|
c.JSON(http.StatusForbidden, model.WrapperResponse{Code: 403, Msg: "超级管理员才能删除"})
|
|
return
|
|
}
|
|
|
|
var app model.Application
|
|
has, _ := dao.Engine.ID(id).Get(&app)
|
|
if !has {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 404, Msg: "应用不存在"})
|
|
return
|
|
}
|
|
|
|
app.Enabled = false
|
|
app.UpdatedBy = userInfo.Name
|
|
now := time.Now()
|
|
app.UpdatedAt = &now
|
|
dao.Engine.ID(app.Id).Cols("enabled", "updated_by", "updated_at").Update(&app)
|
|
|
|
// soft delete related configs
|
|
dao.Engine.Where("app_id = ?", id).Cols("enabled").Update(&model.AppConfig{Enabled: false})
|
|
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0})
|
|
}
|
|
|
|
func (h *AppHandler) Switch(c *gin.Context) {
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
userInfo := middleware.GetUserInfo(c)
|
|
|
|
var app model.Application
|
|
has, _ := dao.Engine.ID(id).Get(&app)
|
|
if !has {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 404, Msg: "应用不存在"})
|
|
return
|
|
}
|
|
|
|
app.Enabled = !app.Enabled
|
|
app.UpdatedBy = userInfo.Name
|
|
now := time.Now()
|
|
app.UpdatedAt = &now
|
|
dao.Engine.ID(app.Id).Cols("enabled", "updated_by", "updated_at").Update(&app)
|
|
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: true})
|
|
}
|
|
|
|
func (h *AppHandler) Options(c *gin.Context) {
|
|
userInfo := middleware.GetUserInfo(c)
|
|
query := dao.Engine.Where("enabled = 1")
|
|
|
|
if !userInfo.IsSuperAdmin() {
|
|
if userInfo.IsGroupAdmin() && userInfo.GroupId != nil {
|
|
query = query.And("group_id = ?", *userInfo.GroupId)
|
|
} else {
|
|
userId, _ := strconv.Atoi(userInfo.Id)
|
|
userIdStr := strconv.Itoa(userId)
|
|
query = query.And("FIND_IN_SET(?, owner_ids) > 0", userIdStr)
|
|
}
|
|
}
|
|
|
|
var apps []model.Application
|
|
query.Find(&apps)
|
|
|
|
options := make([]model.SelectOption, 0)
|
|
for _, app := range apps {
|
|
options = append(options, model.SelectOption{Value: strconv.Itoa(app.Id), Label: app.Name})
|
|
}
|
|
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: options})
|
|
}
|
|
|
|
func (h *AppHandler) GenerateToken(c *gin.Context) {
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
userInfo := middleware.GetUserInfo(c)
|
|
|
|
var app model.Application
|
|
has, _ := dao.Engine.ID(id).Get(&app)
|
|
if !has {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 404, Msg: "应用不存在"})
|
|
return
|
|
}
|
|
|
|
bytes := make([]byte, 32)
|
|
if _, err := rand.Read(bytes); err != nil {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 500, Msg: "生成 Token 失败"})
|
|
return
|
|
}
|
|
token := hex.EncodeToString(bytes)
|
|
|
|
app.Token = token
|
|
app.UpdatedBy = userInfo.Name
|
|
now := time.Now()
|
|
app.UpdatedAt = &now
|
|
dao.Engine.ID(app.Id).Cols("token", "updated_by", "updated_at").Update(&app)
|
|
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: token})
|
|
}
|
|
|
|
func (h *AppHandler) DeleteToken(c *gin.Context) {
|
|
id, _ := strconv.Atoi(c.Param("id"))
|
|
userInfo := middleware.GetUserInfo(c)
|
|
|
|
var app model.Application
|
|
has, _ := dao.Engine.ID(id).Get(&app)
|
|
if !has {
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 404, Msg: "应用不存在"})
|
|
return
|
|
}
|
|
|
|
app.Token = ""
|
|
app.UpdatedBy = userInfo.Name
|
|
now := time.Now()
|
|
app.UpdatedAt = &now
|
|
dao.Engine.ID(app.Id).Cols("token", "updated_by", "updated_at").Update(&app)
|
|
|
|
c.JSON(http.StatusOK, model.WrapperResponse{Code: 0, Data: true})
|
|
}
|