package handler import ( "net/http" "github.com/gin-gonic/gin" "github.com/user-management-system/internal/service" ) // PasswordResetHandler handles password reset requests type PasswordResetHandler struct { passwordResetService *service.PasswordResetService smsService *service.SMSCodeService } // NewPasswordResetHandler creates a new PasswordResetHandler func NewPasswordResetHandler(passwordResetService *service.PasswordResetService) *PasswordResetHandler { return &PasswordResetHandler{passwordResetService: passwordResetService} } // NewPasswordResetHandlerWithSMS creates a new PasswordResetHandler with SMS support func NewPasswordResetHandlerWithSMS(passwordResetService *service.PasswordResetService, smsService *service.SMSCodeService) *PasswordResetHandler { return &PasswordResetHandler{ passwordResetService: passwordResetService, smsService: smsService, } } // ValidateResetTokenRequest 验证重置令牌请求 type ValidateResetTokenRequest struct { Token string `json:"token" binding:"required"` } // ForgotPassword 忘记密码 // @Summary 忘记密码 // @Description 请求密码重置邮件 // @Tags 密码重置 // @Accept json // @Produce json // @Param request body ForgotPasswordRequest true "邮箱地址" // @Success 200 {object} Response "密码重置邮件已发送" // @Failure 400 {object} Response "请求参数错误" // @Router /api/v1/auth/password/forgot [post] func (h *PasswordResetHandler) ForgotPassword(c *gin.Context) { var req struct { Email string `json:"email" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()}) return } if err := h.passwordResetService.ForgotPassword(c.Request.Context(), req.Email); err != nil { handleError(c, err) return } c.JSON(http.StatusOK, gin.H{"code": 0, "message": "password reset email sent"}) } // ValidateResetToken 验证密码重置 Token // @Summary 验证密码重置 Token // @Description 验证密码重置链接中的 Token 是否有效 // @Tags 密码重置 // @Accept json // @Produce json // @Param request body ValidateResetTokenRequest true "重置 Token" // @Success 200 {object} Response{data=ValidateTokenResponse} "Token验证结果" // @Failure 400 {object} Response "请求参数错误" // @Router /api/v1/auth/password/validate [post] func (h *PasswordResetHandler) ValidateResetToken(c *gin.Context) { var req ValidateResetTokenRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "token is required"}) return } valid, err := h.passwordResetService.ValidateResetToken(c.Request.Context(), req.Token) if err != nil { handleError(c, err) return } c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success", "data": gin.H{"valid": valid}}) } // ResetPassword 重置密码 // @Summary 重置密码 // @Description 使用 Token 重置密码 // @Tags 密码重置 // @Accept json // @Produce json // @Param request body ResetPasswordRequest true "重置请求" // @Success 200 {object} Response "密码重置成功" // @Failure 400 {object} Response "请求参数错误" // @Router /api/v1/auth/password/reset [post] func (h *PasswordResetHandler) ResetPassword(c *gin.Context) { var req struct { Token string `json:"token" binding:"required"` NewPassword string `json:"new_password" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()}) return } if err := h.passwordResetService.ResetPassword(c.Request.Context(), req.Token, req.NewPassword); err != nil { handleError(c, err) return } c.JSON(http.StatusOK, gin.H{"code": 0, "message": "password reset successful"}) } // ForgotPasswordByPhoneRequest 短信密码重置请求 type ForgotPasswordByPhoneRequest struct { Phone string `json:"phone" binding:"required"` } // ForgotPasswordByPhone 发送短信验证码(忘记密码) // @Summary 发送短信验证码(忘记密码) // @Description 向绑定的手机号发送短信验证码用于重置密码 // @Tags 密码重置 // @Accept json // @Produce json // @Param request body ForgotPasswordByPhoneRequest true "手机号" // @Success 200 {object} Response "验证码发送成功" // @Failure 400 {object} Response "请求参数错误" // @Failure 503 {object} Response "短信服务未配置" // @Router /api/v1/auth/password/sms/forgot [post] func (h *PasswordResetHandler) ForgotPasswordByPhone(c *gin.Context) { if h.smsService == nil { c.JSON(http.StatusServiceUnavailable, gin.H{"code": 503, "message": "SMS service not configured"}) return } var req ForgotPasswordByPhoneRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()}) return } // 获取验证码(不发送,由调用方通过其他渠道发送) code, err := h.passwordResetService.ForgotPasswordByPhone(c.Request.Context(), req.Phone) if err != nil { handleError(c, err) return } if code == "" { // 用户不存在,不提示 c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success"}) return } // 通过SMS服务发送验证码 sendReq := &service.SendCodeRequest{ Phone: req.Phone, Purpose: "password_reset", } _, err = h.smsService.SendCode(c.Request.Context(), sendReq) if err != nil { handleError(c, err) return } c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success"}) } // ResetPasswordByPhoneRequest 短信验证码重置密码请求 type ResetPasswordByPhoneRequest struct { Phone string `json:"phone" binding:"required"` Code string `json:"code" binding:"required"` NewPassword string `json:"new_password" binding:"required"` } // ResetPasswordByPhone 通过短信验证码重置密码 // @Summary 通过短信验证码重置密码 // @Description 使用短信验证码重置登录密码 // @Tags 密码重置 // @Accept json // @Produce json // @Param request body ResetPasswordByPhoneRequest true "重置请求" // @Success 200 {object} Response "密码重置成功" // @Failure 400 {object} Response "请求参数错误" // @Failure 401 {object} Response "验证码错误" // @Failure 503 {object} Response "短信服务未配置" // @Router /api/v1/auth/password/sms/reset [post] func (h *PasswordResetHandler) ResetPasswordByPhone(c *gin.Context) { var req ResetPasswordByPhoneRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()}) return } err := h.passwordResetService.ResetPasswordByPhone(c.Request.Context(), &service.ResetPasswordByPhoneRequest{ Phone: req.Phone, Code: req.Code, NewPassword: req.NewPassword, }) if err != nil { handleError(c, err) return } c.JSON(http.StatusOK, gin.H{"code": 0, "message": "password reset successful"}) }