Skip to content

Commit 3edc042

Browse files
authored
Merge pull request #235 from Resgrid/develop
CU-8687aj3gt Adding Apns to Novu provider for Units
2 parents 3fac2b4 + 95ecd5d commit 3edc042

File tree

21 files changed

+353
-213
lines changed

21 files changed

+353
-213
lines changed

Core/Resgrid.Config/ChatConfig.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ public static class ChatConfig
1111
public static string NovuSecretKey = "";
1212

1313
public static string NovuUnitFcmProviderId = "";
14+
public static string NovuUnitApnsProviderId = "";
1415
public static string NovuResponderFcmProviderId = "";
1516
public static string NovuDispatchUnitWorkflowId = "unit-dispatch";
17+
public static string NovuDispatchUserWorkflowId = "user-dispatch";
18+
public static string NovuMessageUserWorkflowId = "user-message";
19+
public static string NovuNotificationUserWorkflowId = "user-notification";
1620
}
1721
}

Core/Resgrid.Model/Messages/StandardPushMessage.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ public class StandardPushMessage
66
public string Title { get; set; }
77
public string SubTitle { get; set; }
88
public string Id { get; set; }
9+
public string DepartmentCode { get; set; }
910
}
1011
}

Core/Resgrid.Model/Platforms.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
{
33
public enum Platforms
44
{
5-
WindowsPhone7 = 0,
6-
iPhone = 1,
7-
iPad = 2,
8-
Android = 3,
5+
None = 0,
6+
iOS = 1,
7+
Android = 2,
8+
Web = 3,
99
Windows8 = 4,
10-
WindowsPhone8 = 5,
11-
Blackberry = 6,
12-
UnitIOS = 7,
13-
UnitAndroid = 8,
14-
UnitWin = 9
10+
//Windows8 = 4,
11+
//WindowsPhone8 = 5,
12+
//Blackberry = 6,
13+
//UnitIOS = 7,
14+
//UnitAndroid = 8,
15+
//UnitWin = 9
1516
}
16-
}
17+
}

Core/Resgrid.Model/Providers/Models/INovuProvider.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,96 @@
22

33
namespace Resgrid.Model.Providers;
44

