Files
gochat/internal/repository/notification_repo.go
T
2026-06-04 15:44:48 +08:00

168 lines
5.7 KiB
Go

package repository
import (
"context"
"time"
"gorm.io/gorm"
"github.com/gochat/gochat/internal/model"
)
// NotificationRepo implements GORM repository for Notification.
// Reference: Chatwoot app/models/notification.rb
type NotificationRepo struct {
db *gorm.DB
}
// NewNotificationRepo creates a new Notification repository.
func NewNotificationRepo(db *gorm.DB) *NotificationRepo {
return &NotificationRepo{db: db}
}
// FindByID retrieves a notification by primary key.
func (r *NotificationRepo) FindByID(ctx context.Context, id uint) (*model.Notification, error) {
var n model.Notification
err := r.db.WithContext(ctx).First(&n, id).Error
if err != nil {
return nil, err
}
return &n, nil
}
// ListByUser retrieves all notifications for a user with pagination.
func (r *NotificationRepo) ListByUser(ctx context.Context, userID uint, offset, limit int) ([]model.Notification, int64, error) {
var notifications []model.Notification
var total int64
db := r.db.WithContext(ctx).Where("user_id = ?", userID)
if err := db.Model(&model.Notification{}).Count(&total).Error; err != nil {
return nil, 0, err
}
if err := db.Order("created_at DESC").Offset(offset).Limit(limit).Find(&notifications).Error; err != nil {
return nil, 0, err
}
return notifications, total, nil
}
// ListByUserAndAccount retrieves notifications for a user within an account.
func (r *NotificationRepo) ListByUserAndAccount(ctx context.Context, userID uint, accountID uint, offset, limit int) ([]model.Notification, int64, error) {
var notifications []model.Notification
var total int64
db := r.db.WithContext(ctx).Where("user_id = ? AND account_id = ?", userID, accountID)
if err := db.Model(&model.Notification{}).Count(&total).Error; err != nil {
return nil, 0, err
}
if err := db.Order("created_at DESC").Offset(offset).Limit(limit).Find(&notifications).Error; err != nil {
return nil, 0, err
}
return notifications, total, nil
}
// Create inserts a new notification.
func (r *NotificationRepo) Create(ctx context.Context, notification *model.Notification) error {
return r.db.WithContext(ctx).Create(notification).Error
}
// Update modifies an existing notification.
func (r *NotificationRepo) Update(ctx context.Context, notification *model.Notification) error {
return r.db.WithContext(ctx).Save(notification).Error
}
// MarkRead marks a single notification as read.
func (r *NotificationRepo) MarkRead(ctx context.Context, id uint) error {
now := time.Now()
result := r.db.WithContext(ctx).Model(&model.Notification{}).
Where("id = ?", id).
Update("read_at", now)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return gorm.ErrRecordNotFound
}
return nil
}
// MarkAllReadByUser marks all unread notifications for a user as read.
func (r *NotificationRepo) MarkAllReadByUser(ctx context.Context, userID uint) error {
now := time.Now()
return r.db.WithContext(ctx).Model(&model.Notification{}).
Where("user_id = ? AND read_at IS NULL", userID).
Update("read_at", now).Error
}
// MarkAllReadByUserAndAccount marks all unread notifications for a user within an account as read.
func (r *NotificationRepo) MarkAllReadByUserAndAccount(ctx context.Context, userID uint, accountID uint) error {
now := time.Now()
return r.db.WithContext(ctx).Model(&model.Notification{}).
Where("user_id = ? AND account_id = ? AND read_at IS NULL", userID, accountID).
Update("read_at", now).Error
}
// Delete soft-deletes a notification.
func (r *NotificationRepo) Delete(ctx context.Context, id uint) error {
return r.db.WithContext(ctx).Delete(&model.Notification{}, id).Error
}
// CountUnreadByUser counts unread notifications for a user.
func (r *NotificationRepo) CountUnreadByUser(ctx context.Context, userID uint) (int64, error) {
var count int64
err := r.db.WithContext(ctx).Model(&model.Notification{}).
Where("user_id = ? AND read_at IS NULL", userID).
Count(&count).Error
return count, err
}
// Snooze sets the snoozed_until timestamp and clears read_at for a notification.
// Returns the updated notification.
// Reference: Chatwoot notifications_controller.rb#snooze
func (r *NotificationRepo) Snooze(ctx context.Context, id, userID, accountID uint, snoozedUntil time.Time) (*model.Notification, error) {
result := r.db.WithContext(ctx).Model(&model.Notification{}).
Where("id = ? AND user_id = ? AND account_id = ?", id, userID, accountID).
Updates(map[string]interface{}{"snoozed_until": snoozedUntil, "read_at": nil})
if result.Error != nil {
return nil, result.Error
}
if result.RowsAffected == 0 {
return nil, gorm.ErrRecordNotFound
}
var notif model.Notification
if err := r.db.WithContext(ctx).First(&notif, id).Error; err != nil {
return nil, err
}
return &notif, nil
}
// MarkUnread clears read_at for a notification, marking it as unread.
// Returns the updated notification.
// Reference: Chatwoot notifications_controller.rb#unread
func (r *NotificationRepo) MarkUnread(ctx context.Context, id, userID, accountID uint) (*model.Notification, error) {
result := r.db.WithContext(ctx).Model(&model.Notification{}).
Where("id = ? AND user_id = ? AND account_id = ?", id, userID, accountID).
Update("read_at", nil)
if result.Error != nil {
return nil, result.Error
}
if result.RowsAffected == 0 {
return nil, gorm.ErrRecordNotFound
}
var notif model.Notification
if err := r.db.WithContext(ctx).First(&notif, id).Error; err != nil {
return nil, err
}
return &notif, nil
}
// DeleteAllByUser soft-deletes all notifications for a user within an account.
// Reference: Chatwoot notifications_controller.rb#destroy_all
func (r *NotificationRepo) DeleteAllByUser(ctx context.Context, userID, accountID uint) error {
return r.db.WithContext(ctx).
Where("user_id = ? AND account_id = ?", userID, accountID).
Delete(&model.Notification{}).Error
}