hub/internal/notification/manager.go

85 lines
2.5 KiB
Go

package notification
import (
"context"
"encoding/json"
"fmt"
"github.com/artifacthub/hub/internal/hub"
"github.com/jackc/pgx/v4"
"github.com/satori/uuid"
)
const (
// Database queries
addNotificationDBQ = `select add_notification($1::jsonb)`
getPendingNotificationDBQ = `select get_pending_notification()`
updateNotificationStatusDBQ = `select update_notification_status($1::uuid, $2::boolean, $3::text)`
)
// Manager provides an API to manage notifications.
type Manager struct{}
// NewManager creates a new Manager instance.
func NewManager() *Manager {
return &Manager{}
}
// Add adds the provided notification to the database.
func (m *Manager) Add(ctx context.Context, tx pgx.Tx, n *hub.Notification) error {
if _, err := uuid.FromString(n.Event.EventID); err != nil {
return fmt.Errorf("%w: %s", hub.ErrInvalidInput, "invalid event id")
}
if n.User == nil && n.Webhook == nil {
return fmt.Errorf("%w: %s", hub.ErrInvalidInput, "user or webhook must be provided")
}
if n.User != nil && n.Webhook != nil {
return fmt.Errorf("%w: %s", hub.ErrInvalidInput, "both user and webhook were provided")
}
if n.User != nil {
if _, err := uuid.FromString(n.User.UserID); err != nil {
return fmt.Errorf("%w: %s", hub.ErrInvalidInput, "invalid user id")
}
}
if n.Webhook != nil {
if _, err := uuid.FromString(n.Webhook.WebhookID); err != nil {
return fmt.Errorf("%w: %s", hub.ErrInvalidInput, "invalid webhook id")
}
}
nJSON, _ := json.Marshal(n)
_, err := tx.Exec(ctx, addNotificationDBQ, nJSON)
return err
}
// GetPending returns a pending notification to be delivered if available.
func (m *Manager) GetPending(ctx context.Context, tx pgx.Tx) (*hub.Notification, error) {
var dataJSON []byte
if err := tx.QueryRow(ctx, getPendingNotificationDBQ).Scan(&dataJSON); err != nil {
return nil, err
}
var n *hub.Notification
if err := json.Unmarshal(dataJSON, &n); err != nil {
return nil, err
}
return n, nil
}
// UpdateStatus the provided notification status in the database.
func (m *Manager) UpdateStatus(
ctx context.Context,
tx pgx.Tx,
notificationID string,
processed bool,
processedErr error,
) error {
if _, err := uuid.FromString(notificationID); err != nil {
return fmt.Errorf("%w: %s", hub.ErrInvalidInput, "invalid notification id")
}
var processedErrStr string
if processedErr != nil {
processedErrStr = processedErr.Error()
}
_, err := tx.Exec(ctx, updateNotificationStatusDBQ, notificationID, processed, processedErrStr)
return err
}