5+
/// <summary>
6+
/// Defines operations for managing Novu notification subscribers and sending notifications.
7+
/// </summary>
58
public interface INovuProvider
69
{
10+
/// <summary>
11+
/// Creates a Novu subscriber for a user.
12+
/// </summary>
13+
/// <param name="userId">The unique identifier of the user.</param>
14+
/// <param name="code">The Novu integration code or API key.</param>
15+
/// <param name="departmentId">The department the user belongs to.</param>
16+
/// <param name="email">The user's email address.</param>
17+
/// <param name="firstName">The user's first name.</param>
18+
/// <param name="lastName">The user's last name.</param>
19+
/// <returns>True if the subscriber was created successfully; otherwise, false.</returns>
720
Task<bool> CreateUserSubscriber(string userId, string code, int departmentId, string email, string firstName, string lastName);
21+
22+
/// <summary>
23+
/// Creates a Novu subscriber for a unit (device or group).
24+
/// </summary>
25+
/// <param name="unitId">The unique identifier of the unit.</param>
26+
/// <param name="code">The Novu integration code or API key.</param>
27+
/// <param name="departmentId">The department the unit belongs to.</param>
28+
/// <param name="unitName">The name of the unit.</param>
29+
/// <param name="deviceId">The device identifier associated with the unit.</param>
30+
/// <returns>True if the subscriber was created successfully; otherwise, false.</returns>
831
Task<bool> CreateUnitSubscriber(int unitId, string code, int departmentId, string unitName, string deviceId);
32+
33+
/// <summary>
34+
/// Updates the Firebase Cloud Messaging (FCM) token for a user subscriber.
35+
/// </summary>
36+
/// <param name="userId">The unique identifier of the user.</param>
37+
/// <param name="code">The Novu integration code or API key.</param>
38+
/// <param name="token">The FCM token to associate with the user.</param>
39+
/// <returns>True if the token was updated successfully; otherwise, false.</returns>
940
Task<bool> UpdateUserSubscriberFcm(string userId, string code, string token);
41+
42+
/// <summary>
43+
/// Updates the Firebase Cloud Messaging (FCM) token for a unit subscriber.
44+
/// </summary>
45+
/// <param name="unitId">The unique identifier of the unit.</param>
46+
/// <param name="code">The Novu integration code or API key.</param>
47+
/// <param name="token">The FCM token to associate with the unit.</param>
48+
/// <returns>True if the token was updated successfully; otherwise, false.</returns>
1049
Task<bool> UpdateUnitSubscriberFcm(int unitId, string code, string token);
1150

51+
/// <summary>
52+
/// Updates the Apple Push Notification Service (APNS) token for a unit subscriber.
53+
/// </summary>
54+
/// <param name="unitId">The unique identifier of the unit.</param>
55+
/// <param name="code">The Novu integration code or API key.</param>
56+
/// <param name="token">The APNS token to associate with the unit.</param>
57+
/// <returns>True if the token was updated successfully; otherwise, false.</returns>
58+
Task<bool> UpdateUnitSubscriberApns(int unitId, string code, string token);
59+
60+
/// <summary>
61+
/// Updates the Apple Push Notification Service (APNS) token for a user subscriber.
62+
/// </summary>
63+
/// <param name="userId">The unique identifier of the user.</param>
64+
/// <param name="code">The Novu integration code or API key.</param>
65+
/// <param name="token">The APNS token to associate with the user.</param>
66+
/// <returns>True if the token was updated successfully; otherwise, false.</returns>
67+
Task<bool> UpdateUserSubscriberApns(string userId, string code, string token);
68+
69+
/// <summary>
70+
/// Sends a dispatch notification to a unit.
71+
/// </summary>
72+
/// <param name="title">The notification title.</param>
73+
/// <param name="body">The notification body content.</param>
74+
/// <param name="unitId">The unique identifier of the unit to notify.</param>
75+
/// <param name="depCode">The department code.</param>
76+
/// <param name="eventCode">The event code associated with the dispatch.</param>
77+
/// <param name="type">The type of notification.</param>
78+
/// <param name="enableCustomSounds">Whether to enable custom notification sounds.</param>
79+
/// <param name="count">The badge or notification count.</param>
80+
/// <param name="color">The color code for the notification.</param>
81+
/// <returns>True if the notification was sent successfully; otherwise, false.</returns>
1282
Task<bool> SendUnitDispatch(string title, string body, int unitId, string depCode, string eventCode, string type,
1383
bool enableCustomSounds, int count, string color);
1484

85+
/// <summary>
86+
/// Deletes a notification message by its identifier.
87+
/// </summary>
88+
/// <param name="messageId">The unique identifier of the message to delete.</param>
89+
/// <returns>True if the message was deleted successfully; otherwise, false.</returns>
1590
Task<bool> DeleteMessage(string messageId);
91+
92+
Task<bool> SendUserDispatch(string title, string body, string userId, string depCode, string eventCode, string type, bool enableCustomSounds, int count, string color);
93+
94+
Task<bool> SendUserMessage(string title, string body, string userId, string depCode, string eventCode, string type);
95+
96+
Task<bool> SendUserNotification(string title, string body, string userId, string depCode, string eventCode, string type);
1697
}

Core/Resgrid.Model/PushUri.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ public string PushLocation
4545
{
4646
_pushLocation = value;
4747

48-
if (((Platforms)PlatformType) == Platforms.Windows8 || ((Platforms)PlatformType) == Platforms.WindowsPhone7 || ((Platforms)PlatformType) == Platforms.WindowsPhone8 || ((Platforms)PlatformType) == Platforms.UnitWin)
49-
ChannelUri = new Uri(_pushLocation, UriKind.Absolute);
48+
//if (((Platforms)PlatformType) == Platforms.Windows8 || ((Platforms)PlatformType) == Platforms.WindowsPhone7 || ((Platforms)PlatformType) == Platforms.WindowsPhone8 || ((Platforms)PlatformType) == Platforms.UnitWin)
49+
// ChannelUri = new Uri(_pushLocation, UriKind.Absolute);
5050
}
5151
}
5252
}

