Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
62 changes: 47 additions & 15 deletions docs/api/administration-service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5529,11 +5529,6 @@ paths:
responses:
'200':
description: The business partner numbers have been added successfully.
content:
application/json:
schema:
type: integer
format: int32
'400':
description: Business Partner Numbers must not exceed 20 characters.
content:
Expand Down Expand Up @@ -5575,11 +5570,6 @@ paths:
responses:
'200':
description: The business partner number have been added successfully.
content:
application/json:
schema:
type: integer
format: int32
'400':
description: Business Partner Numbers must not exceed 20 characters.
content:
Expand Down Expand Up @@ -5630,11 +5620,6 @@ paths:
responses:
'200':
description: Empty response on success.
content:
application/json:
schema:
type: integer
format: int32
'403':
description: ForbiddenException if both users does not belongs to same company
content:
Expand Down Expand Up @@ -5935,6 +5920,45 @@ paths:
description: Internal Server Error
'401':
description: The User is unauthorized
'/api/administration/user/{processId}/retrigger-user-bpn-process':
post:
tags:
- User
summary: 'Retriggers the last failed step (Authorization required - Roles: modify_user_account)'
parameters:
- name: processId
in: path
description: Id of the process that should be triggered
required: true
schema:
type: string
format: uuid
example: 251e4596-5ff0-4176-b544-840b04ebeb93
- name: processStepTypeId
in: query
description: Id of the process step type which should be retriggered
schema:
$ref: '#/components/schemas/ProcessStepTypeId'
example: ProcessStepTypeId.DELETE_BPN_FROM_CENTRAL_USER
responses:
'204':
description: Empty response on success.
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: No Process found for the processId
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
'401':
description: The User is unauthorized
components:
schemas:
AgreementConsentData:
Expand Down Expand Up @@ -7596,6 +7620,14 @@ components:
- SELF_DESCRIPTION_COMPANY_CREATION
- RETRIGGER_SELF_DESCRIPTION_CONNECTOR_CREATION
- RETRIGGER_SELF_DESCRIPTION_COMPANY_CREATION
- DELETE_BPN_FROM_CENTRAL_USER
- DELETE_BPN_FROM_IDENTITY
- RETRIGGER_DELETE_BPN_FROM_CENTRAL_USER
- CHECK_LEGAL_ENTITY_DATA
- ADD_BPN_TO_IDENTITY
- CLEANUP_USER_BPN
- RETRIGGER_CHECK_LEGAL_ENTITY_DATA
- RETRIGGER_ADD_BPN_TO_IDENTITY
type: string
ProviderDetailData:
type: object
Expand Down
8 changes: 8 additions & 0 deletions docs/api/apps-service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3685,6 +3685,14 @@ components:
- SELF_DESCRIPTION_COMPANY_CREATION
- RETRIGGER_SELF_DESCRIPTION_CONNECTOR_CREATION
- RETRIGGER_SELF_DESCRIPTION_COMPANY_CREATION
- DELETE_BPN_FROM_CENTRAL_USER
- DELETE_BPN_FROM_IDENTITY
- RETRIGGER_DELETE_BPN_FROM_CENTRAL_USER
- CHECK_LEGAL_ENTITY_DATA
- ADD_BPN_TO_IDENTITY
- CLEANUP_USER_BPN
- RETRIGGER_CHECK_LEGAL_ENTITY_DATA
- RETRIGGER_ADD_BPN_TO_IDENTITY
type: string
SubscriberSubscriptionDetailData:
type: object
Expand Down
8 changes: 8 additions & 0 deletions docs/api/services-service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2256,6 +2256,14 @@ components:
- SELF_DESCRIPTION_COMPANY_CREATION
- RETRIGGER_SELF_DESCRIPTION_CONNECTOR_CREATION
- RETRIGGER_SELF_DESCRIPTION_COMPANY_CREATION
- DELETE_BPN_FROM_CENTRAL_USER
- DELETE_BPN_FROM_IDENTITY
- RETRIGGER_DELETE_BPN_FROM_CENTRAL_USER
- CHECK_LEGAL_ENTITY_DATA
- ADD_BPN_TO_IDENTITY
- CLEANUP_USER_BPN
- RETRIGGER_CHECK_LEGAL_ENTITY_DATA
- RETRIGGER_ADD_BPN_TO_IDENTITY
type: string
ProviderSubscriptionDetailData:
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Models;

namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLogic;
Expand All @@ -32,8 +33,8 @@ public interface IUserBusinessLogic
Task<Guid> CreateOwnCompanyIdpUserAsync(Guid identityProviderId, UserCreationInfoIdp userCreationInfo);
Task<Pagination.Response<CompanyUserData>> GetOwnCompanyUserDatasAsync(int page, int size, GetOwnCompanyUsersFilter filter);
Task<CompanyUserDetailData> GetOwnCompanyUserDetailsAsync(Guid userId);
Task<CompanyUsersBpnDetails> AddOwnCompanyUsersBusinessPartnerNumbersAsync(Guid userId, string token, IEnumerable<string> businessPartnerNumbers, CancellationToken cancellationToken);
Task<CompanyUsersBpnDetails> AddOwnCompanyUsersBusinessPartnerNumberAsync(Guid userId, string token, string businessPartnerNumber, CancellationToken cancellationToken);
Task AddOwnCompanyUsersBusinessPartnerNumbersAsync(Guid userId, IEnumerable<string> businessPartnerNumbers, CancellationToken cancellationToken);
Task AddOwnCompanyUsersBusinessPartnerNumberAsync(Guid userId, string businessPartnerNumber, CancellationToken cancellationToken);
Task<CompanyOwnUserDetails> GetOwnUserDetails();
Task<CompanyUserDetails> UpdateOwnUserDetails(Guid companyUserId, OwnCompanyUserEditableDetails ownCompanyUserEditableDetails);

