package repository import ( "time" "with_you/internal/model" "gorm.io/gorm" ) // DeviceTokenRepository 设备Token仓储接口 type DeviceTokenRepository interface { Create(token *model.DeviceToken) error GetByID(id int64) (*model.DeviceToken, error) Update(token *model.DeviceToken) error Delete(id int64) error GetByUserID(userID string) ([]*model.DeviceToken, error) GetActiveByUserID(userID string) ([]*model.DeviceToken, error) GetByDeviceID(deviceID string) (*model.DeviceToken, error) GetByPushToken(pushToken string) (*model.DeviceToken, error) // DeactivateByPushToken 失效指定 pushToken 的所有记录 // 用于处理同设备多账号场景:registration_id 是设备级标识, // 当新账号在同一设备注册时,需失效旧账号对该 pushToken 的关联,避免跨账号误推 DeactivateByPushToken(pushToken string) error DeactivateAllExcept(userID int64, deviceID string) error Upsert(token *model.DeviceToken) error UpdateLastUsed(deviceID string) error Deactivate(deviceID string) error Activate(deviceID string) error DeleteByUserID(userID int64) error GetDeviceCountByUserID(userID int64) (int64, error) GetActiveDeviceCountByUserID(userID int64) (int64, error) DeleteInactiveDevices(before time.Time) error } // deviceTokenRepository 设备Token仓储实现 type deviceTokenRepository struct { db *gorm.DB } // NewDeviceTokenRepository 创建设备Token仓储 func NewDeviceTokenRepository(db *gorm.DB) DeviceTokenRepository { return &deviceTokenRepository{db: db} } // Create 创建设备Token func (r *deviceTokenRepository) Create(token *model.DeviceToken) error { return r.db.Create(token).Error } // GetByID 根据ID获取设备Token func (r *deviceTokenRepository) GetByID(id int64) (*model.DeviceToken, error) { var token model.DeviceToken err := r.db.First(&token, "id = ?", id).Error if err != nil { return nil, err } return &token, nil } // Update 更新设备Token func (r *deviceTokenRepository) Update(token *model.DeviceToken) error { return r.db.Save(token).Error } // Delete 删除设备Token(软删除) func (r *deviceTokenRepository) Delete(id int64) error { return r.db.Delete(&model.DeviceToken{}, id).Error } // GetByUserID 获取用户所有设备 // userID 参数为 string 类型(UUID格式),与JWT中user_id保持一致 func (r *deviceTokenRepository) GetByUserID(userID string) ([]*model.DeviceToken, error) { var tokens []*model.DeviceToken err := r.db.Where("user_id = ?", userID). Order("created_at DESC"). Find(&tokens).Error return tokens, err } // GetActiveByUserID 获取用户活跃设备 // userID 参数为 string 类型(UUID格式),与JWT中user_id保持一致 func (r *deviceTokenRepository) GetActiveByUserID(userID string) ([]*model.DeviceToken, error) { var tokens []*model.DeviceToken err := r.db.Where("user_id = ? AND is_active = ?", userID, true). Order("last_used_at DESC"). Find(&tokens).Error return tokens, err } // GetByDeviceID 根据设备ID获取设备Token func (r *deviceTokenRepository) GetByDeviceID(deviceID string) (*model.DeviceToken, error) { var token model.DeviceToken err := r.db.Where("device_id = ?", deviceID).First(&token).Error if err != nil { return nil, err } return &token, nil } // GetByPushToken 根据推送Token获取设备信息 func (r *deviceTokenRepository) GetByPushToken(pushToken string) (*model.DeviceToken, error) { var token model.DeviceToken err := r.db.Where("push_token = ?", pushToken).First(&token).Error if err != nil { return nil, err } return &token, nil } // DeactivateByPushToken 失效指定 pushToken 的所有记录 // registration_id(pushToken)是设备级标识,同一物理设备登录不同账号时 pushToken 不变。 // 失效旧关联可防止给账号 A 推送时,同设备的账号 B 也收到通知。 func (r *deviceTokenRepository) DeactivateByPushToken(pushToken string) error { return r.db.Model(&model.DeviceToken{}). Where("push_token = ?", pushToken). Update("is_active", false).Error } // DeactivateAllExcept 登出其他设备(停用除指定设备外的所有设备) func (r *deviceTokenRepository) DeactivateAllExcept(userID int64, deviceID string) error { return r.db.Model(&model.DeviceToken{}). Where("user_id = ? AND device_id != ?", userID, deviceID). Update("is_active", false).Error } // Upsert 创建或更新设备Token // 如果设备ID已存在,则更新Token和激活状态;否则创建新记录 func (r *deviceTokenRepository) Upsert(token *model.DeviceToken) error { var existing model.DeviceToken err := r.db.Where("device_id = ?", token.DeviceID).First(&existing).Error if err == gorm.ErrRecordNotFound { // 创建新记录 return r.db.Create(token).Error } else if err != nil { return err } // 更新现有记录(包括 user_id,设备可能在用户间转移) return r.db.Model(&existing).Updates(map[string]any{ "user_id": token.UserID, "push_token": token.PushToken, "device_type": token.DeviceType, "is_active": true, "device_name": token.DeviceName, "last_used_at": time.Now(), }).Error } // UpdateLastUsed 更新最后使用时间 func (r *deviceTokenRepository) UpdateLastUsed(deviceID string) error { return r.db.Model(&model.DeviceToken{}). Where("device_id = ?", deviceID). Update("last_used_at", time.Now()).Error } // Deactivate 停用设备 func (r *deviceTokenRepository) Deactivate(deviceID string) error { return r.db.Model(&model.DeviceToken{}). Where("device_id = ?", deviceID). Update("is_active", false).Error } // Activate 激活设备 func (r *deviceTokenRepository) Activate(deviceID string) error { return r.db.Model(&model.DeviceToken{}). Where("device_id = ?", deviceID). Updates(map[string]any{ "is_active": true, "last_used_at": time.Now(), }).Error } // DeleteByUserID 删除用户所有设备Token func (r *deviceTokenRepository) DeleteByUserID(userID int64) error { return r.db.Where("user_id = ?", userID).Delete(&model.DeviceToken{}).Error } // GetDeviceCountByUserID 获取用户设备数量 func (r *deviceTokenRepository) GetDeviceCountByUserID(userID int64) (int64, error) { var count int64 err := r.db.Model(&model.DeviceToken{}). Where("user_id = ?", userID). Count(&count).Error return count, err } // GetActiveDeviceCountByUserID 获取用户活跃设备数量 func (r *deviceTokenRepository) GetActiveDeviceCountByUserID(userID int64) (int64, error) { var count int64 err := r.db.Model(&model.DeviceToken{}). Where("user_id = ? AND is_active = ?", userID, true). Count(&count).Error return count, err } // DeleteInactiveDevices 删除长时间未使用的设备 func (r *deviceTokenRepository) DeleteInactiveDevices(before time.Time) error { return r.db.Where("is_active = ? AND last_used_at < ?", false, before). Delete(&model.DeviceToken{}).Error }