mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-28 15:51:15 +00:00
notification_cursors table stores one read-cursor per user per tenant; GET /v1/activity returns unreadCount + readAt, POST /v1/activity/read persists the cursor. Reminder dispatches now append reminder.sent / reminder.failed system events so delivery history reaches the feed. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
72 lines
2.1 KiB
Go
72 lines
2.1 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
func (r *PGRepository) AppendActivityEvent(ctx context.Context, params ActivityEventParams) error {
|
|
_, err := r.pool.Exec(ctx, `
|
|
INSERT INTO activity_events
|
|
(tenant_id, actor_kind, actor_subject, actor_name, action, entity_type, entity_id, summary)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
`, params.TenantID, params.ActorKind, params.ActorSubject, params.ActorName,
|
|
params.Action, params.EntityType, params.EntityID, params.Summary)
|
|
return err
|
|
}
|
|
|
|
func (r *PGRepository) ListActivityEvents(ctx context.Context, tenantID string, limit int) ([]ActivityEventRecord, error) {
|
|
rows, err := r.pool.Query(ctx, `
|
|
SELECT id, tenant_id, actor_kind, actor_name, action, entity_type, entity_id, summary, created_at
|
|
FROM activity_events
|
|
WHERE tenant_id = $1
|
|
ORDER BY created_at DESC
|
|
LIMIT $2
|
|
`, tenantID, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var events []ActivityEventRecord
|
|
for rows.Next() {
|
|
var rec ActivityEventRecord
|
|
if err := rows.Scan(
|
|
&rec.ID, &rec.TenantID, &rec.ActorKind, &rec.ActorName,
|
|
&rec.Action, &rec.EntityType, &rec.EntityID, &rec.Summary, &rec.CreatedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
events = append(events, rec)
|
|
}
|
|
return events, rows.Err()
|
|
}
|
|
|
|
func (r *PGRepository) GetNotificationCursor(ctx context.Context, tenantID string, userSubject string) (*time.Time, error) {
|
|
var readAt time.Time
|
|
err := r.pool.QueryRow(ctx, `
|
|
SELECT read_at FROM notification_cursors
|
|
WHERE tenant_id = $1 AND user_subject = $2
|
|
`, tenantID, userSubject).Scan(&readAt)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &readAt, nil
|
|
}
|
|
|
|
func (r *PGRepository) SetNotificationCursor(ctx context.Context, tenantID string, userSubject string, readAt time.Time) error {
|
|
_, err := r.pool.Exec(ctx, `
|
|
INSERT INTO notification_cursors (tenant_id, user_subject, read_at)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (tenant_id, user_subject)
|
|
DO UPDATE SET read_at = EXCLUDED.read_at, updated_at = now()
|
|
`, tenantID, userSubject, readAt)
|
|
return err
|
|
}
|