Files
ycc-proxy-server/app/main/api/internal/service/userService.go

266 lines
8.0 KiB
Go
Raw Normal View History

2025-11-27 13:09:54 +08:00
package service
import (
"context"
2025-12-09 18:55:28 +08:00
"database/sql"
2025-11-27 13:09:54 +08:00
"ycc-server/app/main/api/internal/config"
"ycc-server/app/main/model"
"ycc-server/common/ctxdata"
jwtx "ycc-server/common/jwt"
"ycc-server/common/xerr"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type UserService struct {
Config *config.Config
userModel model.UserModel
userAuthModel model.UserAuthModel
agentModel model.AgentModel
}
// NewUserService 创建UserService实例
2025-12-09 18:55:28 +08:00
func NewUserService(config *config.Config, userModel model.UserModel, userAuthModel model.UserAuthModel, agentModel model.AgentModel) *UserService {
2025-11-27 13:09:54 +08:00
return &UserService{
Config: config,
userModel: userModel,
userAuthModel: userAuthModel,
agentModel: agentModel,
}
}
// GenerateUUIDUserId 生成UUID用户ID
func (s *UserService) GenerateUUIDUserId(ctx context.Context) (string, error) {
id := uuid.NewString()
return id, nil
}
// RegisterUUIDUser 注册UUID用户返回用户ID
2025-12-09 18:55:28 +08:00
func (s *UserService) RegisterUUIDUser(ctx context.Context) (string, error) {
2025-11-27 13:09:54 +08:00
// 生成UUID
uuidStr, err := s.GenerateUUIDUserId(ctx)
if err != nil {
2025-12-09 18:55:28 +08:00
return "", err
2025-11-27 13:09:54 +08:00
}
2025-12-09 18:55:28 +08:00
var userId string
2025-11-27 13:09:54 +08:00
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
2025-12-09 18:55:28 +08:00
user := &model.User{Id: uuid.NewString()}
if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil {
return userInsertErr
}
userId = user.Id
userAuth := &model.UserAuth{Id: uuid.NewString(), UserId: userId, AuthType: model.UserAuthTypeUUID, AuthKey: uuidStr}
_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, userAuth)
return userAuthInsertErr
2025-11-27 13:09:54 +08:00
})
if err != nil {
2025-12-09 18:55:28 +08:00
return "", err
2025-11-27 13:09:54 +08:00
}
return userId, nil
}
2025-12-10 13:10:39 +08:00
// GetUserType 根据user.Mobile字段动态计算用户类型
// 如果有mobile则为正式用户(UserTypeNormal),否则为临时用户(UserTypeTemp)
func (s *UserService) GetUserType(ctx context.Context, userID string) (int64, error) {
user, err := s.userModel.FindOne(ctx, userID)
if err != nil {
return 0, err
}
if user.Mobile.Valid && user.Mobile.String != "" {
return model.UserTypeNormal, nil
}
return model.UserTypeTemp, nil
}
// GeneralUserToken 生成用户token动态计算userType
func (s *UserService) GeneralUserToken(ctx context.Context, userID string) (string, error) {
2025-11-27 13:09:54 +08:00
platform, err := ctxdata.GetPlatformFromCtx(ctx)
if err != nil {
return "", err
}
var isAgent int64
2025-12-09 18:55:28 +08:00
var agentID string
var authType string
var authKey string
2025-12-10 13:56:45 +08:00
// 获取用户信息根据mobile字段动态计算userType
user, err := s.userModel.FindOne(ctx, userID)
if err != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取用户信息失败: %v", err)
}
2025-12-10 13:10:39 +08:00
2025-12-10 13:56:45 +08:00
// 根据mobile判断用户类型
var userType int64
if user.Mobile.Valid && user.Mobile.String != "" {
userType = model.UserTypeNormal
2025-12-09 18:55:28 +08:00
} else {
2025-12-10 13:56:45 +08:00
userType = model.UserTypeTemp
}
agent, err := s.agentModel.FindOneByUserId(ctx, userID)
if err != nil && !errors.Is(err, model.ErrNotFound) {
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新token, 获取用户代理信息失败: %v", err)
}
if agent != nil {
agentID = agent.Id
isAgent = model.AgentStatusYes
}
platAuthType := s.getAuthTypeByPlatform(platform)
ua, err := s.userAuthModel.FindOneByUserIdAuthType(ctx, userID, platAuthType)
if err == nil && ua != nil {
authType = ua.AuthType
authKey = ua.AuthKey
2025-11-27 13:09:54 +08:00
}
token, generaErr := jwtx.GenerateJwtToken(jwtx.JwtClaims{
UserId: userID,
AgentId: agentID,
Platform: platform,
UserType: userType,
IsAgent: isAgent,
2025-12-09 18:55:28 +08:00
AuthType: authType,
AuthKey: authKey,
2025-11-27 13:09:54 +08:00
}, s.Config.JwtAuth.AccessSecret, s.Config.JwtAuth.AccessExpire)
if generaErr != nil {
2025-12-09 18:55:28 +08:00
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %s", userID)
2025-11-27 13:09:54 +08:00
}
return token, nil
}
2025-12-09 18:55:28 +08:00
func (s *UserService) getAuthTypeByPlatform(platform string) string {
switch platform {
case model.PlatformWxMini:
return model.UserAuthTypeWxMiniOpenID
case model.PlatformWxH5:
return model.UserAuthTypeWxh5OpenID
case model.PlatformH5, model.PlatformApp:
return model.UserAuthTypeUUID
default:
return model.UserAuthTypeUUID
}
}
2025-11-27 13:09:54 +08:00
// RegisterUser 注册用户返回用户ID
2025-12-11 19:01:28 +08:00
// 只负责创建新用户(手机号不存在时),不处理合并逻辑
// 如果有临时用户claims会将临时用户的认证绑定到新用户
2025-12-09 18:55:28 +08:00
func (s *UserService) RegisterUser(ctx context.Context, mobile string) (string, error) {
2025-12-11 19:01:28 +08:00
// 检查手机号是否已存在
2025-11-27 13:09:54 +08:00
user, err := s.userModel.FindOneByMobile(ctx, sql.NullString{String: mobile, Valid: true})
if err != nil && !errors.Is(err, model.ErrNotFound) {
2025-12-09 18:55:28 +08:00
return "", err
2025-11-27 13:09:54 +08:00
}
if user != nil {
2025-12-09 18:55:28 +08:00
return "", errors.New("用户已注册")
2025-11-27 13:09:54 +08:00
}
2025-12-11 19:01:28 +08:00
// 获取当前登录态(可能为空)
claims, err := ctxdata.GetClaimsFromCtx(ctx)
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
2025-12-10 13:10:39 +08:00
return "", err
}
2025-12-11 19:01:28 +08:00
2025-12-09 18:55:28 +08:00
var userId string
2025-11-27 13:09:54 +08:00
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
2025-12-11 19:01:28 +08:00
// 创建新用户
2025-12-09 18:55:28 +08:00
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
2025-11-27 13:09:54 +08:00
}
2025-12-09 18:55:28 +08:00
userId = user.Id
2025-12-11 19:01:28 +08:00
// 创建 mobile 认证
_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{
Id: uuid.NewString(),
UserId: userId,
AuthType: model.UserAuthTypeMobile,
AuthKey: mobile,
})
2025-12-09 18:55:28 +08:00
if userAuthInsertErr != nil {
return userAuthInsertErr
2025-11-27 13:09:54 +08:00
}
2025-12-11 19:01:28 +08:00
// 如果有临时用户,将临时用户的认证绑定到新用户
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
}
}
2025-11-27 13:09:54 +08:00
}
2025-12-11 19:01:28 +08:00
2025-11-27 13:09:54 +08:00
return nil
})
if err != nil {
2025-12-09 18:55:28 +08:00
return "", err
2025-11-27 13:09:54 +08:00
}
return userId, nil
}
2025-12-10 13:10:39 +08:00
// TempUserBindUser 临时用户绑定用户添加mobile使其变为正式用户
2025-12-09 18:55:28 +08:00
func (s *UserService) TempUserBindUser(ctx context.Context, session sqlx.Session, normalUserID string) error {
2025-11-27 13:09:54 +08:00
claims, err := ctxdata.GetClaimsFromCtx(ctx)
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
return err
}
2025-12-10 13:10:39 +08:00
if claims == nil {
2025-11-27 13:09:54 +08:00
return errors.New("无临时用户")
}
2025-12-10 13:10:39 +08:00
// 检查当前用户是否已经绑定了mobile根据mobile判断而不是userType
tempUser, err := s.userModel.FindOne(ctx, claims.UserId)
if err != nil && !errors.Is(err, model.ErrNotFound) {
return err
}
if tempUser != nil && tempUser.Mobile.Valid && tempUser.Mobile.String != "" {
return errors.New("临时用户已注册")
}
2025-12-09 18:55:28 +08:00
existingAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, claims.AuthType, claims.AuthKey)
2025-11-27 13:09:54 +08:00
if err != nil && !errors.Is(err, model.ErrNotFound) {
return err
}
2025-12-09 18:55:28 +08:00
if existingAuth != nil {
2025-11-27 13:09:54 +08:00
return errors.New("临时用户已注册")
}
if session == nil {
err := s.userAuthModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
2025-12-09 18:55:28 +08:00
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: normalUserID, AuthType: claims.AuthType, AuthKey: claims.AuthKey})
2025-11-27 13:09:54 +08:00
if err != nil {
return err
}
return nil
})
if err != nil {
return err
}
return nil
} else {
2025-12-09 18:55:28 +08:00
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: normalUserID, AuthType: claims.AuthType, AuthKey: claims.AuthKey})
2025-11-27 13:09:54 +08:00
if err != nil {
return err
}
return nil
}
}