Expand All @@ -46,5 +47,6 @@ public interface IUserBusinessLogic
IAsyncEnumerable<Guid> DeleteOwnCompanyUsersAsync(IEnumerable<Guid> userIds);
Task<bool> ExecuteOwnCompanyUserPasswordReset(Guid companyUserId);
Task<Pagination.Response<CompanyAppUserDetails>> GetOwnCompanyAppUsersAsync(Guid appId, int page, int size, CompanyUserFilter filter);
Task<int> DeleteOwnUserBusinessPartnerNumbersAsync(Guid userId, string businessPartnerNumber);
Task DeleteOwnUserBusinessPartnerNumbersAsync(Guid userId, string businessPartnerNumber);
Task RetriggerUserBpnProcess(Guid processId, ProcessStepTypeId processStepTypeId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@
using Org.Eclipse.TractusX.Portal.Backend.Framework.Async;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Identity;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Linq;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Enums;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Processes.Library.Extensions;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Extensions;
using Org.Eclipse.TractusX.Portal.Backend.Processes.Mailing.Library;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.DBAccess;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library;
Expand All @@ -50,7 +53,7 @@ public class UserBusinessLogic(
IIdentityService identityService,
IMailingProcessCreation mailingProcessCreation,
ILogger<UserBusinessLogic> logger,
IBpnAccess bpnAccess,
IBpdmAccessService bpdmAccessService,
IOptions<UserSettings> options) : IUserBusinessLogic
{
private readonly UserSettings _settings = options.Value;
Expand Down Expand Up @@ -267,74 +270,38 @@ await Task.WhenAll(details.IdpUserIds.Select(async x =>
details.Email);
}

public async Task<CompanyUsersBpnDetails> AddOwnCompanyUsersBusinessPartnerNumbersAsync(Guid userId, string token, IEnumerable<string> businessPartnerNumbers, CancellationToken cancellationToken)
public async Task AddOwnCompanyUsersBusinessPartnerNumbersAsync(Guid userId, IEnumerable<string> businessPartnerNumbers, CancellationToken cancellationToken)
{
var companyId = _identityData.CompanyId;

var invalidBpns = businessPartnerNumbers.Where(bpn => bpn.Length > 20);
if (invalidBpns.Any())
{
throw new ControllerArgumentException($"BusinessPartnerNumbers {string.Join(",", invalidBpns)} must not exceed 20 characters");
}

var (assignedBusinessPartnerNumbers, isValidUser) = await portalRepositories.GetInstance<IUserRepository>().GetOwnCompanyUserWithAssignedBusinessPartnerNumbersUntrackedAsync(userId, companyId).ConfigureAwait(ConfigureAwaitOptions.None);
if (!isValidUser)
{
throw new NotFoundException($"user {userId} not found in company {companyId}");
}

var iamUserId = await provisioningManager.GetUserByUserName(userId.ToString()).ConfigureAwait(ConfigureAwaitOptions.None) ??
throw new ConflictException($"user {userId} not found in keycloak");

var (successfulBpns, unsuccessfulBpns) = await businessPartnerNumbers.AggregateAwait(
(SuccessfulBpns: ImmutableList.CreateBuilder<string>(), UnsuccessfulBpns: ImmutableList.CreateBuilder<UnsuccessfulBpns>()),
async (acc, bpn) =>
{
var (bpns, error) = await CompanyUsersBpnCheck(bpn, token, cancellationToken).ConfigureAwait(false);
if (error == null)
{
acc.SuccessfulBpns.Add(bpns);
}
else
{
acc.UnsuccessfulBpns.Add(new UnsuccessfulBpns(bpns, error.Message));
}
return acc;
},
acc => (acc.SuccessfulBpns.ToImmutable(), acc.UnsuccessfulBpns.ToImmutable()),
cancellationToken
).ConfigureAwait(ConfigureAwaitOptions.None);

if (successfulBpns.Count != 0)
Action<CompanyUserAssignedBusinessPartner> CreateProcess()
{
await provisioningManager.AddBpnAttributetoUserAsync(iamUserId, successfulBpns).ConfigureAwait(false);
successfulBpns.Except(assignedBusinessPartnerNumbers).IfAny(businessPartnersToAdd =>
portalRepositories.GetInstance<IUserBusinessPartnerRepository>().CreateCompanyUserAssignedBusinessPartners(businessPartnersToAdd.Select(bpn => (userId, bpn))));
var processStepRepository = portalRepositories.GetInstance<IPortalProcessStepRepository>();
var processId = processStepRepository.CreateProcess(ProcessTypeId.USER_BPN).Id;
processStepRepository.CreateProcessStep(ProcessStepTypeId.CHECK_LEGAL_ENTITY_DATA, ProcessStepStatusId.TODO, processId);
return x => x.ProcessId = processId;
}

await portalRepositories.SaveAsync();
return new CompanyUsersBpnDetails(successfulBpns, unsuccessfulBpns);
}

private async ValueTask<(string bpns, Exception? error)> CompanyUsersBpnCheck(string bpn, string token, CancellationToken cancellationToken)
{
Exception? error = null;
try
{
if (bpn.Length > 20)
{
throw new ControllerArgumentException("BusinessPartnerNumbers must not exceed 20 characters");
}

var legalEntity = await bpnAccess.FetchLegalEntityByBpn(bpn, token, cancellationToken).ConfigureAwait(false);
if (!bpn.Equals(legalEntity.Bpn, StringComparison.OrdinalIgnoreCase))
{
throw new ConflictException("Bpdm did return incorrect bpn legal-entity-data");
}
}
catch (Exception ex)
{
error = ex;
}
portalRepositories.GetInstance<IUserBusinessPartnerRepository>()
.CreateCompanyUserAssignedBusinessPartners(businessPartnerNumbers.Except(assignedBusinessPartnerNumbers).Select(bpn => (userId, bpn, CreateProcess())));

return (bpn, error);
await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None);
}

public Task<CompanyUsersBpnDetails> AddOwnCompanyUsersBusinessPartnerNumberAsync(Guid userId, string token, string businessPartnerNumber, CancellationToken cancellationToken) =>
AddOwnCompanyUsersBusinessPartnerNumbersAsync(userId, token, Enumerable.Repeat(businessPartnerNumber, 1), cancellationToken);
public Task AddOwnCompanyUsersBusinessPartnerNumberAsync(Guid userId, string businessPartnerNumber, CancellationToken cancellationToken) =>
AddOwnCompanyUsersBusinessPartnerNumbersAsync(userId, Enumerable.Repeat(businessPartnerNumber, 1), cancellationToken);

public async Task<CompanyOwnUserDetails> GetOwnUserDetails()
{
Expand Down Expand Up @@ -576,12 +543,10 @@ public async Task<bool> ExecuteOwnCompanyUserPasswordReset(Guid companyUserId)
new[] { UserStatusId.ACTIVE, UserStatusId.INACTIVE },
filter));

