📄
MatDenDagen/Services/NotificationService.cs
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
94
95
96
97
using System; using System.Linq; using System.Threading; using System.Threading.Tasks; using HuaweiWifiSms.Grpc; using MatDenDagen.Infrastructure.Storage.Database; using MatDenDagen.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace MatDenDagen.Services; public sealed class NotificationService( ILogger<NotificationService> logger, IOptions<NotificationServiceOptions> options, DateService dateService, QuestionnaireContext questionnaireContext, SmsSender.SmsSenderClient smsClient, TimeProvider timeProvider ) { private readonly TimeSpan interval = options.Value.CheckInterval; public async Task<DateTimeOffset> CheckAndSendNotificationsAsync( DateTimeOffset? lastCheck, CancellationToken cancellationToken ) { var utcNow = timeProvider.GetUtcNow(); lastCheck ??= utcNow - interval; logger.LogDebug("Checking for notifications between {LastCheck} and {Now}", lastCheck, utcNow); var dateConfig = await dateService.GetDateConfigAsync(); if (dateConfig?.TheDay is not DateOnly theDay) { logger.LogDebug("No date configured in database, cannot send notifications"); return utcNow; } var eventDate = new DateTimeOffset(theDay.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), TimeSpan.Zero); var participants = await questionnaireContext .Participants.AsNoTracking() .Where(p => p.NotificationMinutesOffset.HasValue) .ToListAsync(cancellationToken); foreach (var participant in participants) { if (participant.NotificationMinutesOffset is not int offset) { continue; } var notificationTime = eventDate.AddMinutes(offset); if (lastCheck <= notificationTime && notificationTime <= utcNow) { await SendNotificationAsync(participant, theDay, cancellationToken); } } return utcNow; } private async Task SendNotificationAsync( Participant participant, DateOnly theDay, CancellationToken cancellationToken ) { try { logger.LogInformation("Sending notification to {PhoneNumber} for scheduled time", participant.PhoneNumber); var request = new SmsRequest { RecipientPhoneNumber = participant.PhoneNumber, Content = $"Mat den Dagen påminnelse: Dagen är här! {theDay:yyyy-MM-dd}", }; await smsClient.SendSmsAsync(request, cancellationToken: cancellationToken); logger.LogDebug( "Notification sent successfully to {PhoneNumber}: {Message}", participant.PhoneNumber, request ); } catch (Exception ex) { logger.LogError(ex, "Failed to send notification to {PhoneNumber}", participant.PhoneNumber); } } }