File size: 3,124 Bytes
4e645a3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using Microsoft.EntityFrameworkCore;
using TaskTrackingSystem.Database.AppDbContextModels;
using TaskTrackingSystem.Shared;
using TaskTrackingSystem.Shared.Models.Notification;
using DbNotification = TaskTrackingSystem.Database.AppDbContextModels.Notification;

namespace TaskTrackingSystem.WebApi.Features.Notification;

public class NotificationService
{
    private readonly AppDbContext _db;
    private readonly NotificationRealtimeService _realtimeService;

    public NotificationService(AppDbContext db, NotificationRealtimeService realtimeService)
    {
        _db = db;
        _realtimeService = realtimeService;
    }

    public async Task<IReadOnlyList<NotificationDto>> GetRecentAsync(long userId, int take = 10)
    {
        var items = await (
            from n in _db.Notifications
            where n.RecipientId == userId
            join sender in _db.Users on n.SenderId equals sender.Id into senderGroup
            from sender in senderGroup.DefaultIfEmpty()
            orderby n.CreatedAt descending
            select new NotificationDto
            {
                Id = n.Id,
                Title = n.Title,
                Body = n.Body,
                NotificationType = n.NotificationType,
                SourceType = n.SourceType,
                SourceId = n.SourceId,
                IsRead = n.IsRead,
                CreatedAt = n.CreatedAt,
                ReadAt = n.ReadAt,
                SenderName = sender == null ? null : $"{sender.FirstName} {sender.LastName}"
            })
            .Take(take)
            .ToListAsync();

        foreach (var item in items)
        {
            item.TargetUrl = NotificationNavigation.BuildTargetUrl(item.SourceType, item.SourceId, item.NotificationType);
        }

        return items;
    }

    public async Task<int> GetUnreadCountAsync(long userId)
    {
        return await _db.Notifications.CountAsync(n => n.RecipientId == userId && !n.IsRead);
    }

    public async Task<Result> MarkReadAsync(long userId, long notificationId)
    {
        var notification = await _db.Notifications
            .FirstOrDefaultAsync(n => n.Id == notificationId && n.RecipientId == userId);

        if (notification == null)
        {
            return Result.Failure("Notification not found.", 404);
        }

        if (!notification.IsRead)
        {
            notification.IsRead = true;
            notification.ReadAt = DateTime.UtcNow;
            await _db.SaveChangesAsync();

            var unreadCount = await GetUnreadCountAsync(userId);
            await _realtimeService.SendReadAsync(userId, notificationId, unreadCount);
        }

        return Result.Success();
    }

    public async Task<int> DeleteReadNotificationsAsync(long userId, DateTime? olderThanUtc = null)
    {
        var query = _db.Notifications.Where(n => n.RecipientId == userId && n.IsRead);

        if (olderThanUtc.HasValue)
        {
            var cutoff = olderThanUtc.Value;
            query = query.Where(n => !n.CreatedAt.HasValue || n.CreatedAt < cutoff);
        }

        return await query.ExecuteDeleteAsync();
    }
}