259 lines
8.1 KiB
Go
259 lines
8.1 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
"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实例
|
||
func NewUserService(config *config.Config, userModel model.UserModel, userAuthModel model.UserAuthModel, agentModel model.AgentModel) *UserService {
|
||
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
|
||
func (s *UserService) RegisterUUIDUser(ctx context.Context) (string, error) {
|
||
// 生成UUID
|
||
uuidStr, err := s.GenerateUUIDUserId(ctx)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
var userId string
|
||
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||
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
|
||
})
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
return userId, nil
|
||
}
|
||
|
||
// 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) {
|
||
platform, err := ctxdata.GetPlatformFromCtx(ctx)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
var isAgent int64
|
||
var agentID string
|
||
var authType string
|
||
var authKey string
|
||
// 获取用户信息,根据mobile字段动态计算userType
|
||
user, err := s.userModel.FindOne(ctx, userID)
|
||
if err != nil {
|
||
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取用户信息失败: %v", err)
|
||
}
|
||
|
||
// 根据mobile判断用户类型
|
||
var userType int64
|
||
if user.Mobile.Valid && user.Mobile.String != "" {
|
||
userType = model.UserTypeNormal
|
||
} else {
|
||
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
|
||
}
|
||
token, generaErr := jwtx.GenerateJwtToken(jwtx.JwtClaims{
|
||
UserId: userID,
|
||
AgentId: agentID,
|
||
Platform: platform,
|
||
UserType: userType,
|
||
IsAgent: isAgent,
|
||
AuthType: authType,
|
||
AuthKey: authKey,
|
||
}, s.Config.JwtAuth.AccessSecret, s.Config.JwtAuth.AccessExpire)
|
||
if generaErr != nil {
|
||
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %s", userID)
|
||
}
|
||
return token, nil
|
||
}
|
||
|
||
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
|
||
}
|
||
}
|
||
|
||
// RegisterUser 注册用户,返回用户ID
|
||
// 传入手机号,自动注册,如果ctx存在临时用户则临时用户转为正式用户
|
||
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
|
||
}
|
||
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) {
|
||
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})
|
||
if userAuthInsertErr != nil {
|
||
return userAuthInsertErr
|
||
}
|
||
tempUserBindErr := s.TempUserBindUser(ctx, session, userId)
|
||
if tempUserBindErr != nil {
|
||
return tempUserBindErr
|
||
}
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return userId, nil
|
||
}
|
||
|
||
// TempUserBindUser 临时用户绑定用户(添加mobile使其变为正式用户)
|
||
func (s *UserService) TempUserBindUser(ctx context.Context, session sqlx.Session, normalUserID string) error {
|
||
claims, err := ctxdata.GetClaimsFromCtx(ctx)
|
||
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
|
||
return err
|
||
}
|
||
|
||
if claims == nil {
|
||
return errors.New("无临时用户")
|
||
}
|
||
|
||
// 检查当前用户是否已经绑定了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("临时用户已注册")
|
||
}
|
||
|
||
existingAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, claims.AuthType, claims.AuthKey)
|
||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||
return err
|
||
}
|
||
if existingAuth != nil {
|
||
return errors.New("临时用户已注册")
|
||
}
|
||
|
||
if session == nil {
|
||
err := s.userAuthModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: normalUserID, AuthType: claims.AuthType, AuthKey: claims.AuthKey})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
} else {
|
||
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: normalUserID, AuthType: claims.AuthType, AuthKey: claims.AuthKey})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
}
|