hi-server/internal/handler/public/user/deleteAccountHandler.go
2026-01-27 03:13:15 -08:00

95 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package user
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/perfect-panel/server/internal/config"
"github.com/perfect-panel/server/internal/logic/public/user"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/pkg/constant"
"github.com/perfect-panel/server/pkg/result"
)
// DeleteAccountHandler 注销账号处理器
// 根据当前token删除所有关联设备然后根据各自设备ID重新新建账号
// 新增:需携带邮箱验证码,验证通过后执行注销
type deleteAccountReq struct {
Email string `json:"email" binding:"required,email"` // 用户邮箱
Code string `json:"code" binding:"required"` // 邮箱验证码
}
func DeleteAccountHandler(serverCtx *svc.ServiceContext) gin.HandlerFunc {
return func(c *gin.Context) {
var req deleteAccountReq
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
return
}
// 统一处理邮箱格式:转小写并去空格,与发送验证码逻辑保持一致
req.Email = strings.ToLower(strings.TrimSpace(req.Email))
// 校验邮箱验证码
if err := verifyEmailCode(c.Request.Context(), serverCtx, req.Email, req.Code); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
l := user.NewDeleteAccountLogic(c.Request.Context(), serverCtx)
resp, err := l.DeleteAccount()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
result.HttpResult(c, resp, err)
}
}
// CacheKeyPayload 验证码缓存结构
type CacheKeyPayload struct {
Code string `json:"code"`
LastAt int64 `json:"lastAt"`
}
// verifyEmailCode 校验邮箱验证码
// 支持 DeleteAccount 和 Security 两种场景的验证码
func verifyEmailCode(ctx context.Context, serverCtx *svc.ServiceContext, email string, code string) error {
// 尝试多种场景的验证码
scenes := []string{constant.DeleteAccount.String(), constant.Security.String()}
var verified bool
var cacheKeyUsed string
var payload CacheKeyPayload
for _, scene := range scenes {
cacheKey := fmt.Sprintf("%s:%s:%s", config.AuthCodeCacheKey, scene, email)
value, err := serverCtx.Redis.Get(ctx, cacheKey).Result()
if err != nil || value == "" {
continue
}
if err := json.Unmarshal([]byte(value), &payload); err != nil {
continue
}
// 检查验证码是否匹配且未过期
if payload.Code == code && time.Now().Unix()-payload.LastAt <= serverCtx.Config.VerifyCode.ExpireTime {
verified = true
cacheKeyUsed = cacheKey
break
}
}
if !verified {
return fmt.Errorf("verification code error or expired")
}
// 验证成功后删除缓存
serverCtx.Redis.Del(ctx, cacheKeyUsed)
return nil
}