From 08d1490924b2d1feba5afb1f4e040a4d57db1635 Mon Sep 17 00:00:00 2001 From: Tayyab Fayyaz Janjua Date: Mon, 12 Aug 2024 18:03:57 +0200 Subject: [PATCH 1/3] fix(emailNotification): Add Multiple Users | Invite email didnt receive by User(s) User(s) didnt receive invite emails when invited via Add Multiple Users. Users has been created but invite email does not sent out to users. Ref: #920 --- .../BusinessLogic/UserUploadBusinessLogic.cs | 59 +++++++++++++++++-- .../UserUploadBusinessLogicTests.cs | 32 +++++----- 2 files changed, 72 insertions(+), 19 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs index 63513c11f7..4dd735842f 100644 --- a/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs @@ -23,6 +23,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Service; using Org.Eclipse.TractusX.Portal.Backend.Framework.IO; using Org.Eclipse.TractusX.Portal.Backend.Framework.Linq; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Identities; @@ -41,6 +42,7 @@ public class UserUploadBusinessLogic : IUserUploadBusinessLogic private readonly UserSettings _settings; private readonly IIdentityData _identityData; private readonly IErrorMessageService _errorMessageService; + private readonly IPortalRepositories _portalRepositories; /// /// Constructor. @@ -50,18 +52,21 @@ public class UserUploadBusinessLogic : IUserUploadBusinessLogic /// Access to the identity Service /// ErrorMessage Service /// Settings + /// Portal Repositories public UserUploadBusinessLogic( IUserProvisioningService userProvisioningService, IMailingProcessCreation mailingProcessCreation, IIdentityService identityService, IErrorMessageService errorMessageService, - IOptions settings) + IOptions settings, + IPortalRepositories portalRepositories) { _userProvisioningService = userProvisioningService; _mailingProcessCreation = mailingProcessCreation; _identityData = identityService.IdentityData; _errorMessageService = errorMessageService; _settings = settings.Value; + _portalRepositories = portalRepositories; } public ValueTask UploadOwnCompanyIdpUsersAsync(Guid identityProviderId, IFormFile document, CancellationToken cancellationToken) @@ -167,6 +172,52 @@ await GetUserRoleDatas(parsed.Roles, validRoleData, _identityData.CompanyId).Con } } + private async IAsyncEnumerable<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)> CreateOwnCompanySharedIdpUsersWithEmailAsync(string nameCreatedBy, CompanyNameIdpAliasData companyNameIdpAliasData, IAsyncEnumerable userCreationInfos, [EnumeratorCancellation] CancellationToken cancellationToken) + { + UserCreationRoleDataIdpInfo? userCreationInfo = null; + + var displayName = await _userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias; + + await foreach (var result in + _userProvisioningService + .CreateOwnCompanyIdpUsersAsync( + companyNameIdpAliasData, + userCreationInfos + .Select(info => + { + userCreationInfo = info; + return info; + }), + cancellationToken) + .WithCancellation(cancellationToken) + .ConfigureAwait(false)) + { + if (userCreationInfo == null) + { + throw new UnexpectedConditionException("userCreationInfo should never be null here"); + } + if (result.Error != null || result.CompanyUserId == Guid.Empty || string.IsNullOrEmpty(userCreationInfo.Email)) + { + yield return result; + continue; + } + + var mailParameters = ImmutableDictionary.CreateRange(new[] + { + KeyValuePair.Create("password", result.Password ?? ""), + KeyValuePair.Create("companyName", displayName), + KeyValuePair.Create("nameCreatedBy", nameCreatedBy), + KeyValuePair.Create("url", _settings.Portal.BasePortalAddress), + KeyValuePair.Create("passwordResendUrl", _settings.Portal.PasswordResendAddress), + }); + _mailingProcessCreation.CreateMailProcess(userCreationInfo.Email, "NewUserTemplate", mailParameters); + _mailingProcessCreation.CreateMailProcess(userCreationInfo.Email, "NewUserPasswordTemplate", mailParameters); + await _portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); + + yield return (result.CompanyUserId, result.UserName, result.Password, null); + } + } + private static void ValidateUserCreationRoles(IEnumerable roles) { if (!roles.Any()) @@ -199,7 +250,7 @@ private async ValueTask UploadOwnCompanySharedIdpUsersInterna { using var stream = document.OpenReadStream(); - var (companyNameIdpAliasData, _) = await _userProvisioningService.GetCompanyNameSharedIdpAliasData(_identityData.IdentityId).ConfigureAwait(ConfigureAwaitOptions.None); + var (companyNameIdpAliasData, nameCreatedBy) = await _userProvisioningService.GetCompanyNameSharedIdpAliasData(_identityData.IdentityId).ConfigureAwait(ConfigureAwaitOptions.None); var validRoleData = new List(); @@ -225,8 +276,8 @@ await GetUserRoleDatas(parsed.Roles, validRoleData, _identityData.CompanyId).Con true); }, lines => - _userProvisioningService - .CreateOwnCompanyIdpUsersAsync( + CreateOwnCompanySharedIdpUsersWithEmailAsync( + nameCreatedBy, companyNameIdpAliasData, lines, cancellationToken) diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs index 778e95aa4d..f04a894932 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs @@ -38,6 +38,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLog public class UserUploadBusinessLogicTests { private readonly IFixture _fixture; + private readonly IPortalRepositories _portalRepositories; private readonly IUserProvisioningService _userProvisioningService; private readonly IOptions _options; private readonly IFormFile _document; @@ -58,6 +59,7 @@ public UserUploadBusinessLogicTests() _fixture.Behaviors.OfType().ToList() .ForEach(b => _fixture.Behaviors.Remove(b)); _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _portalRepositories = A.Fake(); _random = new Random(); @@ -94,7 +96,7 @@ public async Task TestSetup() { SetupFakes(new[] { HeaderLine() }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -120,7 +122,7 @@ public async Task TestUserCreationAllSuccess() NextLine() }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -147,7 +149,7 @@ public async Task TestUserCreationHeaderParsingThrows() NextLine() }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); async Task Act() => await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -178,7 +180,7 @@ public async Task TestUserCreationCreationError() .With(x => x.Error, detailError) .Create()); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -220,7 +222,7 @@ public async Task TestUserCreationCreationNoRolesError() NextLine() }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -248,7 +250,7 @@ public async Task TestUserCreationParsingError() NextLine() }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -278,7 +280,7 @@ public async Task TestUserCreationCreationThrows() A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatches(info, creationInfo)))) .Throws(_error); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -302,7 +304,7 @@ public async Task TestSetupSharedIdp() { SetupFakes(new[] { HeaderLineSharedIdp() }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -326,7 +328,7 @@ public async Task TestUserCreationSharedIdpAllSuccess() NextLineSharedIdp() }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -336,7 +338,7 @@ public async Task TestUserCreationSharedIdpAllSuccess() result.Total.Should().Be(5); result.Errors.Should().BeEmpty(); A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, A._, A>._)) - .MustNotHaveHappened(); + .MustHaveHappened(); } [Fact] @@ -353,7 +355,7 @@ public async Task TestUserCreationSharedIdpHeaderParsingThrows() NextLineSharedIdp() }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); async Task Act() => await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -377,7 +379,7 @@ public async Task TestUserCreationSharedIdpNoRolesError() NextLineSharedIdp(), }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -415,7 +417,7 @@ public async Task TestUserCreationSharedIdpCreationError() .With(x => x.Error, detailError) .Create()); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -451,7 +453,7 @@ public async Task TestUserCreationSharedIdpParsingError() NextLineSharedIdp() }); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -480,7 +482,7 @@ public async Task TestUserCreationSharedIdpCreationThrows() A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)))) .Throws(_error); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); From 52c47f1593c423eb80b6034cbc67af216c883480 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Mon, 16 Sep 2024 10:32:14 +0200 Subject: [PATCH 2/3] refactor usercreation creating mail-processes in new onSuccess-callback --- .../BusinessLogic/UserBusinessLogic.cs | 50 +++---- .../BusinessLogic/UserUploadBusinessLogic.cs | 135 ++++------------- .../InvitationProcessService.cs | 2 +- .../Models/UserCreationRoleDataIdpInfo.cs | 5 + .../Service/IUserProvisioningService.cs | 2 +- .../Service/UserProvisioningService.cs | 2 + .../BusinessLogic/UserBusinessLogicTests.cs | 4 +- .../UserUploadBusinessLogicTests.cs | 141 +++++++++++------- .../InvitationProcessServiceTests.cs | 4 +- ...UserProvisioningServiceCreateUsersTests.cs | 92 +++++++++++- .../RegistrationBusinessLogicTest.cs | 8 +- 11 files changed, 250 insertions(+), 195 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs index 002ad52dc5..a611a29dfb 100644 --- a/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs @@ -158,7 +158,31 @@ public async Task CreateOwnCompanyIdpUserAsync(Guid identityProviderId, Us userCreationInfo.UserId, UserStatusId.ACTIVE, true - ), 1).ToAsyncEnumerable()) + ), 1).ToAsyncEnumerable(), + creationData => + { + var mailParameters = ImmutableDictionary.CreateBuilder(); + mailParameters.AddRange([ + new("companyName", displayName), + new("nameCreatedBy", nameCreatedBy), + new("url", _settings.Portal.BasePortalAddress), + new("idpAlias", displayName), + ]); + + IEnumerable mailTemplates = companyNameIdpAliasData.IsSharedIdp + ? ["NewUserTemplate", "NewUserPasswordTemplate"] + : ["NewUserExternalIdpTemplate"]; + + if (companyNameIdpAliasData.IsSharedIdp) + { + mailParameters.Add(new("password", creationData.Password ?? throw new UnexpectedConditionException("password should never be null here"))); + } + + foreach (var template in mailTemplates) + { + mailingProcessCreation.CreateMailProcess(creationData.UserCreationInfo.Email, template, mailParameters.ToImmutable()); + } + }) .FirstAsync() .ConfigureAwait(false); @@ -166,30 +190,6 @@ public async Task CreateOwnCompanyIdpUserAsync(Guid identityProviderId, Us { throw result.Error; } - - var mailParameters = new Dictionary - { - { "companyName", displayName }, - { "nameCreatedBy", nameCreatedBy }, - { "url", _settings.Portal.BasePortalAddress }, - { "idpAlias", displayName }, - }; - - var mailTemplates = companyNameIdpAliasData.IsSharedIdp - ? new[] { "NewUserTemplate", "NewUserPasswordTemplate" } - : new[] { "NewUserExternalIdpTemplate" }; - - if (companyNameIdpAliasData.IsSharedIdp) - { - mailParameters["password"] = result.Password; - } - - foreach (var template in mailTemplates) - { - mailingProcessCreation.CreateMailProcess(userCreationInfo.Email, template, mailParameters.ToImmutableDictionary()); - } - - await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); return result.CompanyUserId; } diff --git a/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs index 4dd735842f..2739abbdd3 100644 --- a/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs @@ -31,7 +31,6 @@ using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Models; using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Service; using System.Collections.Immutable; -using System.Runtime.CompilerServices; namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLogic; @@ -83,6 +82,10 @@ private async ValueTask UploadOwnCompanyIdpUsersInternalAsync var validRoleData = new List(); + var displayName = companyNameIdpAliasData.IsSharedIdp + ? null + : await _userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias; + var (numCreated, numLines, errors) = await CsvParser.ProcessCsvAsync( stream, line => @@ -104,17 +107,23 @@ await GetUserRoleDatas(parsed.Roles, validRoleData, _identityData.CompanyId).Con UserStatusId.ACTIVE, true); }, - lines => (companyNameIdpAliasData.IsSharedIdp - ? _userProvisioningService + lines => + _userProvisioningService .CreateOwnCompanyIdpUsersAsync( companyNameIdpAliasData, lines, + creationData => + { + if (companyNameIdpAliasData.IsSharedIdp) + return; + var mailParameters = ImmutableDictionary.CreateRange([ + new("nameCreatedBy", nameCreatedBy), + new("url", _settings.Portal.BasePortalAddress), + new("idpAlias", displayName ?? throw new UnexpectedConditionException("displayname should never be null here")) + ]); + _mailingProcessCreation.CreateMailProcess(creationData.UserCreationInfo.Email, "NewUserExternalIdpTemplate", mailParameters); + }, cancellationToken) - : CreateOwnCompanyIdpUsersWithEmailAsync( - nameCreatedBy, - companyNameIdpAliasData, - lines, - cancellationToken)) .Select(x => (x.CompanyUserId != Guid.Empty, x.Error)), cancellationToken).ConfigureAwait(false); @@ -125,99 +134,6 @@ await GetUserRoleDatas(parsed.Roles, validRoleData, _identityData.CompanyId).Con errors.Select(error => CreateUserCreationError(error.Line, error.Error))); } - private async IAsyncEnumerable<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)> CreateOwnCompanyIdpUsersWithEmailAsync(string nameCreatedBy, CompanyNameIdpAliasData companyNameIdpAliasData, IAsyncEnumerable userCreationInfos, [EnumeratorCancellation] CancellationToken cancellationToken) - { - if (companyNameIdpAliasData.IsSharedIdp) - { - throw new UnexpectedConditionException($"unexpected call to {nameof(CreateOwnCompanyIdpUsersWithEmailAsync)} for shared-idp"); - } - - UserCreationRoleDataIdpInfo? userCreationInfo = null; - - var displayName = await _userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias; - - await foreach (var result in - _userProvisioningService - .CreateOwnCompanyIdpUsersAsync( - companyNameIdpAliasData, - userCreationInfos - .Select(info => - { - userCreationInfo = info; - return info; - }), - cancellationToken) - .WithCancellation(cancellationToken) - .ConfigureAwait(false)) - { - if (userCreationInfo == null) - { - throw new UnexpectedConditionException("userCreationInfo should never be null here"); - } - if (result.Error != null || result.CompanyUserId == Guid.Empty || string.IsNullOrEmpty(userCreationInfo.Email)) - { - yield return result; - continue; - } - - var mailParameters = ImmutableDictionary.CreateRange(new[] - { - KeyValuePair.Create("nameCreatedBy", nameCreatedBy), - KeyValuePair.Create("url", _settings.Portal.BasePortalAddress), - KeyValuePair.Create("idpAlias", displayName) - }); - _mailingProcessCreation.CreateMailProcess(userCreationInfo.Email, "NewUserExternalIdpTemplate", mailParameters); - - yield return (result.CompanyUserId, result.UserName, result.Password, null); - } - } - - private async IAsyncEnumerable<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)> CreateOwnCompanySharedIdpUsersWithEmailAsync(string nameCreatedBy, CompanyNameIdpAliasData companyNameIdpAliasData, IAsyncEnumerable userCreationInfos, [EnumeratorCancellation] CancellationToken cancellationToken) - { - UserCreationRoleDataIdpInfo? userCreationInfo = null; - - var displayName = await _userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias; - - await foreach (var result in - _userProvisioningService - .CreateOwnCompanyIdpUsersAsync( - companyNameIdpAliasData, - userCreationInfos - .Select(info => - { - userCreationInfo = info; - return info; - }), - cancellationToken) - .WithCancellation(cancellationToken) - .ConfigureAwait(false)) - { - if (userCreationInfo == null) - { - throw new UnexpectedConditionException("userCreationInfo should never be null here"); - } - if (result.Error != null || result.CompanyUserId == Guid.Empty || string.IsNullOrEmpty(userCreationInfo.Email)) - { - yield return result; - continue; - } - - var mailParameters = ImmutableDictionary.CreateRange(new[] - { - KeyValuePair.Create("password", result.Password ?? ""), - KeyValuePair.Create("companyName", displayName), - KeyValuePair.Create("nameCreatedBy", nameCreatedBy), - KeyValuePair.Create("url", _settings.Portal.BasePortalAddress), - KeyValuePair.Create("passwordResendUrl", _settings.Portal.PasswordResendAddress), - }); - _mailingProcessCreation.CreateMailProcess(userCreationInfo.Email, "NewUserTemplate", mailParameters); - _mailingProcessCreation.CreateMailProcess(userCreationInfo.Email, "NewUserPasswordTemplate", mailParameters); - await _portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); - - yield return (result.CompanyUserId, result.UserName, result.Password, null); - } - } - private static void ValidateUserCreationRoles(IEnumerable roles) { if (!roles.Any()) @@ -251,6 +167,7 @@ private async ValueTask UploadOwnCompanySharedIdpUsersInterna using var stream = document.OpenReadStream(); var (companyNameIdpAliasData, nameCreatedBy) = await _userProvisioningService.GetCompanyNameSharedIdpAliasData(_identityData.IdentityId).ConfigureAwait(ConfigureAwaitOptions.None); + var displayName = await _userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias; var validRoleData = new List(); @@ -276,10 +193,22 @@ await GetUserRoleDatas(parsed.Roles, validRoleData, _identityData.CompanyId).Con true); }, lines => - CreateOwnCompanySharedIdpUsersWithEmailAsync( - nameCreatedBy, + _userProvisioningService + .CreateOwnCompanyIdpUsersAsync( companyNameIdpAliasData, lines, + creationData => + { + var mailParameters = ImmutableDictionary.CreateRange([ + new("password", creationData.Password ?? ""), + new("companyName", displayName), + new("nameCreatedBy", nameCreatedBy), + new("url", _settings.Portal.BasePortalAddress), + new("passwordResendUrl", _settings.Portal.PasswordResendAddress), + ]); + _mailingProcessCreation.CreateMailProcess(creationData.UserCreationInfo.Email, "NewUserTemplate", mailParameters); + _mailingProcessCreation.CreateMailProcess(creationData.UserCreationInfo.Email, "NewUserPasswordTemplate", mailParameters); + }, cancellationToken) .Select(x => (x.CompanyUserId != Guid.Empty, x.Error)), cancellationToken).ConfigureAwait(false); diff --git a/src/processes/Invitation.Executor/InvitationProcessService.cs b/src/processes/Invitation.Executor/InvitationProcessService.cs index 4a88d14e0f..241ad5561f 100644 --- a/src/processes/Invitation.Executor/InvitationProcessService.cs +++ b/src/processes/Invitation.Executor/InvitationProcessService.cs @@ -340,7 +340,7 @@ await _idpManagement true )}.ToAsyncEnumerable(); - var (companyUserId, _, password, error) = await _userProvisioningService.CreateOwnCompanyIdpUsersAsync(companyNameIdpAliasData, userCreationInfoIdps, cancellationToken).SingleAsync(cancellationToken).ConfigureAwait(false); + var (companyUserId, _, password, error) = await _userProvisioningService.CreateOwnCompanyIdpUsersAsync(companyNameIdpAliasData, userCreationInfoIdps, cancellationToken: cancellationToken).SingleAsync(cancellationToken).ConfigureAwait(false); if (error is not null) { diff --git a/src/provisioning/Provisioning.Library/Models/UserCreationRoleDataIdpInfo.cs b/src/provisioning/Provisioning.Library/Models/UserCreationRoleDataIdpInfo.cs index 455e22e558..3919e89730 100644 --- a/src/provisioning/Provisioning.Library/Models/UserCreationRoleDataIdpInfo.cs +++ b/src/provisioning/Provisioning.Library/Models/UserCreationRoleDataIdpInfo.cs @@ -33,3 +33,8 @@ public record UserCreationRoleDataIdpInfo( UserStatusId UserStatusId, bool Enabled ); + +public record UserCreationCallbackData( + UserCreationRoleDataIdpInfo UserCreationInfo, + string? Password +); diff --git a/src/provisioning/Provisioning.Library/Service/IUserProvisioningService.cs b/src/provisioning/Provisioning.Library/Service/IUserProvisioningService.cs index a5fc5aa8ca..b40bbcff84 100644 --- a/src/provisioning/Provisioning.Library/Service/IUserProvisioningService.cs +++ b/src/provisioning/Provisioning.Library/Service/IUserProvisioningService.cs @@ -27,7 +27,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Service; public interface IUserProvisioningService { - IAsyncEnumerable<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)> CreateOwnCompanyIdpUsersAsync(CompanyNameIdpAliasData companyNameIdpAliasData, IAsyncEnumerable userCreationInfos, CancellationToken cancellationToken = default); + IAsyncEnumerable<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)> CreateOwnCompanyIdpUsersAsync(CompanyNameIdpAliasData companyNameIdpAliasData, IAsyncEnumerable userCreationInfos, Action? onSuccessfulCreation = null, CancellationToken cancellationToken = default); Task HandleCentralKeycloakCreation(UserCreationRoleDataIdpInfo user, Guid companyUserId, string companyName, string? businessPartnerNumber, Identity? identity, IEnumerable identityProviderLinks, IUserRepository userRepository, IUserRolesRepository userRolesRepository); Task<(CompanyNameIdpAliasData IdpAliasData, string NameCreatedBy)> GetCompanyNameIdpAliasData(Guid identityProviderId, Guid companyUserId); Task<(CompanyNameIdpAliasData IdpAliasData, string NameCreatedBy)> GetCompanyNameSharedIdpAliasData(Guid companyUserId, Guid? applicationId = null); diff --git a/src/provisioning/Provisioning.Library/Service/UserProvisioningService.cs b/src/provisioning/Provisioning.Library/Service/UserProvisioningService.cs index 9f6740e195..dcccba985c 100644 --- a/src/provisioning/Provisioning.Library/Service/UserProvisioningService.cs +++ b/src/provisioning/Provisioning.Library/Service/UserProvisioningService.cs @@ -53,6 +53,7 @@ public UserProvisioningService(IProvisioningManager provisioningManager, IPortal public async IAsyncEnumerable<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)> CreateOwnCompanyIdpUsersAsync( CompanyNameIdpAliasData companyNameIdpAliasData, IAsyncEnumerable userCreationInfos, + Action? onSuccessfulCreation = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { var userRepository = _portalRepositories.GetInstance(); @@ -76,6 +77,7 @@ public UserProvisioningService(IProvisioningManager provisioningManager, IPortal var providerUserId = await CreateSharedIdpUserOrReturnUserId(user, alias, nextPassword, isSharedIdp).ConfigureAwait(ConfigureAwaitOptions.None); await HandleCentralKeycloakCreation(user, companyUserId, companyName, businessPartnerNumber, identity, Enumerable.Repeat(new IdentityProviderLink(alias, providerUserId, user.UserName), 1), userRepository, userRolesRepository).ConfigureAwait(ConfigureAwaitOptions.None); + onSuccessfulCreation?.Invoke(new(user, nextPassword)); } catch (Exception e) when (e is not OperationCanceledException) { diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs index 265b4c6953..8a73d0fe70 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs @@ -1540,8 +1540,8 @@ private void SetupFakesForUserCreation(bool isBulkUserCreation) A.CallTo(() => _userProvisioningService.GetCompanyNameIdpAliasData(A._, A._)).Returns((_fixture.Create(), _fixture.Create())); } - A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A._)) - .ReturnsLazily((CompanyNameIdpAliasData _, IAsyncEnumerable userCreationInfos, CancellationToken _) => + A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A>._, A._)) + .ReturnsLazily((CompanyNameIdpAliasData _, IAsyncEnumerable userCreationInfos, Action _, CancellationToken _) => userCreationInfos.Select(userCreationInfo => _processLine(userCreationInfo))); A.CallTo(() => _userProvisioningService.GetIdentityProviderDisplayName(A._)).Returns(_displayName); diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs index f04a894932..7de3560ef4 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs @@ -24,6 +24,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Service; using Org.Eclipse.TractusX.Portal.Backend.Framework.IO; using Org.Eclipse.TractusX.Portal.Backend.Framework.Tests.Shared; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Identities; @@ -47,7 +48,7 @@ public class UserUploadBusinessLogicTests private readonly IMailingProcessCreation _mailingProcessCreation; private readonly UserSettings _settings; private readonly Encoding _encoding; - private readonly Func _processLine; + private readonly Func?, (Guid CompanyUserId, string UserName, string? Password, Exception? Error)> _processLine; private readonly Exception _error; private readonly Random _random; private readonly IIdentityService _identityService; @@ -84,7 +85,7 @@ public UserUploadBusinessLogicTests() A.CallTo(() => _errorMessageService.GetMessage(typeof(ProvisioningServiceErrors), A._)) .ReturnsLazily((Type type, int code) => $"type: {type.Name} code: {Enum.GetName(type, code)} userName: {{userName}} realm: {{realm}}"); - _processLine = A.Fake>(); + _processLine = A.Fake?, (Guid CompanyUserId, string UserName, string? Password, Exception? Error)>>(); _error = _fixture.Create(); } @@ -94,7 +95,7 @@ public UserUploadBusinessLogicTests() [Fact] public async Task TestSetup() { - SetupFakes(new[] { HeaderLine() }); + SetupFakes([HeaderLine()]); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); @@ -131,7 +132,7 @@ public async Task TestUserCreationAllSuccess() result.Error.Should().Be(0); result.Total.Should().Be(5); result.Errors.Should().BeEmpty(); - A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, A._, A>._)) + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserExternalIdpTemplate", A>._)) .MustHaveHappened(5, Times.Exactly); } @@ -140,14 +141,14 @@ public async Task TestUserCreationHeaderParsingThrows() { var invalidHeader = _fixture.Create(); - SetupFakes(new[] { + SetupFakes([ invalidHeader, NextLine(), NextLine(), NextLine(), NextLine(), NextLine() - }); + ]); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); @@ -155,6 +156,8 @@ public async Task TestUserCreationHeaderParsingThrows() var error = await Assert.ThrowsAsync(Act); error.Message.Should().Be($"invalid format: expected 'FirstName', got '{invalidHeader}' (Parameter 'document')"); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, A._, A>._)) + .MustNotHaveHappened(); } [Fact] @@ -163,18 +166,18 @@ public async Task TestUserCreationCreationError() var creationInfo = _fixture.Create(); var detailError = ConflictException.Create(ProvisioningServiceErrors.USER_CREATION_CONFLICT, new ErrorParameter[] { new("userName", "foo"), new("realm", "bar") }); - SetupFakes(new[] { + SetupFakes([ HeaderLine(), NextLine(), NextLine(), NextLine(creationInfo), NextLine(), NextLine() - }); + ]); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatches(info, creationInfo)))) + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatches(info, creationInfo)), A>._)) .ReturnsLazily( - (UserCreationRoleDataIdpInfo creationInfo) => _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() + (CompanyNameIdpAliasData _, UserCreationRoleDataIdpInfo creationInfo, Action _) => _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() .With(x => x.CompanyUserId, Guid.Empty) .With(x => x.UserName, creationInfo.UserName) .With(x => x.Error, detailError) @@ -184,7 +187,7 @@ public async Task TestUserCreationCreationError() var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatches(info, creationInfo)))).MustHaveHappened(); + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatches(info, creationInfo)), A>._)).MustHaveHappened(); result.Should().NotBeNull(); result.Created.Should().Be(4); @@ -202,7 +205,7 @@ public async Task TestUserCreationCreationError() x.Parameters.Count() == 2 && x.Parameters.First(p => p.Name == "userName").Value == "foo" && x.Parameters.First(p => p.Name == "realm").Value == "bar"); - A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, A._, A>._)) + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserExternalIdpTemplate", A>._)) .MustHaveHappened(4, Times.Exactly); } @@ -213,42 +216,42 @@ public async Task TestUserCreationCreationNoRolesError() .With(x => x.RoleDatas, Enumerable.Empty()) .Create(); - SetupFakes(new[] { + SetupFakes([ HeaderLine(), NextLine(), NextLine(), NextLine(creationInfo), NextLine(), NextLine() - }); + ]); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatches(info, creationInfo)))).MustNotHaveHappened(); - A.CallTo(() => _processLine(A.That.Not.Matches(info => CreationInfoMatches(info, creationInfo)))).MustHaveHappened(4, Times.Exactly); + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatches(info, creationInfo)), A>._)).MustNotHaveHappened(); + A.CallTo(() => _processLine(A._, A.That.Not.Matches(info => CreationInfoMatches(info, creationInfo)), A>._)).MustHaveHappened(4, Times.Exactly); result.Should().NotBeNull(); result.Created.Should().Be(4); result.Error.Should().Be(1); result.Total.Should().Be(5); result.Errors.Should().ContainSingle().Which.Should().Match(x => x.Line == 3 && x.Message == "at least one role must be specified"); - A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, A._, A>._)) + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserExternalIdpTemplate", A>._)) .MustHaveHappened(4, Times.Exactly); } [Fact] public async Task TestUserCreationParsingError() { - SetupFakes(new[] { + SetupFakes([ HeaderLine(), NextLine(), NextLine(), _fixture.Create(), NextLine(), NextLine() - }); + ]); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); @@ -259,7 +262,7 @@ public async Task TestUserCreationParsingError() result.Error.Should().Be(1); result.Total.Should().Be(5); result.Errors.Should().ContainSingle().Which.Should().Match(x => x.Line == 3 && x.Message == "value for LastName type string expected (Parameter 'document')"); - A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, A._, A>._)) + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserExternalIdpTemplate", A>._)) .MustHaveHappened(4, Times.Exactly); } @@ -268,30 +271,30 @@ public async Task TestUserCreationCreationThrows() { var creationInfo = _fixture.Create(); - SetupFakes(new[] { + SetupFakes([ HeaderLine(), NextLine(), NextLine(), NextLine(creationInfo), NextLine(), NextLine() - }); + ]); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatches(info, creationInfo)))) + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatches(info, creationInfo)), A>._)) .Throws(_error); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatches(info, creationInfo)))).MustHaveHappened(); + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatches(info, creationInfo)), A>._)).MustHaveHappened(); result.Should().NotBeNull(); result.Created.Should().Be(2); result.Error.Should().Be(1); result.Total.Should().Be(3); result.Errors.Should().ContainSingle().Which.Should().Match(x => x.Line == 3 && x.Message == _error.Message); - A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, A._, A>._)) + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserExternalIdpTemplate", A>._)) .MustHaveHappened(2, Times.Exactly); } @@ -302,7 +305,7 @@ public async Task TestUserCreationCreationThrows() [Fact] public async Task TestSetupSharedIdp() { - SetupFakes(new[] { HeaderLineSharedIdp() }); + SetupFakes([HeaderLineSharedIdp()]); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); @@ -319,14 +322,14 @@ public async Task TestSetupSharedIdp() [Fact] public async Task TestUserCreationSharedIdpAllSuccess() { - SetupFakes(new[] { + SetupFakes([ HeaderLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp() - }); + ]); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); @@ -337,8 +340,10 @@ public async Task TestUserCreationSharedIdpAllSuccess() result.Error.Should().Be(0); result.Total.Should().Be(5); result.Errors.Should().BeEmpty(); - A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, A._, A>._)) - .MustHaveHappened(); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserTemplate", A>._)) + .MustHaveHappened(5, Times.Exactly); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserPasswordTemplate", A>._)) + .MustHaveHappened(5, Times.Exactly); } [Fact] @@ -346,14 +351,14 @@ public async Task TestUserCreationSharedIdpHeaderParsingThrows() { var invalidHeader = _fixture.Create(); - SetupFakes(new[] { + SetupFakes([ invalidHeader, NextLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp() - }); + ]); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); @@ -361,6 +366,8 @@ public async Task TestUserCreationSharedIdpHeaderParsingThrows() var error = await Assert.ThrowsAsync(Act); error.Message.Should().Be($"invalid format: expected 'FirstName', got '{invalidHeader}' (Parameter 'document')"); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, A._, A>._)) + .MustNotHaveHappened(); } [Fact] @@ -370,21 +377,21 @@ public async Task TestUserCreationSharedIdpNoRolesError() .With(x => x.RoleDatas, Enumerable.Empty()) .Create(); - SetupFakes(new[] { + SetupFakes([ HeaderLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(creationInfo), NextLineSharedIdp(), NextLineSharedIdp(), - }); + ]); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)))).MustNotHaveHappened(); - A.CallTo(() => _processLine(A.That.Not.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)))).MustHaveHappened(4, Times.Exactly); + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)), A>._)).MustNotHaveHappened(); + A.CallTo(() => _processLine(A._, A.That.Not.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)), A>._)).MustHaveHappened(4, Times.Exactly); result.Should().NotBeNull(); result.Created.Should().Be(4); @@ -392,26 +399,30 @@ public async Task TestUserCreationSharedIdpNoRolesError() result.Total.Should().Be(5); result.Errors.Should().HaveCount(1); result.Errors.Should().ContainSingle().Which.Should().Match(x => x.Line == 3 && x.Message == "at least one role must be specified"); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserTemplate", A>._)) + .MustHaveHappened(4, Times.Exactly); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserPasswordTemplate", A>._)) + .MustHaveHappened(4, Times.Exactly); } [Fact] public async Task TestUserCreationSharedIdpCreationError() { var creationInfo = _fixture.Create(); - var detailError = ConflictException.Create(ProvisioningServiceErrors.USER_CREATION_FAILURE, new ErrorParameter[] { new("userName", "foo"), new("realm", "bar") }); + var detailError = ConflictException.Create(ProvisioningServiceErrors.USER_CREATION_FAILURE, [new("userName", "foo"), new("realm", "bar")]); - SetupFakes(new[] { + SetupFakes([ HeaderLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(creationInfo), NextLineSharedIdp(), NextLineSharedIdp() - }); + ]); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)))) + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)), A>._)) .ReturnsLazily( - (UserCreationRoleDataIdpInfo creationInfo) => _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() + (CompanyNameIdpAliasData _, UserCreationRoleDataIdpInfo creationInfo, Action? _) => _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() .With(x => x.CompanyUserId, Guid.Empty) .With(x => x.UserName, creationInfo.UserName) .With(x => x.Error, detailError) @@ -421,7 +432,7 @@ public async Task TestUserCreationSharedIdpCreationError() var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)))).MustHaveHappened(); + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)), A>._)).MustHaveHappened(); result.Should().NotBeNull(); result.Created.Should().Be(4); @@ -439,19 +450,23 @@ public async Task TestUserCreationSharedIdpCreationError() x.Parameters.Count() == 2 && x.Parameters.First(p => p.Name == "userName").Value == "foo" && x.Parameters.First(p => p.Name == "realm").Value == "bar"); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserTemplate", A>._)) + .MustHaveHappened(4, Times.Exactly); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserPasswordTemplate", A>._)) + .MustHaveHappened(4, Times.Exactly); } [Fact] public async Task TestUserCreationSharedIdpParsingError() { - SetupFakes(new[] { + SetupFakes([ HeaderLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(), _fixture.Create(), NextLineSharedIdp(), NextLineSharedIdp() - }); + ]); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); @@ -463,6 +478,10 @@ public async Task TestUserCreationSharedIdpParsingError() result.Total.Should().Be(5); result.Errors.Should().HaveCount(1); result.Errors.Should().ContainSingle().Which.Should().Match(x => x.Line == 3 && x.Message == "value for LastName type string expected (Parameter 'document')"); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserTemplate", A>._)) + .MustHaveHappened(4, Times.Exactly); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserPasswordTemplate", A>._)) + .MustHaveHappened(4, Times.Exactly); } [Fact] @@ -470,29 +489,33 @@ public async Task TestUserCreationSharedIdpCreationThrows() { var creationInfo = _fixture.Create(); - SetupFakes(new[] { + SetupFakes([ HeaderLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(), NextLineSharedIdp(creationInfo), NextLineSharedIdp(), NextLineSharedIdp() - }); + ]); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)))) + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)), A>._)) .Throws(_error); var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); - A.CallTo(() => _processLine(A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)))).MustHaveHappened(); + A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)), A>._)).MustHaveHappened(); result.Should().NotBeNull(); result.Created.Should().Be(2); result.Error.Should().Be(1); result.Total.Should().Be(3); result.Errors.Should().ContainSingle().Which.Should().Match(x => x.Line == 3 && x.Message == _error.Message); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserTemplate", A>._)) + .MustHaveHappened(2, Times.Exactly); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserPasswordTemplate", A>._)) + .MustHaveHappened(2, Times.Exactly); } #endregion @@ -516,15 +539,21 @@ private void SetupFakes(IEnumerable lines) .ReturnsLazily((string clientId, IEnumerable roles, Guid _) => roles.Select(role => _fixture.Build().With(x => x.ClientClientId, clientId).With(x => x.UserRoleText, role).Create())); - A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A._)) - .ReturnsLazily((CompanyNameIdpAliasData _, IAsyncEnumerable userCreationInfos, CancellationToken _) => - userCreationInfos.Select(userCreationInfo => _processLine(userCreationInfo))); + A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A>._, A._)) + .ReturnsLazily((CompanyNameIdpAliasData idpAliasData, IAsyncEnumerable userCreationInfos, Action? onSuccess, CancellationToken _) => + userCreationInfos.Select(userCreationInfo => _processLine(idpAliasData, userCreationInfo, onSuccess))); - A.CallTo(() => _processLine(A._)).ReturnsLazily( - (UserCreationRoleDataIdpInfo creationInfo) => _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() - .With(x => x.UserName, creationInfo.UserName) - .With(x => x.Error, default(Exception?)) - .Create()); + A.CallTo(() => _processLine(A._, A._, A>._)).ReturnsLazily( + (CompanyNameIdpAliasData aliasData, UserCreationRoleDataIdpInfo creationInfo, Action? onSucess) => + { + var password = aliasData.IsSharedIdp ? _fixture.Create() : null; + onSucess?.Invoke(new(creationInfo, password)); + return _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() + .With(x => x.UserName, creationInfo.UserName) + .With(x => x.Password, password) + .With(x => x.Error, default(Exception?)) + .Create(); + }); } private static string HeaderLine() => diff --git a/tests/processes/Invitation.Executor.Tests/InvitationProcessServiceTests.cs b/tests/processes/Invitation.Executor.Tests/InvitationProcessServiceTests.cs index 5d78193614..c38cd76a91 100644 --- a/tests/processes/Invitation.Executor.Tests/InvitationProcessServiceTests.cs +++ b/tests/processes/Invitation.Executor.Tests/InvitationProcessServiceTests.cs @@ -688,7 +688,7 @@ public async Task CreateUser_WithValid_ReturnsExpected() .Returns((true, applicationId, companyId, "testCorp", Enumerable.Repeat((Guid.NewGuid(), "idp"), 1), new UserInvitationInformation("tony", "stark", "tony@stark.com", "ironman"))); A.CallTo(() => _userProvisioningService.GetRoleDatas(A>._)) .Returns(Enumerable.Repeat(new UserRoleData(Guid.NewGuid(), "cl1", "ur 1"), 1).ToAsyncEnumerable()); - A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A._)) + A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A>._, A._)) .Returns(Enumerable.Repeat>((companyUserId, "ironman", "testPw", null), 1).ToAsyncEnumerable()); A.CallTo(() => _companyInvitationRepository.AttachAndModifyCompanyInvitation(companyInvitation.Id, A>._, A>._)) .Invokes((Guid _, Action? initialize, Action modify) => @@ -718,7 +718,7 @@ public async Task CreateUser_WithCreateOwnCompanyIdpUserThrowsException_ThrowsEx .Returns((true, applicationId, companyId, "testCorp", Enumerable.Repeat((Guid.NewGuid(), "idp"), 1), new UserInvitationInformation("tony", "stark", "tony@stark.com", "ironman"))); A.CallTo(() => _userProvisioningService.GetRoleDatas(A>._)) .Returns(Enumerable.Repeat(new UserRoleData(Guid.NewGuid(), "cl1", "ur 1"), 1).ToAsyncEnumerable()); - A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A._)) + A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A>._, A._)) .Returns(Enumerable.Repeat>((companyId, "ironman", "testPw", new ConflictException("test")), 1).ToAsyncEnumerable()); // Act diff --git a/tests/provisioning/Provisioning.Library.Tests/UserProvisioningServiceCreateUsersTests.cs b/tests/provisioning/Provisioning.Library.Tests/UserProvisioningServiceCreateUsersTests.cs index 39514d31bf..15d866d146 100644 --- a/tests/provisioning/Provisioning.Library.Tests/UserProvisioningServiceCreateUsersTests.cs +++ b/tests/provisioning/Provisioning.Library.Tests/UserProvisioningServiceCreateUsersTests.cs @@ -27,6 +27,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Models; using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Service; +using System.Collections.Immutable; namespace Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Tests; @@ -90,9 +91,16 @@ public async Task TestFixtureSetup() var userCreationInfoIdp = CreateUserCreationInfoIdp().ToAsyncEnumerable(); + var onSuccessArguments = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArguments.Add(data); + } + await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasData, userCreationInfoIdp, + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); @@ -102,6 +110,10 @@ await sut.CreateOwnCompanyIdpUsersAsync( A.CallTo(() => _provisioningManager.AddProviderUserLinkToCentralUserAsync(A._, A._)).MustHaveHappened(); A.CallTo(() => _provisioningManager.CreateSharedRealmUserAsync(A._, A._)).MustNotHaveHappened(); A.CallTo(() => _userRepository.AttachAndModifyIdentity(A._, null, A>._)).MustNotHaveHappened(); + + onSuccessArguments.ToImmutable() + .Should().HaveCount(_numUsers) + .And.AllSatisfy(x => x.Password.Should().BeNull()); } [Fact] @@ -111,9 +123,16 @@ public async Task TestSharedIdpFixtureSetup() var userCreationInfoIdp = CreateUserCreationInfoIdp().ToAsyncEnumerable(); + var onSuccessArguments = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArguments.Add(data); + } + await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasDataSharedIdp, userCreationInfoIdp, + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); @@ -123,6 +142,10 @@ await sut.CreateOwnCompanyIdpUsersAsync( A.CallTo(() => _provisioningManager.AddProviderUserLinkToCentralUserAsync(A._, A._)).MustHaveHappened(); A.CallTo(() => _provisioningManager.CreateSharedRealmUserAsync(A._, A._)).MustHaveHappened(); A.CallTo(() => _userRepository.AttachAndModifyIdentity(A._, null, A>._)).MustNotHaveHappened(); + + onSuccessArguments.ToImmutable() + .Should().HaveCount(_numUsers) + .And.AllSatisfy(x => x.Password.Should().NotBeNullOrEmpty()); } [Fact] @@ -131,16 +154,23 @@ public async Task TestCreateUsersAllSuccess() var sut = new UserProvisioningService(_provisioningManager, _portalRepositories); var userCreationInfoIdp = CreateUserCreationInfoIdp().ToList(); + var onSuccessArguments = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArguments.Add(data); + } var result = await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasData, userCreationInfoIdp.ToAsyncEnumerable(), + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); result.Should().HaveCount(_numUsers); - result.Select(r => r.UserName).Should().ContainInOrder(userCreationInfoIdp.Select(u => u.UserName)); + result.Select(r => r.UserName).Should().ContainInConsecutiveOrder(userCreationInfoIdp.Select(u => u.UserName)); result.Should().AllSatisfy(r => r.Error.Should().BeNull()); + onSuccessArguments.ToImmutable().Select(x => x.UserCreationInfo).Should().ContainInConsecutiveOrder(userCreationInfoIdp); } [Fact] @@ -164,9 +194,16 @@ public async Task TestCreateUsersRolesAssignmentError() A.CallTo(() => _provisioningManager.AssignClientRolesToCentralUserAsync(iamUserId, A>>._)) .Returns(new (string, IEnumerable, Exception?)[] { (_clientId, Enumerable.Empty(), new Exception("some error")) }.ToAsyncEnumerable()); + var onSuccessArgumentsBuilder = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArgumentsBuilder.Add(data); + } + var result = await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasData, userCreationInfoIdp.ToAsyncEnumerable(), + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); @@ -177,6 +214,8 @@ public async Task TestCreateUsersRolesAssignmentError() error.Should().NotBeNull(); error.Should().BeOfType(typeof(ConflictException)); error!.Message.Should().Be($"invalid role data [{string.Join(", ", specialUser.RoleDatas.Select(roleData => $"clientId: {roleData.ClientClientId}, role: {roleData.UserRoleText}, error: some error"))}] has not been assigned in keycloak"); + + onSuccessArgumentsBuilder.ToImmutable().Should().HaveCount(_numUsers - 1); } [Fact] @@ -197,9 +236,16 @@ public async Task TestCreateUsersRolesAssignmentNoRolesAssignedSuccess() A.CallTo(() => _provisioningManager.CreateCentralUserAsync(A.That.Matches(p => p.UserName == centralUserName), A)>>._)) .Returns(iamUserId); + var onSuccessArguments = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArguments.Add(data); + } + var result = await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasData, userCreationInfoIdp.ToAsyncEnumerable(), + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); @@ -208,6 +254,7 @@ public async Task TestCreateUsersRolesAssignmentNoRolesAssignedSuccess() result.Should().HaveCount(_numUsers); result.Should().AllSatisfy(r => r.Error.Should().BeNull()); + onSuccessArguments.ToImmutable().Should().HaveCount(_numUsers); } [Fact] @@ -230,9 +277,16 @@ public async Task TestCreateUsersCentralUserDuplicateKeycloakUserError() A.CallTo(() => _provisioningManager.GetProviderUserLinkDataForCentralUserIdAsync(iamUserId)) .Returns(new[] { new IdentityProviderLink(_companyNameIdpAliasData.IdpAlias, userInfo.UserId, userInfo.UserName) }.ToAsyncEnumerable()); + var onSuccessArguments = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArguments.Add(data); + } + var result = await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasData, userCreationInfoIdp.ToAsyncEnumerable(), + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); @@ -267,9 +321,16 @@ public async Task TestCreateUsersCentralUserPotentialMatchWithoutMatchingKeycloa A.CallTo(() => _provisioningManager.GetProviderUserLinkDataForCentralUserIdAsync(iamUserId)) .Returns(_fixture.CreateMany(3).ToAsyncEnumerable()); + var onSuccessArguments = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArguments.Add(data); + } + var result = await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasData, userCreationInfoIdp.ToAsyncEnumerable(), + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); @@ -277,6 +338,8 @@ public async Task TestCreateUsersCentralUserPotentialMatchWithoutMatchingKeycloa result.Should().HaveCount(_numUsers) .And.AllSatisfy(r => r.Error.Should().BeNull()); + + onSuccessArguments.ToImmutable().Should().HaveCount(_numUsers); } [Fact] @@ -291,9 +354,16 @@ public async Task TestCreateUsersKeycloakConflictError() A.CallTo(() => _provisioningManager.CreateCentralUserAsync(A.That.Matches(x => x.FirstName == userInfo.FirstName), A Values)>>._)) .Throws(ConflictException.Create(ProvisioningServiceErrors.USER_CREATION_CONFLICT, new ErrorParameter[] { new("userName", "foo"), new("realm", "bar") })); + var onSuccessArguments = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArguments.Add(data); + } + var result = await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasData, userCreationInfoIdp.ToAsyncEnumerable(), + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); @@ -308,6 +378,8 @@ public async Task TestCreateUsersKeycloakConflictError() x.Parameters.Count() == 2 && x.Parameters.First(p => p.Name == "userName").Value == "foo" && x.Parameters.First(p => p.Name == "realm").Value == "bar"); + + onSuccessArguments.ToImmutable().Should().HaveCount(_numUsers - 1); } [Fact] @@ -337,9 +409,16 @@ public async Task TestCreateUsersNotExistingCompanyUserWithoutKeycloakUserSucces A.CallTo(() => _provisioningManager.CreateCentralUserAsync(A.That.Matches(u => u.FirstName == userInfo.FirstName), A)>>._)) .Returns(centralUserId); + var onSuccessArguments = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArguments.Add(data); + } + var result = await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasData, userCreationInfoIdp.ToAsyncEnumerable(), + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); @@ -356,6 +435,8 @@ public async Task TestCreateUsersNotExistingCompanyUserWithoutKeycloakUserSucces result.Should().HaveCount(_numUsers); result.Should().AllSatisfy(r => r.Error.Should().BeNull()); + + onSuccessArguments.ToImmutable().Should().HaveCount(_numUsers); } [Fact] @@ -376,9 +457,16 @@ public async Task TestCreateUsersExistingCompanyUserWithoutKeycloakUserSuccess() A.CallTo(() => _provisioningManager.CreateCentralUserAsync(A.That.Matches(u => u.FirstName == userInfo.FirstName), A)>>._)) .Returns(centralUserId); + var onSuccessArguments = ImmutableList.CreateBuilder(); + void OnSuccess(UserCreationCallbackData data) + { + onSuccessArguments.Add(data); + } + var result = await sut.CreateOwnCompanyIdpUsersAsync( _companyNameIdpAliasData, userCreationInfoIdp.ToAsyncEnumerable(), + OnSuccess, _cancellationTokenSource.Token ).ToListAsync(); @@ -393,6 +481,8 @@ public async Task TestCreateUsersExistingCompanyUserWithoutKeycloakUserSuccess() result.Should().HaveCount(_numUsers); result.Should().AllSatisfy(r => r.Error.Should().BeNull()); + + onSuccessArguments.ToImmutable().Should().HaveCount(_numUsers); } #endregion diff --git a/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs b/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs index f21f2f66c2..a08c51cb98 100644 --- a/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs +++ b/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs @@ -1554,7 +1554,7 @@ public async Task TestInviteNewUserAsyncSuccess() await sut.InviteNewUserAsync(_existingApplicationId, userCreationInfo); - A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A._)).MustHaveHappened(); + A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A>._, A._)).MustHaveHappened(); A.CallTo(() => _applicationRepository.CreateInvitation(A.That.IsEqualTo(_existingApplicationId), A._)).MustHaveHappened(); A.CallTo(() => _applicationRepository.AttachAndModifyCompanyApplication(_existingApplicationId, A>._)).MustHaveHappenedOnceExactly(); A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappened(); @@ -1655,7 +1655,7 @@ public async Task TestInviteNewUserAsyncCreationErrorThrows() var error = await Assert.ThrowsAsync(Act); error.Message.Should().Be(_error.Message); - A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A._)).MustHaveHappened(); + A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A>._, A._)).MustHaveHappened(); A.CallTo(() => _applicationRepository.CreateInvitation(A.That.IsEqualTo(_existingApplicationId), A._)).MustNotHaveHappened(); A.CallTo(() => _portalRepositories.SaveAsync()).MustNotHaveHappened(); A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A.That.IsEqualTo(userCreationInfo.eMail), A._, A>._)) @@ -3258,8 +3258,8 @@ private void SetupRepositories() private void SetupFakesForInvitation() { - A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A._)) - .ReturnsLazily((CompanyNameIdpAliasData _, IAsyncEnumerable userCreationInfos, CancellationToken _) => + A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A>._, A._)) + .ReturnsLazily((CompanyNameIdpAliasData _, IAsyncEnumerable userCreationInfos, Action? onSuccess, CancellationToken _) => userCreationInfos.Select(userCreationInfo => _processLine(userCreationInfo))); A.CallTo(() => _userProvisioningService.GetRoleDatas(A>._)) From ad7a05afdf88110cfa315f5e49888e8d204fae02 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Mon, 16 Sep 2024 12:30:13 +0200 Subject: [PATCH 3/3] adjust unit-tests --- .../BusinessLogic/UserUploadBusinessLogic.cs | 7 +- .../BusinessLogic/UserBusinessLogicTests.cs | 92 ++++++++++++------- .../UserUploadBusinessLogicTests.cs | 35 ++++--- 3 files changed, 76 insertions(+), 58 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs index 2739abbdd3..eb32fdfe2a 100644 --- a/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/UserUploadBusinessLogic.cs @@ -23,7 +23,6 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Service; using Org.Eclipse.TractusX.Portal.Backend.Framework.IO; using Org.Eclipse.TractusX.Portal.Backend.Framework.Linq; -using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Identities; @@ -41,7 +40,6 @@ public class UserUploadBusinessLogic : IUserUploadBusinessLogic private readonly UserSettings _settings; private readonly IIdentityData _identityData; private readonly IErrorMessageService _errorMessageService; - private readonly IPortalRepositories _portalRepositories; /// /// Constructor. @@ -51,21 +49,18 @@ public class UserUploadBusinessLogic : IUserUploadBusinessLogic /// Access to the identity Service /// ErrorMessage Service /// Settings - /// Portal Repositories public UserUploadBusinessLogic( IUserProvisioningService userProvisioningService, IMailingProcessCreation mailingProcessCreation, IIdentityService identityService, IErrorMessageService errorMessageService, - IOptions settings, - IPortalRepositories portalRepositories) + IOptions settings) { _userProvisioningService = userProvisioningService; _mailingProcessCreation = mailingProcessCreation; _identityData = identityService.IdentityData; _errorMessageService = errorMessageService; _settings = settings.Value; - _portalRepositories = portalRepositories; } public ValueTask UploadOwnCompanyIdpUsersAsync(Guid identityProviderId, IFormFile document, CancellationToken cancellationToken) diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs index 8a73d0fe70..c8880aa92b 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs @@ -76,7 +76,7 @@ public class UserBusinessLogicTests private readonly IIdentityData _identity; private readonly ICollection _addedRoles = new HashSet(); private readonly ICollection _removedRoles = new HashSet(); - private readonly Func _processLine; + private readonly Func?, (Guid CompanyUserId, string UserName, string? Password, Exception? Error)> _processLine; private readonly Func _companyUserSelectFunction; private readonly Exception _error; private readonly UserSettings _settings; @@ -122,7 +122,7 @@ public UserBusinessLogicTests() _createdCentralCompanyId = Guid.NewGuid(); _displayName = _fixture.Create(); - _processLine = A.Fake>(); + _processLine = A.Fake?, (Guid CompanyUserId, string UserName, string? Password, Exception? Error)>>(); _companyUserSelectFunction = A.Fake>(); _identity = A.Fake(); @@ -276,12 +276,15 @@ public async Task TestUserCreationCreationError() CreateUserCreationInfo() }; - A.CallTo(() => _processLine(A.That.Matches(u => - u.FirstName == userCreationInfo.firstName && - u.LastName == userCreationInfo.lastName && - u.Email == userCreationInfo.eMail - ))).ReturnsLazily( - (UserCreationRoleDataIdpInfo creationInfo) => _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() + A.CallTo(() => _processLine( + A._, + A.That.Matches(u => + u.FirstName == userCreationInfo.firstName && + u.LastName == userCreationInfo.lastName && + u.Email == userCreationInfo.eMail), + A>._) + ).ReturnsLazily((CompanyNameIdpAliasData _, UserCreationRoleDataIdpInfo creationInfo, Action? _) => + _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() .With(x => x.UserName, creationInfo.UserName) .With(x => x.Error, error) .Create()); @@ -299,11 +302,14 @@ public async Task TestUserCreationCreationError() var result = await sut.CreateOwnCompanyUsersAsync(userList).ToListAsync(); - A.CallTo(() => _processLine(A.That.Matches(u => - u.FirstName == userCreationInfo.firstName && - u.LastName == userCreationInfo.lastName && - u.Email == userCreationInfo.eMail - ))).MustHaveHappenedOnceExactly(); + A.CallTo(() => _processLine( + A._, + A.That.Matches(u => + u.FirstName == userCreationInfo.firstName && + u.LastName == userCreationInfo.lastName && + u.Email == userCreationInfo.eMail), + A>._) + ).MustHaveHappenedOnceExactly(); A.CallTo(() => _mockLogger.Log(A.That.IsEqualTo(LogLevel.Error), A._, A._)).MustHaveHappenedOnceExactly(); @@ -331,11 +337,14 @@ public async Task TestUserCreationCreationThrows() CreateUserCreationInfo() }; - A.CallTo(() => _processLine(A.That.Matches(u => - u.FirstName == userCreationInfo.firstName && - u.LastName == userCreationInfo.lastName && - u.Email == userCreationInfo.eMail - ))).Throws(() => expected); + A.CallTo(() => _processLine( + A._, + A.That.Matches(u => + u.FirstName == userCreationInfo.firstName && + u.LastName == userCreationInfo.lastName && + u.Email == userCreationInfo.eMail), + A>._) + ).Throws(() => expected); var sut = new UserBusinessLogic( null!, @@ -352,11 +361,14 @@ public async Task TestUserCreationCreationThrows() var error = await Assert.ThrowsAsync(Act); - A.CallTo(() => _processLine(A.That.Matches(u => + A.CallTo(() => _processLine( + A._, + A.That.Matches(u => u.FirstName == userCreationInfo.firstName && u.LastName == userCreationInfo.lastName && - u.Email == userCreationInfo.eMail - ))).MustHaveHappenedOnceExactly(); + u.Email == userCreationInfo.eMail), + A>._) + ).MustHaveHappenedOnceExactly(); A.CallTo(() => _mockLogger.Log(A.That.IsEqualTo(LogLevel.Error), A._, A._)).MustNotHaveHappened(); A.CallTo(() => _mailingProcessCreation.CreateMailProcess(A._, "NewUserTemplate", A>._)) @@ -433,8 +445,12 @@ public async Task TestCreateOwnCompanyIdpUserAsyncError() var userCreationInfoIdp = CreateUserCreationInfoIdp(); - A.CallTo(() => _processLine(A.That.Matches(u => u.FirstName == userCreationInfoIdp.FirstName))).ReturnsLazily( - (UserCreationRoleDataIdpInfo creationInfo) => _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() + A.CallTo(() => _processLine( + A._, + A.That.Matches(u => u.FirstName == userCreationInfoIdp.FirstName), + A>._) + ).ReturnsLazily((CompanyNameIdpAliasData _, UserCreationRoleDataIdpInfo creationInfo, Action? onSuccess) => + _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() .With(x => x.UserName, creationInfo.UserName) .With(x => x.Error, _error) .Create()); @@ -465,7 +481,11 @@ public async Task TestCreateOwnCompanyIdpUserAsyncThrows() var userCreationInfoIdp = CreateUserCreationInfoIdp(); - A.CallTo(() => _processLine(A.That.Matches(u => u.FirstName == userCreationInfoIdp.FirstName))).Throws(_error); + A.CallTo(() => _processLine( + A._, + A.That.Matches(u => u.FirstName == userCreationInfoIdp.FirstName), + A>._) + ).Throws(_error); var sut = new UserBusinessLogic( null!, @@ -1153,7 +1173,7 @@ public async Task GetOwnCompanyAppUsersAsync_ReturnsExpectedResult() A.CallTo(() => _identity.IdentityId).Returns(userId); A.CallTo(() => _userRepository.GetOwnCompanyAppUsersPaginationSourceAsync(A._, A._, A>._, A>._, A._)) - .Returns((skip, take) => Task.FromResult(new Pagination.Source(companyUsers.Count(), companyUsers.Skip(skip).Take(take)))); + .Returns((skip, take) => Task.FromResult?>(new Pagination.Source(companyUsers.Count(), companyUsers.Skip(skip).Take(take)))); var sut = new UserBusinessLogic(null!, null!, null!, _portalRepositories, _identityService, null!, null!, null!, A.Fake>()); // Act @@ -1178,7 +1198,7 @@ public async Task GetOwnCompanyAppUsersAsync_SecondPage_ReturnsExpectedResult() A.CallTo(() => _identity.IdentityId).Returns(userId); A.CallTo(() => _userRepository.GetOwnCompanyAppUsersPaginationSourceAsync(A._, A._, A>._, A>._, A._)) - .Returns((skip, take) => Task.FromResult(new Pagination.Source(companyUsers.Count(), companyUsers.Skip(skip).Take(take)))); + .Returns((skip, take) => Task.FromResult?>(new Pagination.Source(companyUsers.Count(), companyUsers.Skip(skip).Take(take)))); var sut = new UserBusinessLogic(null!, null!, null!, _portalRepositories, _identityService, null!, null!, null!, A.Fake>()); // Act @@ -1541,16 +1561,22 @@ private void SetupFakesForUserCreation(bool isBulkUserCreation) } A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A._, A>._, A>._, A._)) - .ReturnsLazily((CompanyNameIdpAliasData _, IAsyncEnumerable userCreationInfos, Action _, CancellationToken _) => - userCreationInfos.Select(userCreationInfo => _processLine(userCreationInfo))); + .ReturnsLazily((CompanyNameIdpAliasData idpAliasData, IAsyncEnumerable userCreationInfos, Action? onSuccess, CancellationToken _) => + userCreationInfos.Select(userCreationInfo => _processLine(idpAliasData, userCreationInfo, onSuccess))); A.CallTo(() => _userProvisioningService.GetIdentityProviderDisplayName(A._)).Returns(_displayName); - A.CallTo(() => _processLine(A._)).ReturnsLazily( - (UserCreationRoleDataIdpInfo creationInfo) => _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() - .With(x => x.UserName, creationInfo.UserName) - .With(x => x.Error, default(Exception?)) - .Create()); + A.CallTo(() => _processLine(A._, A._, A>._)) + .ReturnsLazily((CompanyNameIdpAliasData aliasData, UserCreationRoleDataIdpInfo creationInfo, Action? onSucess) => + { + var password = aliasData.IsSharedIdp ? _fixture.Create() : null; + onSucess?.Invoke(new(creationInfo, password)); + return _fixture.Build<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)>() + .With(x => x.UserName, creationInfo.UserName) + .With(x => x.Password, password) + .With(x => x.Error, default(Exception?)) + .Create(); + }); } private void SetupFakesForUserDeletion() diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs index 7de3560ef4..fdd434b18a 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/UserUploadBusinessLogicTests.cs @@ -24,7 +24,6 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling.Service; using Org.Eclipse.TractusX.Portal.Backend.Framework.IO; using Org.Eclipse.TractusX.Portal.Backend.Framework.Tests.Shared; -using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Identities; @@ -39,7 +38,6 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLog public class UserUploadBusinessLogicTests { private readonly IFixture _fixture; - private readonly IPortalRepositories _portalRepositories; private readonly IUserProvisioningService _userProvisioningService; private readonly IOptions _options; private readonly IFormFile _document; @@ -60,7 +58,6 @@ public UserUploadBusinessLogicTests() _fixture.Behaviors.OfType().ToList() .ForEach(b => _fixture.Behaviors.Remove(b)); _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); - _portalRepositories = A.Fake(); _random = new Random(); @@ -97,7 +94,7 @@ public async Task TestSetup() { SetupFakes([HeaderLine()]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -114,16 +111,16 @@ public async Task TestSetup() [Fact] public async Task TestUserCreationAllSuccess() { - SetupFakes(new[] { + SetupFakes([ HeaderLine(), NextLine(), NextLine(), NextLine(), NextLine(), NextLine() - }); + ]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -150,7 +147,7 @@ public async Task TestUserCreationHeaderParsingThrows() NextLine() ]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); async Task Act() => await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -183,7 +180,7 @@ public async Task TestUserCreationCreationError() .With(x => x.Error, detailError) .Create()); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -225,7 +222,7 @@ public async Task TestUserCreationCreationNoRolesError() NextLine() ]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -253,7 +250,7 @@ public async Task TestUserCreationParsingError() NextLine() ]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -283,7 +280,7 @@ public async Task TestUserCreationCreationThrows() A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatches(info, creationInfo)), A>._)) .Throws(_error); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanyIdpUsersAsync(_identityProviderId, _document, CancellationToken.None); @@ -307,7 +304,7 @@ public async Task TestSetupSharedIdp() { SetupFakes([HeaderLineSharedIdp()]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -331,7 +328,7 @@ public async Task TestUserCreationSharedIdpAllSuccess() NextLineSharedIdp() ]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -360,7 +357,7 @@ public async Task TestUserCreationSharedIdpHeaderParsingThrows() NextLineSharedIdp() ]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); async Task Act() => await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -386,7 +383,7 @@ public async Task TestUserCreationSharedIdpNoRolesError() NextLineSharedIdp(), ]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -428,7 +425,7 @@ public async Task TestUserCreationSharedIdpCreationError() .With(x => x.Error, detailError) .Create()); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -468,7 +465,7 @@ public async Task TestUserCreationSharedIdpParsingError() NextLineSharedIdp() ]); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None); @@ -501,7 +498,7 @@ public async Task TestUserCreationSharedIdpCreationThrows() A.CallTo(() => _processLine(A._, A.That.Matches(info => CreationInfoMatchesSharedIdp(info, creationInfo)), A>._)) .Throws(_error); - var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options, _portalRepositories); + var sut = new UserUploadBusinessLogic(_userProvisioningService, _mailingProcessCreation, _identityService, _errorMessageService, _options); var result = await sut.UploadOwnCompanySharedIdpUsersAsync(_document, CancellationToken.None);