Files
backend/internal/repository/device_token_repo.go
lafay cb85c62093
All checks were successful
Build Backend / build (push) Successful in 2m32s
Build Backend / build-docker (push) Successful in 6m22s
feat(admin): add admin endpoint to list user devices with JPush registration IDs
- Add AdminDeviceTokenResponse DTO including push_token (RegistrationID) for push debugging
- Add DeviceTokenToAdminResponse and DeviceTokensToAdminResponse converters
- Inject PushService into AdminUserHandler for retrieving user devices
- Register GET /api/v1/admin/users/:id/devices route for querying target user's device tokens
2026-06-18 20:07:24 +08:00

203 lines
6.7 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 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_idpushToken是设备级标识同一物理设备登录不同账号时 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
}