d262f734f0
* mobile: wire notification registration and listener
* implement backend components for push notifications
* refactor: agentic comment cleanup
* docs: use proper module name for particle processor
* set required env variables for push notifications
* bump version
* fix: always upsert push token on mobile start
* Revert "fix: always upsert push token on mobile start"
This reverts commit 90ff18a788.
* send push notifications regardless of online status
96 lines
2.3 KiB
Go
96 lines
2.3 KiB
Go
package pushnotify
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
type repository interface {
|
|
upsert(ctx context.Context, t *PushToken) error
|
|
deleteForHuman(ctx context.Context, humanID, token string) error
|
|
deleteByToken(ctx context.Context, token string) error
|
|
listForHumans(ctx context.Context, humanIDs []string) ([]*PushToken, error)
|
|
}
|
|
|
|
type repositoryImpl struct {
|
|
pool *pgxpool.Pool
|
|
}
|
|
|
|
func newRepository(pool *pgxpool.Pool) repository {
|
|
return &repositoryImpl{pool: pool}
|
|
}
|
|
|
|
func (r *repositoryImpl) upsert(ctx context.Context, t *PushToken) error {
|
|
_, err := r.pool.Exec(ctx,
|
|
`INSERT INTO push_tokens (token, human_id, platform, app_version)
|
|
VALUES ($1, $2, $3, NULLIF($4, ''))
|
|
ON CONFLICT (token) DO UPDATE SET
|
|
human_id = EXCLUDED.human_id,
|
|
platform = EXCLUDED.platform,
|
|
app_version = EXCLUDED.app_version,
|
|
last_seen_at = NOW()`,
|
|
t.Token, t.HumanID, string(t.Platform), t.AppVersion,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (r *repositoryImpl) deleteForHuman(ctx context.Context, humanID, token string) error {
|
|
result, err := r.pool.Exec(ctx,
|
|
`DELETE FROM push_tokens WHERE human_id = $1 AND token = $2`,
|
|
humanID, token,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.RowsAffected() == 0 {
|
|
return ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *repositoryImpl) deleteByToken(ctx context.Context, token string) error {
|
|
_, err := r.pool.Exec(ctx,
|
|
`DELETE FROM push_tokens WHERE token = $1`,
|
|
token,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (r *repositoryImpl) listForHumans(ctx context.Context, humanIDs []string) ([]*PushToken, error) {
|
|
if len(humanIDs) == 0 {
|
|
return nil, nil
|
|
}
|
|
rows, err := r.pool.Query(ctx,
|
|
`SELECT token, human_id, platform, app_version, created_at, last_seen_at
|
|
FROM push_tokens
|
|
WHERE human_id = ANY($1)`,
|
|
humanIDs,
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var tokens []*PushToken
|
|
for rows.Next() {
|
|
var t PushToken
|
|
var appVersion *string
|
|
var platform string
|
|
if err := rows.Scan(&t.Token, &t.HumanID, &platform, &appVersion, &t.CreatedAt, &t.LastSeenAt); err != nil {
|
|
return nil, err
|
|
}
|
|
t.Platform = Platform(platform)
|
|
if appVersion != nil {
|
|
t.AppVersion = *appVersion
|
|
}
|
|
tokens = append(tokens, &t)
|
|
}
|
|
return tokens, rows.Err()
|
|
}
|