diff --git a/Core/Resgrid.Services/CommunicationService.cs b/Core/Resgrid.Services/CommunicationService.cs index 61767159b..99046810f 100644 --- a/Core/Resgrid.Services/CommunicationService.cs +++ b/Core/Resgrid.Services/CommunicationService.cs @@ -712,16 +712,16 @@ public async Task SendChat(string chatId, int departmentId, string sending if (recipients.Count == 1) { var sendingTo = recipients.FirstOrDefault(); - spm.Id = $"T{sendingTo}"; + if (sendingTo == null) + return false; + + spm.Id = $"T{sendingTo.UserId}"; if (!await CanSendToUser(sendingTo.UserId, departmentId)) return false; - if (sendingTo != null) - { - await _pushService.PushChat(spm, sendingTo.UserId, sendingTo); - } + await _pushService.PushChat(spm, sendingTo.UserId, sendingTo); } else { diff --git a/Core/Resgrid.Services/PushService.cs b/Core/Resgrid.Services/PushService.cs index 018349d07..eb7a60f6a 100644 --- a/Core/Resgrid.Services/PushService.cs +++ b/Core/Resgrid.Services/PushService.cs @@ -362,7 +362,7 @@ public async Task PushCall(StandardPushCall call, string userId, UserProfi // Legacy Push Notifications (Azure) try { - await _notificationProvider.SendAllNotifications(call.SubTitle, call.Title, userId, string.Format("C{0}", call.CallId), soundType, true, call.ActiveCallCount, color); + await _notificationProvider.SendAllNotifications(call.Title, call.SubTitle, userId, string.Format("C{0}", call.CallId), soundType, true, call.ActiveCallCount, color); } catch (Exception ex) { diff --git a/Providers/Resgrid.Providers.Bus/Models/APNSPayload.cs b/Providers/Resgrid.Providers.Bus/Models/APNSPayload.cs index 74704c3ad..ea54adb81 100644 --- a/Providers/Resgrid.Providers.Bus/Models/APNSPayload.cs +++ b/Providers/Resgrid.Providers.Bus/Models/APNSPayload.cs @@ -11,5 +11,16 @@ public class ApnsPayload public ApnsHeader aps { get; set; } public string eventCode { get; set; } public string type { get; set; } + public ApnsCustomData body { get; set; } + } + + /// + /// Serialized as the top-level `body` custom key, which is the only key + /// expo-notifications on iOS surfaces to the app as content.data. + /// + public class ApnsCustomData + { + public string eventCode { get; set; } + public string type { get; set; } } } diff --git a/Providers/Resgrid.Providers.Bus/NotificationProvider.cs b/Providers/Resgrid.Providers.Bus/NotificationProvider.cs index d4208d909..c268e7998 100644 --- a/Providers/Resgrid.Providers.Bus/NotificationProvider.cs +++ b/Providers/Resgrid.Providers.Bus/NotificationProvider.cs @@ -322,7 +322,12 @@ public async Task SendAppleNotification(string title, } }, eventCode = eventCode, - type = type + type = type, + body = new ApnsCustomData + { + eventCode = eventCode, + type = type + } }; appleNotification = JsonConvert.SerializeObject(apnsPayload); diff --git a/Providers/Resgrid.Providers.Bus/UnitNotificationProvider.cs b/Providers/Resgrid.Providers.Bus/UnitNotificationProvider.cs index b6a74ab05..f210ca3fd 100644 --- a/Providers/Resgrid.Providers.Bus/UnitNotificationProvider.cs +++ b/Providers/Resgrid.Providers.Bus/UnitNotificationProvider.cs @@ -351,7 +351,12 @@ public async Task SendAppleNotification(string title, } }, eventCode = eventCode, - type = type + type = type, + body = new ApnsCustomData + { + eventCode = eventCode, + type = type + } }; appleNotification = JsonConvert.SerializeObject(apnsPayload); diff --git a/Providers/Resgrid.Providers.Messaging/NovuProvider.cs b/Providers/Resgrid.Providers.Messaging/NovuProvider.cs index 58b7210ea..86896e64d 100644 --- a/Providers/Resgrid.Providers.Messaging/NovuProvider.cs +++ b/Providers/Resgrid.Providers.Messaging/NovuProvider.cs @@ -416,6 +416,17 @@ private async Task SendNotification(string title, string body, string reci eventCode = eventCode, customType = type }, + // expo-notifications on iOS only surfaces the top-level `body` custom key + // as content.data, and per the APNs spec custom keys belong beside `aps`, + // not inside it. The aps-nested eventCode/customType above stay for + // backward compatibility with already deployed apps. + body = new + { + eventCode = eventCode, + type = type + }, + eventCode = eventCode, + type = type }, }, }, @@ -431,7 +442,20 @@ private async Task SendNotification(string title, string body, string reci ["type"] = type, ["category"] = channelName, ["eventCode"] = eventCode, - ["gcm.message_id"] = "123" + ["gcm.message_id"] = "123", + // node-apn merges `payload` in as the custom data at the top level of the + // APNs JSON; the nested `body` key is the one expo-notifications on iOS + // exposes as content.data. + ["payload"] = new Dictionary + { + ["body"] = new + { + eventCode = eventCode, + type = type + }, + ["eventCode"] = eventCode, + ["type"] = type + }, }, }, to = new[]{ new @@ -657,7 +681,12 @@ private string CreateAppleNotification(string title, string subTitle, string typ } }, eventCode = eventCode, - type = type + type = type, + body = new ApnsCustomData + { + eventCode = eventCode, + type = type + } }; var appleNotification = JsonConvert.SerializeObject(apnsPayload); diff --git a/Tests/Resgrid.Tests/Services/PushServiceModernApplicationSoundTests.cs b/Tests/Resgrid.Tests/Services/PushServiceModernApplicationSoundTests.cs index 512f75c68..f2deb7575 100644 --- a/Tests/Resgrid.Tests/Services/PushServiceModernApplicationSoundTests.cs +++ b/Tests/Resgrid.Tests/Services/PushServiceModernApplicationSoundTests.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Moq; using NUnit.Framework; using Resgrid.Config; @@ -178,8 +178,8 @@ public async Task PushCall_uses_effective_department_or_user_sound_setting( await _pushService.PushCall(call, UserId, profile); _notificationProvider.Verify(x => x.SendAllNotifications( - call.SubTitle, call.Title, + call.SubTitle, UserId, "C99", ((int)expectedSound).ToString(),