fix
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -21,8 +21,8 @@ data/*
|
||||
# 打包出来的可执行文件
|
||||
/app/api
|
||||
/app/main/api/main
|
||||
/app/main/api/debug
|
||||
/app/main/api/test
|
||||
/app/main/api/_debug
|
||||
/app/main/api/_test
|
||||
|
||||
# 文档目录
|
||||
documents/*
|
||||
|
||||
@@ -41,7 +41,7 @@ Wxpay:
|
||||
MchPublicKeyPath: "etc/merchant/pub_key.pem"
|
||||
MchPlatformRAS: "5630D013C88EA348BF66E642B6C39AA0180D4B15"
|
||||
NotifyUrl: "https://www.onecha.cn/api/v1/pay/wechat/callback"
|
||||
RefundNotifyUrl: "https://www.onecha.cn/api/v1/wechat/refund_callback"
|
||||
RefundNotifyUrl: "https://www.onecha.cn/api/v1/pay/wechat/refund_callback"
|
||||
Applepay:
|
||||
ProductionVerifyURL: "https://api.storekit.itunes.apple.com/inApps/v1/transactions/receipt"
|
||||
SandboxVerifyURL: "https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/receipt"
|
||||
|
||||
@@ -60,6 +60,35 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前登录态(可能为空)
|
||||
claims, err := ctxdata.GetClaimsFromCtx(l.ctx)
|
||||
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败: %v", err)
|
||||
}
|
||||
|
||||
// 前置检查:如果当前用户是正式用户(有手机号),进行拦截检查
|
||||
if claims != nil {
|
||||
currentUser, err := l.svcCtx.UserModel.FindOne(l.ctx, claims.UserId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户失败: %v", err)
|
||||
}
|
||||
if currentUser != nil && currentUser.Mobile.Valid && currentUser.Mobile.String != "" {
|
||||
// 当前用户是正式用户,检查是否已是代理
|
||||
agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, claims.UserId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理失败: %v", err)
|
||||
}
|
||||
if agent != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("您已经是代理,不能重复注册"), "")
|
||||
}
|
||||
// 正式用户手机号必须匹配
|
||||
if currentUser.Mobile.String != encryptedMobile {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("请输入当前账号的手机号码"), "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证邀请码是否有效
|
||||
var inviteCodeModel *model.AgentInviteCode
|
||||
inviteCodeModel, err = l.svcCtx.AgentInviteCodeModel.FindOneByCode(l.ctx, req.Referrer)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
@@ -77,56 +106,43 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 使用事务处理注册
|
||||
// 使用事务处理注册
|
||||
var userID string
|
||||
var agentID string
|
||||
var agentLevel int64
|
||||
|
||||
err = l.svcCtx.AgentInviteCodeModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 4.1 检查用户是否已存在
|
||||
user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
|
||||
// 1. 查找目标用户(通过手机号)
|
||||
targetUser, findUserErr := l.svcCtx.UserModel.FindOneByMobile(transCtx, sql.NullString{String: encryptedMobile, Valid: true})
|
||||
if findUserErr != nil && !errors.Is(findUserErr, model.ErrNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户失败, %v", findUserErr)
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
// 用户不存在,注册新用户
|
||||
userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "注册用户失败: %v", err)
|
||||
}
|
||||
} else {
|
||||
// 用户已存在,检查是否已是代理
|
||||
existingAgent, err := l.svcCtx.AgentModel.FindOneByUserId(transCtx, user.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
|
||||
}
|
||||
if existingAgent != nil {
|
||||
return errors.Wrapf(xerr.NewErrMsg("您已经是代理"), "")
|
||||
}
|
||||
|
||||
// 检查用户是否有mobile绑定(没有mobile则不能成为代理)
|
||||
// 如果是临时用户(微信环境下),需要先绑定手机号
|
||||
claims, err := ctxdata.GetClaimsFromCtx(l.ctx)
|
||||
if err == nil && claims != nil {
|
||||
// 获取用户的mobile信息
|
||||
if !user.Mobile.Valid || user.Mobile.String == "" {
|
||||
// 临时用户(无mobile)不能直接成为代理,需要先绑定mobile
|
||||
return errors.Wrapf(xerr.NewErrMsg("请先绑定手机号后再申请成为代理"), "")
|
||||
}
|
||||
// 检查是否已绑定手机号认证(用于确保后续可通过手机号登录)
|
||||
userAuth, err := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(l.ctx, user.Id, claims.AuthType)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户认证失败, %v", err)
|
||||
}
|
||||
if userAuth != nil && userAuth.AuthKey != claims.AuthKey {
|
||||
return errors.Wrapf(xerr.NewErrMsg("该手机号已绑定其他微信号"), "")
|
||||
}
|
||||
}
|
||||
|
||||
userID = user.Id
|
||||
// 2. 获取当前登录态信息
|
||||
var currentUserID string
|
||||
var currentAuthType string
|
||||
var currentAuthKey string
|
||||
if claims != nil {
|
||||
currentUserID = claims.UserId
|
||||
currentAuthType = claims.AuthType
|
||||
currentAuthKey = claims.AuthKey
|
||||
}
|
||||
|
||||
// 3. 根据目标用户是否存在,处理用户和认证
|
||||
if targetUser == nil {
|
||||
// 场景1: 手机号不存在
|
||||
userID, err = l.handleMobileNotExists(transCtx, session, encryptedMobile, currentUserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 场景2: 手机号已存在
|
||||
userID, err = l.handleMobileExists(transCtx, session, targetUser, currentUserID, currentAuthType, currentAuthKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// 4. 处理邀请码和上级关系
|
||||
var targetLevel int64
|
||||
var parentAgentId string
|
||||
if inviteCodeModel != nil {
|
||||
@@ -156,7 +172,8 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn
|
||||
}
|
||||
}
|
||||
|
||||
// 4.3 创建代理记录
|
||||
// 5. 创建代理记录
|
||||
|
||||
newAgent := &model.Agent{Id: uuid.NewString(), UserId: userID, Level: targetLevel, Mobile: encryptedMobile}
|
||||
if req.Region != "" {
|
||||
newAgent.Region = sql.NullString{String: req.Region, Valid: true}
|
||||
@@ -165,7 +182,7 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn
|
||||
newAgent.WechatId = sql.NullString{String: req.WechatId, Valid: true}
|
||||
}
|
||||
|
||||
// 4.4 处理上级关系
|
||||
// 6. 处理上级关系
|
||||
if parentAgentId != "" {
|
||||
// 查找上级代理
|
||||
parentAgent, err := l.svcCtx.AgentModel.FindOne(transCtx, parentAgentId)
|
||||
@@ -225,13 +242,13 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn
|
||||
}
|
||||
}
|
||||
|
||||
// 4.5 初始化钱包
|
||||
// 7. 初始化钱包
|
||||
wallet := &model.AgentWallet{Id: uuid.NewString(), AgentId: agentID}
|
||||
if _, err := l.svcCtx.AgentWalletModel.Insert(transCtx, session, wallet); err != nil {
|
||||
return errors.Wrapf(err, "初始化钱包失败")
|
||||
}
|
||||
|
||||
// 4.6 更新邀请码状态
|
||||
// 8. 更新邀请码状态
|
||||
// 钻石级别的邀请码只能使用一次,使用后立即失效
|
||||
// 普通级别的邀请码可以无限使用,不更新状态
|
||||
if targetLevel == 3 {
|
||||
@@ -247,7 +264,7 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn
|
||||
}
|
||||
}
|
||||
|
||||
// 4.7 记录邀请码使用历史(用于统计和查询)
|
||||
// 9. 记录邀请码使用历史(用于统计和查询)
|
||||
if inviteCodeModel != nil {
|
||||
usage := &model.AgentInviteCodeUsage{Id: uuid.NewString(), InviteCodeId: inviteCodeModel.Id, Code: inviteCodeModel.Code, UserId: userID, AgentId: agentID, AgentLevel: targetLevel, UsedTime: time.Now()}
|
||||
if _, err := l.svcCtx.AgentInviteCodeUsageModel.Insert(transCtx, session, usage); err != nil {
|
||||
@@ -263,7 +280,7 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 5. 生成并返回token
|
||||
// 10. 生成并返回token
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成token失败: %v", err)
|
||||
@@ -361,3 +378,195 @@ func (l *RegisterByInviteCodeLogic) allocateAgentCode(ctx context.Context, sessi
|
||||
}
|
||||
return next, nil
|
||||
}
|
||||
|
||||
// handleMobileNotExists 处理手机号不存在的情况
|
||||
func (l *RegisterByInviteCodeLogic) handleMobileNotExists(ctx context.Context, session sqlx.Session, encryptedMobile string, currentUserID string) (string, error) {
|
||||
if currentUserID == "" {
|
||||
// 场景1.1: 未登录 + 手机号不存在 -> 创建新用户
|
||||
newUser := &model.User{Id: uuid.NewString(), Mobile: sql.NullString{String: encryptedMobile, Valid: true}}
|
||||
if _, err := l.svcCtx.UserModel.Insert(ctx, session, newUser); err != nil {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建用户失败: %v", err)
|
||||
}
|
||||
// 创建 mobile 认证
|
||||
if _, err := l.svcCtx.UserAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
Id: uuid.NewString(),
|
||||
UserId: newUser.Id,
|
||||
AuthType: model.UserAuthTypeMobile,
|
||||
AuthKey: encryptedMobile,
|
||||
}); err != nil {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建手机号认证失败: %v", err)
|
||||
}
|
||||
return newUser.Id, nil
|
||||
} else {
|
||||
// 场景1.2: 已登录临时用户 + 手机号不存在 -> 升级为正式用户
|
||||
// 前置检查已保证不是正式用户,所以这里一定是临时用户
|
||||
currentUser, err := l.svcCtx.UserModel.FindOne(ctx, currentUserID)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询当前用户失败: %v", err)
|
||||
}
|
||||
// 升级为正式用户
|
||||
currentUser.Mobile = sql.NullString{String: encryptedMobile, Valid: true}
|
||||
if _, err := l.svcCtx.UserModel.Update(ctx, session, currentUser); err != nil {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新手机号失败: %v", err)
|
||||
}
|
||||
// 创建 mobile 认证
|
||||
if _, err := l.svcCtx.UserAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
Id: uuid.NewString(),
|
||||
UserId: currentUserID,
|
||||
AuthType: model.UserAuthTypeMobile,
|
||||
AuthKey: encryptedMobile,
|
||||
}); err != nil {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建手机号认证失败: %v", err)
|
||||
}
|
||||
return currentUserID, nil
|
||||
}
|
||||
}
|
||||
|
||||
// handleMobileExists 处理手机号已存在的情况
|
||||
func (l *RegisterByInviteCodeLogic) handleMobileExists(ctx context.Context, session sqlx.Session, targetUser *model.User, currentUserID string, currentAuthType string, currentAuthKey string) (string, error) {
|
||||
userID := targetUser.Id
|
||||
|
||||
// 检查目标用户是否已是代理
|
||||
existingAgent, err := l.svcCtx.AgentModel.FindOneByUserId(ctx, userID)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败: %v", err)
|
||||
}
|
||||
if existingAgent != nil {
|
||||
return "", errors.Wrapf(xerr.NewErrMsg("该手机号已经是代理,不能重复注册"), "")
|
||||
}
|
||||
|
||||
if currentUserID == "" {
|
||||
// 场景2.1: 未登录 + 手机号存在 -> 直接使用目标用户(验证码已确认身份)
|
||||
return userID, nil
|
||||
} else if currentUserID == userID {
|
||||
// 场景2.2: 已登录正式用户 + 手机号匹配 -> 直接使用
|
||||
// 前置检查已保证手机号匹配且不是代理
|
||||
return userID, nil
|
||||
} else {
|
||||
// 场景2.3: 已登录临时用户 + 手机号存在 -> 需要合并账号
|
||||
// 前置检查已保证是临时用户(不是正式用户)
|
||||
return l.mergeTempUserToTarget(ctx, session, currentUserID, userID, currentAuthType, currentAuthKey)
|
||||
}
|
||||
}
|
||||
|
||||
// mergeTempUserToTarget 合并临时用户到目标用户
|
||||
func (l *RegisterByInviteCodeLogic) mergeTempUserToTarget(ctx context.Context, session sqlx.Session, sourceUserID string, targetUserID string, currentAuthType string, currentAuthKey string) (string, error) {
|
||||
// 检查目标用户是否已有该认证(除了UUID)
|
||||
if currentAuthType != model.UserAuthTypeUUID {
|
||||
targetAuth, err := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(ctx, targetUserID, currentAuthType)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找认证信息失败: %v", err)
|
||||
}
|
||||
if targetAuth != nil && targetAuth.AuthKey != currentAuthKey {
|
||||
// 目标用户已有该类型的其他认证,证明手机号绑定过其他微信等
|
||||
if currentAuthType == model.UserAuthTypeWxh5OpenID {
|
||||
return "", errors.Wrapf(xerr.NewErrMsg("该手机号已绑定其他微信号"), "")
|
||||
}
|
||||
if currentAuthType == model.UserAuthTypeWxMiniOpenID {
|
||||
return "", errors.Wrapf(xerr.NewErrMsg("该手机号已绑定其他微信号"), "")
|
||||
}
|
||||
return "", errors.Wrapf(xerr.NewErrMsg("该手机号已绑定其他终端"), "")
|
||||
}
|
||||
}
|
||||
|
||||
// 查找当前认证
|
||||
existingAuth, err := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(ctx, currentAuthType, currentAuthKey)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找认证信息失败: %v", err)
|
||||
}
|
||||
|
||||
// 执行账号合并
|
||||
if err := l.mergeUserAccounts(ctx, session, sourceUserID, targetUserID, currentAuthType, currentAuthKey, existingAuth); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return targetUserID, nil
|
||||
}
|
||||
|
||||
// mergeUserAccounts 合并账号:迁移认证、业务数据,删除临时用户
|
||||
func (l *RegisterByInviteCodeLogic) mergeUserAccounts(ctx context.Context, session sqlx.Session, sourceUserID string, targetUserID string, currentAuthType string, currentAuthKey string, existingAuth *model.UserAuth) error {
|
||||
// 1) 认证绑定处理
|
||||
if existingAuth != nil && existingAuth.UserId != targetUserID {
|
||||
// 认证存在但不属于目标用户,迁移到目标用户
|
||||
if currentAuthType == model.UserAuthTypeUUID {
|
||||
// UUID替换策略:如果目标用户已有UUID认证,替换UUID;否则迁移认证
|
||||
targetUUIDAuth, _ := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(ctx, targetUserID, model.UserAuthTypeUUID)
|
||||
if targetUUIDAuth != nil {
|
||||
// 目标用户已有UUID认证,删除源认证并更新目标UUID
|
||||
if err := l.svcCtx.UserAuthModel.Delete(ctx, session, existingAuth.Id); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除旧UUID认证失败: %v", err)
|
||||
}
|
||||
if targetUUIDAuth.AuthKey != currentAuthKey {
|
||||
targetUUIDAuth.AuthKey = currentAuthKey
|
||||
if _, err := l.svcCtx.UserAuthModel.Update(ctx, session, targetUUIDAuth); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新目标UUID认证失败: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 目标用户没有UUID认证,迁移源认证
|
||||
existingAuth.UserId = targetUserID
|
||||
if _, err := l.svcCtx.UserAuthModel.Update(ctx, session, existingAuth); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "迁移UUID认证失败: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 其他认证类型,直接迁移
|
||||
existingAuth.UserId = targetUserID
|
||||
if _, err := l.svcCtx.UserAuthModel.Update(ctx, session, existingAuth); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "迁移认证失败: %v", err)
|
||||
}
|
||||
}
|
||||
} else if existingAuth == nil {
|
||||
// 认证不存在,创建新认证
|
||||
if currentAuthType == model.UserAuthTypeUUID {
|
||||
// UUID特殊处理:如果目标用户已有UUID认证,更新UUID;否则创建新认证
|
||||
targetUUIDAuth, _ := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(ctx, targetUserID, model.UserAuthTypeUUID)
|
||||
if targetUUIDAuth != nil {
|
||||
if targetUUIDAuth.AuthKey != currentAuthKey {
|
||||
targetUUIDAuth.AuthKey = currentAuthKey
|
||||
if _, err := l.svcCtx.UserAuthModel.Update(ctx, session, targetUUIDAuth); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新目标UUID认证失败: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, err := l.svcCtx.UserAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
Id: uuid.NewString(),
|
||||
UserId: targetUserID,
|
||||
AuthType: currentAuthType,
|
||||
AuthKey: currentAuthKey,
|
||||
}); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建UUID认证失败: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 其他认证类型,创建新认证
|
||||
if _, err := l.svcCtx.UserAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
Id: uuid.NewString(),
|
||||
UserId: targetUserID,
|
||||
AuthType: currentAuthType,
|
||||
AuthKey: currentAuthKey,
|
||||
}); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建认证失败: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2) 业务数据迁移:迁移订单和报告到目标用户
|
||||
if err := l.svcCtx.OrderModel.UpdateUserIDWithSession(ctx, session, sourceUserID, targetUserID); err != nil {
|
||||
return errors.Wrapf(err, "迁移订单失败")
|
||||
}
|
||||
if err := l.svcCtx.QueryModel.UpdateUserIDWithSession(ctx, session, sourceUserID, targetUserID); err != nil {
|
||||
return errors.Wrapf(err, "迁移报告失败")
|
||||
}
|
||||
|
||||
// 3) 删除临时用户
|
||||
sourceUser, err := l.svcCtx.UserModel.FindOne(ctx, sourceUserID)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找源用户失败: %v", err)
|
||||
}
|
||||
if err := l.svcCtx.UserModel.Delete(ctx, session, sourceUser.Id); err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除源用户失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -142,12 +142,10 @@ func (s *UserService) getAuthTypeByPlatform(platform string) string {
|
||||
}
|
||||
|
||||
// RegisterUser 注册用户,返回用户ID
|
||||
// 传入手机号,自动注册,如果ctx存在临时用户则临时用户转为正式用户
|
||||
// 只负责创建新用户(手机号不存在时),不处理合并逻辑
|
||||
// 如果有临时用户(claims),会将临时用户的认证绑定到新用户
|
||||
func (s *UserService) RegisterUser(ctx context.Context, mobile string) (string, error) {
|
||||
claims, err := ctxdata.GetClaimsFromCtx(ctx)
|
||||
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
|
||||
return "", err
|
||||
}
|
||||
// 检查手机号是否已存在
|
||||
user, err := s.userModel.FindOneByMobile(ctx, sql.NullString{String: mobile, Valid: true})
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return "", err
|
||||
@@ -155,51 +153,60 @@ func (s *UserService) RegisterUser(ctx context.Context, mobile string) (string,
|
||||
if user != nil {
|
||||
return "", errors.New("用户已注册")
|
||||
}
|
||||
// 普通注册
|
||||
if claims == nil {
|
||||
var userId string
|
||||
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
user := &model.User{Id: uuid.NewString(), Mobile: sql.NullString{String: mobile, Valid: true}}
|
||||
if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil {
|
||||
return userInsertErr
|
||||
}
|
||||
userId = user.Id
|
||||
_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: userId, AuthType: model.UserAuthTypeMobile, AuthKey: mobile})
|
||||
if userAuthInsertErr != nil {
|
||||
return userAuthInsertErr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return userId, nil
|
||||
}
|
||||
|
||||
// 双重判断是否已经注册(根据mobile判断,而不是userType)
|
||||
currentUser, err := s.userModel.FindOne(ctx, claims.UserId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
// 获取当前登录态(可能为空)
|
||||
claims, err := ctxdata.GetClaimsFromCtx(ctx)
|
||||
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
|
||||
return "", err
|
||||
}
|
||||
if currentUser != nil && currentUser.Mobile.Valid && currentUser.Mobile.String != "" {
|
||||
return "", errors.New("用户已注册")
|
||||
}
|
||||
|
||||
var userId string
|
||||
// 临时用户绑定mobile转正式注册
|
||||
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 创建新用户
|
||||
user := &model.User{Id: uuid.NewString(), Mobile: sql.NullString{String: mobile, Valid: true}}
|
||||
if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil {
|
||||
return userInsertErr
|
||||
}
|
||||
userId = user.Id
|
||||
_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: userId, AuthType: model.UserAuthTypeMobile, AuthKey: mobile})
|
||||
|
||||
// 创建 mobile 认证
|
||||
_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
Id: uuid.NewString(),
|
||||
UserId: userId,
|
||||
AuthType: model.UserAuthTypeMobile,
|
||||
AuthKey: mobile,
|
||||
})
|
||||
if userAuthInsertErr != nil {
|
||||
return userAuthInsertErr
|
||||
}
|
||||
tempUserBindErr := s.TempUserBindUser(ctx, session, userId)
|
||||
if tempUserBindErr != nil {
|
||||
return tempUserBindErr
|
||||
|
||||
// 如果有临时用户,将临时用户的认证绑定到新用户
|
||||
if claims != nil {
|
||||
// 检查临时用户是否已有该认证类型
|
||||
existingAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, claims.AuthType, claims.AuthKey)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return err
|
||||
}
|
||||
// 如果认证不存在,创建新的认证绑定
|
||||
if existingAuth == nil {
|
||||
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
Id: uuid.NewString(),
|
||||
UserId: userId,
|
||||
AuthType: claims.AuthType,
|
||||
AuthKey: claims.AuthKey,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if existingAuth.UserId != userId {
|
||||
// 如果认证已存在但属于其他用户,迁移到新用户
|
||||
existingAuth.UserId = userId
|
||||
if _, err := s.userAuthModel.Update(ctx, session, existingAuth); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user