Files
gochat/internal/service/notification_service.go
T

150 lines
5.9 KiB
Go

package service
import (
"context"
"time"
"gorm.io/gorm"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/repository"
)
type NotificationListOptions struct {
IncludeRead bool
IncludeSnoozed bool
SortOrder string
}
type NotificationListResult struct {
Notifications []model.Notification
Total int64
UnreadCount int64
}
// NotificationService provides business logic for notifications and notification preferences.
// Reference: Chatwoot app/services/notification_service.rb
type NotificationService struct {
db *gorm.DB
notifRepo *repository.NotificationRepo
prefRepo *repository.NotificationPreferenceRepo
}
// NewNotificationService creates a new Notification service with required dependencies.
func NewNotificationService(
db *gorm.DB,
notifRepo *repository.NotificationRepo,
prefRepo *repository.NotificationPreferenceRepo,
) *NotificationService {
return &NotificationService{
db: db,
notifRepo: notifRepo,
prefRepo: prefRepo,
}
}
// --- Notification CRUD operations ---
// GetNotification retrieves a single notification by ID.
func (s *NotificationService) GetNotification(ctx context.Context, id uint) (*model.Notification, error) {
return s.notifRepo.FindByID(ctx, id)
}
// ListNotifications retrieves all notifications for a user with pagination.
func (s *NotificationService) ListNotifications(ctx context.Context, userID uint, page, perPage int) ([]model.Notification, int64, error) {
offset := (page - 1) * perPage
return s.notifRepo.ListByUser(ctx, userID, offset, perPage)
}
// ListNotificationsByAccount retrieves notifications for a user within an account.
func (s *NotificationService) ListNotificationsByAccount(ctx context.Context, userID uint, accountID uint, page, perPage int) ([]model.Notification, int64, error) {
offset := (page - 1) * perPage
return s.notifRepo.ListByUserAndAccount(ctx, userID, accountID, offset, perPage)
}
func (s *NotificationService) ListNotificationsByAccountWithOptions(ctx context.Context, userID uint, accountID uint, page, perPage int, opts NotificationListOptions) (*NotificationListResult, error) {
offset := (page - 1) * perPage
items, total, unreadCount, err := s.notifRepo.ListByUserAndAccountFiltered(ctx, userID, accountID, offset, perPage, repository.NotificationListFilter{
IncludeRead: opts.IncludeRead,
IncludeSnoozed: opts.IncludeSnoozed,
SortOrder: opts.SortOrder,
})
if err != nil {
return nil, err
}
return &NotificationListResult{Notifications: items, Total: total, UnreadCount: unreadCount}, nil
}
// CreateNotification creates a new notification.
func (s *NotificationService) CreateNotification(ctx context.Context, notification *model.Notification) error {
return s.notifRepo.Create(ctx, notification)
}
// MarkRead marks a single notification as read.
func (s *NotificationService) MarkRead(ctx context.Context, id uint) error {
return s.notifRepo.MarkRead(ctx, id)
}
// MarkAllRead marks all unread notifications for a user as read.
func (s *NotificationService) MarkAllRead(ctx context.Context, userID uint) error {
return s.notifRepo.MarkAllReadByUser(ctx, userID)
}
// MarkAllReadByAccount marks all unread notifications for a user within an account as read.
func (s *NotificationService) MarkAllReadByAccount(ctx context.Context, userID uint, accountID uint) error {
return s.notifRepo.MarkAllReadByUserAndAccount(ctx, userID, accountID)
}
func (s *NotificationService) MarkPrimaryActorReadByAccount(ctx context.Context, userID, accountID uint, actorType string, actorID uint) error {
return s.notifRepo.MarkPrimaryActorReadByUserAndAccount(ctx, userID, accountID, actorType, actorID)
}
// DeleteNotification soft-deletes a notification.
func (s *NotificationService) DeleteNotification(ctx context.Context, id uint) error {
return s.notifRepo.Delete(ctx, id)
}
// GetUnreadCount returns the number of unread notifications for a user.
func (s *NotificationService) GetUnreadCount(ctx context.Context, userID uint) (int64, error) {
return s.notifRepo.CountUnreadByUser(ctx, userID)
}
// --- Notification Preference operations ---
// GetPreferences retrieves all notification preferences for a user within an account.
func (s *NotificationService) GetPreferences(ctx context.Context, userID uint, accountID uint) ([]model.NotificationPreference, error) {
return s.prefRepo.ListByUserAndAccount(ctx, userID, accountID)
}
// UpdatePreferences upserts notification preferences for a user within an account.
func (s *NotificationService) UpdatePreferences(ctx context.Context, userID uint, accountID uint, prefs []model.NotificationPreference) error {
// Enforce userID and accountID on each preference
for i := range prefs {
prefs[i].UserID = userID
prefs[i].AccountID = &accountID
}
return s.prefRepo.BatchUpsert(ctx, prefs)
}
// --- Notification extension operations (G8) ---
// Reference: Chatwoot notifications_controller.rb#snooze, #unread, #destroy_all
// SnoozeNotification sets a snooze timestamp on a notification and clears its read_at.
func (s *NotificationService) SnoozeNotification(ctx context.Context, id, userID, accountID uint, snoozedUntil time.Time) (*model.Notification, error) {
return s.notifRepo.Snooze(ctx, id, userID, accountID, snoozedUntil)
}
// MarkNotificationUnread clears read_at on a notification, marking it as unread.
func (s *NotificationService) MarkNotificationUnread(ctx context.Context, id, userID, accountID uint) (*model.Notification, error) {
return s.notifRepo.MarkUnread(ctx, id, userID, accountID)
}
// DeleteAllNotifications deletes all notifications for a user within an account.
func (s *NotificationService) DeleteAllNotifications(ctx context.Context, userID, accountID uint) error {
return s.notifRepo.DeleteAllByUser(ctx, userID, accountID)
}
func (s *NotificationService) DeleteReadNotifications(ctx context.Context, userID, accountID uint) error {
return s.notifRepo.DeleteReadByUser(ctx, userID, accountID)
}