package user import ( "context" "fmt" "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/logger" "github.com/perfect-panel/server/pkg/uuidx" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" "gorm.io/gorm" ) type UnbindDeviceLogic struct { logger.Logger ctx context.Context svcCtx *svc.ServiceContext } // Unbind Device func NewUnbindDeviceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UnbindDeviceLogic { return &UnbindDeviceLogic{ Logger: logger.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error { // 获取当前 token 登录的用户 userInfo := l.ctx.Value(constant.CtxKeyUser).(*user.User) // 查询解绑设备是否存在 device, err := l.svcCtx.UserModel.FindOneDevice(l.ctx, req.Id) if err != nil { return errors.Wrapf(xerr.NewErrCode(xerr.DeviceNotExist), "find device") } if device.UserId != userInfo.Id { return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "device not belong to user") } identifier := device.Identifier l.svcCtx.DB.Transaction(func(tx *gorm.DB) error { // 业务逻辑修改: 如果解绑; 那么 就把 设备关系 和 邮箱关系 拆开 var deleteDevice user.Device // 删除了 设备 记录 err = tx.Model(&deleteDevice).Where("id = ?", req.Id).First(&deleteDevice).Error if err != nil { return errors.Wrapf(xerr.NewErrCode(xerr.QueueEnqueueError), "find device err: %v", err) } err = tx.Delete(deleteDevice).Error if err != nil { return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete device err: %v", err) } var userAuth user.AuthMethods err = tx.Model(&userAuth).Where("auth_identifier = ? and auth_type = ?", deleteDevice.Identifier, "device").First(&userAuth).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil } return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find device online record err: %v", err) } err = tx.Delete(&userAuth).Error if err != nil { return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseDeletedError), "delete device online record err: %v", err) } var count int64 err = tx.Model(user.AuthMethods{}).Where("user_id = ?", deleteDevice.UserId).Count(&count).Error if err != nil { return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "count user auth methods err: %v", err) } if count < 1 { _ = tx.Where("id = ?", deleteDevice.UserId).Delete(&user.User{}).Error } //remove device cache deviceCacheKey := fmt.Sprintf("%v:%v", config.DeviceCacheKeyKey, deleteDevice.Identifier) if sessionId, err := l.svcCtx.Redis.Get(l.ctx, deviceCacheKey).Result(); err == nil && sessionId != "" { _ = l.svcCtx.Redis.Del(l.ctx, deviceCacheKey).Err() sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId) _ = l.svcCtx.Redis.Del(l.ctx, sessionIdCacheKey).Err() } return nil }) // 最后 创建一个 新的 设备 用户信息 绕过 赠送套餐 l.registerUserAndDevice(identifier) return nil } func (l *UnbindDeviceLogic) registerUserAndDevice(identifier string) (*user.User, error) { l.Infow("删除新建 设备 用户", logger.Field("identifier", identifier), ) var userInfo *user.User err := l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { // Create new user userInfo = &user.User{ Salt: "default", OnlyFirstPurchase: &l.svcCtx.Config.Invite.OnlyFirstPurchase, } if err := db.Create(userInfo).Error; err != nil { l.Errorw("failed to create user", logger.Field("error", err.Error()), ) return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create user failed: %v", err) } // Update refer code userInfo.ReferCode = uuidx.UserInviteCode(userInfo.Id) if err := db.Model(&user.User{}).Where("id = ?", userInfo.Id).Update("refer_code", userInfo.ReferCode).Error; err != nil { l.Errorw("failed to update refer code", logger.Field("user_id", userInfo.Id), logger.Field("error", err.Error()), ) return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "update refer code failed: %v", err) } // Create device auth method authMethod := &user.AuthMethods{ UserId: userInfo.Id, AuthType: "device", AuthIdentifier: identifier, Verified: true, } if err := db.Create(authMethod).Error; err != nil { l.Errorw("failed to create device auth method", logger.Field("user_id", userInfo.Id), logger.Field("identifier", identifier), logger.Field("error", err.Error()), ) return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "create device auth method failed: %v", err) } // Insert device record deviceInfo := &user.Device{ Ip: "", UserId: userInfo.Id, UserAgent: "", Identifier: identifier, Enabled: true, Online: false, } if err := db.Create(deviceInfo).Error; err != nil { l.Errorw("failed to insert device", logger.Field("user_id", userInfo.Id), logger.Field("identifier", identifier), logger.Field("error", err.Error()), ) return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseInsertError), "insert device failed: %v", err) } return nil }) if err != nil { l.Errorw("device registration failed", logger.Field("identifier", identifier), logger.Field("error", err.Error()), ) return nil, err } l.Infow("device registration completed successfully", logger.Field("user_id", userInfo.Id), logger.Field("identifier", identifier), logger.Field("refer_code", userInfo.ReferCode), ) return userInfo, nil }