public async Task<int> DeleteOwnUserBusinessPartnerNumbersAsync(Guid userId, string businessPartnerNumber)
public async Task DeleteOwnUserBusinessPartnerNumbersAsync(Guid userId, string businessPartnerNumber)
{
var userBusinessPartnerRepository = portalRepositories.GetInstance<IUserBusinessPartnerRepository>();

var (isValidUser, isAssignedBusinessPartner, isSameCompany) = await userBusinessPartnerRepository.GetOwnCompanyUserWithAssignedBusinessPartnerNumbersAsync(userId, _identityData.CompanyId, businessPartnerNumber.ToUpper()).ConfigureAwait(ConfigureAwaitOptions.None);

if (!isValidUser)
{
throw new NotFoundException($"user {userId} does not exist");
Expand All @@ -597,12 +562,21 @@ public async Task<int> DeleteOwnUserBusinessPartnerNumbersAsync(Guid userId, str
throw new ForbiddenException($"userId {userId} and adminUserId {_identityData.IdentityId} do not belong to same company");
}

var iamUserId = await provisioningManager.GetUserByUserName(userId.ToString()).ConfigureAwait(ConfigureAwaitOptions.None) ?? throw new ConflictException($"user {userId} is not associated with a user in keycloak");

userBusinessPartnerRepository.DeleteCompanyUserAssignedBusinessPartner(userId, businessPartnerNumber.ToUpper());
var processStepRepository = portalRepositories.GetInstance<IPortalProcessStepRepository>();
var processId = processStepRepository.CreateProcess(ProcessTypeId.USER_BPN).Id;
processStepRepository.CreateProcessStep(ProcessStepTypeId.DELETE_BPN_FROM_CENTRAL_USER, ProcessStepStatusId.TODO, processId);
userBusinessPartnerRepository.AttachAndModifyCompanyUserAssignedBusinessPartner(userId, businessPartnerNumber, c => c.ProcessId = processId);
await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None);
}

await provisioningManager.DeleteCentralUserBusinessPartnerNumberAsync(iamUserId, businessPartnerNumber.ToUpper()).ConfigureAwait(ConfigureAwaitOptions.None);
public Task RetriggerUserBpnProcess(Guid processId, ProcessStepTypeId processStepTypeId)
{
var (processType, _) = ProcessTypeExtensions.GetProcessStepForRetrigger(processStepTypeId);
if (processType != ProcessTypeId.USER_BPN)
{
throw new ConflictException($"{processStepTypeId} can't be retriggered for Process {processId}");
}

return await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None);
return processStepTypeId.TriggerProcessStep(processId, portalRepositories, ProcessTypeExtensions.GetProcessStepForRetrigger);
}
}
Loading
Loading