Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(emailNotification): Add Multiple Users | Invite email didnt receive by User(s) #922

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -158,38 +158,38 @@ public async Task<Guid> CreateOwnCompanyIdpUserAsync(Guid identityProviderId, Us
userCreationInfo.UserId,
UserStatusId.ACTIVE,
true
), 1).ToAsyncEnumerable())
), 1).ToAsyncEnumerable(),
creationData =>
{
var mailParameters = ImmutableDictionary.CreateBuilder<string, string>();
mailParameters.AddRange([
new("companyName", displayName),
new("nameCreatedBy", nameCreatedBy),
new("url", _settings.Portal.BasePortalAddress),
new("idpAlias", displayName),
]);

IEnumerable<string> 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);

if (result.Error != null)
{
throw result.Error;
}

var mailParameters = new Dictionary<string, string>
{
{ "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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@
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;
using Org.Eclipse.TractusX.Portal.Backend.Processes.Mailing.Library;
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;

Expand All @@ -41,6 +41,7 @@ public class UserUploadBusinessLogic : IUserUploadBusinessLogic
private readonly UserSettings _settings;
private readonly IIdentityData _identityData;
private readonly IErrorMessageService _errorMessageService;
private readonly IPortalRepositories _portalRepositories;

/// <summary>
/// Constructor.
Expand All @@ -50,18 +51,21 @@ public class UserUploadBusinessLogic : IUserUploadBusinessLogic
/// <param name="identityService">Access to the identity Service</param>
/// <param name="errorMessageService">ErrorMessage Service</param>
/// <param name="settings">Settings</param>
/// <param name="portalRepositories">Portal Repositories</param>
public UserUploadBusinessLogic(
IUserProvisioningService userProvisioningService,
IMailingProcessCreation mailingProcessCreation,
IIdentityService identityService,
IErrorMessageService errorMessageService,
IOptions<UserSettings> settings)
IOptions<UserSettings> settings,
IPortalRepositories portalRepositories)
{
_userProvisioningService = userProvisioningService;
_mailingProcessCreation = mailingProcessCreation;
_identityData = identityService.IdentityData;
_errorMessageService = errorMessageService;
_settings = settings.Value;
_portalRepositories = portalRepositories;
}

public ValueTask<UserCreationStats> UploadOwnCompanyIdpUsersAsync(Guid identityProviderId, IFormFile document, CancellationToken cancellationToken)
Expand All @@ -78,6 +82,10 @@ private async ValueTask<UserCreationStats> UploadOwnCompanyIdpUsersInternalAsync

var validRoleData = new List<UserRoleData>();

var displayName = companyNameIdpAliasData.IsSharedIdp
? null
: await _userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;

var (numCreated, numLines, errors) = await CsvParser.ProcessCsvAsync(
stream,
line =>
Expand All @@ -99,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<string, string>([
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);

Expand All @@ -120,53 +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<UserCreationRoleDataIdpInfo> 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 static void ValidateUserCreationRoles(IEnumerable<string> roles)
{
if (!roles.Any())
Expand Down Expand Up @@ -199,7 +166,8 @@ private async ValueTask<UserCreationStats> 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 displayName = await _userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;

var validRoleData = new List<UserRoleData>();

Expand Down Expand Up @@ -229,6 +197,18 @@ await GetUserRoleDatas(parsed.Roles, validRoleData, _identityData.CompanyId).Con
.CreateOwnCompanyIdpUsersAsync(
companyNameIdpAliasData,
lines,
creationData =>
{
var mailParameters = ImmutableDictionary.CreateRange<string, string>([
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ public record UserCreationRoleDataIdpInfo(
UserStatusId UserStatusId,
bool Enabled
);

public record UserCreationCallbackData(
UserCreationRoleDataIdpInfo UserCreationInfo,
string? Password
);
Original file line number Diff line number Diff line change
Expand Up @@ -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<UserCreationRoleDataIdpInfo> userCreationInfos, CancellationToken cancellationToken = default);
IAsyncEnumerable<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)> CreateOwnCompanyIdpUsersAsync(CompanyNameIdpAliasData companyNameIdpAliasData, IAsyncEnumerable<UserCreationRoleDataIdpInfo> userCreationInfos, Action<UserCreationCallbackData>? onSuccessfulCreation = null, CancellationToken cancellationToken = default);
Task HandleCentralKeycloakCreation(UserCreationRoleDataIdpInfo user, Guid companyUserId, string companyName, string? businessPartnerNumber, Identity? identity, IEnumerable<IdentityProviderLink> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public UserProvisioningService(IProvisioningManager provisioningManager, IPortal
public async IAsyncEnumerable<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)> CreateOwnCompanyIdpUsersAsync(
CompanyNameIdpAliasData companyNameIdpAliasData,
IAsyncEnumerable<UserCreationRoleDataIdpInfo> userCreationInfos,
Action<UserCreationCallbackData>? onSuccessfulCreation = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var userRepository = _portalRepositories.GetInstance<IUserRepository>();
Expand All @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1540,8 +1540,8 @@ private void SetupFakesForUserCreation(bool isBulkUserCreation)
A.CallTo(() => _userProvisioningService.GetCompanyNameIdpAliasData(A<Guid>._, A<Guid>._)).Returns((_fixture.Create<CompanyNameIdpAliasData>(), _fixture.Create<string>()));
}

A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A<CompanyNameIdpAliasData>._, A<IAsyncEnumerable<UserCreationRoleDataIdpInfo>>._, A<CancellationToken>._))
.ReturnsLazily((CompanyNameIdpAliasData _, IAsyncEnumerable<UserCreationRoleDataIdpInfo> userCreationInfos, CancellationToken _) =>
A.CallTo(() => _userProvisioningService.CreateOwnCompanyIdpUsersAsync(A<CompanyNameIdpAliasData>._, A<IAsyncEnumerable<UserCreationRoleDataIdpInfo>>._, A<Action<UserCreationCallbackData>>._, A<CancellationToken>._))
.ReturnsLazily((CompanyNameIdpAliasData _, IAsyncEnumerable<UserCreationRoleDataIdpInfo> userCreationInfos, Action<UserCreationCallbackData> _, CancellationToken _) =>
userCreationInfos.Select(userCreationInfo => _processLine(userCreationInfo)));

A.CallTo(() => _userProvisioningService.GetIdentityProviderDisplayName(A<string>._)).Returns(_displayName);
Expand Down
Loading
Loading