Skip to content

Commit

Permalink
cleanup concurrency
Browse files Browse the repository at this point in the history
  • Loading branch information
ntruchsess committed Jan 24, 2024
1 parent 6af5772 commit 8151a11
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

using Microsoft.Extensions.Options;
using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Async;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models;
using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail;
Expand All @@ -31,7 +32,6 @@
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Models;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Service;
using System.Collections.Concurrent;

namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLogic;

Expand Down Expand Up @@ -224,9 +224,8 @@ public async Task<Guid> CreateOwnCompanyIdpUserAsync(Guid identityProviderId, Us
return result.CompanyUserId;
}

public async Task<Pagination.Response<CompanyUserData>> GetOwnCompanyUserDatasAsync(int page, int size, GetOwnCompanyUsersFilter filter)
public Task<Pagination.Response<CompanyUserData>> GetOwnCompanyUserDatasAsync(int page, int size, GetOwnCompanyUsersFilter filter)
{
var aliasDisplayNameMapping = new ConcurrentDictionary<string, string>();
async Task<Pagination.Source<CompanyUserData>?> GetCompanyUserData(int skip, int take)
{
var companyData = await _portalRepositories.GetInstance<IUserRepository>().GetOwnCompanyUserData(
Expand All @@ -239,30 +238,40 @@ public async Task<Guid> CreateOwnCompanyIdpUserAsync(Guid identityProviderId, Us
filter.Email,
_settings.CompanyUserStatusIds
)(page, size).ConfigureAwait(false);
return companyData == null
? null
: new Pagination.Source<CompanyUserData>(
companyData.Count,
await Task.WhenAll(companyData.Data.Select(async d => new CompanyUserData(
d.CompanyUserId,
d.UserStatusId,
d.FirstName,
d.LastName,
d.Email,
d.Roles,
await Task.WhenAll(d.IdpUserIds.Select(async x =>
new IdpUserId(
await GetAliasForDisplayNameMapping(aliasDisplayNameMapping, x.Alias ?? throw new ConflictException("Alias must not be null")).ConfigureAwait(false),
x.Alias,
x.UserId))).ConfigureAwait(false)))).ConfigureAwait(false));
}
return await Pagination.CreateResponseAsync(

if (companyData == null)
return null;

var displayNames = await companyData.Data
.SelectMany(x => x.IdpUserIds)
.Select(x => x.Alias ?? throw new ConflictException("Alias must not be null"))
.Distinct()
.ToImmutableDictionaryAsync(GetDisplayName).ConfigureAwait(false);

return new Pagination.Source<CompanyUserData>(
companyData.Count,
companyData.Data.Select(d => new CompanyUserData(
d.CompanyUserId,
d.UserStatusId,
d.FirstName,
d.LastName,
d.Email,
d.Roles,
d.IdpUserIds.Select(x =>
new IdpUserId(
displayNames[x.Alias!],
x.Alias!,
x.UserId)))));
}
return Pagination.CreateResponseAsync(
page,
size,
_settings.ApplicationsMaxPageSize,
GetCompanyUserData).ConfigureAwait(false);
GetCompanyUserData);
}

private async Task<string> GetDisplayName(string alias) => await _provisioningManager.GetIdentityProviderDisplayName(alias).ConfigureAwait(false) ?? throw new ConflictException($"Display Name should not be null for alias: {alias}");

