243 lines
6.9 KiB
Go
243 lines
6.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"stock-user-system/internal/config"
|
|
"stock-user-system/internal/middleware"
|
|
"stock-user-system/internal/models"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type AdminHandler struct {
|
|
DB *gorm.DB
|
|
CFG *config.Config
|
|
}
|
|
|
|
func allowedRolesForCreation(actor models.RoleName) []models.RoleName {
|
|
switch actor {
|
|
case models.RoleSystemAdmin:
|
|
return []models.RoleName{models.RoleAdmin, models.RoleUser}
|
|
case models.RoleAdmin:
|
|
return []models.RoleName{models.RoleUser}
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func containsRole(roles []models.RoleName, target models.RoleName) bool {
|
|
for _, r := range roles {
|
|
if r == target {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (h *AdminHandler) ListUsers(c *gin.Context) {
|
|
var users []models.User
|
|
if err := h.DB.Preload("Role").Order("created_at DESC").Find(&users).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "internal server error"})
|
|
return
|
|
}
|
|
|
|
result := make([]models.PublicUserInfo, 0, len(users))
|
|
for _, u := range users {
|
|
result = append(result, u.ToPublicInfo())
|
|
}
|
|
c.JSON(http.StatusOK, result)
|
|
}
|
|
|
|
func (h *AdminHandler) CreateUser(c *gin.Context) {
|
|
current, _ := middleware.GetCurrentUser(c)
|
|
|
|
var req struct {
|
|
Username string `json:"username" binding:"required"`
|
|
Email *string `json:"email"`
|
|
Password string `json:"password" binding:"required"`
|
|
Role string `json:"role"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "请求参数错误"})
|
|
return
|
|
}
|
|
|
|
targetRole := models.RoleUser
|
|
if req.Role != "" {
|
|
parsed, err := models.ParseRoleName(req.Role)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "无效的角色"})
|
|
return
|
|
}
|
|
targetRole = parsed
|
|
}
|
|
|
|
if !containsRole(allowedRolesForCreation(current.Role), targetRole) {
|
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "权限不足"})
|
|
return
|
|
}
|
|
|
|
if err := validateUsername(req.Username); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": err.Error()})
|
|
return
|
|
}
|
|
if len(req.Password) < 6 {
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "密码长度至少 6 位"})
|
|
return
|
|
}
|
|
|
|
var role models.Role
|
|
if err := h.DB.Where("name = ?", targetRole.String()).First(&role).Error; err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "角色不存在"})
|
|
return
|
|
}
|
|
|
|
hash, err := hashPassword(req.Password)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "internal server error"})
|
|
return
|
|
}
|
|
|
|
username := strings.ToLower(strings.TrimSpace(req.Username))
|
|
var email *string
|
|
if req.Email != nil && *req.Email != "" {
|
|
e := strings.ToLower(strings.TrimSpace(*req.Email))
|
|
email = &e
|
|
}
|
|
|
|
user := models.User{
|
|
Username: username,
|
|
Email: email,
|
|
PasswordHash: hash,
|
|
RoleID: role.ID,
|
|
Status: "active",
|
|
}
|
|
|
|
if err := h.DB.Create(&user).Error; err != nil {
|
|
if strings.Contains(err.Error(), "duplicate key") {
|
|
c.JSON(http.StatusConflict, gin.H{"success": false, "error": "用户名或邮箱已存在"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "internal server error"})
|
|
return
|
|
}
|
|
|
|
h.DB.Preload("Role").First(&user, "id = ?", user.ID)
|
|
c.JSON(http.StatusOK, user.ToPublicInfo())
|
|
}
|
|
|
|
func (h *AdminHandler) UpdateUser(c *gin.Context) {
|
|
current, _ := middleware.GetCurrentUser(c)
|
|
userID := c.Param("id")
|
|
|
|
var req struct {
|
|
Email *string `json:"email"`
|
|
Role string `json:"role"`
|
|
Status string `json:"status"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "请求参数错误"})
|
|
return
|
|
}
|
|
|
|
var target models.User
|
|
if err := h.DB.Preload("Role").Where("id = ?", userID).First(&target).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"success": false, "error": "not found"})
|
|
return
|
|
}
|
|
|
|
if !current.Role.CanManage(target.Role.NameEnum()) && current.ID != userID {
|
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "权限不足"})
|
|
return
|
|
}
|
|
|
|
updates := map[string]interface{}{}
|
|
|
|
if req.Email != nil && *req.Email != "" {
|
|
updates["email"] = strings.ToLower(strings.TrimSpace(*req.Email))
|
|
}
|
|
|
|
if req.Status != "" {
|
|
if target.Role.NameEnum() == models.RoleSystemAdmin && req.Status != "active" {
|
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "不能禁用系统管理员账号"})
|
|
return
|
|
}
|
|
updates["status"] = req.Status
|
|
}
|
|
|
|
if req.Role != "" {
|
|
newRole, err := models.ParseRoleName(req.Role)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "无效的角色"})
|
|
return
|
|
}
|
|
if target.Role.NameEnum() == models.RoleSystemAdmin && newRole != models.RoleSystemAdmin {
|
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "不能修改系统管理员账号的角色"})
|
|
return
|
|
}
|
|
if !containsRole(allowedRolesForCreation(current.Role), newRole) || !current.Role.CanManage(newRole) {
|
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "权限不足"})
|
|
return
|
|
}
|
|
var role models.Role
|
|
if err := h.DB.Where("name = ?", newRole.String()).First(&role).Error; err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "角色不存在"})
|
|
return
|
|
}
|
|
updates["role_id"] = role.ID
|
|
}
|
|
|
|
if err := h.DB.Model(&target).Updates(updates).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "internal server error"})
|
|
return
|
|
}
|
|
|
|
h.DB.Preload("Role").First(&target, "id = ?", userID)
|
|
c.JSON(http.StatusOK, target.ToPublicInfo())
|
|
}
|
|
|
|
func (h *AdminHandler) DeleteUser(c *gin.Context) {
|
|
current, _ := middleware.GetCurrentUser(c)
|
|
userID := c.Param("id")
|
|
|
|
if current.ID == userID {
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "不能删除自己"})
|
|
return
|
|
}
|
|
|
|
var target models.User
|
|
if err := h.DB.Preload("Role").Where("id = ?", userID).First(&target).Error; err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"success": false, "error": "not found"})
|
|
return
|
|
}
|
|
|
|
if !current.Role.CanManage(target.Role.NameEnum()) {
|
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "权限不足"})
|
|
return
|
|
}
|
|
|
|
if target.Role.NameEnum() == models.RoleSystemAdmin {
|
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "不能删除系统管理员账号"})
|
|
return
|
|
}
|
|
|
|
if err := h.DB.Delete(&target).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "internal server error"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "用户已删除"})
|
|
}
|
|
|
|
func (h *AdminHandler) ListRoles(c *gin.Context) {
|
|
var roles []models.Role
|
|
if err := h.DB.Order("id").Find(&roles).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "internal server error"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, roles)
|
|
}
|