85 lines
2.9 KiB
Go
85 lines
2.9 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// CustomerDevice is one install of the customer app that can receive push
|
|
// notifications.
|
|
type CustomerDevice struct {
|
|
CustomerID uuid.UUID
|
|
DeviceID string
|
|
Platform *string
|
|
FCMToken string
|
|
AppVersion *string
|
|
}
|
|
|
|
// CustomerDeviceRepository keeps the FCM tokens of the customer app.
|
|
type CustomerDeviceRepository interface {
|
|
// Register saves the device's current token. A token is only ever one customer's:
|
|
// registering it takes it away from whoever had it before on that phone, so they
|
|
// stop getting this customer's notifications.
|
|
Register(ctx context.Context, device CustomerDevice, now time.Time) error
|
|
// Unregister forgets a device, for instance on logout. An unknown device is not an error.
|
|
Unregister(ctx context.Context, customerID uuid.UUID, deviceID string) error
|
|
ListTokens(ctx context.Context, customerID uuid.UUID) ([]string, error)
|
|
}
|
|
|
|
type customerDeviceRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewCustomerDeviceRepository(db *gorm.DB) CustomerDeviceRepository {
|
|
return &customerDeviceRepository{db: db}
|
|
}
|
|
|
|
func (r *customerDeviceRepository) Register(ctx context.Context, d CustomerDevice, now time.Time) error {
|
|
return DBFromContext(ctx, r.db).WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
err := tx.Exec(`DELETE FROM customer_devices WHERE fcm_token = ? AND NOT (customer_id = ? AND device_id = ?)`,
|
|
d.FCMToken, d.CustomerID, d.DeviceID).Error
|
|
if err != nil {
|
|
return fmt.Errorf("failed to release FCM token: %w", err)
|
|
}
|
|
err = tx.Exec(`INSERT INTO customer_devices (customer_id, device_id, platform, fcm_token, app_version, last_active_at)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (customer_id, device_id) DO UPDATE SET
|
|
platform = EXCLUDED.platform,
|
|
fcm_token = EXCLUDED.fcm_token,
|
|
app_version = EXCLUDED.app_version,
|
|
last_active_at = EXCLUDED.last_active_at,
|
|
updated_at = NOW()`,
|
|
d.CustomerID, d.DeviceID, d.Platform, d.FCMToken, d.AppVersion, now).Error
|
|
if err != nil {
|
|
return fmt.Errorf("failed to register customer device: %w", err)
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (r *customerDeviceRepository) Unregister(ctx context.Context, customerID uuid.UUID, deviceID string) error {
|
|
err := DBFromContext(ctx, r.db).WithContext(ctx).
|
|
Exec(`DELETE FROM customer_devices WHERE customer_id = ? AND device_id = ?`, customerID, deviceID).Error
|
|
if err != nil {
|
|
return fmt.Errorf("failed to unregister customer device: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *customerDeviceRepository) ListTokens(ctx context.Context, customerID uuid.UUID) ([]string, error) {
|
|
var tokens []string
|
|
err := DBFromContext(ctx, r.db).WithContext(ctx).
|
|
Table("customer_devices").
|
|
Where("customer_id = ? AND fcm_token <> ''", customerID).
|
|
Order("last_active_at DESC NULLS LAST").
|
|
Pluck("fcm_token", &tokens).Error
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list customer FCM tokens: %w", err)
|
|
}
|
|
return tokens, nil
|
|
}
|