Skip to content

Commit

Permalink
refactor usercreation creating mail-processes in new onSuccess-callback
Browse files Browse the repository at this point in the history
  • Loading branch information
ntruchsess committed Sep 16, 2024
1 parent eb85556 commit 5a2edaf
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 195 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,38 +184,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 @@ -83,6 +83,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 @@ -104,17 +108,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 @@ -125,99 +135,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 async IAsyncEnumerable<(Guid CompanyUserId, string UserName, string? Password, Exception? Error)> CreateOwnCompanySharedIdpUsersWithEmailAsync(string nameCreatedBy, CompanyNameIdpAliasData companyNameIdpAliasData, IAsyncEnumerable<UserCreationRoleDataIdpInfo> 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<string> roles)
{
if (!roles.Any())
Expand Down Expand Up @@ -251,6 +168,7 @@ private async ValueTask<UserCreationStats> 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<UserRoleData>();

Expand All @@ -276,10 +194,22 @@ await GetUserRoleDatas(parsed.Roles, validRoleData, _identityData.CompanyId).Con
true);
},
lines =>
CreateOwnCompanySharedIdpUsersWithEmailAsync(
nameCreatedBy,
_userProvisioningService
.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 @@ -54,6 +54,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 @@ -77,6 +78,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 @@ -1413,8 +1413,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

0 comments on commit 5a2edaf

Please sign in to comment.