[Obsolete("to be replaced by UserRolesBusinessLogic.GetAppRolesAsync. Remove as soon frontend is adjusted")]
public async IAsyncEnumerable<ClientRoles> GetClientRolesAsync(Guid appId, string? languageShortName = null)
{
Expand Down Expand Up @@ -292,7 +301,6 @@ public async Task<CompanyUserDetailData> GetOwnCompanyUserDetailsAsync(Guid user
throw new NotFoundException($"no company-user data found for user {userId} in company {companyId}");
}

var aliasDisplayNameMapping = new ConcurrentDictionary<string, string>();
return new CompanyUserDetailData(
details.CompanyUserId,
details.CreatedAt,
Expand All @@ -302,22 +310,11 @@ public async Task<CompanyUserDetailData> GetOwnCompanyUserDetailsAsync(Guid user
details.AssignedRoles,
await Task.WhenAll(details.IdpUserIds.Select(async x =>
new IdpUserId(
await GetAliasForDisplayNameMapping(aliasDisplayNameMapping, x.Alias ?? throw new ConflictException("Alias must not be null")).ConfigureAwait(false),
await GetDisplayName(x.Alias ?? throw new ConflictException("Alias must not be null")).ConfigureAwait(false),
x.Alias,
x.UserId))).ConfigureAwait(false));
}

private async Task<string> GetAliasForDisplayNameMapping(ConcurrentDictionary<string, string> aliasDisplayNameMapping, string alias)
{
if (!aliasDisplayNameMapping.TryGetValue(alias, out var displayName))
{
displayName = await _provisioningManager.GetIdentityProviderDisplayName(alias).ConfigureAwait(false) ?? throw new ConflictException($"Display Name should not be null for alias: {alias}");
aliasDisplayNameMapping.TryAdd(alias, displayName);
}

return displayName;
}

public async Task<int> AddOwnCompanyUsersBusinessPartnerNumbersAsync(Guid userId, IEnumerable<string> businessPartnerNumbers)
{
if (businessPartnerNumbers.Any(businessPartnerNumber => businessPartnerNumber.Length > 20))
Expand Down Expand Up @@ -357,7 +354,6 @@ public async Task<CompanyOwnUserDetails> GetOwnUserDetails()
throw new NotFoundException($"no company-user data found for user {userId}");
}

var aliasDisplayNameMapping = new ConcurrentDictionary<string, string>();
return new CompanyOwnUserDetails(
details.CompanyUserId,
details.CreatedAt,
Expand All @@ -368,7 +364,7 @@ public async Task<CompanyOwnUserDetails> GetOwnUserDetails()
details.AdminDetails,
await Task.WhenAll(details.IdpUserIds.Select(async x =>
new IdpUserId(
await GetAliasForDisplayNameMapping(aliasDisplayNameMapping, x.Alias ?? throw new ConflictException("Alias must not be null")).ConfigureAwait(false),
await GetDisplayName(x.Alias ?? throw new ConflictException("Alias must not be null")).ConfigureAwait(false),
x.Alias,
x.UserId))).ConfigureAwait(false));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/********************************************************************************
* Copyright (c) 2021, 2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

using System.Collections.Immutable;

namespace Org.Eclipse.TractusX.Portal.Backend.Framework.Async;

public static class ToImmutableDictionaryAsyncExtension
{
public static async Task<IImmutableDictionary<K, V>> ToImmutableDictionaryAsync<K, V>(this IEnumerable<K> keys, Func<K, Task<V>> selector) where K : notnull
{
var builder = ImmutableDictionary.CreateBuilder<K, V>();
builder.AddRange(
await Task.WhenAll(
keys.Select(async key => new KeyValuePair<K, V>(
key,
await selector(key).ConfigureAwait(false)))).ConfigureAwait(false));
return builder.ToImmutableDictionary();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ public record CompanyUserAssignedRoleDetails(
[property: JsonPropertyName("roles")] IEnumerable<string> UserRoles);

public record IdpUserId(
[property: JsonPropertyName("idpDisplayName")] string? IdpDisplayName,
[property: JsonPropertyName("idpAlias")] string? IdpAlias,
[property: JsonPropertyName("idpDisplayName")] string IdpDisplayName,
[property: JsonPropertyName("idpAlias")] string IdpAlias,
[property: JsonPropertyName("userId")] string UserId);

public record CompanyOwnUserTransferDetails(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/********************************************************************************
* Copyright (c) 2021, 2023 BMW Group AG
* Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
Expand Down Expand Up @@ -35,20 +34,3 @@ public record ProviderLinkTransferData(
string? Alias,
string ProviderUserId
);

public record CompanyUserIdentityProviderProcessData(
Guid CompanyUserId,
string? FirstName,
string? LastName,
string? Email,
string CompanyName,
string? Bpn,
IEnumerable<ProviderLinkData> ProviderLinkData
);

public record ProviderLinkData(
string UserName,
string? Alias,
string? DisplayName,
string ProviderUserId
);
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/********************************************************************************
* Copyright (c) 2021,2023 BMW Group AG
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
Expand All @@ -24,5 +23,5 @@ public enum ProcessTypeId
{
APPLICATION_CHECKLIST = 1,
OFFER_SUBSCRIPTION = 3,
PARTNER_REGISTRATION = 4
PARTNER_REGISTRATION = 4,
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
********************************************************************************/

using Microsoft.Extensions.Options;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Async;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Keycloak.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail;
Expand All @@ -29,7 +30,6 @@
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Models;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Service;
using System.Collections.Concurrent;

namespace Org.Eclipse.TractusX.Portal.Backend.Processes.NetworkRegistration.Library;

Expand Down Expand Up @@ -104,33 +104,37 @@ public NetworkRegistrationHandler(
continue;
}

await _userProvisioningService.HandleCentralKeycloakCreation(new UserCreationRoleDataIdpInfo(cu.FirstName!, cu.LastName!, cu.Email!, roleData, string.Empty, string.Empty, UserStatusId.ACTIVE, true), cu.CompanyUserId, cu.CompanyName, cu.Bpn, null, cu.ProviderLinkData.Select(x => new IdentityProviderLink(x.Alias!, x.ProviderUserId, x.UserName)), userRepository, userRoleRepository).ConfigureAwait(false);
await _userProvisioningService.HandleCentralKeycloakCreation(
new UserCreationRoleDataIdpInfo(cu.FirstName!, cu.LastName!, cu.Email!, roleData, string.Empty, string.Empty, UserStatusId.ACTIVE, true),
cu.CompanyUserId,
cu.CompanyName,
cu.Bpn,
null,
cu.ProviderLinkData.Select(x => new IdentityProviderLink(x.Alias!, x.ProviderUserId, x.UserName)),
userRepository,
userRoleRepository).ConfigureAwait(false);
}
catch (Exception e)
{
throw new ServiceException(e.Message, true);
}
}