Core/Resgrid.Model/Services/ICommunicationService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Task<bool> SendUnitCallAsync(Call call, CallDispatchUnit dispatch, string depart
5555
/// <param name="title">The title.</param>
5656
/// <param name="profile">The profile.</param>
5757
/// <returns>Task&lt;System.Boolean&gt;.</returns>
58-
Task<bool> SendNotificationAsync(string userId, int departmentId, string message, string departmentNumber,
58+
Task<bool> SendNotificationAsync(string userId, int departmentId, string message, string departmentNumber, Department department,
5959
string title = "Notification", UserProfile profile = null);
6060

6161
/// <summary>

Core/Resgrid.Services/CalendarService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,9 +487,9 @@ public async Task<bool> NotifyNewCalendarItemAsync(CalendarItem calendarItem)
487487
foreach (var member in group.Members)
488488
{
489489
if (profiles.ContainsKey(member.UserId))
490-
await _communicationService.SendNotificationAsync(member.UserId, calendarItem.DepartmentId, message, departmentNumber, title, profiles[member.UserId]);
490+
await _communicationService.SendNotificationAsync(member.UserId, calendarItem.DepartmentId, message, departmentNumber, department, title, profiles[member.UserId]);
491491
else
492-
await _communicationService.SendNotificationAsync(member.UserId, calendarItem.DepartmentId, message, departmentNumber, title, null);
492+
await _communicationService.SendNotificationAsync(member.UserId, calendarItem.DepartmentId, message, departmentNumber, department, title, null);
493493
}
494494
}
495495
}

Core/Resgrid.Services/CommunicationService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ public async Task<bool> SendUnitCallAsync(Call call, CallDispatchUnit dispatch,
290290
return true;
291291
}
292292

