veza/veza-backend-api/internal/services/notification_service.go
2025-12-03 20:29:37 +01:00

149 lines
3.6 KiB
Go

package services
import (
"context"
"fmt"
"github.com/google/uuid"
"veza-backend-api/internal/database"
"go.uber.org/zap"
)
// NotificationService handles notification operations
type NotificationService struct {
db *database.Database
logger *zap.Logger
}
// Notification represents a notification
type Notification struct {
ID uuid.UUID `json:"id" db:"id"`
UserID uuid.UUID `json:"user_id" db:"user_id"`
Type string `json:"type" db:"type"`
Title string `json:"title" db:"title"`
Content string `json:"content" db:"content"`
Link string `json:"link" db:"link"`
Read bool `json:"read" db:"read"`
CreatedAt string `json:"created_at" db:"created_at"`
}
// NewNotificationService creates a new notification service
func NewNotificationService(db *database.Database, logger *zap.Logger) *NotificationService {
return &NotificationService{
db: db,
logger: logger,
}
}
// CreateNotification creates a new notification
func (ns *NotificationService) CreateNotification(userID uuid.UUID, notificationType, title, content, link string) error {
ctx := context.Background()
_, err := ns.db.ExecContext(ctx, `
INSERT INTO notifications (user_id, type, title, content, link)
VALUES ($1, $2, $3, $4, $5)
`, userID, notificationType, title, content, link)
if err != nil {
return fmt.Errorf("failed to create notification: %w", err)
}
return nil
}
// GetNotifications retrieves notifications for a user
func (ns *NotificationService) GetNotifications(userID uuid.UUID, unreadOnly bool) ([]Notification, error) {
ctx := context.Background()
query := `
SELECT id, user_id, type, title, content, link, read, created_at
FROM notifications
WHERE user_id = $1
`
args := []interface{}{userID}
if unreadOnly {
query += " AND read = FALSE"
}
query += " ORDER BY created_at DESC LIMIT 50"
rows, err := ns.db.QueryContext(ctx, query, args...)
if err != nil {
return nil, fmt.Errorf("failed to get notifications: %w", err)
}
defer rows.Close()
var notifications []Notification
for rows.Next() {
var notification Notification
if err := rows.Scan(
&notification.ID,
&notification.UserID,
&notification.Type,
&notification.Title,
&notification.Content,
&notification.Link,
&notification.Read,
&notification.CreatedAt,
); err != nil {
continue
}
notifications = append(notifications, notification)
}
return notifications, nil
}
// MarkAsRead marks a notification as read
func (ns *NotificationService) MarkAsRead(userID uuid.UUID, notificationID uuid.UUID) error {
ctx := context.Background()
_, err := ns.db.ExecContext(ctx, `
UPDATE notifications
SET read = TRUE
WHERE id = $1 AND user_id = $2
`, notificationID, userID)
if err != nil {
return fmt.Errorf("failed to mark notification as read: %w", err)
}
return nil
}
// MarkAllAsRead marks all notifications as read for a user
func (ns *NotificationService) MarkAllAsRead(userID uuid.UUID) error {
ctx := context.Background()
_, err := ns.db.ExecContext(ctx, `
UPDATE notifications
SET read = TRUE
WHERE user_id = $1 AND read = FALSE
`, userID)
if err != nil {
return fmt.Errorf("failed to mark all notifications as read: %w", err)
}
return nil
}
// GetUnreadCount returns the count of unread notifications
func (ns *NotificationService) GetUnreadCount(userID uuid.UUID) (int, error) {
ctx := context.Background()
var count int
err := ns.db.QueryRowContext(ctx, `
SELECT COUNT(*)
FROM notifications
WHERE user_id = $1 AND read = FALSE
`, userID).Scan(&count)
if err != nil {
return 0, fmt.Errorf("failed to get unread count: %w", err)
}
return count, nil
}