hi-server/internal/logic/public/user/bindEmailWithVerificationLogic.go
shanshanzhong 2442831cd7
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 7m28s
feat(设备管理): 添加设备在线记录查询功能并优化设备列表排序
添加FindLatestDeviceOnlineRecord接口用于查询设备最新在线记录
实现GetOnlineDeviceLoginTime方法获取设备登录时间
优化设备列表查询按最后活动时间排序
移除未使用的依赖项
2025-11-27 23:24:48 -08:00

611 lines
24 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 user
import (
"context"
"fmt"
"time"
"github.com/perfect-panel/server/internal/config"
"github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/constant"
"github.com/perfect-panel/server/pkg/jwt"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/tool"
"github.com/perfect-panel/server/pkg/uuidx"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
"gorm.io/gorm"
)
type BindEmailWithVerificationLogic struct {
logger.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
// NewBindEmailWithVerificationLogic Bind Email With Verification
func NewBindEmailWithVerificationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BindEmailWithVerificationLogic {
return &BindEmailWithVerificationLogic{
Logger: logger.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// BindEmailWithVerification 处理邮箱绑定流程,并在邮箱已存在时转移设备归属
// 参数说明:
// - req: 绑定邮箱请求,包含邮箱地址等信息
// 返回值:
// - *types.BindEmailWithVerificationResponse: 包含绑定结果、消息、token、用户ID
// - error: 发生错误时返回具体错误
func (l *BindEmailWithVerificationLogic) BindEmailWithVerification(req *types.BindEmailWithVerificationRequest) (*types.BindEmailWithVerificationResponse, error) {
// 获取当前用户
u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User)
if !ok {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
}
// 获取当前用户的设备标识符
deviceIdentifier, err := l.getCurrentUserDeviceIdentifier(l.ctx, u.Id)
if err != nil {
l.Errorw("获取用户设备标识符失败", logger.Field("error", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "获取用户设备信息失败: %v", err)
}
// 检测当设备是否已经绑定过邮箱
existingDevice, err := l.svcCtx.UserModel.FindUserAuthMethods(l.ctx, u.Id)
if err != nil {
l.Errorw("查询用户设备信息失败", logger.Field("error", err.Error()), logger.Field("device_identifier", deviceIdentifier))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "查询用户设备信息失败")
}
for _, method := range existingDevice {
if method.AuthType == "email" {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.EmailBindError), "该设备已绑定邮箱")
}
}
// 检查邮箱是否已被其他用户绑定
existingMethod, err := l.svcCtx.UserModel.FindUserAuthMethodByOpenID(l.ctx, "email", req.Email)
var emailUserId int64
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// 邮箱不存在,不创建新用户,直接将邮箱认证绑定到当前设备用户
l.Infow(" 为当前设备做 邮箱绑定操作; 在 user_auth_methods 中添加记录", logger.Field("email", req.Email))
err = l.addAuthMethodForEmailUser(u.Id, req.Email)
if err != nil {
l.Errorw("添加邮箱用户认证方法失败", logger.Field("error", err.Error()), logger.Field("user_id", u.Id))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "添加邮箱用户认证方法失败")
}
// 关键修复:为后续 token 生成与返回结果赋值绑定后的用户ID
emailUserId = u.Id
} else {
// 数据库查询错误
l.Errorw("查询邮箱绑定状态失败", logger.Field("error", err.Error()))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "查询邮箱绑定状态失败")
}
} else if existingMethod.Id != 0 {
// 邮箱已存在,使用现有的邮箱用户
emailUserId = existingMethod.UserId
l.Infow("邮箱已存在,将设备转移到现有邮箱用户",
logger.Field("email", req.Email),
logger.Field("email_user_id", emailUserId))
// 创建前 需要 吧 原本的 user_devices 表中过的数据删除掉 防止出现两个记录
devices, _, err := l.svcCtx.UserModel.QueryDeviceList(l.ctx, u.Id)
if err != nil {
l.Errorw("查询用户设备列表失败", logger.Field("error", err.Error()), logger.Field("email_user_id", emailUserId))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "查询用户设备列表失败")
}
for _, device := range devices {
// 删除原本的设备记录
err = l.svcCtx.UserModel.DeleteDevice(l.ctx, device.Id)
if err != nil {
l.Errorw("删除邮箱用户设备记录失败", logger.Field("error", err.Error()), logger.Field("email_user_id", emailUserId))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "删除原本的设备记录失败")
}
}
// 再次更新 user_auth_method 因为之前 默认 设备登录的时候 创建了一个设备认证数据
// 现在需要 更新 为 邮箱认证
err = l.updateAuthMethodForEmailUser(emailUserId, deviceIdentifier)
if err != nil {
l.Errorw("更新邮箱用户认证方法失败", logger.Field("error", err.Error()), logger.Field("email_user_id", emailUserId))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "更新邮箱用户认证方法失败")
}
// 需要删除原本 user 表中的 记录: 根据 设备 ID
err = l.deleteUserRecordForEmailUser(u.Id)
if err != nil {
l.Errorw("删除用户记录失败", logger.Field("error", err.Error()), logger.Field("email_user_id", emailUserId))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "删除用户记录失败")
}
err = l.createDeviceRecordForEmailUser(emailUserId, deviceIdentifier, "")
if err != nil {
l.Errorw("创建邮箱用户设备记录失败", logger.Field("error", err.Error()), logger.Field("email_user_id", emailUserId))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "创建邮箱用户设备记录失败")
}
}
// 4. 生成新的JWT token
token, err := l.generateTokenForUser(emailUserId)
if err != nil {
l.Errorw("生成JWT token失败", logger.Field("error", err.Error()), logger.Field("email_user_id", emailUserId))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "生成JWT token失败")
}
return &types.BindEmailWithVerificationResponse{
Success: true,
Message: "设备关联成功",
Token: token,
UserId: emailUserId,
}, nil
}
// getCurrentUserDeviceIdentifier 获取当前用户的设备标识符
func (l *BindEmailWithVerificationLogic) getCurrentUserDeviceIdentifier(ctx context.Context, userId int64) (string, error) {
authMethods, err := l.svcCtx.UserModel.FindUserAuthMethods(ctx, userId)
if err != nil {
return "", err
}
// 查找设备认证方式
for _, method := range authMethods {
if method.AuthType == "device" {
return method.AuthIdentifier, nil
}
}
return "", errors.New("用户没有设备认证方式")
}
// checkIfPureDeviceUser 检查用户是否为纯设备用户(只有设备认证方式)
func (l *BindEmailWithVerificationLogic) checkIfPureDeviceUser(ctx context.Context, userId int64) (bool, string, error) {
authMethods, err := l.svcCtx.UserModel.FindUserAuthMethods(ctx, userId)
if err != nil {
l.Errorw("查询用户认证方式失败", logger.Field("error", err.Error()), logger.Field("user_id", userId))
return false, "", errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "查询用户认证方式失败")
}
// 检查是否只有一个设备认证方式
if len(authMethods) == 1 && authMethods[0].AuthType == "device" {
return true, authMethods[0].AuthIdentifier, nil
}
return false, "", nil
}
// 邮箱存在的情况:在 user_devices 中创建一条设备记录
func (l *BindEmailWithVerificationLogic) createDeviceRecordForEmailUser(emailUserId int64, deviceIdentifier string, userAgent string) error {
// online 默认 0 enabled 默认 1
l.Infow("创建邮箱用户设备记录",
logger.Field("email_user_id", emailUserId),
logger.Field("device_identifier", deviceIdentifier),
logger.Field("online", true),
logger.Field("enabled", false),
logger.Field("user_agent", userAgent))
err := l.svcCtx.UserModel.InsertDevice(l.ctx, &user.Device{
UserId: emailUserId,
Identifier: deviceIdentifier,
Online: false,
Enabled: false,
UserAgent: userAgent,
})
if err != nil {
l.Errorw("创建邮箱用户设备记录失败", logger.Field("error", err.Error()), logger.Field("email_user_id", emailUserId))
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "创建邮箱用户设备记录失败")
}
l.Infow("成功创建邮箱用户设备记录",
logger.Field("email_user_id", emailUserId),
logger.Field("device_identifier", deviceIdentifier))
return nil
}
// 邮箱不存在的情况: 在 user_auth_methods 中添加记录 以当前设备ID 做关联, 此时 user_devices 中不需要变动
func (l *BindEmailWithVerificationLogic) addAuthMethodForEmailUser(userId int64, email string) error {
l.Infow("添加邮箱用户认证方法",
logger.Field("user_id", userId),
logger.Field("email", email))
// 插入邮箱用户认证方法
err := l.svcCtx.UserModel.InsertUserAuthMethods(l.ctx, &user.AuthMethods{
UserId: userId,
AuthType: "email",
AuthIdentifier: email,
})
if err != nil {
l.Errorw("插入邮箱用户认证方法失败", logger.Field("error", err.Error()), logger.Field("user_id", userId))
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "插入邮箱用户认证方法失败")
}
l.Infow("成功添加邮箱用户认证方法",
logger.Field("user_id", userId),
logger.Field("email", email))
return nil
}
// transferDeviceToEmailUser
func (l *BindEmailWithVerificationLogic) transferDeviceToEmailUser(deviceUserId, emailUserId int64, deviceIdentifier string) (*types.BindEmailWithVerificationResponse, error) {
l.Infow("开始设备转移",
logger.Field("device_user_id", deviceUserId),
logger.Field("email_user_id", emailUserId),
logger.Field("device_identifier", deviceIdentifier))
// 1. 先获取当前用户的SessionId用于后续清理 可以不需要
currentSessionId := ""
if sessionIdValue := l.ctx.Value(constant.CtxKeySessionID); sessionIdValue != nil {
currentSessionId = sessionIdValue.(string)
}
// 2. 在事务中执行设备转移
err := l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error {
// 1. 检查目标邮箱用户状态
emailUser, err := l.svcCtx.UserModel.FindOne(l.ctx, emailUserId)
if err != nil {
l.Errorw("查询邮箱用户失败", logger.Field("error", err.Error()), logger.Field("email_user_id", emailUserId))
return err
}
// 2. 获取原设备用户信息
deviceUser, err := l.svcCtx.UserModel.FindOne(l.ctx, deviceUserId)
if err != nil {
l.Errorw("查询设备用户失败", logger.Field("error", err.Error()), logger.Field("device_user_id", deviceUserId))
return err
}
// 3. 如果邮箱用户没有ReferCode则从设备用户转移或生成新的
if emailUser.ReferCode == "" {
if deviceUser.ReferCode != "" {
// 转移设备用户的ReferCode
if err := db.Model(&user.User{}).Where("id = ?", emailUserId).Update("refer_code", deviceUser.ReferCode).Error; err != nil {
l.Errorw("转移ReferCode失败", logger.Field("error", err.Error()))
return err
}
l.Infow("已转移设备用户的ReferCode到邮箱用户",
logger.Field("device_user_id", deviceUserId),
logger.Field("email_user_id", emailUserId),
logger.Field("refer_code", deviceUser.ReferCode))
} else {
// 为邮箱用户生成新的ReferCode
newReferCode := uuidx.UserInviteCode(emailUserId)
if err := db.Model(&user.User{}).Where("id = ?", emailUserId).Update("refer_code", newReferCode).Error; err != nil {
l.Errorw("生成邮箱用户ReferCode失败", logger.Field("error", err.Error()))
return err
}
l.Infow("已为邮箱用户生成新的ReferCode",
logger.Field("email_user_id", emailUserId),
logger.Field("refer_code", newReferCode))
}
}
// 4. 如果邮箱用户没有RefererId但设备用户有则转移RefererId
if emailUser.RefererId == 0 && deviceUser.RefererId != 0 {
if err := db.Model(&user.User{}).Where("id = ?", emailUserId).Update("referer_id", deviceUser.RefererId).Error; err != nil {
l.Errorw("转移RefererId失败", logger.Field("error", err.Error()))
return err
}
l.Infow("已转移设备用户的RefererId到邮箱用户",
logger.Field("device_user_id", deviceUserId),
logger.Field("email_user_id", emailUserId),
logger.Field("referer_id", deviceUser.RefererId))
}
// 5. 检查设备是否已经关联到目标用户
existingDevice, err := l.svcCtx.UserModel.FindOneDeviceByIdentifier(l.ctx, deviceIdentifier)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
l.Errorw("查询设备信息失败", logger.Field("error", err.Error()), logger.Field("device_identifier", deviceIdentifier))
return err
}
if existingDevice != nil && existingDevice.UserId == emailUserId {
// 设备已经关联到目标用户直接生成token
l.Infow("设备已关联到目标用户", logger.Field("device_id", existingDevice.Id))
return nil
}
// 6. 处理设备冲突 - 将现有设备记录的归属修改为邮箱用户
if existingDevice != nil && existingDevice.UserId != emailUserId {
l.Infow("更新冲突设备记录的归属", logger.Field("existing_device_id", existingDevice.Id), logger.Field("old_user_id", existingDevice.UserId), logger.Field("new_user_id", emailUserId))
if err := db.Model(&user.Device{}).Where("identifier = ? AND user_id = ?", deviceIdentifier, existingDevice.UserId).Update("user_id", emailUserId).Error; err != nil {
l.Errorw("更新冲突设备记录归属失败", logger.Field("error", err.Error()))
return err
}
}
// 7. 更新user_auth_methods表 - 将设备认证方式转移到邮箱用户
if err := db.Model(&user.AuthMethods{}).
Where("user_id = ? AND auth_type = ? AND auth_identifier = ?", deviceUserId, "device", deviceIdentifier).
Update("user_id", emailUserId).Error; err != nil {
l.Errorw("更新设备认证方式失败", logger.Field("error", err.Error()))
return err
}
// 8. 更新user_device表 - 将设备记录转移到邮箱用户
if err := db.Model(&user.Device{}).
Where("user_id = ? AND identifier = ?", deviceUserId, deviceIdentifier).
Update("user_id", emailUserId).Error; err != nil {
l.Errorw("更新设备记录失败", logger.Field("error", err.Error()))
return err
}
l.Infow("设备转移成功",
logger.Field("device_user_id", deviceUserId),
logger.Field("email_user_id", emailUserId),
logger.Field("device_identifier", deviceIdentifier))
return nil
})
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "设备转移失败: %v", err)
}
// 3. 清理原用户的SessionId缓存使旧token失效
if currentSessionId != "" {
sessionKey := fmt.Sprintf("%v:%v", config.SessionIdKey, currentSessionId)
if err := l.svcCtx.Redis.Del(l.ctx, sessionKey).Err(); err != nil {
l.Errorw("清理原SessionId缓存失败", logger.Field("error", err.Error()), logger.Field("session_id", currentSessionId))
// 不返回错误,继续执行
} else {
l.Infow("已清理原SessionId缓存", logger.Field("session_id", currentSessionId))
}
}
// 4. 生成新的JWT token
token, err := l.generateTokenForUser(emailUserId)
if err != nil {
return nil, err
}
// // 5. 强制清除邮箱用户的所有相关缓存(确保获取最新数据)// 清除邮箱用户缓存
// emailUser, _ := l.svcCtx.UserModel.FindOne(l.ctx, emailUserId)
// if emailUser != nil {
// // 清除用户的批量相关缓存(包括设备、认证方法等)
// if err := l.svcCtx.UserModel.BatchClearRelatedCache(l.ctx, emailUser); err != nil {
// l.Errorw("清理邮箱用户相关缓存失败", logger.Field("error", err.Error()), logger.Field("user_id", emailUser.Id))
// }
// }
// 6. 清除设备相关缓存
// l.clearDeviceRelatedCache(deviceIdentifier, deviceUserId, emailUserId)
return &types.BindEmailWithVerificationResponse{
Success: true,
Message: "设备关联成功",
Token: token,
UserId: emailUserId,
}, nil
}
// generateTokenForUser 为指定用户生成JWT token
func (l *BindEmailWithVerificationLogic) generateTokenForUser(userId int64) (string, error) {
// 生成JWT token
accessExpire := l.svcCtx.Config.JwtAuth.AccessExpire
sessionId := uuidx.NewUUID().String()
jwtToken, err := jwt.NewJwtToken(
l.svcCtx.Config.JwtAuth.AccessSecret,
time.Now().Unix(),
l.svcCtx.Config.JwtAuth.AccessExpire,
jwt.WithOption("UserId", userId),
jwt.WithOption("SessionId", sessionId),
jwt.WithOption("LoginType", "device"),
)
if err != nil {
l.Errorw("生成JWT token失败", logger.Field("error", err.Error()), logger.Field("user_id", userId))
return "", errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "生成token失败: %v", err)
}
// 设置session缓存
sessionKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId)
if err := l.svcCtx.Redis.Set(l.ctx, sessionKey, userId, time.Duration(accessExpire)*time.Second).Err(); err != nil {
l.Errorw("设置session缓存失败", logger.Field("error", err.Error()), logger.Field("user_id", userId))
// session缓存失败不影响token生成只记录错误
}
l.Infow("为用户生成token成功", logger.Field("user_id", userId))
return jwtToken, nil
}
// createEmailUser 创建新的邮箱用户
func (l *BindEmailWithVerificationLogic) createEmailUser(email string) (int64, error) {
// 检查是否启用了强制邀请码
if l.svcCtx.Config.Invite.ForcedInvite {
l.Errorw("邮箱绑定创建新用户时需要邀请码但当前API不支持邀请码参数",
logger.Field("email", email),
logger.Field("forced_invite", true))
return 0, xerr.NewErrMsg("创建新用户需要邀请码,请使用支持邀请码的注册方式")
}
var newUserId int64
err := l.svcCtx.UserModel.Transaction(l.ctx, func(tx *gorm.DB) error {
// 1. 创建新用户
enabled := true
newUser := &user.User{
Enable: &enabled, // 启用状态
OnlyFirstPurchase: &l.svcCtx.Config.Invite.OnlyFirstPurchase,
}
if err := tx.Create(newUser).Error; err != nil {
l.Errorw("创建用户失败", logger.Field("error", err.Error()))
return err
}
newUserId = newUser.Id
l.Infow("创建新用户成功", logger.Field("user_id", newUserId))
// 2. 生成并设置用户的ReferCode
newUser.ReferCode = uuidx.UserInviteCode(newUserId)
if err := tx.Model(&user.User{}).Where("id = ?", newUserId).Update("refer_code", newUser.ReferCode).Error; err != nil {
l.Errorw("更新用户ReferCode失败", logger.Field("error", err.Error()))
return err
}
l.Infow("设置用户ReferCode成功",
logger.Field("user_id", newUserId),
logger.Field("refer_code", newUser.ReferCode))
// 3. 创建邮箱认证方法
emailAuth := &user.AuthMethods{
UserId: newUserId,
AuthType: "email",
AuthIdentifier: email,
Verified: true, // 直接设置为已验证
}
if err := tx.Create(emailAuth).Error; err != nil {
l.Errorw("创建邮箱认证方法失败", logger.Field("error", err.Error()))
return err
}
l.Infow("创建邮箱认证方法成功",
logger.Field("user_id", newUserId),
logger.Field("email", email))
// 4. 检查是否需要激活试用订阅
if l.svcCtx.Config.Register.EnableTrial {
if err := l.activeTrial(newUserId, tx); err != nil {
l.Errorw("激活试用订阅失败",
logger.Field("error", err.Error()),
logger.Field("user_id", newUserId))
return err
}
l.Infow("激活试用订阅成功", logger.Field("user_id", newUserId))
}
return nil
})
if err != nil {
return 0, err
}
return newUserId, nil
}
// clearDeviceRelatedCache 清除设备相关缓存
func (l *BindEmailWithVerificationLogic) clearDeviceRelatedCache(deviceIdentifier string, oldUserId, newUserId int64) {
// 清除设备相关的缓存键
deviceCacheKeys := []string{
fmt.Sprintf("cache:device:identifier:%s", deviceIdentifier),
fmt.Sprintf("cache:user:devices:%d", oldUserId),
fmt.Sprintf("cache:user:devices:%d", newUserId),
fmt.Sprintf("cache:user:auth_methods:%d", oldUserId),
fmt.Sprintf("cache:user:auth_methods:%d", newUserId),
fmt.Sprintf("cache:user:%d", oldUserId),
fmt.Sprintf("cache:user:%d", newUserId),
}
for _, key := range deviceCacheKeys {
if err := l.svcCtx.Redis.Del(l.ctx, key).Err(); err != nil {
l.Errorw("清除设备缓存失败", logger.Field("error", err.Error()), logger.Field("cache_key", key))
} else {
l.Infow("已清除设备缓存", logger.Field("cache_key", key))
}
}
}
// activeTrial 为新用户激活试用订阅
func (l *BindEmailWithVerificationLogic) activeTrial(userId int64, tx *gorm.DB) error {
// 获取试用订阅模板
sub, err := l.svcCtx.SubscribeModel.FindOne(l.ctx, l.svcCtx.Config.Register.TrialSubscribe)
if err != nil {
l.Errorw("获取试用订阅模板失败",
logger.Field("user_id", userId),
logger.Field("trial_subscribe_id", l.svcCtx.Config.Register.TrialSubscribe),
logger.Field("error", err.Error()))
return err
}
// 计算试用期时间
startTime := time.Now()
expireTime := tool.AddTime(l.svcCtx.Config.Register.TrialTimeUnit, l.svcCtx.Config.Register.TrialTime, startTime)
subscribeToken := uuidx.SubscribeToken(fmt.Sprintf("Trial-%v", userId))
subscribeUUID := uuidx.NewUUID().String()
// 创建用户订阅记录
userSub := &user.Subscribe{
UserId: userId,
OrderId: 0,
SubscribeId: sub.Id,
StartTime: startTime,
ExpireTime: expireTime,
Traffic: sub.Traffic,
Download: 0,
Upload: 0,
Token: subscribeToken,
UUID: subscribeUUID,
Status: 1,
}
// 插入订阅记录
if err := tx.Create(userSub).Error; err != nil {
l.Errorw("插入试用订阅记录失败",
logger.Field("user_id", userId),
logger.Field("error", err.Error()))
return err
}
l.Infow("试用订阅激活成功",
logger.Field("user_id", userId),
logger.Field("subscribe_id", sub.Id),
logger.Field("expire_time", expireTime),
logger.Field("traffic", sub.Traffic))
return nil
}
// updateAuthMethodForEmailUser 根据 设备ID 找到原本的记录 然后 调整 user_id
func (l *BindEmailWithVerificationLogic) updateAuthMethodForEmailUser(userId int64, deviceIdentifier string) error {
var userAuth user.AuthMethods
if err := l.svcCtx.UserModel.Transaction(l.ctx, func(tx *gorm.DB) error {
// 查询设备认证方法
if err := tx.Model(&user.AuthMethods{}).
Where("auth_identifier = ? AND auth_type = ?", deviceIdentifier, "device").
First(&userAuth).Error; err != nil {
l.Errorw("查询设备认证方法失败",
logger.Field("device_identifier", deviceIdentifier),
logger.Field("error", err.Error()))
return err
}
// 更新用户认证方法为 email
if err := tx.Model(&user.AuthMethods{}).
Where("id = ?", userAuth.Id).
Update("user_id", userId).Error; err != nil {
l.Errorw("更新用户设备 用户关联 失败",
logger.Field("user_id", userId),
logger.Field("device_identifier", deviceIdentifier),
logger.Field("error", err.Error()))
return err
}
l.Infow("更新用户设备 用户关联 成功",
logger.Field("user_id", userId),
logger.Field("device_identifier", deviceIdentifier))
return nil
}); err != nil {
return err
}
return nil
}
// 根据用户iD 删除 user 表中的记录
func (l *BindEmailWithVerificationLogic) deleteUserRecordForEmailUser(userId int64) error {
if err := l.svcCtx.UserModel.Transaction(l.ctx, func(tx *gorm.DB) error {
// 删除用户记录
if err := tx.Delete(&user.User{}, userId).Error; err != nil {
l.Errorw("删除用户记录失败",
logger.Field("user_id", userId),
logger.Field("error", err.Error()))
return err
}
l.Infow("删除用户记录成功", logger.Field("user_id", userId))
return nil
}); err != nil {
return err
}
return nil
}