From 8f44923cfb03a0e719c17ddf7a48e25e4cb1b5dd Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Fri, 19 Jul 2024 12:02:01 +0200 Subject: [PATCH] implement optimistic locking for serviceaccounts --- .../ServiceAccountBusinessLogic.cs | 135 ++- ...tionServiceAccountErrorMessageContainer.cs | 6 +- .../Framework.Async/Directory.Build.props | 2 +- .../Framework.Cors/Directory.Build.props | 2 +- .../Framework.DBAccess/Directory.Build.props | 2 +- .../VersionedEntityExtensions.cs | 3 +- .../Directory.Build.props | 2 +- .../Directory.Build.props | 2 +- .../Directory.Build.props | 2 +- .../Directory.Build.props | 2 +- .../Directory.Build.props | 2 +- .../Directory.Build.props | 2 +- .../Framework.IO/Directory.Build.props | 2 +- .../Framework.Linq/Directory.Build.props | 2 +- .../Framework.Logging/Directory.Build.props | 2 +- .../Framework.Models/Directory.Build.props | 2 +- .../Framework.Seeding/Directory.Build.props | 2 +- .../Framework.Swagger/Directory.Build.props | 2 +- .../Framework.Token/Directory.Build.props | 2 +- .../Framework.Web/Directory.Build.props | 2 +- ...mpanyServiceAccountWithRoleDataClientId.cs | 10 +- .../Models/OwnServiceAccountData.cs | 4 +- ...talRepositoriesStartupServiceExtensions.cs | 1 - .../Repositories/IProcessStepRepository.cs | 4 +- .../Repositories/IServiceAccountRepository.cs | 2 +- .../Repositories/ProcessStepRepository.cs | 16 +- .../Repositories/ServiceAccountRepository.cs | 19 +- ...02071934_809-AddDeleteDimUser.Designer.cs} | 844 ++++++++++-------- ...=> 20240802071934_809-AddDeleteDimUser.cs} | 72 +- .../PortalDbContextModelSnapshot.cs | 56 +- .../PortalBackend.Migrations/Program.cs | 1 - .../Entities/CompanyServiceAccount.cs | 6 +- .../Enums/ProcessStepTypeId.cs | 12 +- .../DimUserProcessService.cs | 28 +- .../DimUserProcessTypeExecutor.cs | 4 +- .../IDimUserProcessService.cs | 3 +- .../ManualProcessStepData.cs | 2 +- .../ManualProcessStepDataExtensions.cs | 42 +- .../ServiceAccountBusinessLogicTests.cs | 114 +-- .../Service/OfferSetupServiceTests.cs | 2 +- .../ServiceAccountRespotitoryTests.cs | 39 +- .../DimUserProcessServiceTests.cs | 23 +- .../DimUserProcessTypeExecutorTests.cs | 14 +- .../Extensions/ServiceAccountCreationTests.cs | 4 +- 44 files changed, 822 insertions(+), 678 deletions(-) rename src/portalbackend/PortalBackend.Migrations/Migrations/{20240703123105_809-AddDeleteDimUser.Designer.cs => 20240802071934_809-AddDeleteDimUser.Designer.cs} (98%) rename src/portalbackend/PortalBackend.Migrations/Migrations/{20240703123105_809-AddDeleteDimUser.cs => 20240802071934_809-AddDeleteDimUser.cs} (55%) diff --git a/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs index a48a016056..61da42031c 100644 --- a/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs @@ -21,8 +21,6 @@ using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; using Org.Eclipse.TractusX.Portal.Backend.Dim.Library.Models; -using Org.Eclipse.TractusX.Portal.Backend.Framework.DateTimeProvider; -using Org.Eclipse.TractusX.Portal.Backend.Framework.DBAccess; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Linq; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; @@ -45,13 +43,11 @@ public class ServiceAccountBusinessLogic( IPortalRepositories portalRepositories, IOptions options, IServiceAccountCreation serviceAccountCreation, - IIdentityService identityService, - IDateTimeProvider dateTimeProvider) + IIdentityService identityService) : IServiceAccountBusinessLogic { private readonly IIdentityData _identityData = identityService.IdentityData; private readonly ServiceAccountSettings _settings = options.Value; - private readonly TimeSpan _lockExpiryTime = new(options.Value.LockExpirySeconds * 10000000L); private const string CompanyId = "companyId"; @@ -115,16 +111,28 @@ public async Task DeleteOwnCompanyServiceAccountAsync(Guid serviceAccountId throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_USERID_ACTIVATION_ACTIVE_CONFLICT); } - if (!result.ServiceAccount.TryLock(dateTimeProvider.OffsetNow.Add(_lockExpiryTime))) + // serviceAccount + if (result.IsDimServiceAccount) { - throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_LOCKED, [new("serviceAccountId", serviceAccountId.ToString())]); - } + var processId = result.ProcessId ?? throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, [new("serviceAccountId", serviceAccountId.ToString())]); - // save the lock of the service account here to make sure no process overwrites it - await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); + var processData = await portalRepositories.GetInstance() + .GetProcessDataForServiceAccountDeletionCallback(processId, null) + .ConfigureAwait(ConfigureAwaitOptions.None); - // serviceAccount - if (!string.IsNullOrWhiteSpace(result.ClientClientId) && !result.IsDimServiceAccount) + var context = processData.ProcessData.CreateManualProcessData(null, + portalRepositories, () => $"externalId {processId}"); + + context.ProcessSteps.Where(step => step.ProcessStepTypeId != ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER).IfAny(pending => + throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_PENDING_PROCESS_STEPS, [new("serviceAccountId", serviceAccountId.ToString()), new("processStepTypeIds", string.Join(",", pending))])); + + if (!context.ProcessSteps.Any(step => step.ProcessStepTypeId == ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER)) + { + context.ScheduleProcessSteps([ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER]); + context.FinalizeProcessStep(); + } + } + else if (!string.IsNullOrWhiteSpace(result.ClientClientId)) { await provisioningManager.DeleteCentralClientAsync(result.ClientClientId).ConfigureAwait(ConfigureAwaitOptions.None); portalRepositories.GetInstance().AttachAndModifyIdentity(serviceAccountId, null, i => @@ -133,17 +141,6 @@ public async Task DeleteOwnCompanyServiceAccountAsync(Guid serviceAccountId }); } - if (result.IsDimServiceAccount) - { - if (result.ProcessId == null) - { - throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, [new("serviceAccountId", serviceAccountId.ToString())]); - } - - var processStepRepository = portalRepositories.GetInstance(); - processStepRepository.CreateProcessStep(ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER, ProcessStepStatusId.TODO, result.ProcessId.Value); - } - portalRepositories.GetInstance().DeleteCompanyUserAssignedRoles(result.UserRoleIds.Select(userRoleId => (serviceAccountId, userRoleId))); if (result.ConnectorId != null) @@ -159,7 +156,6 @@ public async Task DeleteOwnCompanyServiceAccountAsync(Guid serviceAccountId }); } - result.ServiceAccount.ReleaseLock(); return await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); } @@ -267,24 +263,16 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAs throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_INACTIVE_CONFLICT, [new("serviceAccountId", serviceAccountId.ToString())]); } - if (result.ServiceAccount.ClientClientId == null) + if (result.ClientClientId == null) { throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_CLIENTID_NOT_NULL_CONFLICT, [new("serviceAccountId", serviceAccountId.ToString())]); } - if (!result.ServiceAccount.TryLock(dateTimeProvider.OffsetNow.Add(_lockExpiryTime))) - { - throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_LOCKED, [new("serviceAccountId", serviceAccountId.ToString())]); - } - - // save the lock of the service account here to make sure no process overwrites it - await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); - ClientAuthData? authData; - if (result.ServiceAccount.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL) + if (result.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL) { var internalClientId = await provisioningManager.UpdateCentralClientAsync( - result.ServiceAccount.ClientClientId, + result.ClientClientId, new ClientConfigData( serviceAccountDetails.Name, serviceAccountDetails.Description, @@ -297,23 +285,33 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAs authData = null; } - result.ServiceAccount.Name = serviceAccountDetails.Name; - result.ServiceAccount.Description = serviceAccountDetails.Description; + serviceAccountRepository.AttachAndModifyCompanyServiceAccount( + serviceAccountId, + result.ServiceAccountVersion, + sa => + { + sa.Name = result.Name; + sa.Description = result.Description; + }, + sa => + { + sa.Name = serviceAccountDetails.Name; + sa.Description = serviceAccountDetails.Description; + }); - result.ServiceAccount.ReleaseLock(); await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); return new ServiceAccountDetails( - result.ServiceAccount.Id, - result.ServiceAccount.ClientClientId, + serviceAccountId, + result.ClientClientId, serviceAccountDetails.Name, serviceAccountDetails.Description, result.UserStatusId, authData?.IamClientAuthMethod, result.UserRoleDatas, - result.ServiceAccount.CompanyServiceAccountTypeId, + result.CompanyServiceAccountTypeId, authData?.Secret, - result.ServiceAccount.OfferSubscriptionId); + result.OfferSubscriptionId); } public Task> GetOwnCompanyServiceAccountsDataAsync(int page, int size, string? clientId, bool? isOwner, bool filterForInactive, IEnumerable? userStatusIds) @@ -349,37 +347,29 @@ public async Task HandleServiceAccountCreationCallback(Guid processId, Authentic { throw new ConflictException($"ServiceAccountId must be set for process {processId}"); } - - switch (processData.ProcessTypeId) + if (processData.ServiceAccountVersion is null) { - case ProcessTypeId.OFFER_SUBSCRIPTION: - HandleOfferSubscriptionTechnicalUserCallback(processData.ServiceAccountId.Value, callbackData, context); - break; - case ProcessTypeId.DIM_TECHNICAL_USER: - CreateDimServiceAccount(callbackData, processData.ServiceAccountId.Value); - break; - default: - throw new ControllerArgumentException($"process {processId} has invalid processType {processData.ProcessTypeId}"); + throw new UnexpectedConditionException("ServiceAccountVersion or IdentityVersion should never be null here"); } + CreateDimServiceAccount(callbackData, processData.ServiceAccountId.Value, processData.ServiceAccountVersion.Value); + + if (processData.ProcessTypeId == ProcessTypeId.OFFER_SUBSCRIPTION) + { + context.ScheduleProcessSteps([ProcessStepTypeId.TRIGGER_ACTIVATE_SUBSCRIPTION]); + } context.FinalizeProcessStep(); await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); } - private void HandleOfferSubscriptionTechnicalUserCallback(Guid serviceAccountId, AuthenticationDetail callbackData, ManualProcessStepData context) - { - CreateDimServiceAccount(callbackData, serviceAccountId); - context.ScheduleProcessSteps([ProcessStepTypeId.TRIGGER_ACTIVATE_SUBSCRIPTION]); - } - - private void CreateDimServiceAccount(AuthenticationDetail callbackData, Guid serviceAccountId) + private void CreateDimServiceAccount(AuthenticationDetail callbackData, Guid serviceAccountId, Guid serviceAccountVersion) { var serviceAccountRepository = portalRepositories.GetInstance(); portalRepositories.GetInstance().AttachAndModifyIdentity(serviceAccountId, i => { i.UserStatusId = UserStatusId.PENDING; }, i => { i.UserStatusId = UserStatusId.ACTIVE; }); - serviceAccountRepository.AttachAndModifyCompanyServiceAccount(serviceAccountId, + serviceAccountRepository.AttachAndModifyCompanyServiceAccount(serviceAccountId, serviceAccountVersion, sa => { sa.ClientClientId = null; }, sa => { sa.ClientClientId = callbackData.ClientId; }); @@ -399,25 +389,14 @@ public async Task HandleServiceAccountDeletionCallback(Guid processId) var context = processData.ProcessData.CreateManualProcessData(ProcessStepTypeId.AWAIT_DELETE_DIM_TECHNICAL_USER, portalRepositories, () => $"externalId {processId}"); - if (processData.ServiceAccount is null) - { - throw new ConflictException($"ServiceAccountId must be set for process {processId}"); - } - - if (!processData.ServiceAccount.TryLock(dateTimeProvider.OffsetNow.Add(_lockExpiryTime))) - { - throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_LOCKED, [new("serviceAccountId", processData.ServiceAccount.Id.ToString())]); - } - - // save the lock of the service account here to make sure no process overwrites it - await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); - - portalRepositories.GetInstance().AttachAndModifyIdentity(processData.ServiceAccount.Id, null, i => - { - i.UserStatusId = UserStatusId.INACTIVE; - }); + portalRepositories.GetInstance().AttachAndModifyIdentity( + processData.ServiceAccountId ?? throw new ConflictException($"ServiceAccountId must be set for process {processId}"), + null, + i => + { + i.UserStatusId = UserStatusId.INACTIVE; + }); - processData.ServiceAccount.ReleaseLock(); context.FinalizeProcessStep(); await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); } diff --git a/src/administration/Administration.Service/ErrorHandling/AdministrationServiceAccountErrorMessageContainer.cs b/src/administration/Administration.Service/ErrorHandling/AdministrationServiceAccountErrorMessageContainer.cs index 87b0b4714e..90a1929a07 100644 --- a/src/administration/Administration.Service/ErrorHandling/AdministrationServiceAccountErrorMessageContainer.cs +++ b/src/administration/Administration.Service/ErrorHandling/AdministrationServiceAccountErrorMessageContainer.cs @@ -38,7 +38,8 @@ public class AdministrationServiceAccountErrorMessageContainer : IErrorMessageCo { AdministrationServiceAccountErrors.SERVICE_INACTIVE_CONFLICT, "serviceAccount {serviceAccountId} is already INACTIVE"}, { AdministrationServiceAccountErrors.SERVICE_CLIENTID_NOT_NULL_CONFLICT, "clientClientId of serviceAccount {serviceAccountId} should not be null"}, { AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, "Service Account {serviceAccountId} is not linked to a process" }, - { AdministrationServiceAccountErrors.SERVICE_ACCOUNT_LOCKED, "Service Account {serviceAccountId} is locked by another process" } + { AdministrationServiceAccountErrors.SERVICE_ACCOUNT_LOCKED, "Service Account {serviceAccountId} is locked by another process" }, + { AdministrationServiceAccountErrors.SERVICE_ACCOUNT_PENDING_PROCESS_STEPS, "Service Account {serviceAccountId} has pending process steps {processStepTypeIds}"} }.ToImmutableDictionary(x => (int)x.Key, x => x.Value); public Type Type { get => typeof(AdministrationServiceAccountErrors); } @@ -60,5 +61,6 @@ public enum AdministrationServiceAccountErrors SERVICE_INACTIVE_CONFLICT, SERVICE_CLIENTID_NOT_NULL_CONFLICT, SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, - SERVICE_ACCOUNT_LOCKED + SERVICE_ACCOUNT_LOCKED, + SERVICE_ACCOUNT_PENDING_PROCESS_STEPS } diff --git a/src/framework/Framework.Async/Directory.Build.props b/src/framework/Framework.Async/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.Async/Directory.Build.props +++ b/src/framework/Framework.Async/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.Cors/Directory.Build.props b/src/framework/Framework.Cors/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.Cors/Directory.Build.props +++ b/src/framework/Framework.Cors/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.DBAccess/Directory.Build.props b/src/framework/Framework.DBAccess/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.DBAccess/Directory.Build.props +++ b/src/framework/Framework.DBAccess/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.DBAccess/VersionedEntityExtensions.cs b/src/framework/Framework.DBAccess/VersionedEntityExtensions.cs index 0ff12f6aaf..107f17c28a 100644 --- a/src/framework/Framework.DBAccess/VersionedEntityExtensions.cs +++ b/src/framework/Framework.DBAccess/VersionedEntityExtensions.cs @@ -1,5 +1,4 @@ /******************************************************************************** - * Copyright (c) 2022 BMW Group AG * Copyright (c) 2022 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional @@ -22,7 +21,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Framework.DBAccess; public static class VersionedEntityExtensions { - public static void UpdateVersion(this ILockableEntity entity) + public static void UpdateVersion(this IVersionedEntity entity) { entity.Version = Guid.NewGuid(); } diff --git a/src/framework/Framework.DateTimeProvider/Directory.Build.props b/src/framework/Framework.DateTimeProvider/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.DateTimeProvider/Directory.Build.props +++ b/src/framework/Framework.DateTimeProvider/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.DependencyInjection/Directory.Build.props b/src/framework/Framework.DependencyInjection/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.DependencyInjection/Directory.Build.props +++ b/src/framework/Framework.DependencyInjection/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.ErrorHandling.Controller/Directory.Build.props b/src/framework/Framework.ErrorHandling.Controller/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.ErrorHandling.Controller/Directory.Build.props +++ b/src/framework/Framework.ErrorHandling.Controller/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.ErrorHandling.Web/Directory.Build.props b/src/framework/Framework.ErrorHandling.Web/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.ErrorHandling.Web/Directory.Build.props +++ b/src/framework/Framework.ErrorHandling.Web/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.ErrorHandling/Directory.Build.props b/src/framework/Framework.ErrorHandling/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.ErrorHandling/Directory.Build.props +++ b/src/framework/Framework.ErrorHandling/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.HttpClientExtensions/Directory.Build.props b/src/framework/Framework.HttpClientExtensions/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.HttpClientExtensions/Directory.Build.props +++ b/src/framework/Framework.HttpClientExtensions/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.IO/Directory.Build.props b/src/framework/Framework.IO/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.IO/Directory.Build.props +++ b/src/framework/Framework.IO/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.Linq/Directory.Build.props b/src/framework/Framework.Linq/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.Linq/Directory.Build.props +++ b/src/framework/Framework.Linq/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.Logging/Directory.Build.props b/src/framework/Framework.Logging/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.Logging/Directory.Build.props +++ b/src/framework/Framework.Logging/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.Models/Directory.Build.props b/src/framework/Framework.Models/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.Models/Directory.Build.props +++ b/src/framework/Framework.Models/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.Seeding/Directory.Build.props b/src/framework/Framework.Seeding/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.Seeding/Directory.Build.props +++ b/src/framework/Framework.Seeding/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.Swagger/Directory.Build.props b/src/framework/Framework.Swagger/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.Swagger/Directory.Build.props +++ b/src/framework/Framework.Swagger/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.Token/Directory.Build.props b/src/framework/Framework.Token/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.Token/Directory.Build.props +++ b/src/framework/Framework.Token/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/framework/Framework.Web/Directory.Build.props b/src/framework/Framework.Web/Directory.Build.props index 7ec978c602..f53f08f151 100644 --- a/src/framework/Framework.Web/Directory.Build.props +++ b/src/framework/Framework.Web/Directory.Build.props @@ -19,7 +19,7 @@ - 2.4.2 + 2.5.0 diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyServiceAccountWithRoleDataClientId.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyServiceAccountWithRoleDataClientId.cs index 554b8e6cdf..c6e1f1a6bd 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyServiceAccountWithRoleDataClientId.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyServiceAccountWithRoleDataClientId.cs @@ -1,5 +1,4 @@ /******************************************************************************** - * Copyright (c) 2022 BMW Group AG * Copyright (c) 2022 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional @@ -18,12 +17,17 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; public record CompanyServiceAccountWithRoleDataClientId( - CompanyServiceAccount ServiceAccount, + Guid ServiceAccountVersion, + string Name, + string Description, + string? ClientClientId, + CompanyServiceAccountTypeId CompanyServiceAccountTypeId, + CompanyServiceAccountKindId CompanyServiceAccountKindId, + Guid? OfferSubscriptionId, UserStatusId UserStatusId, IEnumerable UserRoleDatas); diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/OwnServiceAccountData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/OwnServiceAccountData.cs index 5015a0b932..2551ccd7f3 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/OwnServiceAccountData.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/OwnServiceAccountData.cs @@ -17,14 +17,14 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; public record OwnServiceAccountData( IEnumerable UserRoleIds, - CompanyServiceAccount ServiceAccount, + Guid ServiceAccountId, + Guid ServiceAccountVersion, Guid? ConnectorId, string? ClientClientId, ConnectorStatusId? StatusId, diff --git a/src/portalbackend/PortalBackend.DBAccess/PortalRepositoriesStartupServiceExtensions.cs b/src/portalbackend/PortalBackend.DBAccess/PortalRepositoriesStartupServiceExtensions.cs index 1ea5f2da20..d09f809548 100644 --- a/src/portalbackend/PortalBackend.DBAccess/PortalRepositoriesStartupServiceExtensions.cs +++ b/src/portalbackend/PortalBackend.DBAccess/PortalRepositoriesStartupServiceExtensions.cs @@ -1,5 +1,4 @@ /******************************************************************************** - * Copyright (c) 2022 BMW Group AG * Copyright (c) 2022 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IProcessStepRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IProcessStepRepository.cs index 18518ede2b..ae4390b5f2 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IProcessStepRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IProcessStepRepository.cs @@ -37,6 +37,6 @@ public interface IProcessStepRepository IAsyncEnumerable GetActiveProcesses(IEnumerable processTypeIds, IEnumerable processStepTypeIds, DateTimeOffset lockExpiryDate); IAsyncEnumerable<(Guid ProcessStepId, ProcessStepTypeId ProcessStepTypeId)> GetProcessStepData(Guid processId); public Task<(bool ProcessExists, VerifyProcessData ProcessData)> IsValidProcess(Guid processId, ProcessTypeId processTypeId, IEnumerable processStepTypeIds); - Task<(ProcessTypeId ProcessTypeId, VerifyProcessData ProcessData, Guid? ServiceAccountId)> GetProcessDataForServiceAccountCallback(Guid processId, IEnumerable processStepTypeIds); - Task<(ProcessTypeId ProcessTypeId, VerifyProcessData ProcessData, CompanyServiceAccount? ServiceAccount)> GetProcessDataForServiceAccountDeletionCallback(Guid processId, IEnumerable processStepTypeIds); + Task<(ProcessTypeId ProcessTypeId, VerifyProcessData ProcessData, Guid? ServiceAccountId, Guid? ServiceAccountVersion)> GetProcessDataForServiceAccountCallback(Guid processId, IEnumerable processStepTypeIds); + Task<(ProcessTypeId ProcessTypeId, VerifyProcessData ProcessData, Guid? ServiceAccountId)> GetProcessDataForServiceAccountDeletionCallback(Guid processId, IEnumerable? processStepTypeIds); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs index a78520734a..a059863f68 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs @@ -34,7 +34,7 @@ CompanyServiceAccount CreateCompanyServiceAccount(Guid identityId, CompanyServiceAccountKindId companyServiceAccountKindId, Action? setOptionalParameters = null); - void AttachAndModifyCompanyServiceAccount(Guid id, Action? initialize, Action modify); + void AttachAndModifyCompanyServiceAccount(Guid id, Guid version, Action? initialize, Action modify); Task GetOwnCompanyServiceAccountWithIamClientIdAsync(Guid serviceAccountId, Guid userCompanyId); Task GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(Guid serviceAccountId, Guid companyId); Task GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(Guid serviceAccountId, Guid companyId); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ProcessStepRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ProcessStepRepository.cs index e1503825e8..af4077983e 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ProcessStepRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ProcessStepRepository.cs @@ -121,11 +121,11 @@ public IAsyncEnumerable GetActiveProcesses(IEnumerable p )) .SingleOrDefaultAsync(); - public Task<(ProcessTypeId ProcessTypeId, VerifyProcessData ProcessData, Guid? ServiceAccountId)> GetProcessDataForServiceAccountCallback(Guid processId, IEnumerable processStepTypeIds) => + public Task<(ProcessTypeId ProcessTypeId, VerifyProcessData ProcessData, Guid? ServiceAccountId, Guid? ServiceAccountVersion)> GetProcessDataForServiceAccountCallback(Guid processId, IEnumerable processStepTypeIds) => _context.Processes .AsNoTracking() .Where(x => x.Id == processId) - .Select(x => new ValueTuple( + .Select(x => new ValueTuple( x.ProcessTypeId, new VerifyProcessData( x, @@ -133,22 +133,24 @@ public IAsyncEnumerable GetActiveProcesses(IEnumerable p .Where(step => processStepTypeIds.Contains(step.ProcessStepTypeId) && step.ProcessStepStatusId == ProcessStepStatusId.TODO)), - x.DimUserCreationData!.ServiceAccountId) + x.DimUserCreationData!.ServiceAccountId, + x.DimUserCreationData.ServiceAccount!.Version) ) .SingleOrDefaultAsync(); - public Task<(ProcessTypeId ProcessTypeId, VerifyProcessData ProcessData, CompanyServiceAccount? ServiceAccount)> GetProcessDataForServiceAccountDeletionCallback(Guid processId, IEnumerable processStepTypeIds) => + public Task<(ProcessTypeId ProcessTypeId, VerifyProcessData ProcessData, Guid? ServiceAccountId)> GetProcessDataForServiceAccountDeletionCallback(Guid processId, IEnumerable? processStepTypeIds) => _context.Processes + .AsNoTracking() .Where(x => x.Id == processId && x.ProcessTypeId == ProcessTypeId.DIM_TECHNICAL_USER) - .Select(x => new ValueTuple( + .Select(x => new ValueTuple( x.ProcessTypeId, new VerifyProcessData( x, x.ProcessSteps .Where(step => - processStepTypeIds.Contains(step.ProcessStepTypeId) && + (processStepTypeIds == null || processStepTypeIds.Contains(step.ProcessStepTypeId)) && step.ProcessStepStatusId == ProcessStepStatusId.TODO)), - x.DimUserCreationData!.ServiceAccount) + x.DimUserCreationData!.ServiceAccountId) ) .SingleOrDefaultAsync(); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs index 22ce6aa60a..00bd547861 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs @@ -40,11 +40,11 @@ public CompanyServiceAccount CreateCompanyServiceAccount( { var entity = new CompanyServiceAccount( identityId, + Guid.NewGuid(), name, description, companyServiceAccountTypeId, - companyServiceAccountKindId, - Guid.NewGuid()) + companyServiceAccountKindId) { ClientClientId = clientClientId }; @@ -54,19 +54,21 @@ public CompanyServiceAccount CreateCompanyServiceAccount( public void AttachAndModifyCompanyServiceAccount( Guid id, + Guid version, Action? initialize, Action modify) { var companyServiceAccount = new CompanyServiceAccount( id, + version, null!, null!, default, - default, default); initialize?.Invoke(companyServiceAccount); portalDbContext.Attach(companyServiceAccount); modify(companyServiceAccount); + companyServiceAccount.UpdateVersion(); } public Task GetOwnCompanyServiceAccountWithIamClientIdAsync(Guid serviceAccountId, Guid userCompanyId) => @@ -76,7 +78,13 @@ public void AttachAndModifyCompanyServiceAccount( && serviceAccount.Identity!.UserStatusId == UserStatusId.ACTIVE && serviceAccount.Identity.CompanyId == userCompanyId) .Select(serviceAccount => new CompanyServiceAccountWithRoleDataClientId( - serviceAccount, + serviceAccount.Version, + serviceAccount.Name, + serviceAccount.Description, + serviceAccount.ClientClientId, + serviceAccount.CompanyServiceAccountTypeId, + serviceAccount.CompanyServiceAccountKindId, + serviceAccount.OfferSubscriptionId, serviceAccount.Identity!.UserStatusId, serviceAccount.Identity!.IdentityAssignedRoles .Select(assignedRole => assignedRole.UserRole) @@ -94,7 +102,8 @@ public void AttachAndModifyCompanyServiceAccount( (serviceAccount.CompaniesLinkedServiceAccount!.Owners == companyId || serviceAccount.CompaniesLinkedServiceAccount!.Provider == companyId)) .Select(sa => new OwnServiceAccountData( sa.Identity!.IdentityAssignedRoles.Select(r => r.UserRoleId), - sa, + sa.Id, + sa.Version, sa.Connector!.Id, sa.ClientClientId, sa.Connector!.StatusId, diff --git a/src/portalbackend/PortalBackend.Migrations/Migrations/20240703123105_809-AddDeleteDimUser.Designer.cs b/src/portalbackend/PortalBackend.Migrations/Migrations/20240802071934_809-AddDeleteDimUser.Designer.cs similarity index 98% rename from src/portalbackend/PortalBackend.Migrations/Migrations/20240703123105_809-AddDeleteDimUser.Designer.cs rename to src/portalbackend/PortalBackend.Migrations/Migrations/20240802071934_809-AddDeleteDimUser.Designer.cs index 3736092e9a..1426507d0b 100644 --- a/src/portalbackend/PortalBackend.Migrations/Migrations/20240703123105_809-AddDeleteDimUser.Designer.cs +++ b/src/portalbackend/PortalBackend.Migrations/Migrations/20240802071934_809-AddDeleteDimUser.Designer.cs @@ -18,21 +18,18 @@ ********************************************************************************/ // -using System; -using System.Text.Json; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities; +using System.Text.Json; #nullable disable namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.Migrations.Migrations { [DbContext(typeof(PortalDbContext))] - [Migration("20240703123105_809-AddDeleteDimUser")] + [Migration("20240802071934_809-AddDeleteDimUser")] partial class _809AddDeleteDimUser { /// @@ -42,7 +39,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder .HasDefaultSchema("portal") .UseCollation("en_US.utf8") - .HasAnnotation("ProductVersion", "8.0.5") + .HasAnnotation("ProductVersion", "8.0.7") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -178,14 +175,26 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("uuid") .HasColumnName("document_id"); + b.Property("ExternalCertificateNumber") + .HasColumnType("text") + .HasColumnName("external_certificate_number"); + b.Property("Id") .HasColumnType("uuid") .HasColumnName("id"); + b.Property("Issuer") + .HasColumnType("text") + .HasColumnName("issuer"); + b.Property("LastEditorId") .HasColumnType("uuid") .HasColumnName("last_editor_id"); + b.Property("TrustLevel") + .HasColumnType("text") + .HasColumnName("trust_level"); + b.Property("ValidFrom") .HasColumnType("timestamp with time zone") .HasColumnName("valid_from"); @@ -194,6 +203,10 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("timestamp with time zone") .HasColumnName("valid_till"); + b.Property("Validator") + .HasColumnType("text") + .HasColumnName("validator"); + b.HasKey("AuditV1Id") .HasName("pk_audit_certificate_management20240416"); @@ -2068,256 +2081,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("audit_user_role20231115", "portal"); }); - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificate", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CompanyCertificateStatusId") - .HasColumnType("integer") - .HasColumnName("company_certificate_status_id"); - - b.Property("CompanyCertificateTypeId") - .HasColumnType("integer") - .HasColumnName("company_certificate_type_id"); - - b.Property("CompanyId") - .HasColumnType("uuid") - .HasColumnName("company_id"); - - b.Property("DateLastChanged") - .HasColumnType("timestamp with time zone") - .HasColumnName("date_last_changed"); - - b.Property("DocumentId") - .HasColumnType("uuid") - .HasColumnName("document_id"); - - b.Property("LastEditorId") - .HasColumnType("uuid") - .HasColumnName("last_editor_id"); - - b.Property("ValidFrom") - .HasColumnType("timestamp with time zone") - .HasColumnName("valid_from"); - - b.Property("ValidTill") - .HasColumnType("timestamp with time zone") - .HasColumnName("valid_till"); - - b.HasKey("Id") - .HasName("pk_company_certificates"); - - b.HasIndex("CompanyCertificateStatusId") - .HasDatabaseName("ix_company_certificates_company_certificate_status_id"); - - b.HasIndex("CompanyCertificateTypeId") - .HasDatabaseName("ix_company_certificates_company_certificate_type_id"); - - b.HasIndex("CompanyId") - .HasDatabaseName("ix_company_certificates_company_id"); - - b.HasIndex("DocumentId") - .HasDatabaseName("ix_company_certificates_document_id"); - - b.ToTable("company_certificates", "portal", t => - { - t.HasTrigger("LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE"); - - t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE"); - }); - - b - .HasAnnotation("LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_certificate_management20240416\" (\"id\", \"valid_from\", \"valid_till\", \"company_certificate_type_id\", \"company_certificate_status_id\", \"company_id\", \"document_id\", \"date_last_changed\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"valid_from\", \r\n NEW.\"valid_till\", \r\n NEW.\"company_certificate_type_id\", \r\n NEW.\"company_certificate_status_id\", \r\n NEW.\"company_id\", \r\n NEW.\"document_id\", \r\n NEW.\"date_last_changed\", \r\n NEW.\"last_editor_id\", \r\n gen_random_uuid(), \r\n 1, \r\n CURRENT_TIMESTAMP, \r\n NEW.\"last_editor_id\";\r\nRETURN NEW;\r\nEND;\r\n$LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE AFTER INSERT\r\nON \"portal\".\"company_certificates\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE\"();") - .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_certificate_management20240416\" (\"id\", \"valid_from\", \"valid_till\", \"company_certificate_type_id\", \"company_certificate_status_id\", \"company_id\", \"document_id\", \"date_last_changed\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"valid_from\", \r\n NEW.\"valid_till\", \r\n NEW.\"company_certificate_type_id\", \r\n NEW.\"company_certificate_status_id\", \r\n NEW.\"company_id\", \r\n NEW.\"document_id\", \r\n NEW.\"date_last_changed\", \r\n NEW.\"last_editor_id\", \r\n gen_random_uuid(), \r\n 2, \r\n CURRENT_TIMESTAMP, \r\n NEW.\"last_editor_id\";\r\nRETURN NEW;\r\nEND;\r\n$LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE AFTER UPDATE\r\nON \"portal\".\"company_certificates\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE\"();"); - }); - - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateStatus", b => - { - b.Property("Id") - .HasColumnType("integer") - .HasColumnName("id"); - - b.Property("Label") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("label"); - - b.HasKey("Id") - .HasName("pk_company_certificate_statuses"); - - b.ToTable("company_certificate_statuses", "portal"); - - b.HasData( - new - { - Id = 1, - Label = "ACTIVE" - }, - new - { - Id = 2, - Label = "INACTIVE" - }); - }); - - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateType", b => - { - b.Property("Id") - .HasColumnType("integer") - .HasColumnName("id"); - - b.Property("Label") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("label"); - - b.HasKey("Id") - .HasName("pk_company_certificate_types"); - - b.ToTable("company_certificate_types", "portal"); - - b.HasData( - new - { - Id = 1, - Label = "AEO_CTPAT_Security_Declaration" - }, - new - { - Id = 2, - Label = "ISO_9001" - }, - new - { - Id = 3, - Label = "IATF_16949" - }, - new - { - Id = 4, - Label = "ISO_14001_EMAS_or_national_certification" - }, - new - { - Id = 5, - Label = "ISO_45001_OHSAS_18001_or_national_certification" - }, - new - { - Id = 6, - Label = "ISO_IEC_27001" - }, - new - { - Id = 7, - Label = "ISO_50001_or_national_certification" - }, - new - { - Id = 8, - Label = "ISO_IEC_17025" - }, - new - { - Id = 9, - Label = "ISO_15504_SPICE" - }, - new - { - Id = 10, - Label = "B_BBEE_Certificate_of_South_Africa" - }, - new - { - Id = 11, - Label = "IATF" - }, - new - { - Id = 12, - Label = "TISAX" - }); - }); - - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateTypeAssignedStatus", b => - { - b.Property("CompanyCertificateTypeId") - .HasColumnType("integer") - .HasColumnName("company_certificate_type_id"); - - b.Property("CompanyCertificateTypeStatusId") - .HasColumnType("integer") - .HasColumnName("company_certificate_type_status_id"); - - b.HasKey("CompanyCertificateTypeId") - .HasName("pk_company_certificate_type_assigned_statuses"); - - b.HasIndex("CompanyCertificateTypeStatusId") - .HasDatabaseName("ix_company_certificate_type_assigned_statuses_company_certific"); - - b.ToTable("company_certificate_type_assigned_statuses", "portal"); - }); - - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateTypeDescription", b => - { - b.Property("CompanyCertificateTypeId") - .HasColumnType("integer") - .HasColumnName("company_certificate_type_id"); - - b.Property("LanguageShortName") - .HasMaxLength(2) - .HasColumnType("character(2)") - .HasColumnName("language_short_name"); - - b.Property("Description") - .IsRequired() - .HasColumnType("text") - .HasColumnName("description"); - - b.HasKey("CompanyCertificateTypeId", "LanguageShortName") - .HasName("pk_company_certificate_type_descriptions"); - - b.HasIndex("LanguageShortName") - .HasDatabaseName("ix_company_certificate_type_descriptions_language_short_name"); - - b.ToTable("company_certificate_type_descriptions", "portal"); - }); - - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateTypeStatus", b => - { - b.Property("Id") - .HasColumnType("integer") - .HasColumnName("id"); - - b.Property("Label") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("label"); - - b.HasKey("Id") - .HasName("pk_company_certificate_type_statuses"); - - b.ToTable("company_certificate_type_statuses", "portal"); - - b.HasData( - new - { - Id = 1, - Label = "ACTIVE" - }, - new - { - Id = 2, - Label = "INACTIVE" - }); - }); - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Address", b => { b.Property("Id") @@ -3304,23 +3067,305 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_COMPANYASSIGNEDROLE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYASSIGNEDROLE\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_COMPANYASSIGNEDROLE$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_company_assigned_role2023316\" (\"company_id\", \"company_role_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"company_id\", \r\n NEW.\"company_role_id\", \r\n NEW.\"last_editor_id\", \r\n gen_random_uuid(), \r\n 2, \r\n CURRENT_TIMESTAMP, \r\n NEW.\"last_editor_id\";\r\nRETURN NEW;\r\nEND;\r\n$LC_TRIGGER_AFTER_UPDATE_COMPANYASSIGNEDROLE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_COMPANYASSIGNEDROLE AFTER UPDATE\r\nON \"portal\".\"company_assigned_roles\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYASSIGNEDROLE\"();"); }); - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyAssignedUseCase", b => + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyAssignedUseCase", b => + { + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("UseCaseId") + .HasColumnType("uuid") + .HasColumnName("use_case_id"); + + b.HasKey("CompanyId", "UseCaseId") + .HasName("pk_company_assigned_use_cases"); + + b.HasIndex("UseCaseId") + .HasDatabaseName("ix_company_assigned_use_cases_use_case_id"); + + b.ToTable("company_assigned_use_cases", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CompanyCertificateStatusId") + .HasColumnType("integer") + .HasColumnName("company_certificate_status_id"); + + b.Property("CompanyCertificateTypeId") + .HasColumnType("integer") + .HasColumnName("company_certificate_type_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DocumentId") + .HasColumnType("uuid") + .HasColumnName("document_id"); + + b.Property("ExternalCertificateNumber") + .HasColumnType("text") + .HasColumnName("external_certificate_number"); + + b.Property("Issuer") + .HasColumnType("text") + .HasColumnName("issuer"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("TrustLevel") + .HasColumnType("text") + .HasColumnName("trust_level"); + + b.Property("ValidFrom") + .HasColumnType("timestamp with time zone") + .HasColumnName("valid_from"); + + b.Property("ValidTill") + .HasColumnType("timestamp with time zone") + .HasColumnName("valid_till"); + + b.Property("Validator") + .HasColumnType("text") + .HasColumnName("validator"); + + b.HasKey("Id") + .HasName("pk_company_certificates"); + + b.HasIndex("CompanyCertificateStatusId") + .HasDatabaseName("ix_company_certificates_company_certificate_status_id"); + + b.HasIndex("CompanyCertificateTypeId") + .HasDatabaseName("ix_company_certificates_company_certificate_type_id"); + + b.HasIndex("CompanyId") + .HasDatabaseName("ix_company_certificates_company_id"); + + b.HasIndex("DocumentId") + .HasDatabaseName("ix_company_certificates_document_id"); + + b.ToTable("company_certificates", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_certificate_management20240416\" (\"id\", \"valid_from\", \"valid_till\", \"company_certificate_type_id\", \"company_certificate_status_id\", \"company_id\", \"document_id\", \"external_certificate_number\", \"issuer\", \"trust_level\", \"validator\", \"date_last_changed\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"valid_from\", \r\n NEW.\"valid_till\", \r\n NEW.\"company_certificate_type_id\", \r\n NEW.\"company_certificate_status_id\", \r\n NEW.\"company_id\", \r\n NEW.\"document_id\", \r\n NEW.\"external_certificate_number\", \r\n NEW.\"issuer\", \r\n NEW.\"trust_level\", \r\n NEW.\"validator\", \r\n NEW.\"date_last_changed\", \r\n NEW.\"last_editor_id\", \r\n gen_random_uuid(), \r\n 1, \r\n CURRENT_TIMESTAMP, \r\n NEW.\"last_editor_id\";\r\nRETURN NEW;\r\nEND;\r\n$LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE AFTER INSERT\r\nON \"portal\".\"company_certificates\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYCERTIFICATE\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_certificate_management20240416\" (\"id\", \"valid_from\", \"valid_till\", \"company_certificate_type_id\", \"company_certificate_status_id\", \"company_id\", \"document_id\", \"external_certificate_number\", \"issuer\", \"trust_level\", \"validator\", \"date_last_changed\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"valid_from\", \r\n NEW.\"valid_till\", \r\n NEW.\"company_certificate_type_id\", \r\n NEW.\"company_certificate_status_id\", \r\n NEW.\"company_id\", \r\n NEW.\"document_id\", \r\n NEW.\"external_certificate_number\", \r\n NEW.\"issuer\", \r\n NEW.\"trust_level\", \r\n NEW.\"validator\", \r\n NEW.\"date_last_changed\", \r\n NEW.\"last_editor_id\", \r\n gen_random_uuid(), \r\n 2, \r\n CURRENT_TIMESTAMP, \r\n NEW.\"last_editor_id\";\r\nRETURN NEW;\r\nEND;\r\n$LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE AFTER UPDATE\r\nON \"portal\".\"company_certificates\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYCERTIFICATE\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateAssignedSite", b => + { + b.Property("CompanyCertificateId") + .HasColumnType("uuid") + .HasColumnName("company_certificate_id"); + + b.Property("Site") + .HasColumnType("text") + .HasColumnName("site"); + + b.HasKey("CompanyCertificateId", "Site") + .HasName("pk_company_certificate_assigned_sites"); + + b.ToTable("company_certificate_assigned_sites", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateStatus", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("label"); + + b.HasKey("Id") + .HasName("pk_company_certificate_statuses"); + + b.ToTable("company_certificate_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "ACTIVE" + }, + new + { + Id = 2, + Label = "INACTIVE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateType", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id"); + + b.Property("Label") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("label"); + + b.HasKey("Id") + .HasName("pk_company_certificate_types"); + + b.ToTable("company_certificate_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "AEO_CTPAT_Security_Declaration" + }, + new + { + Id = 2, + Label = "ISO_9001" + }, + new + { + Id = 3, + Label = "IATF_16949" + }, + new + { + Id = 4, + Label = "ISO_14001_EMAS_or_national_certification" + }, + new + { + Id = 5, + Label = "ISO_45001_OHSAS_18001_or_national_certification" + }, + new + { + Id = 6, + Label = "ISO_IEC_27001" + }, + new + { + Id = 7, + Label = "ISO_50001_or_national_certification" + }, + new + { + Id = 8, + Label = "ISO_IEC_17025" + }, + new + { + Id = 9, + Label = "ISO_15504_SPICE" + }, + new + { + Id = 10, + Label = "B_BBEE_Certificate_of_South_Africa" + }, + new + { + Id = 11, + Label = "IATF" + }, + new + { + Id = 12, + Label = "TISAX" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateTypeAssignedStatus", b => + { + b.Property("CompanyCertificateTypeId") + .HasColumnType("integer") + .HasColumnName("company_certificate_type_id"); + + b.Property("CompanyCertificateTypeStatusId") + .HasColumnType("integer") + .HasColumnName("company_certificate_type_status_id"); + + b.HasKey("CompanyCertificateTypeId") + .HasName("pk_company_certificate_type_assigned_statuses"); + + b.HasIndex("CompanyCertificateTypeStatusId") + .HasDatabaseName("ix_company_certificate_type_assigned_statuses_company_certific"); + + b.ToTable("company_certificate_type_assigned_statuses", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateTypeDescription", b => + { + b.Property("CompanyCertificateTypeId") + .HasColumnType("integer") + .HasColumnName("company_certificate_type_id"); + + b.Property("LanguageShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("language_short_name"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text") + .HasColumnName("description"); + + b.HasKey("CompanyCertificateTypeId", "LanguageShortName") + .HasName("pk_company_certificate_type_descriptions"); + + b.HasIndex("LanguageShortName") + .HasDatabaseName("ix_company_certificate_type_descriptions_language_short_name"); + + b.ToTable("company_certificate_type_descriptions", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateTypeStatus", b => { - b.Property("CompanyId") - .HasColumnType("uuid") - .HasColumnName("company_id"); + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id"); - b.Property("UseCaseId") - .HasColumnType("uuid") - .HasColumnName("use_case_id"); + b.Property("Label") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("label"); - b.HasKey("CompanyId", "UseCaseId") - .HasName("pk_company_assigned_use_cases"); + b.HasKey("Id") + .HasName("pk_company_certificate_type_statuses"); - b.HasIndex("UseCaseId") - .HasDatabaseName("ix_company_assigned_use_cases_use_case_id"); + b.ToTable("company_certificate_type_statuses", "portal"); - b.ToTable("company_assigned_use_cases", "portal"); + b.HasData( + new + { + Id = 1, + Label = "ACTIVE" + }, + new + { + Id = 2, + Label = "INACTIVE" + }); }); modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyIdentifier", b => @@ -3574,10 +3619,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("text") .HasColumnName("description"); - b.Property("LockExpiryDate") - .HasColumnType("timestamp with time zone") - .HasColumnName("lock_expiry_date"); - b.Property("Name") .IsRequired() .HasMaxLength(255) @@ -6459,16 +6500,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) Label = "RETRIGGER_OFFERSUBSCRIPTION_CREATE_DIM_TECHNICAL_USER" }, new - { - Id = 114, - Label = "AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" - }, - new - { - Id = 115, - Label = "RETRIGGER_AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" - }, - new { Id = 200, Label = "SYNCHRONIZE_USER" @@ -6644,6 +6675,31 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) Label = "RETRIGGER_CREATE_DIM_TECHNICAL_USER" }, new + { + Id = 502, + Label = "AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" + }, + new + { + Id = 503, + Label = "RETRIGGER_AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" + }, + new + { + Id = 504, + Label = "DELETE_DIM_TECHNICAL_USER" + }, + new + { + Id = 505, + Label = "AWAIT_DELETE_DIM_TECHNICAL_USER" + }, + new + { + Id = 506, + Label = "RETRIGGER_DELETE_DIM_TECHNICAL_USER" + }, + new { Id = 600, Label = "DELETE_CENTRAL_USER" @@ -6692,21 +6748,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { Id = 706, Label = "DELETE_IDENTITY_PROVIDER" - }, - new - { - Id = 800, - Label = "DELETE_DIM_TECHNICAL_USER" - }, - new - { - Id = 801, - Label = "AWAIT_DELETE_DIM_TECHNICAL_USER" - }, - new - { - Id = 802, - Label = "RETRIGGER_DELETE_DIM_TECHNICAL_USER" }); }); @@ -7319,83 +7360,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToView("offer_subscription_view", "portal"); }); - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificate", b => - { - b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateStatus", "CompanyCertificateStatus") - .WithMany("CompanyCertificates") - .HasForeignKey("CompanyCertificateStatusId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_company_certificates_company_certificate_statuses_company_c"); - - b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateType", "CompanyCertificateType") - .WithMany("CompanyCertificates") - .HasForeignKey("CompanyCertificateTypeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_company_certificates_company_certificate_types_company_cert"); - - b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") - .WithMany("CompanyCertificates") - .HasForeignKey("CompanyId") - .IsRequired() - .HasConstraintName("fk_company_certificates_companies_company_id"); - - b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", "Document") - .WithMany("CompanyCertificates") - .HasForeignKey("DocumentId") - .IsRequired() - .HasConstraintName("fk_company_certificates_documents_document_id"); - - b.Navigation("Company"); - - b.Navigation("CompanyCertificateStatus"); - - b.Navigation("CompanyCertificateType"); - - b.Navigation("Document"); - }); - - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateTypeAssignedStatus", b => - { - b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateType", "CompanyCertificateType") - .WithOne("CompanyCertificateTypeAssignedStatus") - .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateTypeAssignedStatus", "CompanyCertificateTypeId") - .IsRequired() - .HasConstraintName("fk_company_certificate_type_assigned_statuses_company_certific"); - - b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateTypeStatus", "CompanyCertificateTypeStatus") - .WithMany("CompanyCertificateTypeAssignedStatuses") - .HasForeignKey("CompanyCertificateTypeStatusId") - .IsRequired() - .HasConstraintName("fk_company_certificate_type_assigned_statuses_company_certific1"); - - b.Navigation("CompanyCertificateType"); - - b.Navigation("CompanyCertificateTypeStatus"); - }); - - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateTypeDescription", b => - { - b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateType", "CompanyCertificateType") - .WithMany("CompanyCertificateTypeDescriptions") - .HasForeignKey("CompanyCertificateTypeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_company_certificate_type_descriptions_company_certificate_t"); - - b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") - .WithMany("CompanyCertificateTypeDescriptions") - .HasForeignKey("LanguageShortName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_company_certificate_type_descriptions_languages_language_sh"); - - b.Navigation("CompanyCertificateType"); - - b.Navigation("Language"); - }); - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Address", b => { b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Country", "Country") @@ -7769,6 +7733,95 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("UseCase"); }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificate", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateStatus", "CompanyCertificateStatus") + .WithMany("CompanyCertificates") + .HasForeignKey("CompanyCertificateStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_certificates_company_certificate_statuses_company_c"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateType", "CompanyCertificateType") + .WithMany("CompanyCertificates") + .HasForeignKey("CompanyCertificateTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_certificates_company_certificate_types_company_cert"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany("CompanyCertificates") + .HasForeignKey("CompanyId") + .IsRequired() + .HasConstraintName("fk_company_certificates_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", "Document") + .WithMany("CompanyCertificates") + .HasForeignKey("DocumentId") + .IsRequired() + .HasConstraintName("fk_company_certificates_documents_document_id"); + + b.Navigation("Company"); + + b.Navigation("CompanyCertificateStatus"); + + b.Navigation("CompanyCertificateType"); + + b.Navigation("Document"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateAssignedSite", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificate", "CompanyCertificate") + .WithMany("CompanyCertificateAssignedSites") + .HasForeignKey("CompanyCertificateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_certificate_assigned_sites_company_certificates_com"); + + b.Navigation("CompanyCertificate"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateTypeAssignedStatus", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateType", "CompanyCertificateType") + .WithOne("CompanyCertificateTypeAssignedStatus") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateTypeAssignedStatus", "CompanyCertificateTypeId") + .IsRequired() + .HasConstraintName("fk_company_certificate_type_assigned_statuses_company_certific"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateTypeStatus", "CompanyCertificateTypeStatus") + .WithMany("CompanyCertificateTypeAssignedStatuses") + .HasForeignKey("CompanyCertificateTypeStatusId") + .IsRequired() + .HasConstraintName("fk_company_certificate_type_assigned_statuses_company_certific1"); + + b.Navigation("CompanyCertificateType"); + + b.Navigation("CompanyCertificateTypeStatus"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateTypeDescription", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateType", "CompanyCertificateType") + .WithMany("CompanyCertificateTypeDescriptions") + .HasForeignKey("CompanyCertificateTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_certificate_type_descriptions_company_certificate_t"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") + .WithMany("CompanyCertificateTypeDescriptions") + .HasForeignKey("LanguageShortName") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_certificate_type_descriptions_languages_language_sh"); + + b.Navigation("CompanyCertificateType"); + + b.Navigation("Language"); + }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyIdentifier", b => { b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") @@ -9002,25 +9055,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("CompanyServiceAccount"); }); - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateStatus", b => - { - b.Navigation("CompanyCertificates"); - }); - - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateType", b => - { - b.Navigation("CompanyCertificateTypeAssignedStatus"); - - b.Navigation("CompanyCertificateTypeDescriptions"); - - b.Navigation("CompanyCertificates"); - }); - - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.CompanyCertificateTypeStatus", b => - { - b.Navigation("CompanyCertificateTypeAssignedStatuses"); - }); - modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Address", b => { b.Navigation("Companies"); @@ -9131,6 +9165,30 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("CompanyApplications"); }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificate", b => + { + b.Navigation("CompanyCertificateAssignedSites"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateStatus", b => + { + b.Navigation("CompanyCertificates"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateType", b => + { + b.Navigation("CompanyCertificateTypeAssignedStatus"); + + b.Navigation("CompanyCertificateTypeDescriptions"); + + b.Navigation("CompanyCertificates"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyCertificateTypeStatus", b => + { + b.Navigation("CompanyCertificateTypeAssignedStatuses"); + }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRole", b => { b.Navigation("AgreementAssignedCompanyRoles"); diff --git a/src/portalbackend/PortalBackend.Migrations/Migrations/20240703123105_809-AddDeleteDimUser.cs b/src/portalbackend/PortalBackend.Migrations/Migrations/20240802071934_809-AddDeleteDimUser.cs similarity index 55% rename from src/portalbackend/PortalBackend.Migrations/Migrations/20240703123105_809-AddDeleteDimUser.cs rename to src/portalbackend/PortalBackend.Migrations/Migrations/20240802071934_809-AddDeleteDimUser.cs index c9f116998f..4afbaef5e1 100644 --- a/src/portalbackend/PortalBackend.Migrations/Migrations/20240703123105_809-AddDeleteDimUser.cs +++ b/src/portalbackend/PortalBackend.Migrations/Migrations/20240802071934_809-AddDeleteDimUser.cs @@ -18,7 +18,6 @@ ********************************************************************************/ using Microsoft.EntityFrameworkCore.Migrations; -using System; #nullable disable @@ -32,20 +31,13 @@ public partial class _809AddDeleteDimUser : Migration /// protected override void Up(MigrationBuilder migrationBuilder) { - migrationBuilder.AddColumn( - name: "lock_expiry_date", - schema: "portal", - table: "company_service_accounts", - type: "timestamp with time zone", - nullable: true); - migrationBuilder.AddColumn( name: "version", schema: "portal", table: "company_service_accounts", type: "uuid", nullable: false, - defaultValue: Guid.NewGuid()); + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); migrationBuilder.InsertData( schema: "portal", @@ -53,42 +45,80 @@ protected override void Up(MigrationBuilder migrationBuilder) columns: new[] { "id", "label" }, values: new object[,] { - { 800, "DELETE_DIM_TECHNICAL_USER" }, - { 801, "AWAIT_DELETE_DIM_TECHNICAL_USER" }, - { 802, "RETRIGGER_DELETE_DIM_TECHNICAL_USER" } + { 502, "AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" }, + { 503, "RETRIGGER_AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" }, + { 504, "DELETE_DIM_TECHNICAL_USER" }, + { 505, "AWAIT_DELETE_DIM_TECHNICAL_USER" }, + { 506, "RETRIGGER_DELETE_DIM_TECHNICAL_USER" } }); + + migrationBuilder.Sql("UPDATE portal.process_steps SET process_step_type_id = 502 WHERE process_step_type_id = 114"); + migrationBuilder.Sql("UPDATE portal.process_steps SET process_step_type_id = 503 WHERE process_step_type_id = 115"); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 114); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 115); + } /// protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropColumn( + name: "version", + schema: "portal", + table: "company_service_accounts"); + + migrationBuilder.InsertData( + schema: "portal", + table: "process_step_types", + columns: new[] { "id", "label" }, + values: new object[,] + { + { 114, "AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" }, + { 115, "RETRIGGER_AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" } + }); + + migrationBuilder.Sql("UPDATE portal.process_steps SET process_step_type_id = 114 WHERE process_step_type_id = 502"); + migrationBuilder.Sql("UPDATE portal.process_steps SET process_step_type_id = 115 WHERE process_step_type_id = 503"); + migrationBuilder.DeleteData( schema: "portal", table: "process_step_types", keyColumn: "id", - keyValue: 800); + keyValue: 502); migrationBuilder.DeleteData( schema: "portal", table: "process_step_types", keyColumn: "id", - keyValue: 801); + keyValue: 503); migrationBuilder.DeleteData( schema: "portal", table: "process_step_types", keyColumn: "id", - keyValue: 802); + keyValue: 504); - migrationBuilder.DropColumn( - name: "lock_expiry_date", + migrationBuilder.DeleteData( schema: "portal", - table: "company_service_accounts"); + table: "process_step_types", + keyColumn: "id", + keyValue: 505); - migrationBuilder.DropColumn( - name: "version", + migrationBuilder.DeleteData( schema: "portal", - table: "company_service_accounts"); + table: "process_step_types", + keyColumn: "id", + keyValue: 506); } } } diff --git a/src/portalbackend/PortalBackend.Migrations/Migrations/PortalDbContextModelSnapshot.cs b/src/portalbackend/PortalBackend.Migrations/Migrations/PortalDbContextModelSnapshot.cs index 2f3b4c73a7..9e1b67a64d 100644 --- a/src/portalbackend/PortalBackend.Migrations/Migrations/PortalDbContextModelSnapshot.cs +++ b/src/portalbackend/PortalBackend.Migrations/Migrations/PortalDbContextModelSnapshot.cs @@ -36,7 +36,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder .HasDefaultSchema("portal") .UseCollation("en_US.utf8") - .HasAnnotation("ProductVersion", "8.0.5") + .HasAnnotation("ProductVersion", "8.0.7") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -3616,10 +3616,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("text") .HasColumnName("description"); - b.Property("LockExpiryDate") - .HasColumnType("timestamp with time zone") - .HasColumnName("lock_expiry_date"); - b.Property("Name") .IsRequired() .HasMaxLength(255) @@ -6501,16 +6497,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) Label = "RETRIGGER_OFFERSUBSCRIPTION_CREATE_DIM_TECHNICAL_USER" }, new - { - Id = 114, - Label = "AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" - }, - new - { - Id = 115, - Label = "RETRIGGER_AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" - }, - new { Id = 200, Label = "SYNCHRONIZE_USER" @@ -6686,6 +6672,31 @@ protected override void BuildModel(ModelBuilder modelBuilder) Label = "RETRIGGER_CREATE_DIM_TECHNICAL_USER" }, new + { + Id = 502, + Label = "AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" + }, + new + { + Id = 503, + Label = "RETRIGGER_AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE" + }, + new + { + Id = 504, + Label = "DELETE_DIM_TECHNICAL_USER" + }, + new + { + Id = 505, + Label = "AWAIT_DELETE_DIM_TECHNICAL_USER" + }, + new + { + Id = 506, + Label = "RETRIGGER_DELETE_DIM_TECHNICAL_USER" + }, + new { Id = 600, Label = "DELETE_CENTRAL_USER" @@ -6734,21 +6745,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) { Id = 706, Label = "DELETE_IDENTITY_PROVIDER" - }, - new - { - Id = 800, - Label = "DELETE_DIM_TECHNICAL_USER" - }, - new - { - Id = 801, - Label = "AWAIT_DELETE_DIM_TECHNICAL_USER" - }, - new - { - Id = 802, - Label = "RETRIGGER_DELETE_DIM_TECHNICAL_USER" }); }); diff --git a/src/portalbackend/PortalBackend.Migrations/Program.cs b/src/portalbackend/PortalBackend.Migrations/Program.cs index d35ea966fe..093d525866 100644 --- a/src/portalbackend/PortalBackend.Migrations/Program.cs +++ b/src/portalbackend/PortalBackend.Migrations/Program.cs @@ -1,5 +1,4 @@ /******************************************************************************** - * Copyright (c) 2022 BMW Group AG * Copyright (c) 2022 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional diff --git a/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyServiceAccount.cs b/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyServiceAccount.cs index 3970840237..4422ef2e93 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyServiceAccount.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyServiceAccount.cs @@ -25,9 +25,9 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; -public class CompanyServiceAccount : IBaseEntity, ILockableEntity +public class CompanyServiceAccount : IBaseEntity, IVersionedEntity { - public CompanyServiceAccount(Guid id, string name, string description, CompanyServiceAccountTypeId companyServiceAccountTypeId, CompanyServiceAccountKindId companyServiceAccountKindId, Guid version) + public CompanyServiceAccount(Guid id, Guid version, string name, string description, CompanyServiceAccountTypeId companyServiceAccountTypeId, CompanyServiceAccountKindId companyServiceAccountKindId) { Id = id; Name = name; @@ -56,8 +56,6 @@ public CompanyServiceAccount(Guid id, string name, string description, CompanySe [ConcurrencyCheck] public Guid Version { get; set; } - public DateTimeOffset? LockExpiryDate { get; set; } - // Navigation properties public virtual Identity? Identity { get; set; } public virtual CompanyServiceAccountType? CompanyServiceAccountType { get; set; } diff --git a/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessStepTypeId.cs b/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessStepTypeId.cs index 63b68df100..a6814f40e0 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessStepTypeId.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessStepTypeId.cs @@ -68,8 +68,6 @@ public enum ProcessStepTypeId TRIGGER_ACTIVATE_SUBSCRIPTION = 111, OFFERSUBSCRIPTION_CREATE_DIM_TECHNICAL_USER = 112, RETRIGGER_OFFERSUBSCRIPTION_CREATE_DIM_TECHNICAL_USER = 113, - AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE = 114, - RETRIGGER_AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE = 115, // NetworkRegistration SYNCHRONIZE_USER = 200, @@ -113,6 +111,11 @@ public enum ProcessStepTypeId // DIM_TECHNICAL_USER CREATE_DIM_TECHNICAL_USER = 500, RETRIGGER_CREATE_DIM_TECHNICAL_USER = 501, + AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE = 502, + RETRIGGER_AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE = 503, + DELETE_DIM_TECHNICAL_USER = 504, + AWAIT_DELETE_DIM_TECHNICAL_USER = 505, + RETRIGGER_DELETE_DIM_TECHNICAL_USER = 506, // USER_PROVISIONING DELETE_CENTRAL_USER = 600, @@ -127,9 +130,4 @@ public enum ProcessStepTypeId DELETE_CENTRAL_IDENTITY_PROVIDER = 704, RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER = 705, DELETE_IDENTITY_PROVIDER = 706, - - // DIM_DELETE_TECHNICAL_USER - DELETE_DIM_TECHNICAL_USER = 800, - AWAIT_DELETE_DIM_TECHNICAL_USER = 801, - RETRIGGER_DELETE_DIM_TECHNICAL_USER = 802 } diff --git a/src/processes/DimUserProcess.Executor/DimUserProcessService.cs b/src/processes/DimUserProcess.Executor/DimUserProcessService.cs index 5e2dd3852d..06d5bbb071 100644 --- a/src/processes/DimUserProcess.Executor/DimUserProcessService.cs +++ b/src/processes/DimUserProcess.Executor/DimUserProcessService.cs @@ -30,7 +30,22 @@ public class DimUserProcessService( IDimService dimService, IPortalRepositories portalRepositories) : IDimUserProcessService { - public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateDeleteDimUser(Guid processId, Guid dimServiceAccountId, bool createUser, CancellationToken cancellationToken) + + public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateDimUser(Guid processId, Guid dimServiceAccountId, CancellationToken cancellationToken) + { + var (bpn, dimName) = await GetBpnDimName(dimServiceAccountId).ConfigureAwait(ConfigureAwaitOptions.None); + await dimService.CreateTechnicalUser(bpn, new TechnicalUserData(processId, dimName), cancellationToken).ConfigureAwait(false); + return ([ProcessStepTypeId.AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE], ProcessStepStatusId.DONE, true, null); + } + + public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> DeleteDimUser(Guid processId, Guid dimServiceAccountId, CancellationToken cancellationToken) + { + var (bpn, dimName) = await GetBpnDimName(dimServiceAccountId).ConfigureAwait(ConfigureAwaitOptions.None); + await dimService.DeleteTechnicalUser(bpn, new TechnicalUserData(processId, dimName), cancellationToken).ConfigureAwait(false); + return ([ProcessStepTypeId.AWAIT_DELETE_DIM_TECHNICAL_USER], ProcessStepStatusId.DONE, true, null); + } + + private async Task<(string Bpn, string DimName)> GetBpnDimName(Guid dimServiceAccountId) { var serviceAccountRepository = portalRepositories.GetInstance(); var (isValid, bpn, name) = await serviceAccountRepository.GetDimServiceAccountData(dimServiceAccountId) @@ -52,15 +67,6 @@ public class DimUserProcessService( } var dimName = string.Concat(name.Where(c => !char.IsWhiteSpace(c))); // DIM doesn't accept whitespace chars in name - if (createUser) - { - await dimService.CreateTechnicalUser(bpn, new TechnicalUserData(processId, dimName), cancellationToken).ConfigureAwait(false); - } - else - { - await dimService.DeleteTechnicalUser(bpn, new TechnicalUserData(processId, dimName), cancellationToken).ConfigureAwait(false); - } - - return (Enumerable.Repeat(createUser ? ProcessStepTypeId.AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE : ProcessStepTypeId.AWAIT_DELETE_DIM_TECHNICAL_USER, 1), ProcessStepStatusId.DONE, true, null); + return (bpn, dimName); } } diff --git a/src/processes/DimUserProcess.Executor/DimUserProcessTypeExecutor.cs b/src/processes/DimUserProcess.Executor/DimUserProcessTypeExecutor.cs index 4ea977a8a1..d6bdc11b5a 100644 --- a/src/processes/DimUserProcess.Executor/DimUserProcessTypeExecutor.cs +++ b/src/processes/DimUserProcess.Executor/DimUserProcessTypeExecutor.cs @@ -88,10 +88,10 @@ public bool IsExecutableStepTypeId(ProcessStepTypeId processStepTypeId) => (nextStepTypeIds, stepStatusId, modified, processMessage) = processStepTypeId switch { ProcessStepTypeId.CREATE_DIM_TECHNICAL_USER => await dimUserProcessService - .CreateDeleteDimUser(_processId, _dimServiceAccountId, true, cancellationToken) + .CreateDimUser(_processId, _dimServiceAccountId, cancellationToken) .ConfigureAwait(ConfigureAwaitOptions.None), ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER => await dimUserProcessService - .CreateDeleteDimUser(_processId, _dimServiceAccountId, false, cancellationToken) + .DeleteDimUser(_processId, _dimServiceAccountId, cancellationToken) .ConfigureAwait(ConfigureAwaitOptions.None), _ => throw new UnexpectedConditionException( $"Execution for {processStepTypeId} is currently not supported.") diff --git a/src/processes/DimUserProcess.Executor/IDimUserProcessService.cs b/src/processes/DimUserProcess.Executor/IDimUserProcessService.cs index 1ede1cd364..efeaf7746d 100644 --- a/src/processes/DimUserProcess.Executor/IDimUserProcessService.cs +++ b/src/processes/DimUserProcess.Executor/IDimUserProcessService.cs @@ -23,5 +23,6 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Processes.DimUserCreationProcess.E public interface IDimUserProcessService { - Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateDeleteDimUser(Guid processId, Guid dimServiceAccountId, bool createUser, CancellationToken cancellationToken); + Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateDimUser(Guid processId, Guid dimServiceAccountId, CancellationToken cancellationToken); + Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> DeleteDimUser(Guid processId, Guid dimServiceAccountId, CancellationToken cancellationToken); } diff --git a/src/processes/Processes.Library/ManualProcessStepData.cs b/src/processes/Processes.Library/ManualProcessStepData.cs index c0d2493b8c..ec0cd5768f 100644 --- a/src/processes/Processes.Library/ManualProcessStepData.cs +++ b/src/processes/Processes.Library/ManualProcessStepData.cs @@ -25,7 +25,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Processes.Library; public record ManualProcessStepData( - ProcessStepTypeId ProcessStepTypeId, + ProcessStepTypeId? ProcessStepTypeId, Process Process, IEnumerable ProcessSteps, IPortalRepositories PortalRepositories diff --git a/src/processes/Processes.Library/ManualProcessStepDataExtensions.cs b/src/processes/Processes.Library/ManualProcessStepDataExtensions.cs index fbf8b82cec..685a5b5baf 100644 --- a/src/processes/Processes.Library/ManualProcessStepDataExtensions.cs +++ b/src/processes/Processes.Library/ManualProcessStepDataExtensions.cs @@ -31,7 +31,7 @@ public static class VerifyProcessDataExtensions { public static ManualProcessStepData CreateManualProcessData( this VerifyProcessData? processData, - ProcessStepTypeId processStepTypeId, + ProcessStepTypeId? processStepTypeId, IPortalRepositories portalRepositories, Func getProcessEntityName) { @@ -60,9 +60,9 @@ public static ManualProcessStepData CreateManualProcessData( throw new UnexpectedConditionException("processSteps should never have any other status than TODO here"); } - if (processData.ProcessSteps.All(step => step.ProcessStepTypeId != processStepTypeId)) + if (processStepTypeId != null && processData.ProcessSteps.All(step => step.ProcessStepTypeId != processStepTypeId.Value)) { - throw new ConflictException($"{getProcessEntityName()}, process step {processStepTypeId} is not eligible to run"); + throw new ConflictException($"{getProcessEntityName()}, process step {processStepTypeId.Value} is not eligible to run"); } return new(processStepTypeId, processData.Process, processData.ProcessSteps, portalRepositories); @@ -86,7 +86,7 @@ public static void SkipProcessSteps(this ManualProcessStepData context, IEnumera context.PortalRepositories.GetInstance() .AttachAndModifyProcessSteps( context.ProcessSteps - .Where(step => step.ProcessStepTypeId != context.ProcessStepTypeId) + .Where(step => !context.ProcessStepTypeId.HasValue || step.ProcessStepTypeId != context.ProcessStepTypeId.Value) .GroupBy(step => step.ProcessStepTypeId) .IntersectBy(processStepTypeIds, group => group.Key) .SelectMany(group => ModifyStepStatusRange(group, ProcessStepStatusId.SKIPPED))); @@ -95,7 +95,7 @@ public static void SkipProcessStepsExcept(this ManualProcessStepData context, IE context.PortalRepositories.GetInstance() .AttachAndModifyProcessSteps( context.ProcessSteps - .Where(step => step.ProcessStepTypeId != context.ProcessStepTypeId) + .Where(step => !context.ProcessStepTypeId.HasValue || step.ProcessStepTypeId != context.ProcessStepTypeId.Value) .GroupBy(step => step.ProcessStepTypeId) .ExceptBy(processStepTypeIds, group => group.Key) .SelectMany(group => ModifyStepStatusRange(group, ProcessStepStatusId.SKIPPED))); @@ -109,8 +109,11 @@ public static void ScheduleProcessSteps(this ManualProcessStepData context, IEnu public static void FinalizeProcessStep(this ManualProcessStepData context) { - context.PortalRepositories.GetInstance().AttachAndModifyProcessSteps( - ModifyStepStatusRange(context.ProcessSteps.Where(step => step.ProcessStepTypeId == context.ProcessStepTypeId), ProcessStepStatusId.DONE)); + if (context.ProcessStepTypeId != null) + { + context.PortalRepositories.GetInstance().AttachAndModifyProcessSteps( + ModifyStepStatusRange(context.ProcessSteps.Where(step => step.ProcessStepTypeId == context.ProcessStepTypeId.Value), ProcessStepStatusId.DONE)); + } context.PortalRepositories.Attach(context.Process); if (!context.Process.ReleaseLock()) @@ -121,19 +124,26 @@ public static void FinalizeProcessStep(this ManualProcessStepData context) private static IEnumerable<(Guid, Action?, Action)> ModifyStepStatusRange(IEnumerable steps, ProcessStepStatusId processStepStatusId) { - var firstStep = steps.FirstOrDefault(); - - if (firstStep == null) + using var enumerator = steps.GetEnumerator(); + if (!enumerator.MoveNext()) + { yield break; + } + + var current = enumerator.Current; + + yield return ( + current.Id, + ps => ps.ProcessStepStatusId = current.ProcessStepStatusId, + ps => ps.ProcessStepStatusId = processStepStatusId); - foreach (var step in steps) + while (enumerator.MoveNext()) { + current = enumerator.Current; yield return ( - step.Id, - null, - ps => ps.ProcessStepStatusId = ps.Id == firstStep.Id - ? processStepStatusId - : ProcessStepStatusId.DUPLICATE); + current.Id, + ps => ps.ProcessStepStatusId = current.ProcessStepStatusId, + ps => ps.ProcessStepStatusId = ProcessStepStatusId.DUPLICATE); } } } diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs index aef4b743f1..fd8bb81edd 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs @@ -22,7 +22,6 @@ using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; using Org.Eclipse.TractusX.Portal.Backend.Dim.Library.Models; -using Org.Eclipse.TractusX.Portal.Backend.Framework.DateTimeProvider; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; @@ -50,6 +49,7 @@ public class ServiceAccountBusinessLogicTests private static readonly Guid ValidCompanyId = Guid.NewGuid(); private static readonly Guid ValidConnectorId = Guid.NewGuid(); private static readonly Guid ValidServiceAccountId = Guid.NewGuid(); + private static readonly Guid ValidServiceAccountVersion = Guid.NewGuid(); private static readonly Guid ValidServiceAccountWithDimDataId = Guid.NewGuid(); private static readonly Guid InactiveServiceAccount = Guid.NewGuid(); private static readonly Guid ExternalServiceAccount = Guid.NewGuid(); @@ -67,7 +67,6 @@ public class ServiceAccountBusinessLogicTests private readonly IFixture _fixture; private readonly IOptions _options; private readonly IIdentityService _identityService; - private readonly IDateTimeProvider _dateTimeProvider; private readonly ServiceAccountBusinessLogic _sut; private readonly byte[] _encryptionKey; @@ -88,7 +87,6 @@ public ServiceAccountBusinessLogicTests() _identity = A.Fake(); _identityService = A.Fake(); - _dateTimeProvider = A.Fake(); A.CallTo(() => _identity.IdentityId).Returns(Guid.NewGuid()); A.CallTo(() => _identity.IdentityTypeId).Returns(IdentityTypeId.COMPANY_USER); A.CallTo(() => _identity.CompanyId).Returns(ValidCompanyId); @@ -104,7 +102,7 @@ public ServiceAccountBusinessLogicTests() EncryptionConfigs = new[] { new EncryptionModeConfig() { Index = 1, EncryptionKey = Convert.ToHexString(_encryptionKey), CipherMode = System.Security.Cryptography.CipherMode.CBC, PaddingMode = System.Security.Cryptography.PaddingMode.PKCS7 } }, }); - _sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService, _dateTimeProvider); + _sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService); } #region CreateOwnCompanyServiceAccountAsync @@ -115,7 +113,7 @@ public async Task CreateOwnCompanyServiceAccountAsync_WithValidInput_ReturnsCrea // Arrange SetupCreateOwnCompanyServiceAccount(); var serviceAccountCreationInfos = new ServiceAccountCreationInfo("TheName", "Just a short description", IamClientAuthMethod.SECRET, Enumerable.Repeat(UserRoleId1, 1)); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService); // Act var result = await sut.CreateOwnCompanyServiceAccountAsync(serviceAccountCreationInfos); @@ -133,7 +131,7 @@ public async Task CreateOwnCompanyServiceAccountAsync_WithInvalidUser_NotFoundEx A.CallTo(() => _identityService.IdentityData).Returns(identity); SetupCreateOwnCompanyServiceAccount(); var serviceAccountCreationInfos = new ServiceAccountCreationInfo("TheName", "Just a short description", IamClientAuthMethod.SECRET, Enumerable.Repeat(UserRoleId1, 1)); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService); // Act async Task Act() => await sut.CreateOwnCompanyServiceAccountAsync(serviceAccountCreationInfos); @@ -149,7 +147,7 @@ public async Task CreateOwnCompanyServiceAccountAsync_WithEmptyName_ThrowsContro // Arrange SetupCreateOwnCompanyServiceAccount(); var serviceAccountCreationInfos = new ServiceAccountCreationInfo(string.Empty, "Just a short description", IamClientAuthMethod.SECRET, Enumerable.Repeat(UserRoleId1, 1)); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService); // Act async Task Act() => await sut.CreateOwnCompanyServiceAccountAsync(serviceAccountCreationInfos); @@ -168,7 +166,7 @@ public async Task CreateOwnCompanyServiceAccountAsync_WithInvalidIamClientAuthMe // Arrange SetupCreateOwnCompanyServiceAccount(); var serviceAccountCreationInfos = new ServiceAccountCreationInfo("TheName", "Just a short description", IamClientAuthMethod.JWT, Enumerable.Repeat(UserRoleId1, 1)); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService); // Act async Task Act() => await sut.CreateOwnCompanyServiceAccountAsync(serviceAccountCreationInfos); @@ -187,8 +185,8 @@ public async Task CreateOwnCompanyServiceAccountAsync_WithInvalidUserRoleId_Thro // Arrange var wrongUserRoleId = Guid.NewGuid(); SetupCreateOwnCompanyServiceAccount(); - var serviceAccountCreationInfos = new ServiceAccountCreationInfo("TheName", "Just a short description", IamClientAuthMethod.SECRET, new[] { UserRoleId1, wrongUserRoleId }); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService, _dateTimeProvider); + var serviceAccountCreationInfos = new ServiceAccountCreationInfo("TheName", "Just a short description", IamClientAuthMethod.SECRET, [UserRoleId1, wrongUserRoleId]); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, _serviceAccountCreation, _identityService); // Act async Task Act() => await sut.CreateOwnCompanyServiceAccountAsync(serviceAccountCreationInfos); @@ -211,7 +209,7 @@ public async Task GetOwnCompanyServiceAccountDetailsAsync_WithValidInput_GetsAll { // Arrange SetupGetOwnCompanyServiceAccountDetails(); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act var result = await sut.GetOwnCompanyServiceAccountDetailsAsync(ValidServiceAccountId); @@ -226,7 +224,7 @@ public async Task GetOwnCompanyServiceAccountDetailsAsync_WithValidInputAndDimCo { // Arrange SetupGetOwnCompanyServiceAccountDetails(); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act var result = await sut.GetOwnCompanyServiceAccountDetailsAsync(ValidServiceAccountWithDimDataId); @@ -246,7 +244,7 @@ public async Task GetOwnCompanyServiceAccountDetailsAsync_WithInvalidCompany_Not SetupGetOwnCompanyServiceAccountDetails(); var invalidCompanyId = Guid.NewGuid(); A.CallTo(() => _identity.CompanyId).Returns(invalidCompanyId); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.GetOwnCompanyServiceAccountDetailsAsync(ValidServiceAccountId); @@ -262,7 +260,7 @@ public async Task GetOwnCompanyServiceAccountDetailsAsync_WithInvalidServiceAcco // Arrange SetupGetOwnCompanyServiceAccountDetails(); var invalidServiceAccountId = Guid.NewGuid(); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.GetOwnCompanyServiceAccountDetailsAsync(invalidServiceAccountId); @@ -281,7 +279,7 @@ public async Task ResetOwnCompanyServiceAccountSecretAsync_WithValidInput_GetsAl { // Arrange SetupResetOwnCompanyServiceAccountSecret(); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act var result = await sut.ResetOwnCompanyServiceAccountSecretAsync(ValidServiceAccountId); @@ -298,7 +296,7 @@ public async Task ResetOwnCompanyServiceAccountSecretAsync_WithInvalidUser_NotFo SetupResetOwnCompanyServiceAccountSecret(); var invalidUser = _fixture.Create(); A.CallTo(() => _identityService.IdentityData).Returns(invalidUser); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.ResetOwnCompanyServiceAccountSecretAsync(ValidServiceAccountId); @@ -314,7 +312,7 @@ public async Task ResetOwnCompanyServiceAccountSecretAsync_WithInvalidServiceAcc // Arrange SetupResetOwnCompanyServiceAccountSecret(); var invalidServiceAccountId = Guid.NewGuid(); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.ResetOwnCompanyServiceAccountSecretAsync(invalidServiceAccountId); @@ -334,8 +332,19 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAsync_WithValidData_Retur // Arrange SetupUpdateOwnCompanyServiceAccountDetails(); var data = new ServiceAccountEditableDetails(ValidServiceAccountId, "new name", "changed description", IamClientAuthMethod.SECRET); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); - + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); + + CompanyServiceAccount? initial = null; + CompanyServiceAccount? modified = null; + + A.CallTo(() => _serviceAccountRepository.AttachAndModifyCompanyServiceAccount(A._, A._, A>._, A>._)) + .Invokes((Guid id, Guid version, Action? initialize, Action modify) => + { + initial = new CompanyServiceAccount(id, version, null!, null!, default, default); + initialize?.Invoke(initial); + modified = new CompanyServiceAccount(id, version, null!, null!, default, default); + modify(modified); + }); // Act var result = await sut.UpdateOwnCompanyServiceAccountDetailsAsync(ValidServiceAccountId, data); @@ -344,8 +353,12 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAsync_WithValidData_Retur result.Name.Should().Be("new name"); A.CallTo(() => _provisioningManager.UpdateCentralClientAsync(A._, A._)) .MustHaveHappenedOnceExactly(); - A.CallTo(() => _serviceAccountRepository.AttachAndModifyCompanyServiceAccount(ValidServiceAccountId, A>._, A>._)) + A.CallTo(() => _serviceAccountRepository.AttachAndModifyCompanyServiceAccount(ValidServiceAccountId, ValidServiceAccountVersion, A>._, A>._)) .MustHaveHappenedOnceExactly(); + initial.Should().NotBeNull().And.Match( + x => x.Id == ValidServiceAccountId && x.Version == ValidServiceAccountVersion && x.Name == "test" && x.Description == "test"); + modified.Should().NotBeNull().And.Match( + x => x.Name == "new name" && x.Description == "changed description"); } [Fact] @@ -354,7 +367,7 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAsync_WithInvalidAuthMeth // Arrange SetupUpdateOwnCompanyServiceAccountDetails(); var data = new ServiceAccountEditableDetails(ValidServiceAccountId, "new name", "changed description", IamClientAuthMethod.JWT); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.UpdateOwnCompanyServiceAccountDetailsAsync(ValidServiceAccountId, data); @@ -372,7 +385,7 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAsync_WithDifferentServic // Arrange SetupUpdateOwnCompanyServiceAccountDetails(); var data = new ServiceAccountEditableDetails(ValidServiceAccountId, "new name", "changed description", IamClientAuthMethod.SECRET); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.UpdateOwnCompanyServiceAccountDetailsAsync(Guid.NewGuid(), data); @@ -394,7 +407,7 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAsync_WithNotExistingServ A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamClientIdAsync(invalidServiceAccountId, ValidCompanyId)) .Returns(null); var data = new ServiceAccountEditableDetails(invalidServiceAccountId, "new name", "changed description", IamClientAuthMethod.SECRET); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.UpdateOwnCompanyServiceAccountDetailsAsync(invalidServiceAccountId, data); @@ -415,7 +428,7 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAsync_WithInactiveService A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamClientIdAsync(InactiveServiceAccount, ValidCompanyId)) .Returns(inactive); var data = new ServiceAccountEditableDetails(InactiveServiceAccount, "new name", "changed description", IamClientAuthMethod.SECRET); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.UpdateOwnCompanyServiceAccountDetailsAsync(InactiveServiceAccount, data); @@ -430,18 +443,16 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAsync_WithExternalService { // Arrange SetupUpdateOwnCompanyServiceAccountDetails(); - var serviceAccount = new CompanyServiceAccount(Guid.NewGuid(), "test", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.EXTERNAL, Guid.NewGuid()) - { - ClientClientId = "sa-test-1" - }; + var external = _fixture.Build() .With(x => x.UserStatusId, UserStatusId.ACTIVE) - .With(x => x.ServiceAccount, serviceAccount) + .With(x => x.CompanyServiceAccountTypeId, CompanyServiceAccountTypeId.OWN) + .With(x => x.CompanyServiceAccountKindId, CompanyServiceAccountKindId.EXTERNAL) .Create(); A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamClientIdAsync(ExternalServiceAccount, ValidCompanyId)) .Returns(external); var data = new ServiceAccountEditableDetails(ExternalServiceAccount, "new name", "changed description", IamClientAuthMethod.SECRET); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act var result = await sut.UpdateOwnCompanyServiceAccountDetailsAsync(ExternalServiceAccount, data); @@ -453,7 +464,7 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAsync_WithExternalService .MustHaveHappenedOnceExactly(); A.CallTo(() => _provisioningManager.UpdateCentralClientAsync(A._, A._)) .MustNotHaveHappened(); - A.CallTo(() => _serviceAccountRepository.AttachAndModifyCompanyServiceAccount(ExternalServiceAccount, A>._, A>._)) + A.CallTo(() => _serviceAccountRepository.AttachAndModifyCompanyServiceAccount(ExternalServiceAccount, external.ServiceAccountVersion, A>._, A>._)) .MustHaveHappenedOnceExactly(); } @@ -476,7 +487,7 @@ public async Task GetOwnCompanyServiceAccountsDataAsync_GetsExpectedData(IEnumer .Returns((int skip, int take) => Task.FromResult?>(new(data.Count(), data.Skip(skip).Take(take)))); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_serviceAccountRepository); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act var result = await sut.GetOwnCompanyServiceAccountsDataAsync(1, 10, null, null, isUserInactive, userStatusIds); @@ -499,7 +510,7 @@ public async Task DeleteOwnCompanyServiceAccountAsync_WithNotExistingServiceAcco var serviceAccountId = Guid.NewGuid(); SetupDeleteOwnCompanyServiceAccount(false, false); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.DeleteOwnCompanyServiceAccountAsync(serviceAccountId); @@ -515,7 +526,7 @@ public async Task DeleteOwnCompanyServiceAccountAsync_WithExistingOfferSubscript // Arrange SetupDeleteOwnCompanyServiceAccountForValidOfferSubscription(); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.DeleteOwnCompanyServiceAccountAsync(ValidServiceAccountId); @@ -531,7 +542,7 @@ public async Task DeleteOwnCompanyServiceAccountAsync_WithInvalidConnectorStatus // Arrange SetupDeleteOwnCompanyServiceAccountForInvalidConnectorStatus(); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act async Task Act() => await sut.DeleteOwnCompanyServiceAccountAsync(ValidServiceAccountId); @@ -557,7 +568,7 @@ public async Task DeleteOwnCompanyServiceAccountAsync_WithoutClient_CallsExpecte .With(x => x.CompanyServiceAccountId, ValidServiceAccountId) .Create(); SetupDeleteOwnCompanyServiceAccount(withServiceAccount, withClient, connector, identity); - var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + var sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act await sut.DeleteOwnCompanyServiceAccountAsync(ValidServiceAccountId); @@ -594,7 +605,7 @@ public async Task GetServiceAccountRolesAsync_GetsExpectedData() A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRolesRepository); - IServiceAccountBusinessLogic sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService, _dateTimeProvider); + IServiceAccountBusinessLogic sut = new ServiceAccountBusinessLogic(_provisioningManager, _portalRepositories, _options, null!, _identityService); // Act var result = await sut.GetServiceAccountRolesAsync(null).ToListAsync(); @@ -623,7 +634,7 @@ public async Task HandleServiceAccountCreationCallback_WithValidOfferSubscriptio var process = new Process(Guid.NewGuid(), ProcessTypeId.OFFER_SUBSCRIPTION, Guid.NewGuid()); var context = new VerifyProcessData(process, [new ProcessStep(Guid.NewGuid(), stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow)]); A.CallTo(() => _processStepRepository.GetProcessDataForServiceAccountCallback(A._, A>._)) - .Returns((ProcessTypeId.OFFER_SUBSCRIPTION, context, Guid.NewGuid())); + .Returns((ProcessTypeId.OFFER_SUBSCRIPTION, context, Guid.NewGuid(), Guid.NewGuid())); // Act await _sut.HandleServiceAccountCreationCallback(process.Id, _fixture.Create()); @@ -643,7 +654,7 @@ public async Task HandleServiceAccountCreationCallback_WithNotExistingProcess_Th var stepToTrigger = ProcessStepTypeId.AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE; var process = new Process(Guid.NewGuid(), processTypeId, Guid.NewGuid()); A.CallTo(() => _processStepRepository.GetProcessDataForServiceAccountCallback(A._, A>._)) - .Returns<(ProcessTypeId, VerifyProcessData, Guid?)>(default); + .Returns<(ProcessTypeId, VerifyProcessData, Guid?, Guid?)>(default); async Task Act() => await _sut.HandleServiceAccountCreationCallback(process.Id, _fixture.Create()); // Act @@ -663,7 +674,7 @@ public async Task HandleServiceAccountCreationCallback_WithOfferSubscriptionIdNo var process = new Process(Guid.NewGuid(), ProcessTypeId.OFFER_SUBSCRIPTION, Guid.NewGuid()); var context = new VerifyProcessData(process, [new ProcessStep(Guid.NewGuid(), stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow)]); A.CallTo(() => _processStepRepository.GetProcessDataForServiceAccountCallback(A._, A>._)) - .Returns((ProcessTypeId.OFFER_SUBSCRIPTION, context, null)); + .Returns((ProcessTypeId.OFFER_SUBSCRIPTION, context, null, null)); async Task Act() => await _sut.HandleServiceAccountCreationCallback(process.Id, _fixture.Create()); // Act @@ -722,13 +733,14 @@ private void SetupResetOwnCompanyServiceAccountSecret() private void SetupUpdateOwnCompanyServiceAccountDetails() { var authData = new ClientAuthData(IamClientAuthMethod.SECRET) { Secret = "topsecret" }; - var serviceAccount = new CompanyServiceAccount(Guid.NewGuid(), "test", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL, Guid.NewGuid()) - { - ClientClientId = "sa-test-1" - }; var data = _fixture.Build() + .With(x => x.ServiceAccountVersion, ValidServiceAccountVersion) .With(x => x.UserStatusId, UserStatusId.ACTIVE) - .With(x => x.ServiceAccount, serviceAccount) + .With(x => x.Name, "test") + .With(x => x.Description, "test") + .With(x => x.CompanyServiceAccountTypeId, CompanyServiceAccountTypeId.OWN) + .With(x => x.CompanyServiceAccountKindId, CompanyServiceAccountKindId.INTERNAL) + .With(x => x.ClientClientId, "sa-test-1") .Create(); A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamClientIdAsync(ValidServiceAccountId, ValidCompanyId)) .Returns(data); @@ -769,9 +781,9 @@ private void SetupGetOwnCompanyServiceAccount() private void SetupDeleteOwnCompanyServiceAccount(bool withServiceAccount, bool withClient, Connector? connector = null, Identity? identity = null) { - var serviceAccount = new CompanyServiceAccount(Guid.NewGuid(), "test-sa", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL, Guid.NewGuid()); + var serviceAccount = new CompanyServiceAccount(Guid.NewGuid(), Guid.NewGuid(), "test-sa", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL); A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(ValidServiceAccountId, ValidCompanyId)) - .Returns(new OwnServiceAccountData(_userRoleIds, serviceAccount, withServiceAccount ? ValidConnectorId : null, withClient ? ClientId : null, ConnectorStatusId.INACTIVE, OfferSubscriptionStatusId.PENDING, false, null)); + .Returns(new OwnServiceAccountData(_userRoleIds, serviceAccount.Id, serviceAccount.Version, withServiceAccount ? ValidConnectorId : null, withClient ? ClientId : null, ConnectorStatusId.INACTIVE, OfferSubscriptionStatusId.PENDING, false, null)); A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(A.That.Not.Matches(x => x == ValidServiceAccountId), A._)) .Returns(null); @@ -802,9 +814,9 @@ private void SetupDeleteOwnCompanyServiceAccount(bool withServiceAccount, bool w private void SetupDeleteOwnCompanyServiceAccountForInvalidConnectorStatus() { - var serviceAccount = new CompanyServiceAccount(Guid.NewGuid(), "test-sa", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL, Guid.NewGuid()); + var serviceAccount = new CompanyServiceAccount(Guid.NewGuid(), Guid.NewGuid(), "test-sa", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL); A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(ValidServiceAccountId, ValidCompanyId)) - .Returns(new OwnServiceAccountData(_userRoleIds, serviceAccount, null, null, ConnectorStatusId.ACTIVE, OfferSubscriptionStatusId.PENDING, false, null)); + .Returns(new OwnServiceAccountData(_userRoleIds, serviceAccount.Id, serviceAccount.Version, null, null, ConnectorStatusId.ACTIVE, OfferSubscriptionStatusId.PENDING, false, null)); A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(A.That.Not.Matches(x => x == ValidServiceAccountId), A._)) .Returns(null); @@ -814,9 +826,9 @@ private void SetupDeleteOwnCompanyServiceAccountForInvalidConnectorStatus() private void SetupDeleteOwnCompanyServiceAccountForValidOfferSubscription() { - var serviceAccount = new CompanyServiceAccount(Guid.NewGuid(), "test-sa", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL, Guid.NewGuid()); + var serviceAccount = new CompanyServiceAccount(Guid.NewGuid(), Guid.NewGuid(), "test-sa", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL); A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(ValidServiceAccountId, ValidCompanyId)) - .Returns(new OwnServiceAccountData(_userRoleIds, serviceAccount, null, null, ConnectorStatusId.INACTIVE, OfferSubscriptionStatusId.ACTIVE, false, null)); + .Returns(new OwnServiceAccountData(_userRoleIds, serviceAccount.Id, serviceAccount.Version, null, null, ConnectorStatusId.INACTIVE, OfferSubscriptionStatusId.ACTIVE, false, null)); A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(A.That.Not.Matches(x => x == ValidServiceAccountId), A._)) .Returns(null); diff --git a/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs b/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs index fc04aa18d1..f45051fd8d 100644 --- a/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs +++ b/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs @@ -131,7 +131,7 @@ public async Task AutoSetup_WithValidData_ReturnsExpectedNotificationAndSecret(O { // Arrange var offerSubscription = new OfferSubscription(Guid.NewGuid(), Guid.Empty, Guid.Empty, OfferSubscriptionStatusId.PENDING, Guid.Empty, default); - var companyServiceAccount = new CompanyServiceAccount(Guid.NewGuid(), "test", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL, Guid.NewGuid()); + var companyServiceAccount = new CompanyServiceAccount(Guid.NewGuid(), Guid.NewGuid(), "test", "test", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL); var createNotificationsEnumerator = SetupAutoSetup(offerTypeId, offerSubscription, isSingleInstance, companyServiceAccount); var clientId = Guid.NewGuid(); var appInstanceId = Guid.NewGuid(); diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs index 8bddf9029d..9f56c0f2f1 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs @@ -17,6 +17,7 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +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.DBAccess.Tests.Setup; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities; @@ -92,9 +93,9 @@ public async Task GetOwnCompanyServiceAccountWithIamClientIdAsync_ReturnsExpecte var result = await sut.GetOwnCompanyServiceAccountWithIamClientIdAsync(_validServiceAccountId, _validCompanyId); // Assert - result.Should().NotBeNull(); - result!.ServiceAccount.CompanyServiceAccountTypeId.Should().Be(CompanyServiceAccountTypeId.OWN); - result.ServiceAccount.CompanyServiceAccountKindId.Should().Be(CompanyServiceAccountKindId.INTERNAL); + result.Should().NotBeNull().And.Match( + x => x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.OWN && + x.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL); } [Fact] @@ -492,6 +493,38 @@ public async Task CreateDimUserCreationData_ReturnsExpectedResult() #endregion + #region AttachAndModifyServiceAccount + + [Fact] + public async Task AttachAndModifyServiceAccount_ReturnsExpected() + { + // Arrange + var id = Guid.NewGuid(); + var version = Guid.NewGuid(); + + var (sut, context) = await CreateSut(); + + // Act + sut.AttachAndModifyCompanyServiceAccount(id, version, + x => + { + x.Description = "test"; + x.ClientClientId = "foo"; + }, + x => x.ClientClientId = "bar"); + + // Assert + var changeTracker = context.ChangeTracker; + changeTracker.HasChanges().Should().BeTrue(); + changeTracker.Entries().Should().ContainSingle() + .Which.Entity.Should().BeOfType() + .Which.Should().Match( + x => x.Id == id && x.Version != version && x.Description == "test" && x.ClientClientId == "bar" + ); + } + + #endregion + #region Setup private async Task<(ServiceAccountRepository, PortalDbContext)> CreateSut() diff --git a/tests/processes/DimUserProcess.Executor.Tests/DimUserProcessServiceTests.cs b/tests/processes/DimUserProcess.Executor.Tests/DimUserProcessServiceTests.cs index ebca45f5d1..3b49d3b8c1 100644 --- a/tests/processes/DimUserProcess.Executor.Tests/DimUserProcessServiceTests.cs +++ b/tests/processes/DimUserProcess.Executor.Tests/DimUserProcessServiceTests.cs @@ -55,7 +55,7 @@ public DimUserProcessServiceTests() #region CreateDeleteDimUser [Fact] - public async Task CreateDeleteDimUser_WithValidCreate_ReturnsExpected() + public async Task CreateDimUser_ReturnsExpected() { // Arrange var dimServiceAccountId = Guid.NewGuid(); @@ -65,7 +65,7 @@ public async Task CreateDeleteDimUser_WithValidCreate_ReturnsExpected() .Returns((true, Bpn, "dim-sa-test Foo Bar")); // Act - var result = await _sut.CreateDeleteDimUser(processId, dimServiceAccountId, true, CancellationToken.None); + var result = await _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(dimServiceAccountId)) @@ -80,7 +80,7 @@ public async Task CreateDeleteDimUser_WithValidCreate_ReturnsExpected() } [Fact] - public async Task CreateDeleteDimUser_WithValidDelete_ReturnsExpected() + public async Task DeleteDimUser_ReturnsExpected() { // Arrange var dimServiceAccountId = Guid.NewGuid(); @@ -90,7 +90,7 @@ public async Task CreateDeleteDimUser_WithValidDelete_ReturnsExpected() .Returns((true, Bpn, "dim-sa-test Foo Bar")); // Act - var result = await _sut.CreateDeleteDimUser(processId, dimServiceAccountId, false, CancellationToken.None); + var result = await _sut.DeleteDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(dimServiceAccountId)) @@ -114,7 +114,10 @@ public async Task CreateDeleteDimUser_WithInvalidDimServiceAccountId_ThrowsNotFo var processId = Guid.NewGuid(); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) .Returns(default((bool, string?, string))); - Task Act() => _sut.CreateDeleteDimUser(processId, dimServiceAccountId, createUser, CancellationToken.None); + + Task Act() => createUser + ? _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None) + : _sut.DeleteDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act var ex = await Assert.ThrowsAsync(Act); @@ -137,7 +140,10 @@ public async Task CreateDimUser_WithBpnNotSet_ThrowsConflictException(bool creat var processId = Guid.NewGuid(); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) .Returns((true, null, "foo")); - Task Act() => _sut.CreateDeleteDimUser(processId, dimServiceAccountId, createUser, CancellationToken.None); + + Task Act() => createUser + ? _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None) + : _sut.DeleteDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act var ex = await Assert.ThrowsAsync(Act); @@ -160,7 +166,10 @@ public async Task CreateDimUser_WithValidMissingServiceAccountName_ThrowsConflic var processId = Guid.NewGuid(); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) .Returns((true, Bpn, " ")); - Task Act() => _sut.CreateDeleteDimUser(processId, dimServiceAccountId, createUser, CancellationToken.None); + + Task Act() => createUser + ? _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None) + : _sut.DeleteDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act var ex = await Assert.ThrowsAsync(Act); diff --git a/tests/processes/DimUserProcess.Executor.Tests/DimUserProcessTypeExecutorTests.cs b/tests/processes/DimUserProcess.Executor.Tests/DimUserProcessTypeExecutorTests.cs index 1bce3664ff..7be4652f63 100644 --- a/tests/processes/DimUserProcess.Executor.Tests/DimUserProcessTypeExecutorTests.cs +++ b/tests/processes/DimUserProcess.Executor.Tests/DimUserProcessTypeExecutorTests.cs @@ -197,14 +197,14 @@ public async Task ExecuteProcessStep_ThrowingTestException_ReturnsExpected() // Arrange execute var error = _fixture.Create(); - A.CallTo(() => _dimUserProcessService.CreateDeleteDimUser(processId, dimServiceAccountId, true, A._)) + A.CallTo(() => _dimUserProcessService.CreateDimUser(processId, dimServiceAccountId, A._)) .Throws(error); // Act execute var executionResult = await _executor.ExecuteProcessStep(ProcessStepTypeId.CREATE_DIM_TECHNICAL_USER, Enumerable.Empty(), CancellationToken.None); // Assert execute - A.CallTo(() => _dimUserProcessService.CreateDeleteDimUser(processId, dimServiceAccountId, true, CancellationToken.None)) + A.CallTo(() => _dimUserProcessService.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None)) .MustHaveHappenedOnceExactly(); executionResult.Modified.Should().BeTrue(); @@ -234,14 +234,14 @@ public async Task ExecuteProcessStep_ThrowingRecoverableServiceException_Returns // Arrange execute var error = new ServiceException(_fixture.Create(), true); - A.CallTo(() => _dimUserProcessService.CreateDeleteDimUser(processId, dimServiceAccountId, true, A._)) + A.CallTo(() => _dimUserProcessService.CreateDimUser(processId, dimServiceAccountId, A._)) .Throws(error); // Act execute var executionResult = await _executor.ExecuteProcessStep(ProcessStepTypeId.CREATE_DIM_TECHNICAL_USER, Enumerable.Empty(), CancellationToken.None); // Assert execute - A.CallTo(() => _dimUserProcessService.CreateDeleteDimUser(processId, dimServiceAccountId, true, A._)) + A.CallTo(() => _dimUserProcessService.CreateDimUser(processId, dimServiceAccountId, A._)) .MustHaveHappenedOnceExactly(); executionResult.Modified.Should().BeTrue(); @@ -270,7 +270,7 @@ public async Task ExecuteProcessStep_ThrowingSystemException_Throws() // Arrange execute var error = new SystemException(_fixture.Create()); - A.CallTo(() => _dimUserProcessService.CreateDeleteDimUser(processId, dimServiceAccountId, true, CancellationToken.None)) + A.CallTo(() => _dimUserProcessService.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None)) .Throws(error); // Act execute @@ -350,10 +350,10 @@ public void GetExecutableStepTypeIds_ReturnsExpected() private void SetupFakes() { - A.CallTo(() => _dimUserProcessService.CreateDeleteDimUser(A._, _dimServiceAccountId, true, A._)) + A.CallTo(() => _dimUserProcessService.CreateDimUser(A._, _dimServiceAccountId, A._)) .Returns(new ValueTuple?, ProcessStepStatusId, bool, string?>(Enumerable.Repeat(ProcessStepTypeId.AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE, 1), ProcessStepStatusId.DONE, true, null)); - A.CallTo(() => _dimUserProcessService.CreateDeleteDimUser(A._, _dimServiceAccountId, false, A._)) + A.CallTo(() => _dimUserProcessService.DeleteDimUser(A._, _dimServiceAccountId, A._)) .Returns(new ValueTuple?, ProcessStepStatusId, bool, string?>(Enumerable.Repeat(ProcessStepTypeId.AWAIT_DELETE_DIM_TECHNICAL_USER, 1), ProcessStepStatusId.DONE, true, null)); } diff --git a/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs b/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs index e4b6422f27..98c6d69bce 100644 --- a/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs +++ b/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs @@ -384,11 +384,11 @@ private void Setup(ICollection? serviceAccounts = null, I { var sa = new CompanyServiceAccount( identityId, + Guid.NewGuid(), name, description, companyServiceAccountTypeId, - companyServiceAccountKindId, - Guid.NewGuid()) + companyServiceAccountKindId) { ClientClientId = clientClientId };