diff --git a/src/Api/Controllers/PushController.cs b/src/Api/Controllers/PushController.cs index f41035b51..d760aaa5d 100644 --- a/src/Api/Controllers/PushController.cs +++ b/src/Api/Controllers/PushController.cs @@ -39,7 +39,7 @@ public class PushController : Controller { CheckUsage(); await _pushRegistrationService.CreateOrUpdateRegistrationAsync(model.PushToken, Prefix(model.DeviceId), - Prefix(model.UserId), Prefix(model.Identifier), model.Type); + Prefix(model.UserId), Prefix(model.Identifier), model.Type, model.OrganizationIds); } [HttpPost("delete")] diff --git a/src/Core/Models/Api/Request/PushRegistrationRequestModel.cs b/src/Core/Models/Api/Request/PushRegistrationRequestModel.cs index 580c1c3b6..ee787dd08 100644 --- a/src/Core/Models/Api/Request/PushRegistrationRequestModel.cs +++ b/src/Core/Models/Api/Request/PushRegistrationRequestModel.cs @@ -15,4 +15,5 @@ public class PushRegistrationRequestModel public DeviceType Type { get; set; } [Required] public string Identifier { get; set; } + public IEnumerable OrganizationIds { get; set; } } diff --git a/src/Core/NotificationHub/NotificationHubPushRegistrationService.cs b/src/Core/NotificationHub/NotificationHubPushRegistrationService.cs index f12d7d7fb..30c307057 100644 --- a/src/Core/NotificationHub/NotificationHubPushRegistrationService.cs +++ b/src/Core/NotificationHub/NotificationHubPushRegistrationService.cs @@ -11,20 +11,17 @@ public class NotificationHubPushRegistrationService : IPushRegistrationService { private readonly IInstallationDeviceRepository _installationDeviceRepository; private readonly INotificationHubPool _notificationHubPool; - private readonly IOrganizationUserRepository _organizationUserRepository; public NotificationHubPushRegistrationService( IInstallationDeviceRepository installationDeviceRepository, - INotificationHubPool notificationHubPool, - IOrganizationUserRepository organizationUserRepository) + INotificationHubPool notificationHubPool) { _installationDeviceRepository = installationDeviceRepository; _notificationHubPool = notificationHubPool; - _organizationUserRepository = organizationUserRepository; } public async Task CreateOrUpdateRegistrationAsync(string pushToken, string deviceId, string userId, - string identifier, DeviceType type) + string identifier, DeviceType type, IEnumerable organizationIds) { if (string.IsNullOrWhiteSpace(pushToken)) { @@ -47,10 +44,10 @@ public class NotificationHubPushRegistrationService : IPushRegistrationService installation.Tags.Add("deviceIdentifier:" + identifier); } - foreach (var organizationUserDetails in await _organizationUserRepository.GetManyDetailsByUserAsync( - Guid.Parse(userId), OrganizationUserStatusType.Confirmed)) + var organizationIdsList = organizationIds.ToList(); + foreach (var organizationId in organizationIdsList) { - installation.Tags.Add($"organizationId:{organizationUserDetails.OrganizationId}"); + installation.Tags.Add($"organizationId:{organizationId}"); } string payloadTemplate = null, messageTemplate = null, badgeMessageTemplate = null; @@ -82,10 +79,12 @@ public class NotificationHubPushRegistrationService : IPushRegistrationService break; } - BuildInstallationTemplate(installation, "payload", payloadTemplate, userId, identifier, clientType); - BuildInstallationTemplate(installation, "message", messageTemplate, userId, identifier, clientType); + BuildInstallationTemplate(installation, "payload", payloadTemplate, userId, identifier, clientType, + organizationIdsList); + BuildInstallationTemplate(installation, "message", messageTemplate, userId, identifier, clientType, + organizationIdsList); BuildInstallationTemplate(installation, "badgeMessage", badgeMessageTemplate ?? messageTemplate, - userId, identifier, clientType); + userId, identifier, clientType, organizationIdsList); await ClientFor(GetComb(deviceId)).CreateOrUpdateInstallationAsync(installation); if (InstallationDeviceEntity.IsInstallationDeviceId(deviceId)) @@ -95,7 +94,7 @@ public class NotificationHubPushRegistrationService : IPushRegistrationService } private void BuildInstallationTemplate(Installation installation, string templateId, string templateBody, - string userId, string identifier, ClientType clientType) + string userId, string identifier, ClientType clientType, List organizationIds) { if (templateBody == null) { @@ -118,6 +117,11 @@ public class NotificationHubPushRegistrationService : IPushRegistrationService template.Tags.Add($"{fullTemplateId}_deviceIdentifier:{identifier}"); } + foreach (var organizationId in organizationIds) + { + template.Tags.Add($"organizationId:{organizationId}"); + } + installation.Templates.Add(fullTemplateId, template); } diff --git a/src/Core/Services/IPushRegistrationService.cs b/src/Core/Services/IPushRegistrationService.cs index 985246de0..304387581 100644 --- a/src/Core/Services/IPushRegistrationService.cs +++ b/src/Core/Services/IPushRegistrationService.cs @@ -5,7 +5,7 @@ namespace Bit.Core.Services; public interface IPushRegistrationService { Task CreateOrUpdateRegistrationAsync(string pushToken, string deviceId, string userId, - string identifier, DeviceType type); + string identifier, DeviceType type, IEnumerable organizationIds); Task DeleteRegistrationAsync(string deviceId); Task AddUserRegistrationOrganizationAsync(IEnumerable deviceIds, string organizationId); Task DeleteUserRegistrationOrganizationAsync(IEnumerable deviceIds, string organizationId); diff --git a/src/Core/Services/Implementations/DeviceService.cs b/src/Core/Services/Implementations/DeviceService.cs index 638e4c5e0..cc45bf62a 100644 --- a/src/Core/Services/Implementations/DeviceService.cs +++ b/src/Core/Services/Implementations/DeviceService.cs @@ -1,6 +1,7 @@ using Bit.Core.Auth.Models.Api.Request; using Bit.Core.Auth.Utilities; using Bit.Core.Entities; +using Bit.Core.Enums; using Bit.Core.Exceptions; using Bit.Core.Repositories; @@ -10,13 +11,16 @@ public class DeviceService : IDeviceService { private readonly IDeviceRepository _deviceRepository; private readonly IPushRegistrationService _pushRegistrationService; + private readonly IOrganizationUserRepository _organizationUserRepository; public DeviceService( IDeviceRepository deviceRepository, - IPushRegistrationService pushRegistrationService) + IPushRegistrationService pushRegistrationService, + IOrganizationUserRepository organizationUserRepository) { _deviceRepository = deviceRepository; _pushRegistrationService = pushRegistrationService; + _organizationUserRepository = organizationUserRepository; } public async Task SaveAsync(Device device) @@ -31,8 +35,13 @@ public class DeviceService : IDeviceService await _deviceRepository.ReplaceAsync(device); } + var organizationIdsString = + (await _organizationUserRepository.GetManyDetailsByUserAsync(device.UserId, + OrganizationUserStatusType.Confirmed)) + .Select(ou => ou.OrganizationId.ToString()); + await _pushRegistrationService.CreateOrUpdateRegistrationAsync(device.PushToken, device.Id.ToString(), - device.UserId.ToString(), device.Identifier, device.Type); + device.UserId.ToString(), device.Identifier, device.Type, organizationIdsString); } public async Task ClearTokenAsync(Device device) diff --git a/src/Core/Services/Implementations/RelayPushRegistrationService.cs b/src/Core/Services/Implementations/RelayPushRegistrationService.cs index d0f7736e9..3000f1545 100644 --- a/src/Core/Services/Implementations/RelayPushRegistrationService.cs +++ b/src/Core/Services/Implementations/RelayPushRegistrationService.cs @@ -25,7 +25,7 @@ public class RelayPushRegistrationService : BaseIdentityClientService, IPushRegi } public async Task CreateOrUpdateRegistrationAsync(string pushToken, string deviceId, string userId, - string identifier, DeviceType type) + string identifier, DeviceType type, IEnumerable organizationIds) { var requestModel = new PushRegistrationRequestModel { @@ -33,7 +33,8 @@ public class RelayPushRegistrationService : BaseIdentityClientService, IPushRegi Identifier = identifier, PushToken = pushToken, Type = type, - UserId = userId + UserId = userId, + OrganizationIds = organizationIds }; await SendAsync(HttpMethod.Post, "push/register", requestModel); } diff --git a/src/Core/Services/NoopImplementations/NoopPushRegistrationService.cs b/src/Core/Services/NoopImplementations/NoopPushRegistrationService.cs index f6279c946..4db799580 100644 --- a/src/Core/Services/NoopImplementations/NoopPushRegistrationService.cs +++ b/src/Core/Services/NoopImplementations/NoopPushRegistrationService.cs @@ -10,7 +10,7 @@ public class NoopPushRegistrationService : IPushRegistrationService } public Task CreateOrUpdateRegistrationAsync(string pushToken, string deviceId, string userId, - string identifier, DeviceType type) + string identifier, DeviceType type, IEnumerable organizationIds) { return Task.FromResult(0); } diff --git a/test/Core.Test/NotificationHub/NotificationHubPushRegistrationServiceTests.cs b/test/Core.Test/NotificationHub/NotificationHubPushRegistrationServiceTests.cs index 9c63c2c1b..d51df9c88 100644 --- a/test/Core.Test/NotificationHub/NotificationHubPushRegistrationServiceTests.cs +++ b/test/Core.Test/NotificationHub/NotificationHubPushRegistrationServiceTests.cs @@ -1,8 +1,6 @@ #nullable enable using Bit.Core.Enums; -using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.NotificationHub; -using Bit.Core.Repositories; using Bit.Core.Utilities; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; @@ -19,11 +17,12 @@ public class NotificationHubPushRegistrationServiceTests [BitAutoData([null])] [BitAutoData("")] [BitAutoData(" ")] - public async void CreateOrUpdateRegistrationAsync_PushTokenNullOrEmpty_InstallationNotCreated(string? pushToken, - SutProvider sutProvider, Guid deviceId, Guid userId, Guid identifier) + public async Task CreateOrUpdateRegistrationAsync_PushTokenNullOrEmpty_InstallationNotCreated(string? pushToken, + SutProvider sutProvider, Guid deviceId, Guid userId, Guid identifier, + Guid organizationId) { await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(), - identifier.ToString(), DeviceType.Android); + identifier.ToString(), DeviceType.Android, [organizationId.ToString()]); sutProvider.GetDependency() .Received(0) @@ -31,10 +30,13 @@ public class NotificationHubPushRegistrationServiceTests } [Theory] - [BitAutoData(false)] - [BitAutoData(true)] - public async void CreateOrUpdateRegistrationAsync_DeviceTypeAndroid_InstallationCreated(bool identifierNull, - SutProvider sutProvider, Guid deviceId, Guid userId, Guid? identifier) + [BitAutoData(false, false)] + [BitAutoData(false, true)] + [BitAutoData(true, false)] + [BitAutoData(true, true)] + public async Task CreateOrUpdateRegistrationAsync_DeviceTypeAndroid_InstallationCreated(bool identifierNull, + bool partOfOrganizationId, SutProvider sutProvider, Guid deviceId, + Guid userId, Guid? identifier, Guid organizationId) { var notificationHubClient = Substitute.For(); sutProvider.GetDependency().ClientFor(Arg.Any()).Returns(notificationHubClient); @@ -42,7 +44,8 @@ public class NotificationHubPushRegistrationServiceTests var pushToken = "test push token"; await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(), - identifierNull ? null : identifier.ToString(), DeviceType.Android); + identifierNull ? null : identifier.ToString(), DeviceType.Android, + partOfOrganizationId ? [organizationId.ToString()] : []); sutProvider.GetDependency() .Received(1) @@ -53,10 +56,10 @@ public class NotificationHubPushRegistrationServiceTests installation.InstallationId == deviceId.ToString() && installation.PushChannel == pushToken && installation.Platform == NotificationPlatform.FcmV1 && - installation.Tags.Count == (identifierNull ? 2 : 3) && installation.Tags.Contains($"userId:{userId}") && installation.Tags.Contains("clientType:Mobile") && (identifierNull || installation.Tags.Contains($"deviceIdentifier:{identifier}")) && + (!partOfOrganizationId || installation.Tags.Contains($"organizationId:{organizationId}")) && installation.Templates.Count == 3)); await notificationHubClient .Received(1) @@ -68,7 +71,8 @@ public class NotificationHubPushRegistrationServiceTests "template:payload", $"template:payload_userId:{userId}", "clientType:Mobile", - identifierNull ? null : $"template:payload_deviceIdentifier:{identifier}" + identifierNull ? null : $"template:payload_deviceIdentifier:{identifier}", + partOfOrganizationId ? $"organizationId:{organizationId}" : null, }))); await notificationHubClient .Received(1) @@ -80,7 +84,8 @@ public class NotificationHubPushRegistrationServiceTests "template:message", $"template:message_userId:{userId}", "clientType:Mobile", - identifierNull ? null : $"template:message_deviceIdentifier:{identifier}" + identifierNull ? null : $"template:message_deviceIdentifier:{identifier}", + partOfOrganizationId ? $"organizationId:{organizationId}" : null, }))); await notificationHubClient .Received(1) @@ -92,15 +97,19 @@ public class NotificationHubPushRegistrationServiceTests "template:badgeMessage", $"template:badgeMessage_userId:{userId}", "clientType:Mobile", - identifierNull ? null : $"template:badgeMessage_deviceIdentifier:{identifier}" + identifierNull ? null : $"template:badgeMessage_deviceIdentifier:{identifier}", + partOfOrganizationId ? $"organizationId:{organizationId}" : null, }))); } [Theory] - [BitAutoData(false)] - [BitAutoData(true)] - public async void CreateOrUpdateRegistrationAsync_DeviceTypeIOS_InstallationCreated(bool identifierNull, - SutProvider sutProvider, Guid deviceId, Guid userId, Guid identifier) + [BitAutoData(false, false)] + [BitAutoData(false, true)] + [BitAutoData(true, false)] + [BitAutoData(true, true)] + public async Task CreateOrUpdateRegistrationAsync_DeviceTypeIOS_InstallationCreated(bool identifierNull, + bool partOfOrganizationId, SutProvider sutProvider, Guid deviceId, + Guid userId, Guid identifier, Guid organizationId) { var notificationHubClient = Substitute.For(); sutProvider.GetDependency().ClientFor(Arg.Any()).Returns(notificationHubClient); @@ -108,7 +117,8 @@ public class NotificationHubPushRegistrationServiceTests var pushToken = "test push token"; await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(), - identifierNull ? null : identifier.ToString(), DeviceType.iOS); + identifierNull ? null : identifier.ToString(), DeviceType.iOS, + partOfOrganizationId ? [organizationId.ToString()] : []); sutProvider.GetDependency() .Received(1) @@ -119,10 +129,10 @@ public class NotificationHubPushRegistrationServiceTests installation.InstallationId == deviceId.ToString() && installation.PushChannel == pushToken && installation.Platform == NotificationPlatform.Apns && - installation.Tags.Count == (identifierNull ? 2 : 3) && installation.Tags.Contains($"userId:{userId}") && installation.Tags.Contains("clientType:Mobile") && (identifierNull || installation.Tags.Contains($"deviceIdentifier:{identifier}")) && + (!partOfOrganizationId || installation.Tags.Contains($"organizationId:{organizationId}")) && installation.Templates.Count == 3)); await notificationHubClient .Received(1) @@ -134,7 +144,8 @@ public class NotificationHubPushRegistrationServiceTests "template:payload", $"template:payload_userId:{userId}", "clientType:Mobile", - identifierNull ? null : $"template:payload_deviceIdentifier:{identifier}" + identifierNull ? null : $"template:payload_deviceIdentifier:{identifier}", + partOfOrganizationId ? $"organizationId:{organizationId}" : null, }))); await notificationHubClient .Received(1) @@ -146,7 +157,8 @@ public class NotificationHubPushRegistrationServiceTests "template:message", $"template:message_userId:{userId}", "clientType:Mobile", - identifierNull ? null : $"template:message_deviceIdentifier:{identifier}" + identifierNull ? null : $"template:message_deviceIdentifier:{identifier}", + partOfOrganizationId ? $"organizationId:{organizationId}" : null, }))); await notificationHubClient .Received(1) @@ -158,15 +170,19 @@ public class NotificationHubPushRegistrationServiceTests "template:badgeMessage", $"template:badgeMessage_userId:{userId}", "clientType:Mobile", - identifierNull ? null : $"template:badgeMessage_deviceIdentifier:{identifier}" + identifierNull ? null : $"template:badgeMessage_deviceIdentifier:{identifier}", + partOfOrganizationId ? $"organizationId:{organizationId}" : null, }))); } [Theory] - [BitAutoData(false)] - [BitAutoData(true)] - public async void CreateOrUpdateRegistrationAsync_DeviceTypeAndroidAmazon_InstallationCreated(bool identifierNull, - SutProvider sutProvider, Guid deviceId, Guid userId, Guid identifier) + [BitAutoData(false, false)] + [BitAutoData(false, true)] + [BitAutoData(true, false)] + [BitAutoData(true, true)] + public async Task CreateOrUpdateRegistrationAsync_DeviceTypeAndroidAmazon_InstallationCreated(bool identifierNull, + bool partOfOrganizationId, SutProvider sutProvider, Guid deviceId, + Guid userId, Guid identifier, Guid organizationId) { var notificationHubClient = Substitute.For(); sutProvider.GetDependency().ClientFor(Arg.Any()).Returns(notificationHubClient); @@ -174,7 +190,8 @@ public class NotificationHubPushRegistrationServiceTests var pushToken = "test push token"; await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(), - identifierNull ? null : identifier.ToString(), DeviceType.AndroidAmazon); + identifierNull ? null : identifier.ToString(), DeviceType.AndroidAmazon, + partOfOrganizationId ? [organizationId.ToString()] : []); sutProvider.GetDependency() .Received(1) @@ -185,10 +202,10 @@ public class NotificationHubPushRegistrationServiceTests installation.InstallationId == deviceId.ToString() && installation.PushChannel == pushToken && installation.Platform == NotificationPlatform.Adm && - installation.Tags.Count == (identifierNull ? 2 : 3) && installation.Tags.Contains($"userId:{userId}") && installation.Tags.Contains("clientType:Mobile") && (identifierNull || installation.Tags.Contains($"deviceIdentifier:{identifier}")) && + (!partOfOrganizationId || installation.Tags.Contains($"organizationId:{organizationId}")) && installation.Templates.Count == 3)); await notificationHubClient .Received(1) @@ -200,7 +217,8 @@ public class NotificationHubPushRegistrationServiceTests "template:payload", $"template:payload_userId:{userId}", "clientType:Mobile", - identifierNull ? null : $"template:payload_deviceIdentifier:{identifier}" + identifierNull ? null : $"template:payload_deviceIdentifier:{identifier}", + partOfOrganizationId ? $"organizationId:{organizationId}" : null, }))); await notificationHubClient .Received(1) @@ -212,7 +230,8 @@ public class NotificationHubPushRegistrationServiceTests "template:message", $"template:message_userId:{userId}", "clientType:Mobile", - identifierNull ? null : $"template:message_deviceIdentifier:{identifier}" + identifierNull ? null : $"template:message_deviceIdentifier:{identifier}", + partOfOrganizationId ? $"organizationId:{organizationId}" : null, }))); await notificationHubClient .Received(1) @@ -224,7 +243,8 @@ public class NotificationHubPushRegistrationServiceTests "template:badgeMessage", $"template:badgeMessage_userId:{userId}", "clientType:Mobile", - identifierNull ? null : $"template:badgeMessage_deviceIdentifier:{identifier}" + identifierNull ? null : $"template:badgeMessage_deviceIdentifier:{identifier}", + partOfOrganizationId ? $"organizationId:{organizationId}" : null, }))); } @@ -232,8 +252,9 @@ public class NotificationHubPushRegistrationServiceTests [BitAutoData(DeviceType.ChromeBrowser)] [BitAutoData(DeviceType.ChromeExtension)] [BitAutoData(DeviceType.MacOsDesktop)] - public async void CreateOrUpdateRegistrationAsync_DeviceTypeNotMobile_InstallationCreated(DeviceType deviceType, - SutProvider sutProvider, Guid deviceId, Guid userId, Guid identifier) + public async Task CreateOrUpdateRegistrationAsync_DeviceTypeNotMobile_InstallationCreated(DeviceType deviceType, + SutProvider sutProvider, Guid deviceId, Guid userId, Guid identifier, + Guid organizationId) { var notificationHubClient = Substitute.For(); sutProvider.GetDependency().ClientFor(Arg.Any()).Returns(notificationHubClient); @@ -241,7 +262,7 @@ public class NotificationHubPushRegistrationServiceTests var pushToken = "test push token"; await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(), - identifier.ToString(), deviceType); + identifier.ToString(), deviceType, [organizationId.ToString()]); sutProvider.GetDependency() .Received(1) @@ -251,45 +272,13 @@ public class NotificationHubPushRegistrationServiceTests .CreateOrUpdateInstallationAsync(Arg.Is(installation => installation.InstallationId == deviceId.ToString() && installation.PushChannel == pushToken && - installation.Tags.Count == 3 && installation.Tags.Contains($"userId:{userId}") && installation.Tags.Contains($"clientType:{DeviceTypes.ToClientType(deviceType)}") && installation.Tags.Contains($"deviceIdentifier:{identifier}") && + installation.Tags.Contains($"organizationId:{organizationId}") && installation.Templates.Count == 0)); } - [Theory] - [BitAutoData] - public async void CreateOrUpdateRegistrationAsync_UserPartOfOrganization_InstallationCreated( - SutProvider sutProvider, Guid deviceId, Guid userId, Guid identifier, - OrganizationUserOrganizationDetails organizationDetails) - { - var notificationHubClient = Substitute.For(); - sutProvider.GetDependency().ClientFor(Arg.Any()).Returns(notificationHubClient); - sutProvider.GetDependency() - .GetManyDetailsByUserAsync(userId, OrganizationUserStatusType.Confirmed) - .Returns([organizationDetails]); - - var pushToken = "test push token"; - - await sutProvider.Sut.CreateOrUpdateRegistrationAsync(pushToken, deviceId.ToString(), userId.ToString(), - identifier.ToString(), DeviceType.ChromeBrowser); - - sutProvider.GetDependency() - .Received(1) - .ClientFor(deviceId); - await notificationHubClient - .Received(1) - .CreateOrUpdateInstallationAsync(Arg.Is(installation => - installation.InstallationId == deviceId.ToString() && - installation.PushChannel == pushToken && - installation.Tags.Count == 4 && - installation.Tags.Contains($"userId:{userId}") && - installation.Tags.Contains($"clientType:{DeviceTypes.ToClientType(DeviceType.ChromeBrowser)}") && - installation.Tags.Contains($"deviceIdentifier:{identifier}") && - installation.Tags.Contains($"organizationId:{organizationDetails.OrganizationId}"))); - } - private static bool MatchingInstallationTemplate(IDictionary templates, string key, string body, List tags) { diff --git a/test/Core.Test/Services/DeviceServiceTests.cs b/test/Core.Test/Services/DeviceServiceTests.cs index cb2aebc99..10aa8761f 100644 --- a/test/Core.Test/Services/DeviceServiceTests.cs +++ b/test/Core.Test/Services/DeviceServiceTests.cs @@ -3,6 +3,7 @@ using Bit.Core.Auth.Models.Api.Request; using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Exceptions; +using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Test.Common.AutoFixture; @@ -15,15 +16,23 @@ namespace Bit.Core.Test.Services; [SutProviderCustomize] public class DeviceServiceTests { - [Fact] - public async Task DeviceSaveShouldUpdateRevisionDateAndPushRegistration() + [Theory] + [BitAutoData] + public async Task SaveAsync_IdProvided_UpdatedRevisionDateAndPushRegistration(Guid id, Guid userId, + Guid organizationId1, Guid organizationId2, + OrganizationUserOrganizationDetails organizationUserOrganizationDetails1, + OrganizationUserOrganizationDetails organizationUserOrganizationDetails2) { + organizationUserOrganizationDetails1.OrganizationId = organizationId1; + organizationUserOrganizationDetails2.OrganizationId = organizationId2; + var deviceRepo = Substitute.For(); var pushRepo = Substitute.For(); - var deviceService = new DeviceService(deviceRepo, pushRepo); + var organizationUserRepository = Substitute.For(); + organizationUserRepository.GetManyDetailsByUserAsync(Arg.Any(), Arg.Any()) + .Returns([organizationUserOrganizationDetails1, organizationUserOrganizationDetails2]); + var deviceService = new DeviceService(deviceRepo, pushRepo, organizationUserRepository); - var id = Guid.NewGuid(); - var userId = Guid.NewGuid(); var device = new Device { Id = id, @@ -36,8 +45,53 @@ public class DeviceServiceTests await deviceService.SaveAsync(device); Assert.True(device.RevisionDate - DateTime.UtcNow < TimeSpan.FromSeconds(1)); - await pushRepo.Received().CreateOrUpdateRegistrationAsync("testtoken", id.ToString(), - userId.ToString(), "testid", DeviceType.Android); + await pushRepo.Received(1).CreateOrUpdateRegistrationAsync("testtoken", id.ToString(), + userId.ToString(), "testid", DeviceType.Android, + Arg.Do>(organizationIds => + { + var organizationIdsList = organizationIds.ToList(); + Assert.Equal(2, organizationIdsList.Count); + Assert.Contains(organizationId1.ToString(), organizationIdsList); + Assert.Contains(organizationId2.ToString(), organizationIdsList); + })); + } + + [Theory] + [BitAutoData] + public async Task SaveAsync_IdNotProvided_CreatedAndPushRegistration(Guid userId, Guid organizationId1, + Guid organizationId2, + OrganizationUserOrganizationDetails organizationUserOrganizationDetails1, + OrganizationUserOrganizationDetails organizationUserOrganizationDetails2) + { + organizationUserOrganizationDetails1.OrganizationId = organizationId1; + organizationUserOrganizationDetails2.OrganizationId = organizationId2; + + var deviceRepo = Substitute.For(); + var pushRepo = Substitute.For(); + var organizationUserRepository = Substitute.For(); + organizationUserRepository.GetManyDetailsByUserAsync(Arg.Any(), Arg.Any()) + .Returns([organizationUserOrganizationDetails1, organizationUserOrganizationDetails2]); + var deviceService = new DeviceService(deviceRepo, pushRepo, organizationUserRepository); + + var device = new Device + { + Name = "test device", + Type = DeviceType.Android, + UserId = userId, + PushToken = "testtoken", + Identifier = "testid" + }; + await deviceService.SaveAsync(device); + + await pushRepo.Received(1).CreateOrUpdateRegistrationAsync("testtoken", + Arg.Do(id => Guid.TryParse(id, out var _)), userId.ToString(), "testid", DeviceType.Android, + Arg.Do>(organizationIds => + { + var organizationIdsList = organizationIds.ToList(); + Assert.Equal(2, organizationIdsList.Count); + Assert.Contains(organizationId1.ToString(), organizationIdsList); + Assert.Contains(organizationId2.ToString(), organizationIdsList); + })); } /// @@ -61,12 +115,7 @@ public class DeviceServiceTests sutProvider.GetDependency() .GetManyByUserIdAsync(currentUserId) - .Returns(new List - { - deviceOne, - deviceTwo, - deviceThree, - }); + .Returns(new List { deviceOne, deviceTwo, deviceThree, }); var currentDeviceModel = new DeviceKeysUpdateRequestModel { @@ -84,7 +133,8 @@ public class DeviceServiceTests }, }; - await sutProvider.Sut.UpdateDevicesTrustAsync("current_device", currentUserId, currentDeviceModel, alteredDeviceModels); + await sutProvider.Sut.UpdateDevicesTrustAsync("current_device", currentUserId, currentDeviceModel, + alteredDeviceModels); // Updating trust, "current" or "other" only needs to change the EncryptedPublicKey & EncryptedUserKey await sutProvider.GetDependency() @@ -148,11 +198,7 @@ public class DeviceServiceTests sutProvider.GetDependency() .GetManyByUserIdAsync(currentUserId) - .Returns(new List - { - deviceOne, - deviceTwo, - }); + .Returns(new List { deviceOne, deviceTwo, }); var currentDeviceModel = new DeviceKeysUpdateRequestModel { @@ -170,7 +216,8 @@ public class DeviceServiceTests }, }; - await sutProvider.Sut.UpdateDevicesTrustAsync("current_device", currentUserId, currentDeviceModel, alteredDeviceModels); + await sutProvider.Sut.UpdateDevicesTrustAsync("current_device", currentUserId, currentDeviceModel, + alteredDeviceModels); // Check that UpsertAsync was called for the trusted device await sutProvider.GetDependency() @@ -202,11 +249,7 @@ public class DeviceServiceTests sutProvider.GetDependency() .GetManyByUserIdAsync(currentUserId) - .Returns(new List - { - deviceOne, - deviceTwo, - }); + .Returns(new List { deviceOne, deviceTwo, }); var currentDeviceModel = new DeviceKeysUpdateRequestModel { @@ -236,11 +279,7 @@ public class DeviceServiceTests sutProvider.GetDependency() .GetManyByUserIdAsync(currentUserId) - .Returns(new List - { - deviceOne, - deviceTwo, - }); + .Returns(new List { deviceOne, deviceTwo, }); var currentDeviceModel = new DeviceKeysUpdateRequestModel { @@ -259,6 +298,7 @@ public class DeviceServiceTests }; await Assert.ThrowsAsync(() => - sutProvider.Sut.UpdateDevicesTrustAsync("current_device", currentUserId, currentDeviceModel, alteredDeviceModels)); + sutProvider.Sut.UpdateDevicesTrustAsync("current_device", currentUserId, currentDeviceModel, + alteredDeviceModels)); } }