109 lines
3.3 KiB
Go
109 lines
3.3 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/ponzischeme89/memby/server/internal/cache"
|
|
"github.com/ponzischeme89/memby/server/internal/store"
|
|
)
|
|
|
|
const notificationPreferencesTTL = 5 * time.Minute
|
|
|
|
func notificationPreferencesKey(userID string) string {
|
|
return cache.UserKey(userID, "notification-preferences:v2")
|
|
}
|
|
|
|
// notificationPreferencesFor keeps the ten-second status poll off Postgres. Redis also
|
|
// shares the answer if the gateway is ever run with more than one replica; writes replace
|
|
// it immediately, while the short TTL still picks up an operator's direct database edit.
|
|
func (s *Server) notificationPreferencesFor(ctx context.Context, userID string) (store.NotificationPreferences, error) {
|
|
defaults := store.DefaultNotificationPreferences()
|
|
if userID == "" || s.store == nil {
|
|
return defaults, nil
|
|
}
|
|
if s.cache != nil {
|
|
if raw, err := s.cache.Get(ctx, notificationPreferencesKey(userID)); err == nil {
|
|
prefs := defaults
|
|
if json.Unmarshal(raw, &prefs) == nil {
|
|
return prefs, nil
|
|
}
|
|
}
|
|
}
|
|
prefs, err := s.store.NotificationPreferences(ctx, userID)
|
|
if err != nil {
|
|
return defaults, err
|
|
}
|
|
s.cacheNotificationPreferences(ctx, userID, prefs)
|
|
return prefs, nil
|
|
}
|
|
|
|
func (s *Server) cacheNotificationPreferences(ctx context.Context, userID string, prefs store.NotificationPreferences) {
|
|
if s.cache == nil || userID == "" {
|
|
return
|
|
}
|
|
if raw, err := json.Marshal(prefs); err == nil {
|
|
_ = s.cache.Set(ctx, notificationPreferencesKey(userID), raw, notificationPreferencesTTL)
|
|
}
|
|
}
|
|
|
|
func (s *Server) saveNotificationPreferences(ctx context.Context, userID string, prefs store.NotificationPreferences) error {
|
|
if err := s.store.SetNotificationPreferences(ctx, userID, prefs); err != nil {
|
|
return err
|
|
}
|
|
s.cacheNotificationPreferences(ctx, userID, prefs)
|
|
return nil
|
|
}
|
|
|
|
func filterClientAlerts(alerts []clientAlert, prefs store.NotificationPreferences) []clientAlert {
|
|
if !prefs.Enabled {
|
|
return []clientAlert{}
|
|
}
|
|
filtered := make([]clientAlert, 0, len(alerts))
|
|
for _, alert := range alerts {
|
|
allowed := true
|
|
switch alert.Kind {
|
|
case alertKindSonarrAired:
|
|
allowed = prefs.SonarrAlerts
|
|
case alertKindRadarrImport:
|
|
allowed = prefs.RadarrAlerts
|
|
case alertKindLibrarySync:
|
|
allowed = prefs.LibraryAlerts
|
|
case alertKindServerDown, alertKindServerUp, alertKindDeploying:
|
|
allowed = prefs.SystemAlerts
|
|
}
|
|
if allowed {
|
|
filtered = append(filtered, alert)
|
|
}
|
|
}
|
|
return filtered
|
|
}
|
|
|
|
func filterStoredNotifications(notifications []store.UserNotification, prefs store.NotificationPreferences) []store.UserNotification {
|
|
if !prefs.Enabled {
|
|
return []store.UserNotification{}
|
|
}
|
|
if prefs.SonarrAlerts && prefs.WatchTimeDigest {
|
|
return notifications
|
|
}
|
|
filtered := make([]store.UserNotification, 0, len(notifications))
|
|
for _, notification := range notifications {
|
|
switch notification.Kind {
|
|
case "show-return", "show-added", "show-cancelled", "auto-follow":
|
|
if !prefs.SonarrAlerts {
|
|
continue
|
|
}
|
|
// A summary already sitting in somebody's list is withdrawn the moment they turn
|
|
// these off, rather than waiting to be dismissed one at a time: switching a weekly
|
|
// notice off is a statement about the ones already there as much as the next one.
|
|
case watchTimeWeeklyKind, watchTimeMonthlyKind:
|
|
if !prefs.WatchTimeDigest {
|
|
continue
|
|
}
|
|
}
|
|
filtered = append(filtered, notification)
|
|
}
|
|
return filtered
|
|
}
|