bindbox-game/internal/api/user/sms_login_app.go

153 lines
4.2 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 app
import (
"net/http"
"time"
"bindbox-game/configs"
"bindbox-game/internal/code"
"bindbox-game/internal/pkg/core"
"bindbox-game/internal/pkg/jwtoken"
"bindbox-game/internal/pkg/validation"
"bindbox-game/internal/proposal"
usersvc "bindbox-game/internal/service/user"
"go.uber.org/zap"
)
// ============================================
// 发送短信验证码
// ============================================
type sendSmsCodeRequest struct {
Mobile string `json:"mobile" binding:"required"`
}
type sendSmsCodeResponse struct {
Success bool `json:"success"`
ExpireSeconds int `json:"expire_seconds"`
}
// SendSmsCode 发送短信验证码
// @Summary 发送短信验证码
// @Description 发送短信验证码到指定手机号60秒内不可重复发送每日最多10次
// @Tags APP端.用户
// @Accept json
// @Produce json
// @Param RequestBody body sendSmsCodeRequest true "请求参数"
// @Success 200 {object} sendSmsCodeResponse
// @Failure 400 {object} code.Failure
// @Router /api/app/sms/send-code [post]
func (h *handler) SendSmsCode() core.HandlerFunc {
return func(ctx core.Context) {
req := new(sendSmsCodeRequest)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
if err := h.user.SendSmsCode(ctx.RequestContext(), req.Mobile); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
ctx.Payload(&sendSmsCodeResponse{
Success: true,
ExpireSeconds: 300, // 5分钟有效期
})
}
}
// ============================================
// 短信验证码登录
// ============================================
type smsLoginRequest struct {
Mobile string `json:"mobile" binding:"required"`
Code string `json:"code" binding:"required"`
InviteCode string `json:"invite_code"`
}
type smsLoginResponse struct {
UserID int64 `json:"user_id"`
Nickname string `json:"nickname"`
Avatar string `json:"avatar"`
InviteCode string `json:"invite_code"`
Mobile string `json:"mobile"`
Token string `json:"token"`
OpenID string `json:"openid"`
IsNewUser bool `json:"is_new_user"`
}
// SmsLogin 短信验证码登录
// @Summary 短信验证码登录
// @Description 使用短信验证码登录或注册(新手机号自动创建账户)
// @Tags APP端.用户
// @Accept json
// @Produce json
// @Param RequestBody body smsLoginRequest true "请求参数"
// @Success 200 {object} smsLoginResponse
// @Failure 400 {object} code.Failure
// @Router /api/app/sms/login [post]
func (h *handler) SmsLogin() core.HandlerFunc {
return func(ctx core.Context) {
req := new(smsLoginRequest)
rsp := new(smsLoginResponse)
if err := ctx.ShouldBindJSON(req); err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
return
}
in := usersvc.SmsLoginInput{
Mobile: req.Mobile,
Code: req.Code,
InviteCode: req.InviteCode,
}
out, err := h.user.LoginByCode(ctx.RequestContext(), in)
if err != nil {
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, err.Error()))
return
}
u := out.User
rsp.UserID = u.ID
rsp.Nickname = u.Nickname
rsp.Avatar = u.Avatar
rsp.InviteCode = u.InviteCode
rsp.Mobile = u.Mobile
rsp.OpenID = u.Openid
rsp.IsNewUser = out.IsNewUser
// 触发邀请奖励逻辑
if out.IsNewUser && out.InviterID > 0 {
if err := h.task.OnInviteSuccess(ctx.RequestContext(), out.InviterID, u.ID); err != nil {
h.logger.Error("触发邀请任务失败", zap.Error(err), zap.Int64("inviter_id", out.InviterID), zap.Int64("invitee_id", u.ID))
}
}
h.logger.Info("短信登录返回数据",
zap.Int64("user_id", u.ID),
zap.String("mobile", u.Mobile),
zap.String("openid", u.Openid),
zap.Bool("is_new", out.IsNewUser),
)
// 签发JWT Token
sessionUserInfo := proposal.SessionUserInfo{
Id: int32(u.ID),
UserName: u.Nickname,
NickName: u.Nickname,
IsSuper: 0,
Platform: "APP",
}
tokenString, tErr := jwtoken.New(configs.Get().JWT.PatientSecret).Sign(sessionUserInfo, 30*24*time.Hour)
if tErr == nil {
rsp.Token = tokenString
}
ctx.Payload(rsp)
}
}