var aliasDisplayNameMapping = new ConcurrentDictionary<string, string>();
async Task<string> GetAliasForDisplayNameMapping(string alias)
{
if (!aliasDisplayNameMapping.TryGetValue(alias, out var displayName))
{
displayName = await _provisioningManager.GetIdentityProviderDisplayName(alias).ConfigureAwait(false) ?? throw new ConflictException($"Display Name should not be null for alias: {alias}");
aliasDisplayNameMapping.TryAdd(alias, displayName);
}

return displayName;
}
var displayNames = await companyAssignedIdentityProviders
.SelectMany(assigned => assigned.ProviderLinkData)
.Select(data => data.Alias!)
.Distinct()
.ToImmutableDictionaryAsync(async alias =>
await _provisioningManager.GetIdentityProviderDisplayName(alias).ConfigureAwait(false) ?? throw new ConflictException($"Display Name should not be null for alias: {alias}")).ConfigureAwait(false);

var userData = await Task.WhenAll(companyAssignedIdentityProviders.Select(async userData => new UserMailInformation(
var userData = companyAssignedIdentityProviders.Select(userData => new UserMailInformation(
userData.Email ?? throw new UnexpectedConditionException("userData.Email should never be null here"),
userData.FirstName,
userData.LastName,
await Task.WhenAll(userData.ProviderLinkData.Select(async pld => await GetAliasForDisplayNameMapping(pld.Alias!).ConfigureAwait(false))))))
.ConfigureAwait(false);
userData.ProviderLinkData.Select(data => displayNames[data.Alias!])));

await SendMails(userData, ospName).ConfigureAwait(false);

return new ValueTuple<IEnumerable<ProcessStepTypeId>?, ProcessStepStatusId, bool, string?>(
null,
ProcessStepStatusId.DONE,
Expand Down

0 comments on commit 8151a11

Please sign in to comment.