293-
public async Task<bool> SendNotificationAsync(string userId, int departmentId, string message, string departmentNumber, string title = "Notification", UserProfile profile = null)
293+
public async Task<bool> SendNotificationAsync(string userId, int departmentId, string message, string departmentNumber, Department department, string title = "Notification", UserProfile profile = null)
294294
{
295295
if (Config.SystemBehaviorConfig.DoNotBroadcast && !Config.SystemBehaviorConfig.BypassDoNotBroadcastDepartments.Contains(departmentId))
296296
return false;
@@ -319,6 +319,7 @@ public async Task<bool> SendNotificationAsync(string userId, int departmentId, s
319319
var spm = new StandardPushMessage();
320320
spm.Title = "Notification";
321321
spm.SubTitle = $"{title} {message}";
322+
spm.DepartmentCode = department?.Code;
322323

323324
try
324325
{

Core/Resgrid.Services/PushService.cs

Lines changed: 87 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
using System;
2-
using System.IO;
3-
using System.Linq;
4-
using System.Reflection;
5-
using System.Collections.Generic;
6-
using System.Threading.Tasks;
1+
using DnsClient;
2+
using FirebaseAdmin.Messaging;
73
using Resgrid.Model;
84
using Resgrid.Model.Messages;
95
using Resgrid.Model.Providers;
106
using Resgrid.Model.Services;
11-
using DnsClient;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Drawing;
10+
using System.IO;
11+
using System.Linq;
12+
using System.Reflection;
13+
using System.Threading.Tasks;
1214

1315
namespace Resgrid.Services
1416
{
@@ -36,31 +38,18 @@ public async Task<bool> Register(PushUri pushUri)
3638
if (pushUri == null || String.IsNullOrWhiteSpace(pushUri.DeviceId))
3739
return false;
3840

39-
string deviceId = pushUri.DeviceId.GetHashCode().ToString();
41+
var code = pushUri.PushLocation;
4042

41-
// We just store the full Device Id in the PushUri object, the hashed version is for Azure
42-
//var existingPushUri = _pushUriService.GetPushUriByPlatformDeviceId((Platforms)pushUri.PlatformType, pushUri.DeviceId);
43-
List<PushRegistrationDescription> usersDevices = null;
43+
// 1) iOS -> APNS
44+
if (pushUri.PlatformType == (int)Platforms.iOS)
45+
return await _novuProvider.UpdateUserSubscriberApns(pushUri.UserId, code, pushUri.DeviceId);
4446

45-
try
46-
{
47-
usersDevices = await _notificationProvider.GetRegistrationsByUserId(pushUri.UserId);
48-
49-
if (usersDevices == null || !usersDevices.Any(x => x.Tags.Contains(deviceId)))
50-
await _notificationProvider.RegisterPush(pushUri);
51-
}
52-
catch (TimeoutException)
53-
{ }
54-
catch (TaskCanceledException)
55-
{ }
47+
// 2) Android -> FCM
48+
if (pushUri.PlatformType == (int)Platforms.Android)
49+
return await _novuProvider.UpdateUserSubscriberFcm(pushUri.UserId, code, pushUri.DeviceId);
5650

57-
//if (existingPushUri == null)
58-
// pushUri = _pushUriService.SavePushUri(pushUri);
59-
60-
//if (usersDevices == null || !usersDevices.Any(x => x.Tags.Contains(deviceId)))
61-
// await _notificationProvider.RegisterPush(pushUri);
62-
63-
return true;
51+
// 3) TODO: Web Push (other platforms)
52+
return false;
6453
}
6554

6655
public async Task<bool> UnRegister(PushUri pushUri)
@@ -72,29 +61,22 @@ public async Task<bool> UnRegister(PushUri pushUri)
7261

7362
public async Task<bool> RegisterUnit(PushUri pushUri)
7463
{
75-
//string deviceId = pushUri.DeviceId;
76-
List<PushRegistrationDescription> usersDevices = null;
77-
78-
//try
79-
//{
80-
// usersDevices = await _unitNotificationProvider.GetRegistrationsByUUID(pushUri.PushLocation);
81-
//}
82-
//catch (TimeoutException)
83-
//{ }
64+
if (pushUri == null || !pushUri.UnitId.HasValue || string.IsNullOrWhiteSpace(pushUri.PushLocation))
65+
return false;
8466

85-
if (pushUri.UnitId.HasValue && !string.IsNullOrWhiteSpace(pushUri.PushLocation))
86-
await _novuProvider.UpdateUnitSubscriberFcm(pushUri.UnitId.Value, pushUri.PushLocation, pushUri.DeviceId);
67+
var unitId = pushUri.UnitId.Value;
68+
var code = pushUri.PushLocation;
8769

70+
// 1) iOS -> APNS
71+
if (pushUri.PlatformType == (int)Platforms.iOS)
72+
return await _novuProvider.UpdateUnitSubscriberApns(unitId, code, pushUri.DeviceId);
8873

89-
//if (usersDevices == null || !usersDevices.Any(x => x.Tags.Contains(string.Format("unitId:{0}", pushUri.UnitId.ToString()))))
90-
// await _unitNotificationProvider.RegisterPush(pushUri);
91-
//else
92-
//{
93-
// await _unitNotificationProvider.UnRegisterPushByUUID(pushUri.PushLocation);
94-
// await _unitNotificationProvider.RegisterPush(pushUri);
95-
//}
74+
// 2) Android -> FCM
75+
if (pushUri.PlatformType == (int)Platforms.Android)
76+
return await _novuProvider.UpdateUnitSubscriberFcm(unitId, code, pushUri.DeviceId);
9677

97-
return true;
78+
// 3) TODO: Web Push (other platforms)
79+
return false;
9880
}
9981

10082
public async Task<bool> UnRegisterUnit(PushUri pushUri)
@@ -118,7 +100,25 @@ public async Task<bool> PushMessage(StandardPushMessage message, string userId,
118100
profile = await _userProfileService.GetProfileByUserIdAsync(userId);
119101

120102
if (profile != null && profile.SendMessagePush)
121-
await _notificationProvider.SendAllNotifications(message.Title, message.SubTitle, userId, string.Format("M{0}", message.MessageId), ((int)PushSoundTypes.Message).ToString(), true, 1, "#000000");
103+
{
104+
try
105+
{
106+
await _notificationProvider.SendAllNotifications(message.Title, message.SubTitle, userId, string.Format("M{0}", message.MessageId), ((int)PushSoundTypes.Message).ToString(), true, 1, "#000000");
107+
}
108+
catch (Exception ex)
109+
{
110+
Framework.Logging.LogException(ex);
111+
}
112+
113+
try
114+
{
115+
await _novuProvider.SendUserMessage(message.Title, message.SubTitle, userId, message.DepartmentCode, string.Format("M{0}", message.MessageId), null);
116+
}
117+
catch (Exception ex)
118+
{
119+
Framework.Logging.LogException(ex);
120+
}
121+
}
122122

123123
return true;
124124
}
@@ -132,8 +132,24 @@ public async Task<bool> PushNotification(StandardPushMessage message, string use
132132
profile = await _userProfileService.GetProfileByUserIdAsync(userId);
133133

134134
if (profile != null && profile.SendNotificationPush)
135-
await _notificationProvider.SendAllNotifications(message.Title, message.SubTitle, userId, string.Format("N{0}", message.MessageId), ((int)PushSoundTypes.Notifiation).ToString(), true, 1, "#000000");
136-
135+
{
136+
try
137+
{
138+
await _notificationProvider.SendAllNotifications(message.Title, message.SubTitle, userId, string.Format("N{0}", message.MessageId), ((int)PushSoundTypes.Notifiation).ToString(), true, 1, "#000000");
139+
}
140+
catch (Exception ex)
141+
{
142+
Framework.Logging.LogException(ex);
143+
}
144+
try
145+
{
146+
await _novuProvider.SendUserMessage(message.Title, message.SubTitle, userId, message.DepartmentCode, string.Format("N{0}", message.MessageId), null);
147+
}
148+
catch (Exception ex)
149+
{
150+
Framework.Logging.LogException(ex);
151+
}
152+
}
137153
return true;
138154
}
139155

@@ -167,7 +183,26 @@ public async Task<bool> PushCall(StandardPushCall call, string userId, UserProfi
167183
color = priority.Color;
168184

169185
if (profile != null && profile.SendPush)
170-
await _notificationProvider.SendAllNotifications(call.SubTitle, call.Title, userId, string.Format("C{0}", call.CallId), ConvertCallPriorityToSound((int)call.Priority, priority), true, call.ActiveCallCount, color);
186+
{
187+
// Legacy Push Notifications (Azure)
188+
try
189+
{
190+
await _notificationProvider.SendAllNotifications(call.SubTitle, call.Title, userId, string.Format("C{0}", call.CallId), ConvertCallPriorityToSound((int)call.Priority, priority), true, call.ActiveCallCount, color);
191+
}
192+
catch (Exception ex)
193+
{
194+
Framework.Logging.LogException(ex);
195+
}
196+
197+
try
198+
{
199+
await _novuProvider.SendUserDispatch(call.Title, call.SubTitle, userId, call.DepartmentCode, string.Format("C{0}", call.CallId), ConvertCallPriorityToSound((int)call.Priority, priority), true, call.ActiveCallCount, color);
200+
}
201+
catch (Exception ex)
202+
{
203+
Framework.Logging.LogException(ex);
204+
}
205+
}
171206

172207
return true;
173208
}
@@ -184,15 +219,6 @@ public async Task<bool> PushCallUnit(StandardPushCall call, int unitId, Departme
184219
if (priority != null)
185220
color = priority.Color;
186221

187-
try
188-
{
189-
await _unitNotificationProvider.SendAllNotifications(call.SubTitle, call.Title, unitId, string.Format("C{0}", call.CallId), ConvertCallPriorityToSound((int)call.Priority, priority), true, call.ActiveCallCount, color);
190-
}
191-
catch (Exception ex)
192-
{
193-
Framework.Logging.LogException(ex);
194-
}
195-
196222
try
197223
{
198224
await _novuProvider.SendUnitDispatch(call.Title, call.SubTitle, unitId, call.DepartmentCode, string.Format("C{0}", call.CallId), ConvertCallPriorityToSound((int)call.Priority, priority), true, call.ActiveCallCount, color);

0 commit comments

Comments
 (0)