package app import ( "errors" "fmt" "strconv" "time" "git.echol.cn/loser/lckt/global" "git.echol.cn/loser/lckt/model/app" r "git.echol.cn/loser/lckt/model/common/response" "git.echol.cn/loser/lckt/model/user/request" "git.echol.cn/loser/lckt/utils" "git.echol.cn/loser/lckt/utils/user_jwt" "git.echol.cn/loser/lckt/utils/wechat" "github.com/gin-gonic/gin" "github.com/redis/go-redis/v9" "go.uber.org/zap" ) type AppUserApi struct{} // SendCode 发送验证码 func (*AppUserApi) SendCode(ctx *gin.Context) { var p request.SendCodeReq if err := ctx.ShouldBind(&p); err != nil { r.FailWithMessage(err.Error(), ctx) global.GVA_LOG.Error("参数错误,发送验证码失败", zap.Error(err)) return } if err := userService.SendCode(p); err != nil { r.FailWithMessage("发送验证码失败", ctx) return } r.OkWithMessage("发送验证码成功", ctx) } // Login 用户登录 func (*AppUserApi) Login(ctx *gin.Context) { var p request.CodeLoginReq if err := ctx.ShouldBind(&p); err != nil { r.FailWithMessage(err.Error(), ctx) global.GVA_LOG.Error("参数错误,登录失败", zap.Error(err)) return } if result, _ := global.GVA_REDIS.Get(ctx, fmt.Sprintf("VerifyCode:%s", p.Phone)).Result(); result != p.Code { global.GVA_LOG.Error("验证码错误", zap.String("phone", p.Phone)) r.FailWithMessage("验证码错误", ctx) return } user, err := appUserService.Login(p) if err != nil { r.FailWithMessage("登录失败", ctx) return } // 生成token token, claims, err := user_jwt.LoginToken(user) if err != nil { global.GVA_LOG.Error("获取token失败!", zap.Error(err)) r.FailWithMessage("获取token失败", ctx) return } if _, err = global.GVA_REDIS.Get(ctx, strconv.Itoa(int(user.ID))).Result(); errors.Is(err, redis.Nil) { // 此处过期时间等于jwt过期时间 dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime) if err != nil { return } timer := dr if err := global.GVA_REDIS.Set(ctx, strconv.Itoa(int(user.ID)), token, timer).Err(); err != nil { global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err)) r.FailWithMessage("设置登录状态失败", ctx) return } user_jwt.SetToken(ctx, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix())) r.OkWithDetailed(gin.H{ "User": user, "Token": token, "ExpiresAt": claims.RegisteredClaims.ExpiresAt.Unix() * 1000, }, "登录成功", ctx) } else if err != nil { global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err)) r.FailWithMessage("设置登录状态失败", ctx) } } // WechatLogin 微信登录 func (*AppUserApi) WechatLogin(ctx *gin.Context) { var p request.CodeLoginReq if err := ctx.ShouldBind(&p); err != nil { r.FailWithMessage(err.Error(), ctx) global.GVA_LOG.Error("参数错误,登录失败", zap.Error(err)) return } //Todo 待完善微信登录 info := wechat.GetUserInfo(p.Code) if info == nil { r.FailWithMessage("获取用户信息失败", ctx) return } user, err := appUserService.WechatLogin(info) if err != nil { r.FailWithMessage("登录失败", ctx) return } // 生成token token, claims, err := user_jwt.LoginToken(user) if err != nil { global.GVA_LOG.Error("获取token失败!", zap.Error(err)) r.FailWithMessage("获取token失败", ctx) return } // 此处过期时间等于jwt过期时间 dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime) if err != nil { return } timer := dr if err := global.GVA_REDIS.Set(ctx, strconv.Itoa(int(user.ID)), token, timer).Err(); err != nil { global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err)) r.FailWithMessage("设置登录状态失败", ctx) return } user_jwt.SetToken(ctx, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix())) r.OkWithDetailed(gin.H{ "User": user, "Token": token, "ExpiresAt": claims.RegisteredClaims.ExpiresAt.Unix() * 1000, }, "登录成功", ctx) } // GetUserInfo 获取用户信息 func (*AppUserApi) GetUserInfo(ctx *gin.Context) { id := user_jwt.GetUserID(ctx) if id == 0 { global.GVA_LOG.Error("获取用户ID失败") r.FailWithMessage("获取用户ID失败", ctx) return } user, err := appUserService.GetUserInfo(id) if err != nil { global.GVA_LOG.Error("获取用户信息失败", zap.Error(err)) r.FailWithMessage("获取用户信息失败", ctx) return } r.OkWithDetailed(user, "获取用户信息成功", ctx) } // PwdLogin 密码登录 func (*AppUserApi) PwdLogin(ctx *gin.Context) { var p request.PwdLoginReq if err := ctx.ShouldBind(&p); err != nil { r.FailWithMessage(err.Error(), ctx) global.GVA_LOG.Error("参数错误,登录失败", zap.Error(err)) return } user, err := appUserService.PwdLogin(p) if err != nil { r.FailWithMessage("手机号或密码错误!", ctx) return } // 生成token token, claims, err := user_jwt.LoginToken(user) if err != nil { global.GVA_LOG.Error("获取token失败!", zap.Error(err)) r.FailWithMessage("获取token失败", ctx) return } // 此处过期时间等于jwt过期时间 dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime) if err != nil { return } timer := dr if err := global.GVA_REDIS.Set(ctx, strconv.Itoa(int(user.ID)), token, timer).Err(); err != nil { global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err)) r.FailWithMessage("设置登录状态失败", ctx) return } user_jwt.SetToken(ctx, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix())) r.OkWithDetailed(gin.H{ "User": user, "Token": token, "ExpiresAt": claims.RegisteredClaims.ExpiresAt.Unix() * 1000, }, "登录成功", ctx) } // Register 用户手机注册 func (a *AppUserApi) Register(context *gin.Context) { var p request.RegisterReq if err := context.ShouldBind(&p); err != nil { r.FailWithMessage(err.Error(), context) global.GVA_LOG.Error("参数错误,注册失败", zap.Error(err)) return } if result, _ := global.GVA_REDIS.Get(context, fmt.Sprintf("VerifyCode:%s", p.Phone)).Result(); result != p.Code { global.GVA_LOG.Error("验证码错误", zap.String("phone", p.Phone)) r.FailWithMessage("验证码错误", context) return } user, err := appUserService.Register(p) if err != nil { global.GVA_LOG.Error("注册失败", zap.Error(err)) r.FailWithMessage("注册失败", context) return } // 生成token token, claims, err := user_jwt.LoginToken(user) if err != nil { global.GVA_LOG.Error("获取token失败!", zap.Error(err)) r.FailWithMessage("获取token失败", context) return } // 此处过期时间等于jwt过期时间 dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime) if err != nil { return } timer := dr if err := global.GVA_REDIS.Set(context, user.Phone, token, timer).Err(); err != nil { global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err)) r.FailWithMessage("设置登录状态失败", context) return } user_jwt.SetToken(context, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix())) r.OkWithDetailed(gin.H{ "User": user, "Token": token, "ExpiresAt": claims.RegisteredClaims.ExpiresAt.Unix() * 1000, }, "注册成功", context) } // ApplyTeacher 申请成为教师 func (a *AppUserApi) ApplyTeacher(context *gin.Context) { var p app.TeacherApply if err := context.ShouldBind(&p); err != nil { r.FailWithMessage(err.Error(), context) global.GVA_LOG.Error("参数错误,申请失败", zap.Error(err)) return } id := user_jwt.GetUserID(context) if id == 0 { global.GVA_LOG.Error("获取用户ID失败") r.FailWithMessage("获取用户ID失败", context) return } p.UserId = id if err := appUserService.ApplyTeacher(p); err != nil { global.GVA_LOG.Error("申请失败", zap.Error(err)) r.FailWithMessage("申请失败", context) return } r.OkWithMessage("申请成功", context) } // GetTeacherApply 获取教师申请状态 func (a *AppUserApi) GetTeacherApply(context *gin.Context) { id := user_jwt.GetUserID(context) if id == 0 { global.GVA_LOG.Error("获取用户ID失败") r.FailWithMessage("获取用户ID失败", context) return } status, err := appUserService.GetTeacherApplyStatus(id) if err != nil { global.GVA_LOG.Error("获取教师申请状态失败", zap.Error(err)) r.FailWithMessage("获取教师申请状态失败", context) return } r.OkWithDetailed(status, "获取教师申请状态成功", context) } // BindWechat 手机登录用户绑定微信 func (a *AppUserApi) BindWechat(context *gin.Context) { var p request.BindWechatReq if err := context.ShouldBind(&p); err != nil { global.GVA_LOG.Error("绑定微信请求参数有误") r.FailWithMessage("绑定微信请求参数有误", context) return } user, err := appUserService.BindWechat(p) if err != nil { global.GVA_LOG.Error("绑定微信失败", zap.Error(err)) } // 生成新token token, claims, err := user_jwt.LoginToken(*user) if err != nil { global.GVA_LOG.Error("获取token失败!", zap.Error(err)) r.FailWithMessage("获取token失败", context) return } // 此处过期时间等于jwt过期时间 dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime) if err != nil { global.GVA_LOG.Error("解析JWT过期时间失败", zap.Error(err)) r.FailWithMessage("解析JWT过期时间失败", context) return } timer := dr if err := global.GVA_REDIS.Set(context, user.Phone, token, timer).Err(); err != nil { global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err)) r.FailWithMessage("设置登录状态失败", context) return } user_jwt.SetToken(context, token, int(claims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix())) r.OkWithDetailed(gin.H{ "User": user, "Token": token, "ExpiresAt": claims.RegisteredClaims.ExpiresAt.Unix() * 1000, }, "绑定微信成功", context) } // BindPhone 微信登录用户绑定手机号s func (a *AppUserApi) BindPhone(context *gin.Context) { var p request.BindPhoneReq if err := context.ShouldBind(&p); err != nil { global.GVA_LOG.Error("绑定手机号请求参数有误") r.FailWithMessage("绑定手机号请求参数有误", context) return } // 验证码检查 if result, _ := global.GVA_REDIS.Get(context, fmt.Sprintf("VerifyCode:%s", p.Phone)).Result(); result != p.Code { global.GVA_LOG.Error("验证码错误", zap.String("phone", p.Phone)) r.FailWithMessage("验证码错误", context) return } user, err := appUserService.BindPhone(p) if err != nil { global.GVA_LOG.Error("绑定手机号失败", zap.Error(err)) r.FailWithMessage("绑定手机号失败", context) return } r.OkWithDetailed(user, "绑定手机号成功", context) }