fix: 全面修复项目问题
后端修复: - 验证码存储与校验机制 - 订单创建事务+库存扣减 - GetStats字段名错误 - VerifyEmail改为POST - 供应商更新字段白名单 - 文件删除安全检查 - 抽奖安全随机数 - 用户管理CRUD - 订单取消/确认收货 - 工单回复 - Toggle返回新数据 - 移除死代码 前端修复: - 404兜底路由 - 401软跳转 - API层统一 - 面包屑补充banners - 国际化完善 - 购物车并行删除 - 退出清理购物车 - 供应商Dashboard数据 - 工单详情页 - 订单取消/确认收货
This commit is contained in:
@@ -2,6 +2,8 @@ package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"sale/internal/models"
|
||||
@@ -17,6 +19,43 @@ func NewAuthHandler() *AuthHandler {
|
||||
return &AuthHandler{}
|
||||
}
|
||||
|
||||
var (
|
||||
verifyCodes = make(map[string]verifyCodeEntry)
|
||||
verifyCodesMux sync.Mutex
|
||||
)
|
||||
|
||||
type verifyCodeEntry struct {
|
||||
Code string
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
func storeVerifyCode(email, code string) {
|
||||
verifyCodesMux.Lock()
|
||||
defer verifyCodesMux.Unlock()
|
||||
verifyCodes[email] = verifyCodeEntry{
|
||||
Code: code,
|
||||
ExpiresAt: time.Now().Add(30 * time.Minute),
|
||||
}
|
||||
}
|
||||
|
||||
func checkVerifyCode(email, code string) bool {
|
||||
verifyCodesMux.Lock()
|
||||
defer verifyCodesMux.Unlock()
|
||||
entry, ok := verifyCodes[email]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if time.Now().After(entry.ExpiresAt) {
|
||||
delete(verifyCodes, email)
|
||||
return false
|
||||
}
|
||||
if entry.Code != code {
|
||||
return false
|
||||
}
|
||||
delete(verifyCodes, email)
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *AuthHandler) Register(c *gin.Context) {
|
||||
var req schemas.RegisterRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -68,6 +107,7 @@ func (h *AuthHandler) Register(c *gin.Context) {
|
||||
}
|
||||
|
||||
verifyCode := utils.GenerateVerifyCode()
|
||||
storeVerifyCode(req.Email, verifyCode)
|
||||
utils.SendVerifyEmail(req.Email, verifyCode)
|
||||
|
||||
token, _ := utils.GenerateToken(user.ID, user.Role)
|
||||
@@ -137,6 +177,7 @@ func (h *AuthHandler) ForgotPassword(c *gin.Context) {
|
||||
}
|
||||
|
||||
code := utils.GenerateVerifyCode()
|
||||
storeVerifyCode(req.Email, code)
|
||||
utils.SendResetPasswordEmail(req.Email, code)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "If the email exists, a verification code has been sent"})
|
||||
@@ -149,6 +190,11 @@ func (h *AuthHandler) ResetPassword(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !checkVerifyCode(req.Email, req.Code) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid or expired verification code"})
|
||||
return
|
||||
}
|
||||
|
||||
var user models.User
|
||||
if err := utils.DB.Where("email = ?", req.Email).First(&user).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid email"})
|
||||
@@ -172,6 +218,11 @@ func (h *AuthHandler) VerifyEmail(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !checkVerifyCode(req.Email, req.Code) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid or expired verification code"})
|
||||
return
|
||||
}
|
||||
|
||||
var user models.User
|
||||
if err := utils.DB.Where("email = ?", req.Email).First(&user).Error; err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "User not found"})
|
||||
@@ -261,6 +312,7 @@ func (h *AuthHandler) SendVerifyCode(c *gin.Context) {
|
||||
}
|
||||
|
||||
code := utils.GenerateVerifyCode()
|
||||
storeVerifyCode(user.Email, code)
|
||||
utils.SendVerifyEmail(user.Email, code)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Verification code sent", "expires_at": time.Now().Add(30 * time.Minute)})
|
||||
@@ -320,3 +372,62 @@ func (h *AuthHandler) Install(c *gin.Context) {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (h *AuthHandler) AdminGetUsers(c *gin.Context) {
|
||||
var users []models.User
|
||||
utils.DB.Select("id, username, email, role, purchase_credits, is_active, email_verified, created_at").Find(&users)
|
||||
c.JSON(http.StatusOK, gin.H{"data": users})
|
||||
}
|
||||
|
||||
func (h *AuthHandler) AdminUpdateUser(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
var user models.User
|
||||
if err := utils.DB.First(&user, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Username *string `json:"username"`
|
||||
Email *string `json:"email"`
|
||||
Role *string `json:"role"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
updates := make(map[string]interface{})
|
||||
if req.Username != nil {
|
||||
updates["username"] = *req.Username
|
||||
}
|
||||
if req.Email != nil {
|
||||
updates["email"] = *req.Email
|
||||
}
|
||||
if req.Role != nil {
|
||||
updates["role"] = *req.Role
|
||||
}
|
||||
if req.IsActive != nil {
|
||||
updates["is_active"] = *req.IsActive
|
||||
}
|
||||
|
||||
utils.DB.Model(&user).Updates(updates)
|
||||
utils.DB.First(&user, id)
|
||||
c.JSON(http.StatusOK, gin.H{"data": user})
|
||||
}
|
||||
|
||||
func (h *AuthHandler) AdminDeleteUser(c *gin.Context) {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
var user models.User
|
||||
if err := utils.DB.First(&user, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
|
||||
return
|
||||
}
|
||||
if user.Role == "admin" {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "Cannot delete admin user"})
|
||||
return
|
||||
}
|
||||
utils.DB.Delete(&user)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "User deleted successfully"})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user