feat: complete pet SOP governance workflow
This commit is contained in:
127
internal/member/handler.go
Normal file
127
internal/member/handler.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package member
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/audit"
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/auth"
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/model"
|
||||
"git.iwork-ai.com/xdc/iqudo-top1/internal/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Handler struct{ db *gorm.DB }
|
||||
|
||||
func NewHandler(db *gorm.DB) *Handler { return &Handler{db: db} }
|
||||
|
||||
type MemberItem struct {
|
||||
ID uint64 `json:"id"`
|
||||
UserID uint64 `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"display_name"`
|
||||
RoleCode string `json:"role_code"`
|
||||
RoleName string `json:"role_name"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (h *Handler) List(c *gin.Context) {
|
||||
principal, _ := auth.PrincipalFromContext(c)
|
||||
items := make([]MemberItem, 0)
|
||||
err := h.db.Table("tenant_members tm").Select("tm.id, tm.user_id, u.username, u.display_name, r.code AS role_code, r.name AS role_name, tm.status").Joins("JOIN users u ON u.id = tm.user_id").Joins("JOIN roles r ON r.id = tm.role_id").Where("tm.tenant_id = ?", principal.TenantID).Order("tm.id").Scan(&items).Error
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusInternalServerError, "QUERY_FAILED", "查询企业成员失败")
|
||||
return
|
||||
}
|
||||
roles := make([]model.Role, 0)
|
||||
if err := h.db.Where("tenant_id = ?", principal.TenantID).Order("id").Find(&roles).Error; err != nil {
|
||||
response.Error(c, http.StatusInternalServerError, "QUERY_FAILED", "查询角色失败")
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"items": items, "roles": roles, "total": len(items)})
|
||||
}
|
||||
|
||||
func (h *Handler) Create(c *gin.Context) {
|
||||
principal, _ := auth.PrincipalFromContext(c)
|
||||
var input struct {
|
||||
Username string `json:"username" binding:"required,min=2,max=64"`
|
||||
Password string `json:"password" binding:"required,min=6,max=128"`
|
||||
DisplayName string `json:"display_name" binding:"required,max=128"`
|
||||
RoleCode string `json:"role_code" binding:"required,max=64"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", "成员信息不完整")
|
||||
return
|
||||
}
|
||||
var role model.Role
|
||||
if err := h.db.Where("tenant_id = ? AND code = ?", principal.TenantID, input.RoleCode).First(&role).Error; err != nil {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ROLE", "角色不存在")
|
||||
return
|
||||
}
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusInternalServerError, "CREATE_FAILED", "创建成员失败")
|
||||
return
|
||||
}
|
||||
var user model.User
|
||||
var membership model.TenantMember
|
||||
err = h.db.Transaction(func(tx *gorm.DB) error {
|
||||
user = model.User{Username: input.Username, PasswordHash: string(hash), DisplayName: input.DisplayName, Status: "active"}
|
||||
if err := tx.Create(&user).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
membership = model.TenantMember{TenantID: principal.TenantID, UserID: user.ID, RoleID: role.ID, Status: "active"}
|
||||
return tx.Create(&membership).Error
|
||||
})
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusConflict, "MEMBER_EXISTS", "用户名已存在")
|
||||
return
|
||||
}
|
||||
_ = audit.Record(h.db, principal, "create", "tenant_member", membership.ID, gin.H{"username": input.Username, "role_code": input.RoleCode})
|
||||
response.Created(c, gin.H{"id": membership.ID, "user_id": user.ID})
|
||||
}
|
||||
|
||||
func (h *Handler) Update(c *gin.Context) {
|
||||
principal, _ := auth.PrincipalFromContext(c)
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ID", "成员 ID 不正确")
|
||||
return
|
||||
}
|
||||
var input struct {
|
||||
RoleCode string `json:"role_code" binding:"required,max=64"`
|
||||
Status string `json:"status" binding:"required,oneof=active disabled"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", "成员配置不正确")
|
||||
return
|
||||
}
|
||||
var membership model.TenantMember
|
||||
if err := h.db.Where("id = ? AND tenant_id = ?", id, principal.TenantID).First(&membership).Error; err != nil {
|
||||
response.Error(c, http.StatusNotFound, "NOT_FOUND", "成员不存在")
|
||||
return
|
||||
}
|
||||
if membership.UserID == principal.UserID {
|
||||
response.Error(c, http.StatusConflict, "SELF_UPDATE_FORBIDDEN", "不能修改自己的角色或状态")
|
||||
return
|
||||
}
|
||||
var role model.Role
|
||||
if err := h.db.Where("tenant_id = ? AND code = ?", principal.TenantID, input.RoleCode).First(&role).Error; err != nil {
|
||||
response.Error(c, http.StatusBadRequest, "INVALID_ROLE", "角色不存在")
|
||||
return
|
||||
}
|
||||
err = h.db.Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Model(&membership).Updates(map[string]interface{}{"role_id": role.ID, "status": input.Status}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Model(&model.User{}).Where("id = ?", membership.UserID).Update("status", input.Status).Error
|
||||
})
|
||||
if err != nil {
|
||||
response.Error(c, http.StatusInternalServerError, "UPDATE_FAILED", "更新成员失败")
|
||||
return
|
||||
}
|
||||
_ = audit.Record(h.db, principal, "update", "tenant_member", id, input)
|
||||
response.OK(c, gin.H{"id": id, "role_code": input.RoleCode, "status": input.Status})
|
||||
}
|
||||
Reference in New Issue
Block a user