2025-06-30 19:21:56 +08:00
|
|
|
|
package handlers
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
"tyapi-server/internal/application/user"
|
|
|
|
|
|
"tyapi-server/internal/application/user/dto/commands"
|
2025-06-30 19:21:56 +08:00
|
|
|
|
"tyapi-server/internal/shared/interfaces"
|
|
|
|
|
|
"tyapi-server/internal/shared/middleware"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// UserHandler 用户HTTP处理器
|
|
|
|
|
|
type UserHandler struct {
|
2025-07-13 16:36:20 +08:00
|
|
|
|
appService user.UserApplicationService
|
|
|
|
|
|
response interfaces.ResponseBuilder
|
|
|
|
|
|
validator interfaces.RequestValidator
|
|
|
|
|
|
logger *zap.Logger
|
|
|
|
|
|
jwtAuth *middleware.JWTAuthMiddleware
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewUserHandler 创建用户处理器
|
|
|
|
|
|
func NewUserHandler(
|
2025-07-13 16:36:20 +08:00
|
|
|
|
appService user.UserApplicationService,
|
2025-06-30 19:21:56 +08:00
|
|
|
|
response interfaces.ResponseBuilder,
|
|
|
|
|
|
validator interfaces.RequestValidator,
|
|
|
|
|
|
logger *zap.Logger,
|
|
|
|
|
|
jwtAuth *middleware.JWTAuthMiddleware,
|
|
|
|
|
|
) *UserHandler {
|
|
|
|
|
|
return &UserHandler{
|
2025-07-13 16:36:20 +08:00
|
|
|
|
appService: appService,
|
|
|
|
|
|
response: response,
|
|
|
|
|
|
validator: validator,
|
|
|
|
|
|
logger: logger,
|
|
|
|
|
|
jwtAuth: jwtAuth,
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// SendCode 发送验证码
|
|
|
|
|
|
// @Summary 发送短信验证码
|
|
|
|
|
|
// @Description 向指定手机号发送验证码,支持注册、登录、修改密码等场景
|
|
|
|
|
|
// @Tags 用户认证
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Param request body commands.SendCodeCommand true "发送验证码请求"
|
|
|
|
|
|
// @Success 200 {object} map[string]interface{} "验证码发送成功"
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
|
|
|
|
|
// @Failure 429 {object} map[string]interface{} "请求频率限制"
|
|
|
|
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Router /api/v1/users/send-code [post]
|
2025-07-02 16:17:59 +08:00
|
|
|
|
func (h *UserHandler) SendCode(c *gin.Context) {
|
2025-07-13 16:36:20 +08:00
|
|
|
|
var cmd commands.SendCodeCommand
|
|
|
|
|
|
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
|
|
|
|
|
return
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-02 16:17:59 +08:00
|
|
|
|
clientIP := c.ClientIP()
|
|
|
|
|
|
userAgent := c.GetHeader("User-Agent")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
if err := h.appService.SendCode(c.Request.Context(), &cmd, clientIP, userAgent); err != nil {
|
2025-07-02 16:17:59 +08:00
|
|
|
|
h.response.BadRequest(c, err.Error())
|
2025-06-30 19:21:56 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
h.response.Success(c, nil, "验证码发送成功")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// Register 用户注册
|
|
|
|
|
|
// @Summary 用户注册
|
|
|
|
|
|
// @Description 使用手机号、密码和验证码进行用户注册,需要确认密码
|
|
|
|
|
|
// @Tags 用户认证
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Param request body commands.RegisterUserCommand true "用户注册请求"
|
|
|
|
|
|
// @Success 201 {object} responses.RegisterUserResponse "注册成功"
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
|
|
|
|
|
|
// @Failure 409 {object} map[string]interface{} "手机号已存在"
|
|
|
|
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Router /api/v1/users/register [post]
|
2025-07-02 16:17:59 +08:00
|
|
|
|
func (h *UserHandler) Register(c *gin.Context) {
|
2025-07-13 16:36:20 +08:00
|
|
|
|
var cmd commands.RegisterUserCommand
|
|
|
|
|
|
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
|
|
|
|
|
return
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
resp, err := h.appService.Register(c.Request.Context(), &cmd)
|
2025-06-30 19:21:56 +08:00
|
|
|
|
if err != nil {
|
2025-07-02 16:17:59 +08:00
|
|
|
|
h.logger.Error("注册用户失败", zap.Error(err))
|
2025-06-30 19:21:56 +08:00
|
|
|
|
h.response.BadRequest(c, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
h.response.Created(c, resp, "用户注册成功")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// LoginWithPassword 密码登录
|
|
|
|
|
|
// @Summary 用户密码登录
|
|
|
|
|
|
// @Description 使用手机号和密码进行用户登录,返回JWT令牌
|
|
|
|
|
|
// @Tags 用户认证
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Param request body commands.LoginWithPasswordCommand true "密码登录请求"
|
|
|
|
|
|
// @Success 200 {object} responses.LoginUserResponse "登录成功"
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Failure 401 {object} map[string]interface{} "用户名或密码错误"
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Router /api/v1/users/login-password [post]
|
2025-07-02 16:17:59 +08:00
|
|
|
|
func (h *UserHandler) LoginWithPassword(c *gin.Context) {
|
2025-07-13 16:36:20 +08:00
|
|
|
|
var cmd commands.LoginWithPasswordCommand
|
|
|
|
|
|
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
2025-06-30 19:21:56 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
resp, err := h.appService.LoginWithPassword(c.Request.Context(), &cmd)
|
2025-06-30 19:21:56 +08:00
|
|
|
|
if err != nil {
|
2025-07-02 16:17:59 +08:00
|
|
|
|
h.logger.Error("密码登录失败", zap.Error(err))
|
|
|
|
|
|
h.response.Unauthorized(c, "用户名或密码错误")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
h.response.Success(c, resp, "登录成功")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// LoginWithSMS 短信验证码登录
|
|
|
|
|
|
// @Summary 用户短信验证码登录
|
|
|
|
|
|
// @Description 使用手机号和短信验证码进行用户登录,返回JWT令牌
|
|
|
|
|
|
// @Tags 用户认证
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Param request body commands.LoginWithSMSCommand true "短信登录请求"
|
|
|
|
|
|
// @Success 200 {object} responses.LoginUserResponse "登录成功"
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
|
|
|
|
|
|
// @Failure 401 {object} map[string]interface{} "认证失败"
|
|
|
|
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Router /api/v1/users/login-sms [post]
|
2025-07-02 16:17:59 +08:00
|
|
|
|
func (h *UserHandler) LoginWithSMS(c *gin.Context) {
|
2025-07-13 16:36:20 +08:00
|
|
|
|
var cmd commands.LoginWithSMSCommand
|
|
|
|
|
|
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
2025-06-30 19:21:56 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
resp, err := h.appService.LoginWithSMS(c.Request.Context(), &cmd)
|
2025-06-30 19:21:56 +08:00
|
|
|
|
if err != nil {
|
2025-07-02 16:17:59 +08:00
|
|
|
|
h.logger.Error("短信登录失败", zap.Error(err))
|
|
|
|
|
|
h.response.Unauthorized(c, err.Error())
|
2025-06-30 19:21:56 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
h.response.Success(c, resp, "登录成功")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetProfile 获取当前用户信息
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// @Summary 获取当前用户信息
|
|
|
|
|
|
// @Description 根据JWT令牌获取当前登录用户的详细信息
|
|
|
|
|
|
// @Tags 用户管理
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Security Bearer
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Success 200 {object} responses.UserProfileResponse "用户信息"
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// @Failure 401 {object} map[string]interface{} "未认证"
|
|
|
|
|
|
// @Failure 404 {object} map[string]interface{} "用户不存在"
|
|
|
|
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Router /api/v1/users/me [get]
|
2025-06-30 19:21:56 +08:00
|
|
|
|
func (h *UserHandler) GetProfile(c *gin.Context) {
|
|
|
|
|
|
userID := h.getCurrentUserID(c)
|
|
|
|
|
|
if userID == "" {
|
2025-07-20 20:53:26 +08:00
|
|
|
|
h.response.Unauthorized(c, "用户未登录")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
resp, err := h.appService.GetUserProfile(c.Request.Context(), userID)
|
2025-06-30 19:21:56 +08:00
|
|
|
|
if err != nil {
|
2025-07-02 16:17:59 +08:00
|
|
|
|
h.logger.Error("获取用户资料失败", zap.Error(err))
|
|
|
|
|
|
h.response.NotFound(c, "用户不存在")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
h.response.Success(c, resp, "获取用户资料成功")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ChangePassword 修改密码
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// @Summary 修改密码
|
|
|
|
|
|
// @Description 使用旧密码、新密码确认和验证码修改当前用户的密码
|
|
|
|
|
|
// @Tags 用户管理
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Security Bearer
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Param request body commands.ChangePasswordCommand true "修改密码请求"
|
2025-07-02 16:17:59 +08:00
|
|
|
|
// @Success 200 {object} map[string]interface{} "密码修改成功"
|
|
|
|
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
|
|
|
|
|
|
// @Failure 401 {object} map[string]interface{} "未认证"
|
|
|
|
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
2025-07-13 16:36:20 +08:00
|
|
|
|
// @Router /api/v1/users/me/password [put]
|
2025-06-30 19:21:56 +08:00
|
|
|
|
func (h *UserHandler) ChangePassword(c *gin.Context) {
|
|
|
|
|
|
userID := h.getCurrentUserID(c)
|
|
|
|
|
|
if userID == "" {
|
2025-07-20 20:53:26 +08:00
|
|
|
|
h.response.Unauthorized(c, "用户未登录")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
var cmd commands.ChangePasswordCommand
|
|
|
|
|
|
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
2025-06-30 19:21:56 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-07-13 16:36:20 +08:00
|
|
|
|
cmd.UserID = userID
|
2025-06-30 19:21:56 +08:00
|
|
|
|
|
2025-07-13 16:36:20 +08:00
|
|
|
|
if err := h.appService.ChangePassword(c.Request.Context(), &cmd); err != nil {
|
2025-07-02 16:17:59 +08:00
|
|
|
|
h.logger.Error("修改密码失败", zap.Error(err))
|
2025-06-30 19:21:56 +08:00
|
|
|
|
h.response.BadRequest(c, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-02 16:17:59 +08:00
|
|
|
|
h.response.Success(c, nil, "密码修改成功")
|
2025-06-30 19:21:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 13:21:34 +08:00
|
|
|
|
// ResetPassword 重置密码
|
|
|
|
|
|
// @Summary 重置密码
|
|
|
|
|
|
// @Description 使用手机号、验证码和新密码重置用户密码(忘记密码时使用)
|
|
|
|
|
|
// @Tags 用户认证
|
|
|
|
|
|
// @Accept json
|
|
|
|
|
|
// @Produce json
|
|
|
|
|
|
// @Param request body commands.ResetPasswordCommand true "重置密码请求"
|
|
|
|
|
|
// @Success 200 {object} map[string]interface{} "密码重置成功"
|
|
|
|
|
|
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
|
|
|
|
|
|
// @Failure 404 {object} map[string]interface{} "用户不存在"
|
|
|
|
|
|
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
|
|
|
|
|
// @Router /api/v1/users/reset-password [post]
|
|
|
|
|
|
func (h *UserHandler) ResetPassword(c *gin.Context) {
|
|
|
|
|
|
var cmd commands.ResetPasswordCommand
|
|
|
|
|
|
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := h.appService.ResetPassword(c.Request.Context(), &cmd); err != nil {
|
|
|
|
|
|
h.logger.Error("重置密码失败", zap.Error(err))
|
|
|
|
|
|
h.response.BadRequest(c, err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h.response.Success(c, nil, "密码重置成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-30 19:21:56 +08:00
|
|
|
|
// getCurrentUserID 获取当前用户ID
|
|
|
|
|
|
func (h *UserHandler) getCurrentUserID(c *gin.Context) string {
|
|
|
|
|
|
if userID, exists := c.Get("user_id"); exists {
|
|
|
|
|
|
if id, ok := userID.(string); ok {
|
|
|
|
|
|
return id
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|