From 58f12b7e4724279916d60991355aa014c5d915d0 Mon Sep 17 00:00:00 2001 From: AnuragNagpure <145100366+AnuragNagpure@users.noreply.github.com> Date: Thu, 16 May 2024 12:40:29 +0530 Subject: [PATCH 01/24] feat(document): enhance companyDetailsWithAddress endpoint (#732) * add documents section to endpoint companydetailaddress * remove documents section from applications endpoint * adjust unit tests --------- Co-authored-by: Norbert Truchsess --- .../RegistrationBusinessLogic.cs | 52 +++++++++---------- .../Models/CompanyApplicationDetails.cs | 6 --- .../Models/CompanyWithAddressData.cs | 19 ++++++- .../Models/CompanyUserRoleWithAddress.cs | 6 ++- .../Repositories/ApplicationRepository.cs | 9 +++- .../Repositories/IApplicationRepository.cs | 3 +- .../Enums/DocumentTypeId.cs | 1 - .../RegistrationBusinessLogicTest.cs | 8 +-- .../ApplicationRepositoryTests.cs | 13 +++-- .../Seeder/Data/documents.test.json | 22 ++++++++ .../Seeder/Data/invitations.test.json | 7 +++ 11 files changed, 98 insertions(+), 48 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs index 826669d4b3..abd7a95014 100644 --- a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs @@ -99,10 +99,10 @@ public Task GetCompanyWithAddressAsync(Guid applicationI private async Task GetCompanyWithAddressAsyncInternal(Guid applicationId) { - var companyWithAddress = await _portalRepositories.GetInstance().GetCompanyUserRoleWithAddressUntrackedAsync(applicationId).ConfigureAwait(ConfigureAwaitOptions.None); + var companyWithAddress = await _portalRepositories.GetInstance().GetCompanyUserRoleWithAddressUntrackedAsync(applicationId, _settings.DocumentTypeIds).ConfigureAwait(ConfigureAwaitOptions.None); if (companyWithAddress == null) { - throw NotFoundException.Create(AdministrationRegistrationErrors.APPLICATION_NOT_FOUND, new ErrorParameter[] { new("applicationId", applicationId.ToString()) }); + throw NotFoundException.Create(AdministrationRegistrationErrors.APPLICATION_NOT_FOUND, [new("applicationId", applicationId.ToString())]); } if (!string.IsNullOrEmpty(companyWithAddress.Name) && !Company.IsMatch(companyWithAddress.Name)) { @@ -134,7 +134,10 @@ private async Task GetCompanyWithAddressAsyncInternal(Gu x.FirstName ?? "", x.LastName ?? "", x.Email ?? "")), - companyWithAddress.CompanyIdentifiers.Select(identifier => new CompanyUniqueIdData(identifier.UniqueIdentifierId, identifier.Value)) + companyWithAddress.CompanyIdentifiers.Select(identifier => new CompanyUniqueIdData(identifier.UniqueIdentifierId, identifier.Value)), + companyWithAddress.DocumentData.Select(data => new DocumentDetails(data.DocumentId, data.DocumentTypeId)), + companyWithAddress.Created, + companyWithAddress.LastChanged ); } @@ -165,9 +168,6 @@ private async Task GetCompanyWithAddressAsyncInternal(Gu application.ApplicationStatusId, application.DateCreated, application.Company!.Name, - application.Invitations.SelectMany(invitation => - invitation.CompanyUser!.Documents.Where(document => _settings.DocumentTypeIds.Contains(document.DocumentTypeId)).Select(document => - new DocumentDetails(document.Id, document.DocumentTypeId))), application.Company!.CompanyAssignedRoles.Select(companyAssignedRoles => companyAssignedRoles.CompanyRoleId), application.ApplicationChecklistEntries.Where(x => x.ApplicationChecklistEntryTypeId != ApplicationChecklistEntryTypeId.APPLICATION_ACTIVATION).OrderBy(x => x.ApplicationChecklistEntryTypeId).Select(x => new ApplicationChecklistEntryDetails(x.ApplicationChecklistEntryTypeId, x.ApplicationChecklistEntryStatusId)), application.Invitations @@ -268,22 +268,22 @@ private async Task UpdateCompanyBpnInternal(Guid applicationId, string bpn) .VerifyChecklistEntryAndProcessSteps( applicationId, ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER, - new[] { + [ ApplicationChecklistEntryStatusId.TO_DO, ApplicationChecklistEntryStatusId.IN_PROGRESS, ApplicationChecklistEntryStatusId.FAILED - }, + ], ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_MANUAL, - entryTypeIds: new[] { + entryTypeIds: [ ApplicationChecklistEntryTypeId.REGISTRATION_VERIFICATION - }, - processStepTypeIds: new[] { + ], + processStepTypeIds: [ ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PUSH, ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PULL, ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PULL, ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PUSH, ProcessStepTypeId.CREATE_IDENTITY_WALLET - }) + ]) .ConfigureAwait(ConfigureAwaitOptions.None); _portalRepositories.GetInstance().AttachAndModifyCompany(applicationCompanyData.CompanyId, null, @@ -293,12 +293,12 @@ private async Task UpdateCompanyBpnInternal(Guid applicationId, string bpn) _checklistService.SkipProcessSteps( context, - new[] { + [ ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PUSH, ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PULL, ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PULL, ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PUSH - }); + ]); _checklistService.FinalizeChecklistEntryAndProcessSteps( context, @@ -386,9 +386,9 @@ private async Task TriggerChecklistInternal(Guid applicationId, ApplicationCheck .VerifyChecklistEntryAndProcessSteps( applicationId, entryTypeId, - new[] { ApplicationChecklistEntryStatusId.FAILED }, + [ApplicationChecklistEntryStatusId.FAILED], processStepTypeId, - processStepTypeIds: new[] { nextProcessStepTypeId }) + processStepTypeIds: [nextProcessStepTypeId]) .ConfigureAwait(ConfigureAwaitOptions.None); _checklistService.FinalizeChecklistEntryAndProcessSteps( @@ -405,7 +405,7 @@ private async Task TriggerChecklistInternal(Guid applicationId, ApplicationCheck item.ApplicationChecklistEntryStatusId = checklistEntryStatusId; item.Comment = null; }, - new[] { nextProcessStepTypeId }); + [nextProcessStepTypeId]); await _portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); } @@ -438,10 +438,10 @@ public async Task ApproveRegistrationVerification(Guid applicationId) .VerifyChecklistEntryAndProcessSteps( applicationId, ApplicationChecklistEntryTypeId.REGISTRATION_VERIFICATION, - new[] { ApplicationChecklistEntryStatusId.TO_DO }, + [ApplicationChecklistEntryStatusId.TO_DO], ProcessStepTypeId.VERIFY_REGISTRATION, - new[] { ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER }, - new[] { CreateWalletStep() }) + [ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER], + [CreateWalletStep()]) .ConfigureAwait(ConfigureAwaitOptions.None); var businessPartnerSuccess = context.Checklist[ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER] == new ValueTuple(ApplicationChecklistEntryStatusId.DONE, null); @@ -474,13 +474,13 @@ public async Task DeclineRegistrationVerification(Guid applicationId, string com .VerifyChecklistEntryAndProcessSteps( applicationId, ApplicationChecklistEntryTypeId.REGISTRATION_VERIFICATION, - new[] { ApplicationChecklistEntryStatusId.TO_DO, ApplicationChecklistEntryStatusId.DONE }, + [ApplicationChecklistEntryStatusId.TO_DO, ApplicationChecklistEntryStatusId.DONE], ProcessStepTypeId.DECLINE_APPLICATION, null, - new[] { ProcessStepTypeId.VERIFY_REGISTRATION, }) + [ProcessStepTypeId.VERIFY_REGISTRATION,]) .ConfigureAwait(ConfigureAwaitOptions.None); - _checklistService.SkipProcessSteps(context, new[] { ProcessStepTypeId.VERIFY_REGISTRATION }); + _checklistService.SkipProcessSteps(context, [ProcessStepTypeId.VERIFY_REGISTRATION]); var identityProviderRepository = _portalRepositories.GetInstance(); var userRepository = _portalRepositories.GetInstance(); @@ -572,15 +572,15 @@ private static IEnumerable GetCompanyApplicationStat { case CompanyApplicationStatusFilter.Closed: { - return new[] { CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED }; + return [CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED]; } case CompanyApplicationStatusFilter.InReview: { - return new[] { CompanyApplicationStatusId.SUBMITTED }; + return [CompanyApplicationStatusId.SUBMITTED]; } default: { - return new[] { CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED }; + return [CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED]; } } } diff --git a/src/administration/Administration.Service/Models/CompanyApplicationDetails.cs b/src/administration/Administration.Service/Models/CompanyApplicationDetails.cs index 075717c072..5c28b23c79 100644 --- a/src/administration/Administration.Service/Models/CompanyApplicationDetails.cs +++ b/src/administration/Administration.Service/Models/CompanyApplicationDetails.cs @@ -28,18 +28,12 @@ public record CompanyApplicationDetails( [property: JsonPropertyName("applicationStatus")] CompanyApplicationStatusId CompanyApplicationStatusId, [property: JsonPropertyName("dateCreated")] DateTimeOffset DateCreated, [property: JsonPropertyName("companyName")] string CompanyName, - [property: JsonPropertyName("documents")] IEnumerable Documents, [property: JsonPropertyName("companyRoles")] IEnumerable CompanyRoles, [property: JsonPropertyName("applicationChecklist")] IEnumerable ApplicationChecklist, [property: JsonPropertyName("email")] string? Email, [property: JsonPropertyName("bpn")] string? BusinessPartnerNumber ); -public record DocumentDetails( - [property: JsonPropertyName("documentId")] Guid DocumentId, - [property: JsonPropertyName("documentType")] DocumentTypeId? DocumentTypeId -); - public record ApplicationChecklistEntryDetails( ApplicationChecklistEntryTypeId TypeId, ApplicationChecklistEntryStatusId StatusId diff --git a/src/administration/Administration.Service/Models/CompanyWithAddressData.cs b/src/administration/Administration.Service/Models/CompanyWithAddressData.cs index 86baabf28e..1ce45805e0 100644 --- a/src/administration/Administration.Service/Models/CompanyWithAddressData.cs +++ b/src/administration/Administration.Service/Models/CompanyWithAddressData.cs @@ -40,6 +40,9 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; /// /// /// +/// +/// +/// /// public record CompanyWithAddressData( @@ -56,7 +59,10 @@ public record CompanyWithAddressData( string ZipCode, [property: JsonPropertyName("companyRoles")] IEnumerable AgreementsRoleData, [property: JsonPropertyName("companyUser")] IEnumerable InvitedUserData, - IEnumerable UniqueIds + IEnumerable UniqueIds, + [property: JsonPropertyName("documents")] IEnumerable Documents, + DateTimeOffset? Created, + DateTimeOffset? LastChanged ); /// @@ -95,3 +101,14 @@ public record InvitedUserData( string LastName, string Email ); + +/// +/// +/// +/// +/// +/// +public record DocumentDetails( + [property: JsonPropertyName("documentId")] Guid DocumentId, + [property: JsonPropertyName("documentType")] DocumentTypeId? DocumentTypeId +); diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserRoleWithAddress.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserRoleWithAddress.cs index b011739cbc..6b5b5cba17 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserRoleWithAddress.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserRoleWithAddress.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 @@ -37,7 +36,10 @@ public record CompanyUserRoleWithAddress( string? CountryDe, IEnumerable AgreementsData, IEnumerable InvitedCompanyUserData, - IEnumerable<(UniqueIdentifierId UniqueIdentifierId, string Value)> CompanyIdentifiers + IEnumerable<(UniqueIdentifierId UniqueIdentifierId, string Value)> CompanyIdentifiers, + IEnumerable<(Guid DocumentId, DocumentTypeId DocumentTypeId)> DocumentData, + DateTimeOffset? Created, + DateTimeOffset? LastChanged ); public record AgreementsData(CompanyRoleId CompanyRoleId, Guid AgreementId, ConsentStatusId? ConsentStatusId); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs index 1561f22485..d98c77f9d7 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs @@ -264,7 +264,7 @@ public IQueryable GetAllCompanyApplicationsDetailsQuery(stri .AsNoTracking() .Where(application => companyName == null || EF.Functions.ILike(application.Company!.Name, $"%{companyName.EscapeForILike()}%")); - public Task GetCompanyUserRoleWithAddressUntrackedAsync(Guid companyApplicationId) => + public Task GetCompanyUserRoleWithAddressUntrackedAsync(Guid companyApplicationId, IEnumerable documentTypeIds) => portalDbContext.CompanyApplications .AsSplitQuery() .Where(companyApplication => companyApplication.Id == companyApplicationId) @@ -294,7 +294,12 @@ public IQueryable GetAllCompanyApplicationsDetailsQuery(stri x.CompanyUser!.Firstname, x.CompanyUser.Lastname, x.CompanyUser.Email)), - companyApplication.Company.CompanyIdentifiers.Select(identifier => new ValueTuple(identifier.UniqueIdentifierId, identifier.Value)))) + companyApplication.Company.CompanyIdentifiers.Select(identifier => new ValueTuple(identifier.UniqueIdentifierId, identifier.Value)), + companyApplication.Invitations.SelectMany(invitation => + invitation.CompanyUser!.Documents.Where(document => documentTypeIds.Contains(document.DocumentTypeId)).Select(document => + new ValueTuple(document.Id, document.DocumentTypeId))), + companyApplication.DateCreated, + companyApplication.DateLastChanged)) .AsNoTracking() .SingleOrDefaultAsync(); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs index f16e5e7d7f..9e6e942f9a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.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 @@ -43,7 +42,7 @@ public interface IApplicationRepository IAsyncEnumerable GetInvitedUsersDataByApplicationIdUntrackedAsync(Guid applicationId); IAsyncEnumerable GetEmailDataUntrackedAsync(Guid applicationId); IQueryable GetAllCompanyApplicationsDetailsQuery(string? companyName = null); - Task GetCompanyUserRoleWithAddressUntrackedAsync(Guid companyApplicationId); + Task GetCompanyUserRoleWithAddressUntrackedAsync(Guid companyApplicationId, IEnumerable documentTypeIds); Task<(bool IsValidApplicationId, bool IsValidCompany, RegistrationData? Data)> GetRegistrationDataUntrackedAsync(Guid applicationId, Guid userCompanyId, IEnumerable documentTypes); Task<(string? Bpn, IEnumerable ExistingChecklistEntryTypeIds)> GetBpnAndChecklistCheckForApplicationIdAsync(Guid applicationId); diff --git a/src/portalbackend/PortalBackend.PortalEntities/Enums/DocumentTypeId.cs b/src/portalbackend/PortalBackend.PortalEntities/Enums/DocumentTypeId.cs index 783ae56c77..104d52dc7e 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Enums/DocumentTypeId.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Enums/DocumentTypeId.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/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs index 10f32a29a4..090d0cb93a 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs @@ -192,14 +192,14 @@ public async Task GetCompanyWithAddressAsync_WithDefaultRequest_GetsExpectedResu .With(x => x.AgreementsData, _fixture.CreateMany(20)) .With(x => x.CompanyIdentifiers, Enumerable.Repeat(new ValueTuple(identifierIdType, companyUniqueIds), 1)) .Create(); - A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId)) + A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(A._, A>._)) .Returns(data); // Act var result = await _logic.GetCompanyWithAddressAsync(applicationId); // Assert - A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId, _options.Value.DocumentTypeIds)).MustHaveHappenedOnceExactly(); result.Should().BeOfType(); result.Should().Match(r => r.CompanyId == data.CompanyId && @@ -238,14 +238,14 @@ public async Task GetCompanyWithAddressAsync_WithDefaultRequest_GetsExpectedResu .With(x => x.CountryDe, default(string?)) .With(x => x.InvitedCompanyUserData, _fixture.CreateMany().Select(id => new InvitedCompanyUserData(id, null, null, null))) .Create(); - A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId)) + A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(A._, A>._)) .Returns(data); // Act var result = await _logic.GetCompanyWithAddressAsync(applicationId); // Assert - A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId, _options.Value.DocumentTypeIds)).MustHaveHappenedOnceExactly(); result.Should().BeOfType(); result.Should().Match(r => r.CompanyId == data.CompanyId && diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs index 1653cf0df5..f8db8b2c39 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs @@ -18,6 +18,7 @@ ********************************************************************************/ using Microsoft.EntityFrameworkCore; +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; @@ -55,7 +56,7 @@ public async Task GetCompanyUserRoleWithAddressUntrackedAsync_WithExistingEntry_ // Act var result = await sut - .GetCompanyUserRoleWithAddressUntrackedAsync(new Guid("4f0146c6-32aa-4bb1-b844-df7e8babdcb2")); + .GetCompanyUserRoleWithAddressUntrackedAsync(new Guid("4f0146c6-32aa-4bb1-b844-df7e8babdcb2"), [DocumentTypeId.ADDITIONAL_DETAILS]); // Assert result.Should().NotBeNull(); @@ -76,10 +77,14 @@ public async Task GetCompanyUserRoleWithAddressUntrackedAsync_WithExistingEntry_ result.AgreementsData.Where(x => x.CompanyRoleId == CompanyRoleId.APP_PROVIDER).Should().HaveCount(1); result.AgreementsData.Where(x => x.CompanyRoleId == CompanyRoleId.ACTIVE_PARTICIPANT).Should().HaveCount(3); - result.InvitedCompanyUserData.Should().BeEmpty(); + result.InvitedCompanyUserData.Should().ContainSingle() + .Which.Should().Match(x => x.UserId == new Guid("8b42e6de-7b59-4217-a63c-198e83d93776") && x.FirstName == "First" && x.LastName == "User" && x.Email == "test@email.com"); - result.CompanyIdentifiers.Should().HaveCount(1); - result.CompanyIdentifiers.First().Should().Match<(UniqueIdentifierId UniqueIdentifierId, string Value)>(identifier => identifier.UniqueIdentifierId == UniqueIdentifierId.VAT_ID && identifier.Value == "DE123456789"); + result.CompanyIdentifiers.Should().ContainSingle() + .Which.Should().Match<(UniqueIdentifierId UniqueIdentifierId, string Value)>(identifier => identifier.UniqueIdentifierId == UniqueIdentifierId.VAT_ID && identifier.Value == "DE123456789"); + + result.DocumentData.Should().ContainSingle() + .Which.Should().Match<(Guid DocumentId, DocumentTypeId DocumentTypeId)>(x => x.DocumentId == new Guid("ec12dc7e-a8fa-4aa5-945a-f7e64be30841") && x.DocumentTypeId == DocumentTypeId.ADDITIONAL_DETAILS); } #endregion GetRegistrationDataUntrackedAsync diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/documents.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/documents.test.json index ea83ba55e9..12b413e172 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/documents.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/documents.test.json @@ -141,5 +141,27 @@ "document_hash": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", "document_content": "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", "document_status_id": 2 + }, + { + "id": "ec12dc7e-a8fa-4aa5-945a-f7e64be30841", + "date_created": "2023-10-08T08:00:00.000000+00:00", + "document_name": "ApplicationDetails.pdf", + "media_type_id": 6, + "document_type_id": 5, + "company_user_id": "8b42e6de-7b59-4217-a63c-198e83d93776", + "document_hash": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", + "document_content": "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", + "document_status_id": 2 + }, + { + "id": "ec12dc7e-a8fa-4aa5-945a-f7e64be30842", + "date_created": "2023-10-08T08:00:00.000000+00:00", + "document_name": "OtherCertificate.pdf", + "media_type_id": 6, + "document_type_id": 15, + "company_user_id": "8b42e6de-7b59-4217-a63c-198e83d93776", + "document_hash": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", + "document_content": "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", + "document_status_id": 2 } ] \ No newline at end of file diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/invitations.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/invitations.test.json index c0e1e7fd58..81a6a65e60 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/invitations.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/invitations.test.json @@ -26,5 +26,12 @@ "invitation_status_id": 1, "company_application_id": "6b2d1263-c073-4a48-bfaf-704dc154ca9e", "company_user_id": "1dceacb8-c5a5-4573-a77d-e2487ac4a8aa" + }, + { + "id": "e92b54ed-fbbe-4259-9747-efd8613ce61f", + "date_created": "2022-03-24 18:01:33.439000 +00:00", + "invitation_status_id": 1, + "company_application_id": "4f0146c6-32aa-4bb1-b844-df7e8babdcb2", + "company_user_id": "8b42e6de-7b59-4217-a63c-198e83d93776" } ] From b70ab0d7d24e00914f68ba149991bbb5b276babf Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Thu, 16 May 2024 09:12:34 +0200 Subject: [PATCH 02/24] fix(decline): add decline url for invite process (#727) Refs: #701 --- .../DependencyInjection/InvitationSettings.cs | 3 +++ src/processes/Invitation.Executor/InvitationProcessService.cs | 1 + 2 files changed, 4 insertions(+) diff --git a/src/processes/Invitation.Executor/DependencyInjection/InvitationSettings.cs b/src/processes/Invitation.Executor/DependencyInjection/InvitationSettings.cs index e830f942ec..1c247b74b6 100644 --- a/src/processes/Invitation.Executor/DependencyInjection/InvitationSettings.cs +++ b/src/processes/Invitation.Executor/DependencyInjection/InvitationSettings.cs @@ -46,6 +46,9 @@ public class InvitationSettings [Required] [DistinctValues("x => x.Index")] public IEnumerable EncryptionConfigs { get; set; } = null!; + + [Required(AllowEmptyStrings = false)] + public string CloseApplicationAddress { get; set; } = null!; } public static class InvitationSettingsExtension diff --git a/src/processes/Invitation.Executor/InvitationProcessService.cs b/src/processes/Invitation.Executor/InvitationProcessService.cs index e98516589a..a2323af1b9 100644 --- a/src/processes/Invitation.Executor/InvitationProcessService.cs +++ b/src/processes/Invitation.Executor/InvitationProcessService.cs @@ -360,6 +360,7 @@ await _idpManagement KeyValuePair.Create("companyName", companyName), KeyValuePair.Create("url", _settings.RegistrationAppAddress), KeyValuePair.Create("passwordResendUrl", _settings.PasswordResendAddress), + KeyValuePair.Create("closeApplicationUrl", _settings.CloseApplicationAddress) }); _mailingProcessCreation.CreateMailProcess(userInformation.Email, template, mailParameters); } From b66e69319b2925ba99888b3aa75d3f74a8bdd8a0 Mon Sep 17 00:00:00 2001 From: VPrasannaK94 <117351802+VPrasannaK94@users.noreply.github.com> Date: Thu, 16 May 2024 12:47:37 +0530 Subject: [PATCH 03/24] feat(app): add roleId for exitisting activeRoleDetails (#744) Ref : #705 --- .../PortalBackend.DBAccess/Models/OfferRoleInfos.cs | 1 + .../Repositories/UserRolesRepository.cs | 2 ++ .../BusinessLogic/AppChangeBusinessLogicTest.cs | 10 ++++++---- .../BusinessLogic/AppReleaseBusinessLogicTest.cs | 10 ++++++---- .../UserRolesRepositoryTests.cs | 8 ++++---- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/OfferRoleInfos.cs b/src/portalbackend/PortalBackend.DBAccess/Models/OfferRoleInfos.cs index 3d76f0cfd0..c8eefc307a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/OfferRoleInfos.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/OfferRoleInfos.cs @@ -30,6 +30,7 @@ public record OfferRoleInfos( [property: JsonPropertyName("roles")] IEnumerable RoleInfos); public record ActiveAppRoleDetails( + [property: JsonPropertyName("roleId")] Guid RoleId, [property: JsonPropertyName("role")] string Role, [property: JsonPropertyName("descriptions")] IEnumerable Descriptions); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs index 2cc0dad89e..4f8468806f 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs @@ -299,6 +299,7 @@ public IAsyncEnumerable GetRolesForClient(string technicalUserProfileClien x.Active ? x.Roles.Select(role => new ActiveAppRoleDetails( + role.Id, role.UserRoleText, role.UserRoleDescriptions.Where(description => (languageShortName != null && description.LanguageShortName == languageShortName) || @@ -325,6 +326,7 @@ public IAsyncEnumerable GetRolesForClient(string technicalUserProfileClien x.Provider ? x.Roles.Select(role => new ActiveAppRoleDetails( + role.Id, role.UserRoleText, role.UserRoleDescriptions.Where(description => (languageShortName != null && description.LanguageShortName == languageShortName) || diff --git a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs index d92dfe3f3a..0ffc884c67 100644 --- a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs +++ b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs @@ -1192,10 +1192,12 @@ public async Task GetActiveAppRolesAsync_ReturnsExpected() { // Arrange var appId = _fixture.Create(); - var userRole1 = new ActiveAppRoleDetails("TestRole1", [ + var roleId1 = _fixture.Create(); + var roleId2 = _fixture.Create(); + var userRole1 = new ActiveAppRoleDetails(roleId1, "TestRole1", [ new ActiveAppUserRoleDescription("en", "TestRole1 description") ]); - var userRole2 = new ActiveAppRoleDetails("TestRole2", [ + var userRole2 = new ActiveAppRoleDetails(roleId2, "TestRole2", [ new ActiveAppUserRoleDescription("en", "TestRole2 description") ]); var activeAppRoleDetails = (true, true, new[] { @@ -1212,8 +1214,8 @@ public async Task GetActiveAppRolesAsync_ReturnsExpected() // Assert result.Should().HaveCount(2) .And.Satisfy( - x => x.Role == "TestRole1" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole1 description", - x => x.Role == "TestRole2" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole2 description"); + x => x.RoleId == roleId1 && x.Role == "TestRole1" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole1 description", + x => x.RoleId == roleId2 && x.Role == "TestRole2" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole2 description"); A.CallTo(() => _userRolesRepository.GetActiveOfferRolesAsync(appId, OfferTypeId.APP, "de", "en")) .MustHaveHappenedOnceExactly(); } diff --git a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppReleaseBusinessLogicTest.cs b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppReleaseBusinessLogicTest.cs index d8e1802e67..436180017d 100644 --- a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppReleaseBusinessLogicTest.cs +++ b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppReleaseBusinessLogicTest.cs @@ -1252,10 +1252,12 @@ public async Task GetAppProviderRolesAsync_ReturnsExpected() { // Arrange var appId = _fixture.Create(); - var userRole1 = new ActiveAppRoleDetails("TestRole1", [ + var roleId1 = _fixture.Create(); + var roleId2 = _fixture.Create(); + var userRole1 = new ActiveAppRoleDetails(roleId1, "TestRole1", [ new ActiveAppUserRoleDescription("en", "TestRole1 description") ]); - var userRole2 = new ActiveAppRoleDetails("TestRole2", [ + var userRole2 = new ActiveAppRoleDetails(roleId2, "TestRole2", [ new ActiveAppUserRoleDescription("en", "TestRole2 description") ]); var activeAppRoleDetails = (true, true, new[] { @@ -1272,8 +1274,8 @@ public async Task GetAppProviderRolesAsync_ReturnsExpected() // Assert result.Should().HaveCount(2) .And.Satisfy( - x => x.Role == "TestRole1" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole1 description", - x => x.Role == "TestRole2" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole2 description"); + x => x.RoleId == roleId1 && x.Role == "TestRole1" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole1 description", + x => x.RoleId == roleId2 && x.Role == "TestRole2" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole2 description"); A.CallTo(() => _userRolesRepository.GetOfferProviderRolesAsync(appId, OfferTypeId.APP, _identity.CompanyId, "de", "en")) .MustHaveHappenedOnceExactly(); } diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs index c8ef51116c..524cec69bf 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs @@ -229,8 +229,8 @@ public async Task GetActiveOfferRolesAsync_ActiveApp_ReturnsExpected() data.IsActive.Should().BeTrue(); data.AppRoleDetails.Should().HaveCount(2) .And.Satisfy( - x => x.Role == "EarthCommerce.AdministratorRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"), - x => x.Role == "EarthCommerce.Advanced.BuyerRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en")); + x => x.RoleId == new Guid("efc20368-9e82-46ff-b88f-6495b9810253") && x.Role == "EarthCommerce.AdministratorRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"), + x => x.RoleId == new Guid("aabcdfeb-6669-4c74-89f0-19cda090873f") && x.Role == "EarthCommerce.Advanced.BuyerRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en")); } #endregion @@ -281,8 +281,8 @@ public async Task GetOfferProviderRolesAsync_ValidAppAndProvider_ReturnsExpected data.IsProvider.Should().BeTrue(); data.AppRoleDetails.Should().HaveCount(2) .And.Satisfy( - x => x.Role == "EarthCommerce.AdministratorRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"), - x => x.Role == "EarthCommerce.Advanced.BuyerRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en")); + x => x.RoleId == new Guid("efc20368-9e82-46ff-b88f-6495b9810253") && x.Role == "EarthCommerce.AdministratorRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"), + x => x.RoleId == new Guid("aabcdfeb-6669-4c74-89f0-19cda090873f") && x.Role == "EarthCommerce.Advanced.BuyerRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en")); } #endregion From 9052e37924fa91b78908baf6c594ec68cebfae2d Mon Sep 17 00:00:00 2001 From: AnuragNagpure <145100366+AnuragNagpure@users.noreply.github.com> Date: Thu, 16 May 2024 15:07:43 +0530 Subject: [PATCH 04/24] fix(seeding-data): add self description document for Catena-X (#707) Reviewed-By: Phil Schneider Refs: #702 --- .../Seeder/Data/companies.json | 2 +- .../Seeder/Data/documents.json | 12 ++++++++++++ .../Data/user_role_assigned_collections.json | 16 ++++++++++++++++ .../CompanyRoleCollectionRolesViewTests.cs | 2 +- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/companies.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/companies.json index 77ad96b823..764213b56b 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/companies.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/companies.json @@ -7,6 +7,6 @@ "shortname": "Catena-X", "company_status_id": 2, "address_id": "b4db3945-19a7-4a50-97d6-e66e8dfd04fb", - "self_description_document_id": null + "self_description_document_id": "00000000-0000-0000-0000-000000000009" } ] \ No newline at end of file diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/documents.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/documents.json index 7940cb8cb5..bde3e1621f 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/documents.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/documents.json @@ -97,5 +97,17 @@ "document_hash": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", "document_content": "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MDAwMDAwMDkzMyAwMDAwMCBuIAowMDAwMDExNzI2IDAwMDAwIG4gCjAwMDAwMTQ1NTggMDAwMDAgbiAKMDAwMDAxNTA2NiAwMDAwMCBuIAowMDAwMDE0NzcwIDAwMDAwIG4gCjAwMDAwMTUzMDIgMDAwMDAgbiAKMDAwMDAyMjcyMyAwMDAwMCBuIAowMDAwMDIyMzQ0IDAwMDAwIG4gCjAwMDAwMjI5NTkgMDAwMDAgbiAKMDAwMDAzMzI4NSAwMDAwMCBuIAowMDAwMDMyOTc4IDAwMDAwIG4gCjAwMDAwMzM1MjEgMDAwMDAgbiAKMDAwMDA0MDk5MiAwMDAwMCBuIAowMDAwMDQwNjM3IDAwMDAwIG4gCjAwMDAwNDEyMjggMDAwMDAgbiAKMDAwMDA0OTg5MyAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDMwIC9Sb290IDE2IDAgUiAvSW5mbyAyOSAwIFIgL0lEIFsgPDQzZjZkMjJmYzFiM2NiZjk1MDhjNTliMWE0NjViYTdjPgo8NDNmNmQyMmZjMWIzY2JmOTUwOGM1OWIxYTQ2NWJhN2M+IF0gPj4Kc3RhcnR4cmVmCjUwMTEwCiUlRU9GCg==", "document_status_id": 2 + }, + { + "id": "00000000-0000-0000-0000-000000000009", + "date_created": "2024-01-01T19:29:08.602237+00:00", + "document_name": "SelfDescription_LegalPerson.json", + "media_type_id": 7, + "document_type_id": 8, + "company_user_id": null, + "document_hash": "81a212e6bc3121779f67abfefe7b586240c094412760a1faeb05ae2d4a30de5a781217cdf1be8b21416861819fa15d306fcb5bc62c62044f673d649e569a1dbb", + "document_content": "ewogICJzZWxmRGVzY3JpcHRpb25DcmVkZW50aWFsIjogewogICAgIkxlZ2FsUGVyc29uIjogewogICAgICAiQGNvbnRleHQiOiBbCiAgICAgICAgImh0dHBzOi8vY2FybGEuZGloLWNsb3VkLmNvbS9kZXYvY29tcGxpYW5jZV9zZXJ2aWNlL2NvbnRleHQtanNvbi9jcmVkZW50aWFsc192MV9jb250ZXh0Lmpzb24iLAogICAgICAgICJodHRwczovL2YxYzgyNzg1LTU1OTgtNDFjNy1hMDgzLTAxYThlMWE4MGUxOS5tb2NrLnBzdG1uLmlvL2N0eHNkIgogICAgICBdLAogICAgICAidHlwZSI6IFsKICAgICAgICAiVmVyaWZpYWJsZUNyZWRlbnRpYWwiCiAgICAgIF0sCiAgICAgICJpZCI6ICJodHRwczovL2NhcmxhLmRpaC1jbG91ZC5jb20vdGVzdC9jb21wbGlhbmNlX3NlcnZpY2UvcGFydGljaXBhbnQvQlBOTDAwMDAwMDAzQ1JIS19wYXJ0aWNpcGFudC5qc29uIiwKICAgICAgImNyZWRlbnRpYWxTdWJqZWN0IjogewogICAgICAgICJ0eXBlIjogIkxlZ2FsUGFydGljaXBhbnQiLAogICAgICAgICJicG4iOiAiQlBOTDAwMDAwMDAzQ1JISyIsCiAgICAgICAgInJlZ2lzdHJhdGlvbk51bWJlciI6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgInR5cGUiOiAidmF0SUQiLAogICAgICAgICAgICAidmFsdWUiOiAiREUwMDAwMDAwMDAiCiAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiaGVhZHF1YXJ0ZXJBZGRyZXNzIjogewogICAgICAgICAgImNvdW50cnlDb2RlIjogIkRFIgogICAgICAgIH0sCiAgICAgICAgImxlZ2FsQWRkcmVzcyI6IHsKICAgICAgICAgICJjb3VudHJ5Q29kZSI6ICJERSIKICAgICAgICB9LAogICAgICAgICJpZCI6ICJCUE5MMDAwMDAwMDNDUkhLIgogICAgICB9LAogICAgICAiaXNzdWVyIjogImRpZDp3ZWI6b25seV90ZXN0IiwKICAgICAgImlzc3VhbmNlRGF0ZSI6ICIyMDI0LTA0LTI0VDEwOjI1OjQ4WiIsCiAgICAgICJwcm9vZiI6IHsKICAgICAgICAidHlwZSI6ICJKc29uV2ViU2lnbmF0dXJlMjAyMCIsCiAgICAgICAgImNyZWF0ZWQiOiAiMjAyNC0wNC0yNFQxMDoyNTo0OS43MTFaIiwKICAgICAgICAicHJvb2ZQdXJwb3NlIjogImFzc2VydGlvbk1ldGhvZCIsCiAgICAgICAgImp3cyI6ICJleUpoYkdjaU9pSlFVekkxTmlJc0ltSTJOQ0k2Wm1Gc2MyVXNJbU55YVhRaU9sc2lZalkwSWwxOS4uOGFzZm10VnpmWDQ0OHdtUy16SmZfZ190dF9XZFF0eXREcU1LSDNpNU1xU2drZ1Q4eWhLVUxOYzQ2d3dDbnJoZUk5cGRLUGNmZnJoRTVpeHV0WTZ5MV9UYW5hbEJrTk9GTUN3Sjl6VVFtR0FSamcxTE1kMXNPUnZGR3dyanBwOVUtSHlmWEJQT1BIVUJhelJGNVJjLVZyWmZVTGJGbEpNb05mdnV3UTRhejlzazhhdTZleDJLUnppSnVUWVlDUU43M2s1YTNES3hjNEQ2V09VYmJKWGZub3FLMkhEWDBtRzNZTm1sWHA4UEFjN0R2MXFyV1QyR1QzazlRTDB3OFE3QzByQ29zcDdVMnBiZVdpVUZjQTFYUTFucmg1MF9ScHNCbVprMDhCMkVSdEdvaDlhUTFkUGxLdThXQjRDcHZMLVJVWmEtek5mYUFOYlFEY3BoRFVhNEFBdDRrcHo2WlRlQm4zQUxFbWJLcW53Vk1ZU3VHMUpDOFphZkxRSWo5b1IzWS04Z3V6S3RQYTgwa3JJUTBQekZEbnZrVjQ4WjZqTFNRYm5TVDZrWXczVlFMYVF2TGpWYkFTZzBvZUlrTUFRQ250MjdmRTZYZFlobFVxSENxSDZodk5JZko4c0h6VTNTcUstUDdiWmJVSkhmS3pLY0tENVV4eHdwcHBFalBYN0U2clAtenJ1dERBejdEREdMNWo1THpEQjczcXNFbmk3amhWN3pCOTEzdS13bTItcFZPc0RuaDVQUnQ4Y00yZXlKT011Y1M3TE4tQ21mTTctWDk5UVZ5cXBKTURTcFk0YkZhQUoycTJhZjNwUllZV1hLQzh0bmdFZ3l6ek5qbHBHYm5XM19IQmFiYVpPZWF0b3ctOGFmYW0ydTdJWjlmbEJnSGJlTnRraEtrMWciLAogICAgICAgICJ2ZXJpZmljYXRpb25NZXRob2QiOiAiZGlkOndlYjpvbmx5X3Rlc3QiCiAgICAgIH0KICAgIH0KICB9LAogICJjb21wbGlhbmNlQ3JlZGVudGlhbCI6IHsKICAgICJAY29udGV4dCI6IFsKICAgICAgImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIiwKICAgICAgImh0dHBzOi8vZ3gtcmVnaXN0cnkudGVzdC5kaWgtY2xvdWQuY29tL3YxL2FwaS90cnVzdGVkLXNoYXBlLXJlZ2lzdHJ5L3YxL3NoYXBlcy9qc29ubGQvdHJ1c3RmcmFtZXdvcmsjIgogICAgXSwKICAgICJ0eXBlIjogWwogICAgICAiVmVyaWZpYWJsZUNyZWRlbnRpYWwiCiAgICBdLAogICAgImlkIjogImh0dHBzOi8vY2FybGEuZGloLWNsb3VkLmNvbS90ZXN0L2NvbXBsaWFuY2Vfc2VydmljZS9jcmVkZW50aWFsL0JQTkwwMDAwMDAwM0NSSEtfcGFydGljaXBhbnQuanNvbiIsCiAgICAiY3JlZGVudGlhbFN1YmplY3QiOiBbCiAgICAgIHsKICAgICAgICAidHlwZSI6ICJneDpjb21wbGlhbmNlIiwKICAgICAgICAiaWQiOiAiQlBOTDAwMDAwMDAzQ1JISyIsCiAgICAgICAgImludGVncml0eSI6ICJzaGEyNTYtZDhlZWEzOTlkODAxNzkwMWJlNzk5MGQ1YmU1YTU1ODA5NzlhOGI4OWQ2NWMxZWIzODk5NzU2MGNlNzU2OTFmZCIKICAgICAgfQogICAgXSwKICAgICJpc3N1ZXIiOiAiZGlkOndlYjpvbmx5X3Rlc3QiLAogICAgImlzc3VhbmNlRGF0ZSI6ICIyMDI0LTA0LTI0VDEwOjI1OjUxLjE1MloiLAogICAgImV4cGlyYXRpb25EYXRlIjogIjIwMjUtMDQtMjRUMTA6MjU6NTEuMTUyWiIsCiAgICAicHJvb2YiOiB7CiAgICAgICJ0eXBlIjogIkpzb25XZWJTaWduYXR1cmUyMDIwIiwKICAgICAgImNyZWF0ZWQiOiAiMjAyNC0wNC0yNFQxMDoyNTo1MS4zNzNaIiwKICAgICAgInByb29mUHVycG9zZSI6ICJhc3NlcnRpb25NZXRob2QiLAogICAgICAiandzIjogImV5SmhiR2NpT2lKUVV6STFOaUlzSW1JMk5DSTZabUZzYzJVc0ltTnlhWFFpT2xzaVlqWTBJbDE5Li43SXFTNjZoVDhFbjdqZ2U3LUx4dHIxSFZJTHFCSzlUdjJFUEltdWFsTzhEQ1V6dnBVbHlKaTlncVJiNFhDTkMxanl3Slc5ZEwxR1lxUFRQSTJkZG1KSUhGd20zNmREeVlJWHVwdG42VS0zWFEtRGhUYjVkYXBGOFNyQnRFdUJMakNfQnNTR2ZEdXpMUWdXSDdKb0ZkVmJIX2FLZ0Joa3lrSTZRU2xCbGpILXFWSVZadFBPMkVCQzlHQWFCaHpVVmE3RFBxY1hudUcwQVliN0dYNnBmZDdzZ2lNQjdoeWFPZ3lpaG42eFZxR0c5WFk0Nk50b3dxUkZHZGNMQ0pQZ05iSXlmOGdyVHZNSXRaWUJ3N2ppMlJtcWVjR1pXd0Roc2g3Y3RUcDMzdkNkNHFYeEZuU1ZpbFNUY29lOUJDa1llNnlmSDBvdlZPeHJlY2duNXBXME54aDNreEJmX0tselF3bEhfVktCSHhEWjl3ckV1eHI5VE1fZFVDWlhHOFVyOHRPaENhNzNaMklmUXpsaFhMTENZbm1BclY2bl81UGNVZmZjMTBVMk5Ca1hPY0tEVEx1WGg2N3RhNVVxLVoyT2hnS3JIWEt3SXI4aDdtcm9ncXcwMllTSFNSOW1xNXNEdFNMcU9ZTEVHdEFDdC1ycW1Dc3I2VHhIMUduMnR5ZlQxTWZNSUJKSktQT1drRVA1UUhuUnc5Tk4zOE1hN25vVWN0VlQ3N1ExV25wU0NlNlNuTDQyV1p6WUVZbEdpd3VsRFBoTjQ4S3JiM1hRNk1TLWdmSmRmZkJjZFRIeFVPcW9wTW1XdU5sYjd1VHhDaVZJSzl5QVJGOU1NSXZvel9XUm54QWd0aGYtLVphQmoyMVhQLW0xWXVrd1VrUkU3endQTXR1MkgxOFFsVXZxVSIsCiAgICAgICJ2ZXJpZmljYXRpb25NZXRob2QiOiAiZGlkOndlYjpvbmx5X3Rlc3QiCiAgICB9CiAgfQp9", + "document_status_id": 2, + "last_editor_id": "7e85a0b8-0001-ab67-10d1-0ef508201027" } ] \ No newline at end of file diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json index 3402e881ac..228e7a5064 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json @@ -182,5 +182,21 @@ { "user_role_collection_id": "1a24eca5-901f-4191-84a7-4ef09a894575", "user_role_id": "ec3a3005-b59c-4319-a8eb-3228984cd6e5" + }, + { + "user_role_collection_id": "ec428950-8b64-4646-b336-28af869b5d73", + "user_role_id": "a6b6a5b6-d7fe-42af-94ce-35c16b3ae128" + }, + { + "user_role_collection_id": "ec428950-8b64-4646-b336-28af869b5d73", + "user_role_id": "9956fa8d-e454-49ca-a3b1-45e2c106fe59" + }, + { + "user_role_collection_id": "a5b8b1de-7759-4620-9c87-6b6d74fb4fbc", + "user_role_id": "a6b6a5b6-d7fe-42af-94ce-35c16b3ae128" + }, + { + "user_role_collection_id": "a5b8b1de-7759-4620-9c87-6b6d74fb4fbc", + "user_role_id": "9956fa8d-e454-49ca-a3b1-45e2c106fe59" } ] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs index 65f77cddcc..5017cb887e 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs @@ -45,7 +45,7 @@ public async Task CompanyRoleCollectionRolesView_GetAll_ReturnsExpected() // Act var result = await sut.CompanyRoleCollectionRolesView.ToListAsync(); - result.Should().HaveCount(46); + result.Should().HaveCount(50); } [Fact] From 87cfaa479b7722f7110e18f857af64a5f7574849 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Thu, 16 May 2024 21:35:49 +0200 Subject: [PATCH 05/24] fix(dim) don't create keycloak sa for dim (#745) --- .../Models/UserRoleData.cs | 2 - .../Repositories/IServiceAccountRepository.cs | 2 +- .../Repositories/ServiceAccountRepository.cs | 6 +- .../DimUserCreationProcessService.cs | 9 +- .../Service/ServiceAccountCreation.cs | 48 +-- .../DimUserCreationProcessServiceTests.cs | 12 +- .../Extensions/ServiceAccountCreationTests.cs | 307 +++++++++++++++--- 7 files changed, 297 insertions(+), 89 deletions(-) diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/UserRoleData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/UserRoleData.cs index d30b2ed502..893130dd80 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/UserRoleData.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/UserRoleData.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,7 +17,6 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using System.Text.Json.Serialization; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs index fde2b6f795..368502d740 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs @@ -43,6 +43,6 @@ CompanyServiceAccount CreateCompanyServiceAccount(Guid identityId, public Task<(Guid IdentityId, Guid CompanyId)> GetServiceAccountDataByClientId(string clientId); void CreateDimCompanyServiceAccount(Guid serviceAccountId, string authenticationServiceUrl, byte[] secret, byte[] initializationVector, int encryptionMode); void CreateDimUserCreationData(Guid serviceAccountId, Guid processId); - Task<(bool IsValid, string? Bpn, string? ClientClientId)> GetDimServiceAccountData(Guid dimServiceAccountId); + Task<(bool IsValid, string? Bpn, string Name)> GetDimServiceAccountData(Guid dimServiceAccountId); Task GetDimServiceAccountIdForProcess(Guid processId); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs index 8a2bff66ac..22c8c7c3e2 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs @@ -224,13 +224,13 @@ public void CreateDimCompanyServiceAccount(Guid serviceAccountId, string authent public void CreateDimUserCreationData(Guid serviceAccountId, Guid processId) => _dbContext.DimUserCreationData.Add(new DimUserCreationData(Guid.NewGuid(), serviceAccountId, processId)); - public Task<(bool IsValid, string? Bpn, string? ClientClientId)> GetDimServiceAccountData(Guid dimServiceAccountId) => + public Task<(bool IsValid, string? Bpn, string Name)> GetDimServiceAccountData(Guid dimServiceAccountId) => _dbContext.DimUserCreationData .Where(x => x.Id == dimServiceAccountId) - .Select(x => new ValueTuple( + .Select(x => new ValueTuple( true, x.ServiceAccount!.Identity!.Company!.BusinessPartnerNumber, - x.ServiceAccount!.ClientClientId)) + x.ServiceAccount!.Name)) .SingleOrDefaultAsync(); public Task GetDimServiceAccountIdForProcess(Guid processId) => diff --git a/src/processes/DimUserCreationProcess.Executor/DimUserCreationProcessService.cs b/src/processes/DimUserCreationProcess.Executor/DimUserCreationProcessService.cs index 4dd361e0a1..3a1c589c03 100644 --- a/src/processes/DimUserCreationProcess.Executor/DimUserCreationProcessService.cs +++ b/src/processes/DimUserCreationProcess.Executor/DimUserCreationProcessService.cs @@ -33,7 +33,7 @@ public class DimUserCreationProcessService( public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateDimUser(Guid processId, Guid dimServiceAccountId, CancellationToken cancellationToken) { var serviceAccountRepository = portalRepositories.GetInstance(); - var (isValid, bpn, clientClientId) = await serviceAccountRepository.GetDimServiceAccountData(dimServiceAccountId) + var (isValid, bpn, name) = await serviceAccountRepository.GetDimServiceAccountData(dimServiceAccountId) .ConfigureAwait(ConfigureAwaitOptions.None); if (!isValid) @@ -46,12 +46,13 @@ public class DimUserCreationProcessService( throw new ConflictException("Bpn must not be null"); } - if (string.IsNullOrWhiteSpace(clientClientId)) + if (string.IsNullOrWhiteSpace(name)) { - throw new ConflictException("Service Account Name must not be null"); + throw new ConflictException("Service Account Name must not be empty"); } - await dimService.CreateTechnicalUser(bpn, new TechnicalUserData(processId, $"dim-{clientClientId}"), cancellationToken).ConfigureAwait(false); + var dimName = string.Concat(name.Where(c => !char.IsWhiteSpace(c))); // DIM doesn't accept whitespace chars in name + await dimService.CreateTechnicalUser(bpn, new TechnicalUserData(processId, dimName), cancellationToken).ConfigureAwait(false); return (Enumerable.Repeat(ProcessStepTypeId.AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE, 1), ProcessStepStatusId.DONE, true, null); } } diff --git a/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs b/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs index 4cfb8c5708..53f117c01e 100644 --- a/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs +++ b/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs @@ -59,30 +59,36 @@ public class ServiceAccountCreation( var userRolesRepository = portalRepositories.GetInstance(); var userRoleData = await GetAndValidateUserRoleData(userRolesRepository, userRoleIds).ConfigureAwait(ConfigureAwaitOptions.None); - var serviceAccounts = ImmutableList.CreateBuilder(); + var dimConfigRoles = _settings.DimUserRoles.SelectMany(x => x.UserRoleNames.Select(userRoleName => (x.ClientId, userRoleName))); - var (clientId, enhancedName, serviceAccountData) = await CreateKeycloakServiceAccount(bpns, enhanceTechnicalUserName, enabled, name, description, iamClientAuthMethod, userRoleData).ConfigureAwait(ConfigureAwaitOptions.None); - var serviceAccountId = CreateDatabaseServiceAccount(companyId, UserStatusId.ACTIVE, companyServiceAccountTypeId, CompanyServiceAccountKindId.INTERNAL, name, clientId, description, userRoleData, serviceAccountsRepository, userRolesRepository, setOptionalParameter); - serviceAccounts.Add(new CreatedServiceAccountData( - serviceAccountId, - enhancedName, - description, - UserStatusId.ACTIVE, - clientId, - serviceAccountData, - userRoleData)); + var serviceAccounts = ImmutableList.CreateBuilder(); - var dimRoles = userRoleData - .Join(_settings.DimUserRoles, data => data.ClientClientId, config => config.ClientId, - (data, config) => new { data, config }) - .Where(@t => t.config.UserRoleNames.Contains(@t.data.UserRoleText)) - .Select(@t => t.data) - .ToImmutableList(); + if (userRoleData.ExceptBy(dimConfigRoles, roleData => (roleData.ClientClientId, roleData.UserRoleText)).IfAny( + async roleData => + { + var keycloakRoleData = roleData.ToImmutableList(); + var (clientId, enhancedName, serviceAccountData) = await CreateKeycloakServiceAccount(bpns, enhanceTechnicalUserName, enabled, name, description, iamClientAuthMethod, keycloakRoleData).ConfigureAwait(ConfigureAwaitOptions.None); + var serviceAccountId = CreateDatabaseServiceAccount(companyId, UserStatusId.ACTIVE, companyServiceAccountTypeId, CompanyServiceAccountKindId.INTERNAL, name, clientId, description, keycloakRoleData, serviceAccountsRepository, userRolesRepository, setOptionalParameter); + serviceAccounts.Add(new CreatedServiceAccountData( + serviceAccountId, + enhancedName, + description, + UserStatusId.ACTIVE, + clientId, + serviceAccountData, + keycloakRoleData)); + }, + out var keycloakRolesTask)) + { + await keycloakRolesTask!.ConfigureAwait(ConfigureAwaitOptions.None); + } - var hasExternalServiceAccount = dimRoles.IfAny(roles => + var hasExternalServiceAccount = userRoleData.IntersectBy(dimConfigRoles, roleData => (roleData.ClientClientId, roleData.UserRoleText)).IfAny( + roleData => { + var dimRoleData = roleData.ToImmutableList(); var dimSaName = $"dim-{name}"; - var dimServiceAccountId = CreateDatabaseServiceAccount(companyId, UserStatusId.PENDING, companyServiceAccountTypeId, CompanyServiceAccountKindId.EXTERNAL, dimSaName, null, description, roles, serviceAccountsRepository, userRolesRepository, setOptionalParameter); + var dimServiceAccountId = CreateDatabaseServiceAccount(companyId, UserStatusId.PENDING, companyServiceAccountTypeId, CompanyServiceAccountKindId.EXTERNAL, dimSaName, null, description, dimRoleData, serviceAccountsRepository, userRolesRepository, setOptionalParameter); var processStepRepository = portalRepositories.GetInstance(); if (processData?.ProcessTypeId is not null) { @@ -98,7 +104,7 @@ public class ServiceAccountCreation( processId = processData.ProcessId.Value; } - portalRepositories.GetInstance().CreateDimUserCreationData(serviceAccountId, processId); + portalRepositories.GetInstance().CreateDimUserCreationData(dimServiceAccountId, processId); } serviceAccounts.Add(new CreatedServiceAccountData( @@ -108,7 +114,7 @@ public class ServiceAccountCreation( UserStatusId.PENDING, null, null, - roles)); + dimRoleData)); }); return (hasExternalServiceAccount, serviceAccounts.ToImmutable()); diff --git a/tests/processes/DimUserCreationProcess.Executor.Tests/DimUserCreationProcessServiceTests.cs b/tests/processes/DimUserCreationProcess.Executor.Tests/DimUserCreationProcessServiceTests.cs index f64e7fb518..39a8a4e843 100644 --- a/tests/processes/DimUserCreationProcess.Executor.Tests/DimUserCreationProcessServiceTests.cs +++ b/tests/processes/DimUserCreationProcess.Executor.Tests/DimUserCreationProcessServiceTests.cs @@ -60,9 +60,9 @@ public async Task CreateDimUser_WithValid_ReturnsExpected() // Arrange var dimServiceAccountId = Guid.NewGuid(); var processId = Guid.NewGuid(); - var expectedServiceAccountName = "dim-sa-test"; + var expectedServiceAccountName = "dim-sa-testFooBar"; A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) - .Returns((true, Bpn, "sa-test")); + .Returns((true, Bpn, "dim-sa-test Foo Bar")); // Act var result = await _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None); @@ -86,7 +86,7 @@ public async Task CreateDimUser_WithInvalidDimServiceAccountId_ThrowsNotFoundExc var dimServiceAccountId = Guid.NewGuid(); var processId = Guid.NewGuid(); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) - .Returns(default((bool, string?, string?))); + .Returns(default((bool, string?, string))); Task Act() => _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act @@ -107,7 +107,7 @@ public async Task CreateDimUser_WithBpnNotSet_ThrowsConflictException() var dimServiceAccountId = Guid.NewGuid(); var processId = Guid.NewGuid(); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) - .Returns((true, null, null)); + .Returns((true, null, "foo")); Task Act() => _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act @@ -128,14 +128,14 @@ public async Task CreateDimUser_WithValidMissingServiceAccountName_ThrowsConflic var dimServiceAccountId = Guid.NewGuid(); var processId = Guid.NewGuid(); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) - .Returns((true, Bpn, null)); + .Returns((true, Bpn, " ")); Task Act() => _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act var ex = await Assert.ThrowsAsync(Act); // Act - ex.Message.Should().Be("Service Account Name must not be null"); + ex.Message.Should().Be("Service Account Name must not be empty"); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(dimServiceAccountId)) .MustHaveHappenedOnceExactly(); A.CallTo(() => _dimService.CreateTechnicalUser(Bpn, A._, A._)) diff --git a/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs b/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs index 287b3f132a..72213be07a 100644 --- a/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs +++ b/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs @@ -39,15 +39,21 @@ public class ServiceAccountCreationTests private const string Bpn = "CAXSDUMMYCATENAZZ"; private readonly string _iamUserId = Guid.NewGuid().ToString(); private readonly Guid _companyId = Guid.NewGuid(); - private readonly Guid _serviceAccountId = Guid.NewGuid(); private readonly Guid _identityId = Guid.NewGuid(); + private readonly Guid _secondId = Guid.NewGuid(); + private readonly string _validClientId; private readonly Guid _validUserRoleId = Guid.NewGuid(); + private readonly string _dimClient; + private readonly string _dimRoleText; + private readonly Guid _dimUserRoleId = Guid.NewGuid(); private readonly Guid _invalidUserRoleId = Guid.NewGuid(); + private readonly Guid _processId = Guid.NewGuid(); + private readonly Guid _processStepId = Guid.NewGuid(); private readonly IServiceAccountRepository _serviceAccountRepository; private readonly IUserRepository _userRepository; private readonly IUserRolesRepository _userRolesRepository; - + private readonly IProcessStepRepository _processStepRepository; private readonly IProvisioningManager _provisioningManager; private readonly IPortalRepositories _portalRepositories; private readonly IProvisioningDBAccess _provisioningDbAccess; @@ -60,9 +66,14 @@ public ServiceAccountCreationTests() .ForEach(b => fixture.Behaviors.Remove(b)); fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _validClientId = fixture.Create(); + _dimClient = fixture.Create(); + _dimRoleText = fixture.Create(); + _serviceAccountRepository = A.Fake(); _userRepository = A.Fake(); _userRolesRepository = A.Fake(); + _processStepRepository = A.Fake(); _provisioningManager = A.Fake(); _portalRepositories = A.Fake(); @@ -71,42 +82,57 @@ public ServiceAccountCreationTests() var settings = new ServiceAccountCreationSettings { ServiceAccountClientPrefix = "sa", - DimUserRoles = [new UserRoleConfig("technical_user_management", ["Identity Wallet Management"])] + DimUserRoles = [new UserRoleConfig(_dimClient, [_dimRoleText])] }; A.CallTo(() => _portalRepositories.GetInstance()).Returns(_serviceAccountRepository); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRepository); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRolesRepository); + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_processStepRepository); _sut = new ServiceAccountCreation(_provisioningManager, _portalRepositories, _provisioningDbAccess, Options.Create(settings)); } + private void ServiceAccountCreationAction(CompanyServiceAccount _) { } + [Fact] public async Task CreateServiceAccountAsync_WithInvalidRole_ThrowsNotFoundException() { // Arrange - var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, new[] { _invalidUserRoleId }); + var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, [_invalidUserRoleId]); Setup(); // Act - async Task Act() => await _sut.CreateServiceAccountAsync(creationData, _companyId, Enumerable.Empty(), CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null)); + async Task Act() => await _sut.CreateServiceAccountAsync(creationData, _companyId, Enumerable.Empty(), CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null), ServiceAccountCreationAction); // Assert var ex = await Assert.ThrowsAsync(Act); ex.Message.Should().Be(ProvisioningServiceErrors.USER_NOT_VALID_USERROLEID.ToString()); - A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(A._, A>._)).MustNotHaveHappened(); - A.CallTo(() => _provisioningManager.AddProtocolMapperAsync(A._)).MustNotHaveHappened(); - A.CallTo(() => _userRolesRepository.DeleteCompanyUserAssignedRoles(A>._)).MustNotHaveHappened(); + + A.CallTo(() => _userRepository.CreateIdentity(A._, A._, A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(A._, A._, A._, A._, A._, A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync(A._, A._, A._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.AddProtocolMapperAsync(A._)) + .MustNotHaveHappened(); A.CallTo(() => _portalRepositories.SaveAsync()).MustNotHaveHappened(); } - [Fact] - public async Task CreateServiceAccountAsync_WithValidData_ReturnsExpected() + [Theory] + [InlineData(false, "testName")] + [InlineData(true, "sa1-testName")] + public async Task CreateServiceAccountAsync_WithValidData_ReturnsExpected(bool enhance, string serviceAccountName) { // Arrange var serviceAccounts = new List(); var identities = new List(); - var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, new[] { _validUserRoleId }); + var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, [_validUserRoleId]); var bpns = new[] { Bpn @@ -114,21 +140,64 @@ public async Task CreateServiceAccountAsync_WithValidData_ReturnsExpected() Setup(serviceAccounts, identities); // Act - var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null)); + var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, enhance, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null), ServiceAccountCreationAction); // Assert - result.ServiceAccounts.Should().ContainSingle(); - var serviceAccount = result.ServiceAccounts.Single(); - serviceAccount.UserRoleData.Should().ContainSingle(x => x.UserRoleId == _validUserRoleId && x.UserRoleText == "UserRole"); - serviceAccount.ServiceAccountData.InternalClientId.Should().Be("internal-sa1"); - serviceAccount.ServiceAccountData.IamUserId.Should().Be(_iamUserId); - serviceAccount.ServiceAccountData.AuthData.IamClientAuthMethod.Should().Be(IamClientAuthMethod.SECRET); - A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(_iamUserId, bpns)).MustHaveHappenedOnceExactly(); - A.CallTo(() => _provisioningManager.AddProtocolMapperAsync("internal-sa1")).MustHaveHappenedOnceExactly(); - A.CallTo(() => _portalRepositories.SaveAsync()).MustNotHaveHappened(); + + result.ServiceAccounts.Should().ContainSingle() + .Which.Should().Match(x => + x.ClientId == "sa1" && + x.Description == "abc" && + x.UserRoleData.SequenceEqual(new[] { new UserRoleData(_validUserRoleId, _validClientId, "UserRole") }) && + x.Name == serviceAccountName && + x.ServiceAccountData != null && + x.ServiceAccountData.InternalClientId == "internal-sa1" && + x.ServiceAccountData.IamUserId == _iamUserId && + x.ServiceAccountData.AuthData.IamClientAuthMethod == IamClientAuthMethod.SECRET + ); + + A.CallTo(() => _userRepository.CreateIdentity(_companyId, UserStatusId.ACTIVE, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, null)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_identityId, "testName", "abc", "sa1", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL, ServiceAccountCreationAction)) + .MustHaveHappenedOnceExactly(); + var expectedRolesIds = new[] { (_identityId, _validUserRoleId) }; + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.IsSameSequenceAs(expectedRolesIds))) + .MustHaveHappenedOnceExactly(); + IEnumerable? userRoles; + A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync( + "sa1", + A.That.Matches(x => + x.IamClientAuthMethod == IamClientAuthMethod.SECRET && + x.Name == serviceAccountName && + x.Description == "abc" && + x.ClientRoles.Count() == 1 && + x.ClientRoles.TryGetValue(_validClientId, out userRoles) && + userRoles.SequenceEqual(new[] { "UserRole" })), + true)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(_iamUserId, bpns)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _provisioningManager.AddProtocolMapperAsync("internal-sa1")) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _userRepository.CreateIdentity(A._, UserStatusId.PENDING, A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(A._, A._, A._, A._, A._, CompanyServiceAccountKindId.EXTERNAL, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.Matches(x => x.Any(y => y.Item2 != _validUserRoleId)))) + .MustNotHaveHappened(); + A.CallTo(() => _processStepRepository.CreateProcess(A._)) + .MustNotHaveHappened(); + A.CallTo(() => _processStepRepository.CreateProcessStep(A._, A._, A._)) + .MustNotHaveHappened(); + A.CallTo(() => _serviceAccountRepository.CreateDimUserCreationData(A._, A._)) + .MustNotHaveHappened(); + A.CallTo(() => _portalRepositories.SaveAsync()) + .MustNotHaveHappened(); serviceAccounts.Should().ContainSingle().Which.Should().Match( x => x.Name == "testName" && - x.ClientClientId == "sa1"); + x.ClientClientId == "sa1" && + x.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL); identities.Should().ContainSingle().Which.Should().Match( x => x.CompanyId == _companyId && x.UserStatusId == UserStatusId.ACTIVE && @@ -136,12 +205,12 @@ public async Task CreateServiceAccountAsync_WithValidData_ReturnsExpected() } [Fact] - public async Task CreateServiceAccountAsync_WithNameSetAndValidData_ReturnsExpected() + public async Task CreateServiceAccountAsync_WithValidDimData_ReturnsExpected() { // Arrange var serviceAccounts = new List(); var identities = new List(); - var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, new[] { _validUserRoleId }); + var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, [_dimUserRoleId]); var bpns = new[] { Bpn @@ -149,48 +218,169 @@ public async Task CreateServiceAccountAsync_WithNameSetAndValidData_ReturnsExpec Setup(serviceAccounts, identities); // Act - var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, true, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null)); + var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null), ServiceAccountCreationAction); // Assert - result.ServiceAccounts.Should().ContainSingle(); - var technicalUser = result.ServiceAccounts.Single(); - technicalUser.UserRoleData.Should().ContainSingle(x => x.UserRoleId == _validUserRoleId && x.UserRoleText == "UserRole"); - technicalUser.ServiceAccountData.InternalClientId.Should().Be("internal-sa1"); - technicalUser.ServiceAccountData.IamUserId.Should().Be(_iamUserId); - technicalUser.ServiceAccountData.AuthData.IamClientAuthMethod.Should().Be(IamClientAuthMethod.SECRET); - A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync(A._, A.That.Matches(x => x.Name == "sa1-testName"), A._)).MustHaveHappenedOnceExactly(); - A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(_iamUserId, bpns)).MustHaveHappenedOnceExactly(); - A.CallTo(() => _provisioningManager.AddProtocolMapperAsync("internal-sa1")).MustHaveHappenedOnceExactly(); - A.CallTo(() => _portalRepositories.SaveAsync()).MustNotHaveHappened(); + result.ServiceAccounts.Should().ContainSingle() + .Which.Should().Match(x => + x.ClientId == null && + x.Description == "abc" && + x.UserRoleData.SequenceEqual(new[] { new UserRoleData(_dimUserRoleId, _dimClient, _dimRoleText) }) && + x.Name == "dim-testName" && + x.ServiceAccountData == null && + x.Status == UserStatusId.PENDING + ); + + A.CallTo(() => _userRepository.CreateIdentity(A._, UserStatusId.ACTIVE, A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(A._, A._, A._, A._, A._, CompanyServiceAccountKindId.INTERNAL, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.Matches(x => x.Any(y => y.Item2 != _dimUserRoleId)))) + .MustNotHaveHappened(); + + A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync(A._, A._, A._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.AddProtocolMapperAsync(A._)) + .MustNotHaveHappened(); + + A.CallTo(() => _userRepository.CreateIdentity(_companyId, UserStatusId.PENDING, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, null)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_identityId, "dim-testName", "abc", null, CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.EXTERNAL, ServiceAccountCreationAction)) + .MustHaveHappenedOnceExactly(); + var expectedRolesIds = new[] { (_identityId, _dimUserRoleId) }; + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.IsSameSequenceAs(expectedRolesIds))) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _processStepRepository.CreateProcess(ProcessTypeId.DIM_TECHNICAL_USER)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _processStepRepository.CreateProcessStep(ProcessStepTypeId.CREATE_DIM_TECHNICAL_USER, ProcessStepStatusId.TODO, A._)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateDimUserCreationData(_identityId, _processId)) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _portalRepositories.SaveAsync()) + .MustNotHaveHappened(); + serviceAccounts.Should().ContainSingle().Which.Should().Match( - x => x.Name == "testName" && - x.ClientClientId == "sa1"); + x => x.Name == "dim-testName" && + x.ClientClientId == null && + x.CompanyServiceAccountKindId == CompanyServiceAccountKindId.EXTERNAL); identities.Should().ContainSingle().Which.Should().Match( x => x.CompanyId == _companyId && - x.UserStatusId == UserStatusId.ACTIVE && + x.UserStatusId == UserStatusId.PENDING && x.IdentityTypeId == IdentityTypeId.COMPANY_SERVICE_ACCOUNT); } + [Fact] + public async Task CreateServiceAccountAsync_WithValidDataPlus_ReturnsExpected() + { + // Arrange + var serviceAccounts = new List(); + var identities = new List(); + var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, [_validUserRoleId, _dimUserRoleId]); + var bpns = new[] + { + Bpn + }; + Setup(serviceAccounts, identities); + + // Act + var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null), ServiceAccountCreationAction); + + // Assert + result.ServiceAccounts.Should().HaveCount(2) + .And.Satisfy( + x => x.ClientId == "sa1" && + x.Description == "abc" && + x.UserRoleData.SequenceEqual(new[] { new UserRoleData(_validUserRoleId, _validClientId, "UserRole") }) && + x.Name == "testName" && + x.ServiceAccountData != null && + x.ServiceAccountData.InternalClientId == "internal-sa1" && + x.ServiceAccountData.IamUserId == _iamUserId && + x.ServiceAccountData.AuthData.IamClientAuthMethod == IamClientAuthMethod.SECRET, + x => x.ClientId == null && + x.Description == "abc" && + x.UserRoleData.SequenceEqual(new[] { new UserRoleData(_dimUserRoleId, _dimClient, _dimRoleText) }) && + x.Name == "dim-testName" && + x.ServiceAccountData == null); + + A.CallTo(() => _userRepository.CreateIdentity(_companyId, UserStatusId.ACTIVE, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, null)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_identityId, "testName", "abc", "sa1", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL, ServiceAccountCreationAction)) + .MustHaveHappenedOnceExactly(); + var expectedRolesIds = new[] { (_identityId, _validUserRoleId) }; + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.IsSameSequenceAs(expectedRolesIds))) + .MustHaveHappenedOnceExactly(); + IEnumerable? userRoles; + A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync( + "sa1", + A.That.Matches(x => + x.IamClientAuthMethod == IamClientAuthMethod.SECRET && + x.Name == "testName" && + x.Description == "abc" && + x.ClientRoles.Count() == 1 && + x.ClientRoles.TryGetValue(_validClientId, out userRoles) && + userRoles.SequenceEqual(new[] { "UserRole" })), + true)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(_iamUserId, bpns)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _provisioningManager.AddProtocolMapperAsync("internal-sa1")) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _userRepository.CreateIdentity(_companyId, UserStatusId.ACTIVE, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, null)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_secondId, "dim-testName", "abc", null, CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.EXTERNAL, ServiceAccountCreationAction)) + .MustHaveHappenedOnceExactly(); + var expectedDimRolesIds = new[] { (_secondId, _dimUserRoleId) }; + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.IsSameSequenceAs(expectedDimRolesIds))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _portalRepositories.SaveAsync()) + .MustNotHaveHappened(); + + serviceAccounts.Should().HaveCount(2) + .And.Satisfy( + x => x.Name == "testName" && x.ClientClientId == "sa1" && x.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL, + x => x.Name == "dim-testName" && x.ClientClientId == null && x.CompanyServiceAccountKindId == CompanyServiceAccountKindId.EXTERNAL + ); + identities.Should().HaveCount(2) + .And.AllSatisfy(x => x.Should().Match(x => x.CompanyId == _companyId && x.IdentityTypeId == IdentityTypeId.COMPANY_SERVICE_ACCOUNT)) + .And.Satisfy( + x => x.Id == _identityId && x.UserStatusId == UserStatusId.ACTIVE, + x => x.Id == _secondId && x.UserStatusId == UserStatusId.PENDING + ); + } + #region Setup private void Setup(ICollection? serviceAccounts = null, ICollection? identities = null) { A.CallTo(() => _provisioningDbAccess.GetNextClientSequenceAsync()) - .Returns(1); + .Returns(1).Once(); A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync(A._, A._, A._)) - .Returns(new ServiceAccountData("internal-sa1", _iamUserId, new ClientAuthData(IamClientAuthMethod.SECRET))); + .Returns(new ServiceAccountData("internal-sa1", _iamUserId, new ClientAuthData(IamClientAuthMethod.SECRET))).Once(); - A.CallTo(() => _userRepository.CreateIdentity(_companyId, A._, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, A>._)) - .Invokes((Guid companyId, UserStatusId userStatusId, IdentityTypeId identityTypeId, Action? setOptionalFields) => + A.CallTo(() => _userRepository.CreateIdentity(A._, A._, A._, A>._)) + .ReturnsLazily((Guid companyId, UserStatusId userStatusId, IdentityTypeId identityTypeId, Action? setOptionalFields) => { - var identity = new Identity(Guid.NewGuid(), DateTimeOffset.UtcNow, companyId, userStatusId, identityTypeId); + var identity = new Identity(_identityId, DateTimeOffset.UtcNow, companyId, userStatusId, identityTypeId); setOptionalFields?.Invoke(identity); identities?.Add(identity); - }) - .Returns(new Identity(_identityId, default, default, default, default)); - A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_identityId, A._, A._, A._, A._, A._, A>._)) - .Invokes((Guid identityId, string name, string description, string clientClientId, CompanyServiceAccountTypeId companyServiceAccountTypeId, CompanyServiceAccountKindId companyServiceAccountKindId, Action? setOptionalParameters) => + return identity; + }).Once() + .Then.ReturnsLazily((Guid companyId, UserStatusId userStatusId, IdentityTypeId identityTypeId, Action? setOptionalFields) => + { + var identity = new Identity(_secondId, DateTimeOffset.UtcNow, companyId, userStatusId, identityTypeId); + setOptionalFields?.Invoke(identity); + identities?.Add(identity); + return identity; + }).Once(); + + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(A._, A._, A._, A._, A._, A._, A>._)) + .ReturnsLazily((Guid identityId, string name, string description, string clientClientId, CompanyServiceAccountTypeId companyServiceAccountTypeId, CompanyServiceAccountKindId companyServiceAccountKindId, Action? setOptionalParameters) => { var sa = new CompanyServiceAccount( identityId, @@ -203,13 +393,26 @@ private void Setup(ICollection? serviceAccounts = null, I }; setOptionalParameters?.Invoke(sa); serviceAccounts?.Add(sa); - }) - .Returns(new CompanyServiceAccount(_serviceAccountId, null!, null!, default, default)); + return sa; + }); - A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Matches(x => x.Count(y => y == _validUserRoleId) == 1))) - .Returns(new[] { new UserRoleData(_validUserRoleId, Guid.NewGuid().ToString(), "UserRole") }.ToAsyncEnumerable()); - A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Matches(x => x.Count(y => y == _invalidUserRoleId) == 1))) + A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Contains(_validUserRoleId))) + .Returns(new[] { new UserRoleData(_validUserRoleId, _validClientId, "UserRole") }.ToAsyncEnumerable()); + A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Contains(_dimUserRoleId))) + .Returns(new[] { new UserRoleData(_dimUserRoleId, _dimClient, _dimRoleText) }.ToAsyncEnumerable()); + A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Contains(_invalidUserRoleId))) .Returns(Enumerable.Empty().ToAsyncEnumerable()); + A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.IsSameSequenceAs(new[] { _validUserRoleId, _dimUserRoleId }))) + .Returns(new UserRoleData[] + { + new(_validUserRoleId, _validClientId, "UserRole"), + new(_dimUserRoleId, _dimClient, _dimRoleText) + }.ToAsyncEnumerable()); + + A.CallTo(() => _processStepRepository.CreateProcess(A._)) + .ReturnsLazily((ProcessTypeId processTypeId) => new Process(_processId, processTypeId, Guid.NewGuid())).Once(); + A.CallTo(() => _processStepRepository.CreateProcessStep(A._, A._, A._)) + .ReturnsLazily((ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid processId) => new ProcessStep(_processStepId, processStepTypeId, processStepStatusId, processId, DateTimeOffset.UtcNow)).Once(); } #endregion From d7fd0cc624b35cf46263c082f099634e0ea07ae6 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Tue, 21 May 2024 16:33:39 +0200 Subject: [PATCH 06/24] fix(role-management): fix query selecting role-data for core-offer role assignement (#749) --- .../Repositories/UserRolesRepository.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs index 4f8468806f..0f4637f53b 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs @@ -154,13 +154,16 @@ public IAsyncEnumerable GetAssignedAndMatchingCoreOffe .Select(role => new { Role = role, + IsRequested = userRoles.Contains(role.UserRoleText), IsAssigned = role.IdentityAssignedRoles.Any(iar => iar.IdentityId == identityId), IsAssignable = role.UserRoleCollections.Any(collection => collection.CompanyRoleAssignedRoleCollection!.CompanyRole!.CompanyAssignedRoles.Any(assigned => assigned.Company!.Identities.Any(identity => identity.Id == identityId))) }) - .Where(x => - userRoles.Contains(x.Role.UserRoleText) || - x.IsAssigned || - x.IsAssignable) + // x.IsRequested && x.IsAssigned && x.IsAssignable || // no change but required to detect duplicates + // x.IsRequested && !x.IsAssigned && x.IsAssignable || // to be assigned + // !x.IsRequested && x.IsAssigned || // to be unassigned + // x.IsRequested && !x.IsAssignable // invalid + // can be simplified to: + .Where(x => x.IsRequested || x.IsAssigned) .Select(x => new UserRoleModificationData( x.Role.UserRoleText, x.Role.Id, From 76b5336bddd1b9353b8d5158e487ff95a986832f Mon Sep 17 00:00:00 2001 From: AnuragNagpure <145100366+AnuragNagpure@users.noreply.github.com> Date: Wed, 22 May 2024 12:06:15 +0530 Subject: [PATCH 07/24] feat(services): update permission for api endpoints added (#751) --- .../Services.Service/Controllers/ServicesController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/marketplace/Services.Service/Controllers/ServicesController.cs b/src/marketplace/Services.Service/Controllers/ServicesController.cs index c11e0b7fa9..923c30c5e6 100644 --- a/src/marketplace/Services.Service/Controllers/ServicesController.cs +++ b/src/marketplace/Services.Service/Controllers/ServicesController.cs @@ -262,7 +262,7 @@ public async Task GetServiceDocumentContentAsync([FromRoute] Guid se /// User's company does not provide the service. /// No service or subscription found. [HttpGet] - [Authorize(Roles = "add_service_offering")] + [Authorize(Roles = "service_management")] [Authorize(Policy = PolicyTypes.ValidCompany)] [Route("{serviceId}/subscription/{subscriptionId}/provider")] [ProducesResponseType(typeof(ProviderSubscriptionDetailData), StatusCodes.Status200OK)] @@ -282,7 +282,7 @@ public Task GetSubscriptionDetailForProvider([Fr /// User's company does not provide the service. /// No service or subscription found. [HttpGet] - [Authorize(Roles = "add_service_offering")] + [Authorize(Roles = "subscribe_service")] [Authorize(Policy = PolicyTypes.ValidCompany)] [Route("{serviceId}/subscription/{subscriptionId}/subscriber")] [ProducesResponseType(typeof(SubscriberSubscriptionDetailData), StatusCodes.Status200OK)] @@ -299,7 +299,7 @@ public Task GetSubscriptionDetailForSubscriber /// If sub claim is empty/invalid or user does not exist. [HttpGet] [Route("subscribed/subscription-status")] - [Authorize(Roles = "view_subscription")] + [Authorize(Roles = "view_service_subscriptions")] [Authorize(Policy = PolicyTypes.ValidCompany)] [ProducesResponseType(typeof(Pagination.Response), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)] From 0889ae3713b8e25dc98f4a1fd92d88363c4dd111 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Wed, 22 May 2024 15:59:01 +0200 Subject: [PATCH 08/24] fix(keycloak): set clockSkew to 5 min (#753) --- src/administration/Administration.Service/appsettings.json | 2 +- src/notifications/Notifications.Service/appsettings.json | 2 +- src/registration/Registration.Service/appsettings.json | 2 +- .../appsettings.IntegrationTests.json | 2 +- .../Apps.Service.Tests/appsettings.IntegrationTests.json | 2 +- .../Services.Service.Tests/appsettings.IntegrationTests.json | 2 +- .../appsettings.IntegrationTests.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/administration/Administration.Service/appsettings.json b/src/administration/Administration.Service/appsettings.json index e8e3bf6da9..c700d96794 100644 --- a/src/administration/Administration.Service/appsettings.json +++ b/src/administration/Administration.Service/appsettings.json @@ -57,7 +57,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Provisioning": { diff --git a/src/notifications/Notifications.Service/appsettings.json b/src/notifications/Notifications.Service/appsettings.json index c94a36512a..0cdc02d33f 100644 --- a/src/notifications/Notifications.Service/appsettings.json +++ b/src/notifications/Notifications.Service/appsettings.json @@ -56,7 +56,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Notifications": { diff --git a/src/registration/Registration.Service/appsettings.json b/src/registration/Registration.Service/appsettings.json index bb32ceaa5a..edff4031b9 100644 --- a/src/registration/Registration.Service/appsettings.json +++ b/src/registration/Registration.Service/appsettings.json @@ -63,7 +63,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Provisioning": { diff --git a/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json b/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json index 4fac7a9735..632ec19dfa 100644 --- a/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json @@ -40,7 +40,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Provisioning": { diff --git a/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json b/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json index bc1fa85148..1f00b30b42 100644 --- a/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json @@ -28,7 +28,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "ConnectionStrings": { diff --git a/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json b/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json index 34444dda34..a697823515 100644 --- a/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json @@ -28,7 +28,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "ConnectionStrings": { diff --git a/tests/notifications/Notifications.Service.Tests/appsettings.IntegrationTests.json b/tests/notifications/Notifications.Service.Tests/appsettings.IntegrationTests.json index b4dc0a8f24..c059467684 100644 --- a/tests/notifications/Notifications.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/notifications/Notifications.Service.Tests/appsettings.IntegrationTests.json @@ -55,7 +55,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Notifications": { From cd8c7c18d9aba512e4bad19b7a4c037cbedc4d93 Mon Sep 17 00:00:00 2001 From: Evelyn Gurschler Date: Wed, 22 May 2024 17:42:46 +0200 Subject: [PATCH 09/24] chore: fix file header https://github.com/eclipse-tractusx/portal-backend/issues/752 --- .../Administration.Service/Models/CompanyWithAddressData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/administration/Administration.Service/Models/CompanyWithAddressData.cs b/src/administration/Administration.Service/Models/CompanyWithAddressData.cs index 1ce45805e0..4750ae060e 100644 --- a/src/administration/Administration.Service/Models/CompanyWithAddressData.cs +++ b/src/administration/Administration.Service/Models/CompanyWithAddressData.cs @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 Contributors to the CatenaX (ng) GitHub Organisation. + * Copyright (c) 2022 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. From 6b8a6c7a78718ccc98d59a2779f14ff23344738e Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Wed, 22 May 2024 18:06:39 +0200 Subject: [PATCH 10/24] fix(offersubscription): fix queries throwing a system exception instead of returning default value (#755) * fix 'System.InvalidOperationException: Nullable object must have a value' caused by queries selecting a (non-nullable) guid from a joined table where the joined table does not have a matching dataset resulting in 'null' being returned from the database. --- .../Repositories/CompanyInvitationRepository.cs | 7 ++++--- .../Repositories/NetworkRepository.cs | 6 +++--- .../Repositories/OfferSubscriptionsRepository.cs | 6 +++--- .../Processes.Worker.Library/IProcessTypeExecutor.cs | 2 -- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs index 7dcc20cbcf..8c23f7ab12 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs @@ -38,9 +38,10 @@ public CompanyInvitation CreateCompanyInvitation(string firstName, string lastNa } public Task GetCompanyInvitationForProcessId(Guid processId) => - _context.Processes - .Where(process => process.Id == processId) - .Select(process => process.CompanyInvitation!.Id) + _context.CompanyInvitations + .AsNoTracking() + .Where(i => i.ProcessId == processId) + .Select(i => i.Id) .SingleOrDefaultAsync(); public Task GetOrganisationNameForInvitation(Guid invitationId) => diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/NetworkRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/NetworkRepository.cs index 8ba9cf3959..f5906ae231 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/NetworkRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/NetworkRepository.cs @@ -45,10 +45,10 @@ public Task CheckExternalIdExists(string externalId, Guid onboardingServic /// public Task GetNetworkRegistrationDataForProcessIdAsync(Guid processId) => - _context.Processes + _context.NetworkRegistrations .AsNoTracking() - .Where(process => process.Id == processId) - .Select(process => process.NetworkRegistration!.Id) + .Where(nr => nr.ProcessId == processId) + .Select(nr => nr.Id) .SingleOrDefaultAsync(); public Task<(bool RegistrationIdExists, VerifyProcessData processData)> IsValidRegistration(string externalId, IEnumerable processStepTypeIds) => diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs index eebb679b8c..ac73f4818a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs @@ -332,10 +332,10 @@ public void AttachAndModifyAppSubscriptionDetail(Guid detailId, Guid subscriptio /// public Task GetOfferSubscriptionDataForProcessIdAsync(Guid processId) => - _context.Processes + _context.OfferSubscriptions .AsNoTracking() - .Where(process => process.Id == processId) - .Select(process => process.OfferSubscription!.Id) + .Where(os => os.ProcessId == processId) + .Select(os => os.Id) .SingleOrDefaultAsync(); /// diff --git a/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs b/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs index 16ecb5ef80..3487a64d48 100644 --- a/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs +++ b/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs @@ -1,5 +1,4 @@ /******************************************************************************** - * Copyright (c) 2022 Microsoft and BMW Group AG * Copyright (c) 2022 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional @@ -18,7 +17,6 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; namespace Org.Eclipse.TractusX.Portal.Backend.Processes.Worker.Library; From a4e9119fc0a8ecae27b3ee18ed8a3ace70c58ee8 Mon Sep 17 00:00:00 2001 From: Evelyn Gurschler Date: Wed, 22 May 2024 18:25:55 +0200 Subject: [PATCH 11/24] build(2.0.0-rc9): bump version and update docs --- CHANGELOG.md | 24 ++++++++++++++++++++++++ src/Directory.Build.props | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbebfffbdb..35862989d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,30 @@ New features, fixed bugs, known defects and other noteworthy changes to each release of the Catena-X Portal Backend. +## 2.0.0-RC9 + +### Changes +* **Administration Service** +* enhanced companyDetailsWithAddress endpoint +* **Apps Service** +* added roleId for existing activeRoleDetails +* **Services Service** +* updated permissions for api endpoints + +### Bugfix +* **Invitation** +* added decline url for invite process +* **Seeding** +* added self description document to initial company +* **DIM Process Worker** +* stopped creating technical users for dim +* **Role assignment** +* fixed query for core offer to prevent role assignment triggering cascading role assignments +* **Token lifetime** +* set ClockSkew (security configuration jwtBearerOptions) to 5 minutes for token expiration +* **Offersubscription** +* fixed queries throwing a system exception instead of returning default value + ## 2.0.0-RC8 ### Changes diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 02ae4aacc4..aab938b2ba 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -20,6 +20,6 @@ 2.0.0 - RC8 + RC9 From 028d6b171f186857c61c33573a360e7f0a54f431 Mon Sep 17 00:00:00 2001 From: Evelyn Gurschler Date: Wed, 22 May 2024 19:27:28 +0200 Subject: [PATCH 12/24] build(2.0.0-rc9): merge release into main (#756) * feat(document): enhance companyDetailsWithAddress endpoint (#732) * add documents section to endpoint companydetailaddress * remove documents section from applications endpoint * adjust unit tests --------- Co-authored-by: Norbert Truchsess * fix(decline): add decline url for invite process (#727) Refs: #701 * feat(app): add roleId for exitisting activeRoleDetails (#744) Ref : #705 * fix(seeding-data): add self description document for Catena-X (#707) Reviewed-By: Phil Schneider Refs: #702 * fix(dim) don't create keycloak sa for dim (#745) * fix(role-management): fix query selecting role-data for core-offer role assignement (#749) * feat(services): update permission for api endpoints added (#751) * fix(keycloak): set clockSkew to 5 min (#753) * chore: fix file header https://github.com/eclipse-tractusx/portal-backend/issues/752 * fix(offersubscription): fix queries throwing a system exception instead of returning default value (#755) * fix 'System.InvalidOperationException: Nullable object must have a value' caused by queries selecting a (non-nullable) guid from a joined table where the joined table does not have a matching dataset resulting in 'null' being returned from the database. * build(2.0.0-rc9): bump version and update docs --------- Co-authored-by: AnuragNagpure <145100366+AnuragNagpure@users.noreply.github.com> Co-authored-by: Phil Schneider Co-authored-by: VPrasannaK94 <117351802+VPrasannaK94@users.noreply.github.com> Co-authored-by: Norbert Truchsess --- CHANGELOG.md | 24 ++ src/Directory.Build.props | 2 +- .../RegistrationBusinessLogic.cs | 52 +-- .../Models/CompanyApplicationDetails.cs | 6 - .../Models/CompanyWithAddressData.cs | 21 +- .../Administration.Service/appsettings.json | 2 +- .../Controllers/ServicesController.cs | 6 +- .../Notifications.Service/appsettings.json | 2 +- .../Models/CompanyUserRoleWithAddress.cs | 6 +- .../Models/OfferRoleInfos.cs | 1 + .../Models/UserRoleData.cs | 2 - .../Repositories/ApplicationRepository.cs | 9 +- .../CompanyInvitationRepository.cs | 7 +- .../Repositories/IApplicationRepository.cs | 3 +- .../Repositories/IServiceAccountRepository.cs | 2 +- .../Repositories/NetworkRepository.cs | 6 +- .../OfferSubscriptionsRepository.cs | 6 +- .../Repositories/ServiceAccountRepository.cs | 6 +- .../Repositories/UserRolesRepository.cs | 13 +- .../Seeder/Data/companies.json | 2 +- .../Seeder/Data/documents.json | 12 + .../Data/user_role_assigned_collections.json | 16 + .../Enums/DocumentTypeId.cs | 1 - .../DimUserCreationProcessService.cs | 9 +- .../DependencyInjection/InvitationSettings.cs | 3 + .../InvitationProcessService.cs | 1 + .../IProcessTypeExecutor.cs | 2 - .../Service/ServiceAccountCreation.cs | 48 +-- .../Registration.Service/appsettings.json | 2 +- .../RegistrationBusinessLogicTest.cs | 8 +- .../appsettings.IntegrationTests.json | 2 +- .../AppChangeBusinessLogicTest.cs | 10 +- .../AppReleaseBusinessLogicTest.cs | 10 +- .../appsettings.IntegrationTests.json | 2 +- .../appsettings.IntegrationTests.json | 2 +- .../appsettings.IntegrationTests.json | 2 +- .../ApplicationRepositoryTests.cs | 13 +- .../CompanyRoleCollectionRolesViewTests.cs | 2 +- .../Seeder/Data/documents.test.json | 22 ++ .../Seeder/Data/invitations.test.json | 7 + .../UserRolesRepositoryTests.cs | 8 +- .../DimUserCreationProcessServiceTests.cs | 12 +- .../Extensions/ServiceAccountCreationTests.cs | 307 +++++++++++++++--- 43 files changed, 501 insertions(+), 178 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbebfffbdb..35862989d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,30 @@ New features, fixed bugs, known defects and other noteworthy changes to each release of the Catena-X Portal Backend. +## 2.0.0-RC9 + +### Changes +* **Administration Service** +* enhanced companyDetailsWithAddress endpoint +* **Apps Service** +* added roleId for existing activeRoleDetails +* **Services Service** +* updated permissions for api endpoints + +### Bugfix +* **Invitation** +* added decline url for invite process +* **Seeding** +* added self description document to initial company +* **DIM Process Worker** +* stopped creating technical users for dim +* **Role assignment** +* fixed query for core offer to prevent role assignment triggering cascading role assignments +* **Token lifetime** +* set ClockSkew (security configuration jwtBearerOptions) to 5 minutes for token expiration +* **Offersubscription** +* fixed queries throwing a system exception instead of returning default value + ## 2.0.0-RC8 ### Changes diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 02ae4aacc4..aab938b2ba 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -20,6 +20,6 @@ 2.0.0 - RC8 + RC9 diff --git a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs index 826669d4b3..abd7a95014 100644 --- a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs @@ -99,10 +99,10 @@ public Task GetCompanyWithAddressAsync(Guid applicationI private async Task GetCompanyWithAddressAsyncInternal(Guid applicationId) { - var companyWithAddress = await _portalRepositories.GetInstance().GetCompanyUserRoleWithAddressUntrackedAsync(applicationId).ConfigureAwait(ConfigureAwaitOptions.None); + var companyWithAddress = await _portalRepositories.GetInstance().GetCompanyUserRoleWithAddressUntrackedAsync(applicationId, _settings.DocumentTypeIds).ConfigureAwait(ConfigureAwaitOptions.None); if (companyWithAddress == null) { - throw NotFoundException.Create(AdministrationRegistrationErrors.APPLICATION_NOT_FOUND, new ErrorParameter[] { new("applicationId", applicationId.ToString()) }); + throw NotFoundException.Create(AdministrationRegistrationErrors.APPLICATION_NOT_FOUND, [new("applicationId", applicationId.ToString())]); } if (!string.IsNullOrEmpty(companyWithAddress.Name) && !Company.IsMatch(companyWithAddress.Name)) { @@ -134,7 +134,10 @@ private async Task GetCompanyWithAddressAsyncInternal(Gu x.FirstName ?? "", x.LastName ?? "", x.Email ?? "")), - companyWithAddress.CompanyIdentifiers.Select(identifier => new CompanyUniqueIdData(identifier.UniqueIdentifierId, identifier.Value)) + companyWithAddress.CompanyIdentifiers.Select(identifier => new CompanyUniqueIdData(identifier.UniqueIdentifierId, identifier.Value)), + companyWithAddress.DocumentData.Select(data => new DocumentDetails(data.DocumentId, data.DocumentTypeId)), + companyWithAddress.Created, + companyWithAddress.LastChanged ); } @@ -165,9 +168,6 @@ private async Task GetCompanyWithAddressAsyncInternal(Gu application.ApplicationStatusId, application.DateCreated, application.Company!.Name, - application.Invitations.SelectMany(invitation => - invitation.CompanyUser!.Documents.Where(document => _settings.DocumentTypeIds.Contains(document.DocumentTypeId)).Select(document => - new DocumentDetails(document.Id, document.DocumentTypeId))), application.Company!.CompanyAssignedRoles.Select(companyAssignedRoles => companyAssignedRoles.CompanyRoleId), application.ApplicationChecklistEntries.Where(x => x.ApplicationChecklistEntryTypeId != ApplicationChecklistEntryTypeId.APPLICATION_ACTIVATION).OrderBy(x => x.ApplicationChecklistEntryTypeId).Select(x => new ApplicationChecklistEntryDetails(x.ApplicationChecklistEntryTypeId, x.ApplicationChecklistEntryStatusId)), application.Invitations @@ -268,22 +268,22 @@ private async Task UpdateCompanyBpnInternal(Guid applicationId, string bpn) .VerifyChecklistEntryAndProcessSteps( applicationId, ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER, - new[] { + [ ApplicationChecklistEntryStatusId.TO_DO, ApplicationChecklistEntryStatusId.IN_PROGRESS, ApplicationChecklistEntryStatusId.FAILED - }, + ], ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_MANUAL, - entryTypeIds: new[] { + entryTypeIds: [ ApplicationChecklistEntryTypeId.REGISTRATION_VERIFICATION - }, - processStepTypeIds: new[] { + ], + processStepTypeIds: [ ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PUSH, ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PULL, ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PULL, ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PUSH, ProcessStepTypeId.CREATE_IDENTITY_WALLET - }) + ]) .ConfigureAwait(ConfigureAwaitOptions.None); _portalRepositories.GetInstance().AttachAndModifyCompany(applicationCompanyData.CompanyId, null, @@ -293,12 +293,12 @@ private async Task UpdateCompanyBpnInternal(Guid applicationId, string bpn) _checklistService.SkipProcessSteps( context, - new[] { + [ ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PUSH, ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PULL, ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PULL, ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PUSH - }); + ]); _checklistService.FinalizeChecklistEntryAndProcessSteps( context, @@ -386,9 +386,9 @@ private async Task TriggerChecklistInternal(Guid applicationId, ApplicationCheck .VerifyChecklistEntryAndProcessSteps( applicationId, entryTypeId, - new[] { ApplicationChecklistEntryStatusId.FAILED }, + [ApplicationChecklistEntryStatusId.FAILED], processStepTypeId, - processStepTypeIds: new[] { nextProcessStepTypeId }) + processStepTypeIds: [nextProcessStepTypeId]) .ConfigureAwait(ConfigureAwaitOptions.None); _checklistService.FinalizeChecklistEntryAndProcessSteps( @@ -405,7 +405,7 @@ private async Task TriggerChecklistInternal(Guid applicationId, ApplicationCheck item.ApplicationChecklistEntryStatusId = checklistEntryStatusId; item.Comment = null; }, - new[] { nextProcessStepTypeId }); + [nextProcessStepTypeId]); await _portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); } @@ -438,10 +438,10 @@ public async Task ApproveRegistrationVerification(Guid applicationId) .VerifyChecklistEntryAndProcessSteps( applicationId, ApplicationChecklistEntryTypeId.REGISTRATION_VERIFICATION, - new[] { ApplicationChecklistEntryStatusId.TO_DO }, + [ApplicationChecklistEntryStatusId.TO_DO], ProcessStepTypeId.VERIFY_REGISTRATION, - new[] { ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER }, - new[] { CreateWalletStep() }) + [ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER], + [CreateWalletStep()]) .ConfigureAwait(ConfigureAwaitOptions.None); var businessPartnerSuccess = context.Checklist[ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER] == new ValueTuple(ApplicationChecklistEntryStatusId.DONE, null); @@ -474,13 +474,13 @@ public async Task DeclineRegistrationVerification(Guid applicationId, string com .VerifyChecklistEntryAndProcessSteps( applicationId, ApplicationChecklistEntryTypeId.REGISTRATION_VERIFICATION, - new[] { ApplicationChecklistEntryStatusId.TO_DO, ApplicationChecklistEntryStatusId.DONE }, + [ApplicationChecklistEntryStatusId.TO_DO, ApplicationChecklistEntryStatusId.DONE], ProcessStepTypeId.DECLINE_APPLICATION, null, - new[] { ProcessStepTypeId.VERIFY_REGISTRATION, }) + [ProcessStepTypeId.VERIFY_REGISTRATION,]) .ConfigureAwait(ConfigureAwaitOptions.None); - _checklistService.SkipProcessSteps(context, new[] { ProcessStepTypeId.VERIFY_REGISTRATION }); + _checklistService.SkipProcessSteps(context, [ProcessStepTypeId.VERIFY_REGISTRATION]); var identityProviderRepository = _portalRepositories.GetInstance(); var userRepository = _portalRepositories.GetInstance(); @@ -572,15 +572,15 @@ private static IEnumerable GetCompanyApplicationStat { case CompanyApplicationStatusFilter.Closed: { - return new[] { CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED }; + return [CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED]; } case CompanyApplicationStatusFilter.InReview: { - return new[] { CompanyApplicationStatusId.SUBMITTED }; + return [CompanyApplicationStatusId.SUBMITTED]; } default: { - return new[] { CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED }; + return [CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.DECLINED]; } } } diff --git a/src/administration/Administration.Service/Models/CompanyApplicationDetails.cs b/src/administration/Administration.Service/Models/CompanyApplicationDetails.cs index 075717c072..5c28b23c79 100644 --- a/src/administration/Administration.Service/Models/CompanyApplicationDetails.cs +++ b/src/administration/Administration.Service/Models/CompanyApplicationDetails.cs @@ -28,18 +28,12 @@ public record CompanyApplicationDetails( [property: JsonPropertyName("applicationStatus")] CompanyApplicationStatusId CompanyApplicationStatusId, [property: JsonPropertyName("dateCreated")] DateTimeOffset DateCreated, [property: JsonPropertyName("companyName")] string CompanyName, - [property: JsonPropertyName("documents")] IEnumerable Documents, [property: JsonPropertyName("companyRoles")] IEnumerable CompanyRoles, [property: JsonPropertyName("applicationChecklist")] IEnumerable ApplicationChecklist, [property: JsonPropertyName("email")] string? Email, [property: JsonPropertyName("bpn")] string? BusinessPartnerNumber ); -public record DocumentDetails( - [property: JsonPropertyName("documentId")] Guid DocumentId, - [property: JsonPropertyName("documentType")] DocumentTypeId? DocumentTypeId -); - public record ApplicationChecklistEntryDetails( ApplicationChecklistEntryTypeId TypeId, ApplicationChecklistEntryStatusId StatusId diff --git a/src/administration/Administration.Service/Models/CompanyWithAddressData.cs b/src/administration/Administration.Service/Models/CompanyWithAddressData.cs index 86baabf28e..4750ae060e 100644 --- a/src/administration/Administration.Service/Models/CompanyWithAddressData.cs +++ b/src/administration/Administration.Service/Models/CompanyWithAddressData.cs @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2022 Contributors to the CatenaX (ng) GitHub Organisation. + * Copyright (c) 2022 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -40,6 +40,9 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; /// /// /// +/// +/// +/// /// public record CompanyWithAddressData( @@ -56,7 +59,10 @@ public record CompanyWithAddressData( string ZipCode, [property: JsonPropertyName("companyRoles")] IEnumerable AgreementsRoleData, [property: JsonPropertyName("companyUser")] IEnumerable InvitedUserData, - IEnumerable UniqueIds + IEnumerable UniqueIds, + [property: JsonPropertyName("documents")] IEnumerable Documents, + DateTimeOffset? Created, + DateTimeOffset? LastChanged ); /// @@ -95,3 +101,14 @@ public record InvitedUserData( string LastName, string Email ); + +/// +/// +/// +/// +/// +/// +public record DocumentDetails( + [property: JsonPropertyName("documentId")] Guid DocumentId, + [property: JsonPropertyName("documentType")] DocumentTypeId? DocumentTypeId +); diff --git a/src/administration/Administration.Service/appsettings.json b/src/administration/Administration.Service/appsettings.json index e8e3bf6da9..c700d96794 100644 --- a/src/administration/Administration.Service/appsettings.json +++ b/src/administration/Administration.Service/appsettings.json @@ -57,7 +57,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Provisioning": { diff --git a/src/marketplace/Services.Service/Controllers/ServicesController.cs b/src/marketplace/Services.Service/Controllers/ServicesController.cs index c11e0b7fa9..923c30c5e6 100644 --- a/src/marketplace/Services.Service/Controllers/ServicesController.cs +++ b/src/marketplace/Services.Service/Controllers/ServicesController.cs @@ -262,7 +262,7 @@ public async Task GetServiceDocumentContentAsync([FromRoute] Guid se /// User's company does not provide the service. /// No service or subscription found. [HttpGet] - [Authorize(Roles = "add_service_offering")] + [Authorize(Roles = "service_management")] [Authorize(Policy = PolicyTypes.ValidCompany)] [Route("{serviceId}/subscription/{subscriptionId}/provider")] [ProducesResponseType(typeof(ProviderSubscriptionDetailData), StatusCodes.Status200OK)] @@ -282,7 +282,7 @@ public Task GetSubscriptionDetailForProvider([Fr /// User's company does not provide the service. /// No service or subscription found. [HttpGet] - [Authorize(Roles = "add_service_offering")] + [Authorize(Roles = "subscribe_service")] [Authorize(Policy = PolicyTypes.ValidCompany)] [Route("{serviceId}/subscription/{subscriptionId}/subscriber")] [ProducesResponseType(typeof(SubscriberSubscriptionDetailData), StatusCodes.Status200OK)] @@ -299,7 +299,7 @@ public Task GetSubscriptionDetailForSubscriber /// If sub claim is empty/invalid or user does not exist. [HttpGet] [Route("subscribed/subscription-status")] - [Authorize(Roles = "view_subscription")] + [Authorize(Roles = "view_service_subscriptions")] [Authorize(Policy = PolicyTypes.ValidCompany)] [ProducesResponseType(typeof(Pagination.Response), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)] diff --git a/src/notifications/Notifications.Service/appsettings.json b/src/notifications/Notifications.Service/appsettings.json index c94a36512a..0cdc02d33f 100644 --- a/src/notifications/Notifications.Service/appsettings.json +++ b/src/notifications/Notifications.Service/appsettings.json @@ -56,7 +56,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Notifications": { diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserRoleWithAddress.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserRoleWithAddress.cs index b011739cbc..6b5b5cba17 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserRoleWithAddress.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserRoleWithAddress.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 @@ -37,7 +36,10 @@ public record CompanyUserRoleWithAddress( string? CountryDe, IEnumerable AgreementsData, IEnumerable InvitedCompanyUserData, - IEnumerable<(UniqueIdentifierId UniqueIdentifierId, string Value)> CompanyIdentifiers + IEnumerable<(UniqueIdentifierId UniqueIdentifierId, string Value)> CompanyIdentifiers, + IEnumerable<(Guid DocumentId, DocumentTypeId DocumentTypeId)> DocumentData, + DateTimeOffset? Created, + DateTimeOffset? LastChanged ); public record AgreementsData(CompanyRoleId CompanyRoleId, Guid AgreementId, ConsentStatusId? ConsentStatusId); diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/OfferRoleInfos.cs b/src/portalbackend/PortalBackend.DBAccess/Models/OfferRoleInfos.cs index 3d76f0cfd0..c8eefc307a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/OfferRoleInfos.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/OfferRoleInfos.cs @@ -30,6 +30,7 @@ public record OfferRoleInfos( [property: JsonPropertyName("roles")] IEnumerable RoleInfos); public record ActiveAppRoleDetails( + [property: JsonPropertyName("roleId")] Guid RoleId, [property: JsonPropertyName("role")] string Role, [property: JsonPropertyName("descriptions")] IEnumerable Descriptions); diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/UserRoleData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/UserRoleData.cs index d30b2ed502..893130dd80 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/UserRoleData.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/UserRoleData.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,7 +17,6 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using System.Text.Json.Serialization; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs index 1561f22485..d98c77f9d7 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs @@ -264,7 +264,7 @@ public IQueryable GetAllCompanyApplicationsDetailsQuery(stri .AsNoTracking() .Where(application => companyName == null || EF.Functions.ILike(application.Company!.Name, $"%{companyName.EscapeForILike()}%")); - public Task GetCompanyUserRoleWithAddressUntrackedAsync(Guid companyApplicationId) => + public Task GetCompanyUserRoleWithAddressUntrackedAsync(Guid companyApplicationId, IEnumerable documentTypeIds) => portalDbContext.CompanyApplications .AsSplitQuery() .Where(companyApplication => companyApplication.Id == companyApplicationId) @@ -294,7 +294,12 @@ public IQueryable GetAllCompanyApplicationsDetailsQuery(stri x.CompanyUser!.Firstname, x.CompanyUser.Lastname, x.CompanyUser.Email)), - companyApplication.Company.CompanyIdentifiers.Select(identifier => new ValueTuple(identifier.UniqueIdentifierId, identifier.Value)))) + companyApplication.Company.CompanyIdentifiers.Select(identifier => new ValueTuple(identifier.UniqueIdentifierId, identifier.Value)), + companyApplication.Invitations.SelectMany(invitation => + invitation.CompanyUser!.Documents.Where(document => documentTypeIds.Contains(document.DocumentTypeId)).Select(document => + new ValueTuple(document.Id, document.DocumentTypeId))), + companyApplication.DateCreated, + companyApplication.DateLastChanged)) .AsNoTracking() .SingleOrDefaultAsync(); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs index 7dcc20cbcf..8c23f7ab12 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs @@ -38,9 +38,10 @@ public CompanyInvitation CreateCompanyInvitation(string firstName, string lastNa } public Task GetCompanyInvitationForProcessId(Guid processId) => - _context.Processes - .Where(process => process.Id == processId) - .Select(process => process.CompanyInvitation!.Id) + _context.CompanyInvitations + .AsNoTracking() + .Where(i => i.ProcessId == processId) + .Select(i => i.Id) .SingleOrDefaultAsync(); public Task GetOrganisationNameForInvitation(Guid invitationId) => diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs index f16e5e7d7f..9e6e942f9a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.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 @@ -43,7 +42,7 @@ public interface IApplicationRepository IAsyncEnumerable GetInvitedUsersDataByApplicationIdUntrackedAsync(Guid applicationId); IAsyncEnumerable GetEmailDataUntrackedAsync(Guid applicationId); IQueryable GetAllCompanyApplicationsDetailsQuery(string? companyName = null); - Task GetCompanyUserRoleWithAddressUntrackedAsync(Guid companyApplicationId); + Task GetCompanyUserRoleWithAddressUntrackedAsync(Guid companyApplicationId, IEnumerable documentTypeIds); Task<(bool IsValidApplicationId, bool IsValidCompany, RegistrationData? Data)> GetRegistrationDataUntrackedAsync(Guid applicationId, Guid userCompanyId, IEnumerable documentTypes); Task<(string? Bpn, IEnumerable ExistingChecklistEntryTypeIds)> GetBpnAndChecklistCheckForApplicationIdAsync(Guid applicationId); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs index fde2b6f795..368502d740 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs @@ -43,6 +43,6 @@ CompanyServiceAccount CreateCompanyServiceAccount(Guid identityId, public Task<(Guid IdentityId, Guid CompanyId)> GetServiceAccountDataByClientId(string clientId); void CreateDimCompanyServiceAccount(Guid serviceAccountId, string authenticationServiceUrl, byte[] secret, byte[] initializationVector, int encryptionMode); void CreateDimUserCreationData(Guid serviceAccountId, Guid processId); - Task<(bool IsValid, string? Bpn, string? ClientClientId)> GetDimServiceAccountData(Guid dimServiceAccountId); + Task<(bool IsValid, string? Bpn, string Name)> GetDimServiceAccountData(Guid dimServiceAccountId); Task GetDimServiceAccountIdForProcess(Guid processId); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/NetworkRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/NetworkRepository.cs index 8ba9cf3959..f5906ae231 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/NetworkRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/NetworkRepository.cs @@ -45,10 +45,10 @@ public Task CheckExternalIdExists(string externalId, Guid onboardingServic /// public Task GetNetworkRegistrationDataForProcessIdAsync(Guid processId) => - _context.Processes + _context.NetworkRegistrations .AsNoTracking() - .Where(process => process.Id == processId) - .Select(process => process.NetworkRegistration!.Id) + .Where(nr => nr.ProcessId == processId) + .Select(nr => nr.Id) .SingleOrDefaultAsync(); public Task<(bool RegistrationIdExists, VerifyProcessData processData)> IsValidRegistration(string externalId, IEnumerable processStepTypeIds) => diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs index eebb679b8c..ac73f4818a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs @@ -332,10 +332,10 @@ public void AttachAndModifyAppSubscriptionDetail(Guid detailId, Guid subscriptio /// public Task GetOfferSubscriptionDataForProcessIdAsync(Guid processId) => - _context.Processes + _context.OfferSubscriptions .AsNoTracking() - .Where(process => process.Id == processId) - .Select(process => process.OfferSubscription!.Id) + .Where(os => os.ProcessId == processId) + .Select(os => os.Id) .SingleOrDefaultAsync(); /// diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs index 8a2bff66ac..22c8c7c3e2 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs @@ -224,13 +224,13 @@ public void CreateDimCompanyServiceAccount(Guid serviceAccountId, string authent public void CreateDimUserCreationData(Guid serviceAccountId, Guid processId) => _dbContext.DimUserCreationData.Add(new DimUserCreationData(Guid.NewGuid(), serviceAccountId, processId)); - public Task<(bool IsValid, string? Bpn, string? ClientClientId)> GetDimServiceAccountData(Guid dimServiceAccountId) => + public Task<(bool IsValid, string? Bpn, string Name)> GetDimServiceAccountData(Guid dimServiceAccountId) => _dbContext.DimUserCreationData .Where(x => x.Id == dimServiceAccountId) - .Select(x => new ValueTuple( + .Select(x => new ValueTuple( true, x.ServiceAccount!.Identity!.Company!.BusinessPartnerNumber, - x.ServiceAccount!.ClientClientId)) + x.ServiceAccount!.Name)) .SingleOrDefaultAsync(); public Task GetDimServiceAccountIdForProcess(Guid processId) => diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs index 2cc0dad89e..0f4637f53b 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRolesRepository.cs @@ -154,13 +154,16 @@ public IAsyncEnumerable GetAssignedAndMatchingCoreOffe .Select(role => new { Role = role, + IsRequested = userRoles.Contains(role.UserRoleText), IsAssigned = role.IdentityAssignedRoles.Any(iar => iar.IdentityId == identityId), IsAssignable = role.UserRoleCollections.Any(collection => collection.CompanyRoleAssignedRoleCollection!.CompanyRole!.CompanyAssignedRoles.Any(assigned => assigned.Company!.Identities.Any(identity => identity.Id == identityId))) }) - .Where(x => - userRoles.Contains(x.Role.UserRoleText) || - x.IsAssigned || - x.IsAssignable) + // x.IsRequested && x.IsAssigned && x.IsAssignable || // no change but required to detect duplicates + // x.IsRequested && !x.IsAssigned && x.IsAssignable || // to be assigned + // !x.IsRequested && x.IsAssigned || // to be unassigned + // x.IsRequested && !x.IsAssignable // invalid + // can be simplified to: + .Where(x => x.IsRequested || x.IsAssigned) .Select(x => new UserRoleModificationData( x.Role.UserRoleText, x.Role.Id, @@ -299,6 +302,7 @@ public IAsyncEnumerable GetRolesForClient(string technicalUserProfileClien x.Active ? x.Roles.Select(role => new ActiveAppRoleDetails( + role.Id, role.UserRoleText, role.UserRoleDescriptions.Where(description => (languageShortName != null && description.LanguageShortName == languageShortName) || @@ -325,6 +329,7 @@ public IAsyncEnumerable GetRolesForClient(string technicalUserProfileClien x.Provider ? x.Roles.Select(role => new ActiveAppRoleDetails( + role.Id, role.UserRoleText, role.UserRoleDescriptions.Where(description => (languageShortName != null && description.LanguageShortName == languageShortName) || diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/companies.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/companies.json index 77ad96b823..764213b56b 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/companies.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/companies.json @@ -7,6 +7,6 @@ "shortname": "Catena-X", "company_status_id": 2, "address_id": "b4db3945-19a7-4a50-97d6-e66e8dfd04fb", - "self_description_document_id": null + "self_description_document_id": "00000000-0000-0000-0000-000000000009" } ] \ No newline at end of file diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/documents.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/documents.json index 7940cb8cb5..bde3e1621f 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/documents.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/documents.json @@ -97,5 +97,17 @@ "document_hash": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", "document_content": "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MDAwMDAwMDkzMyAwMDAwMCBuIAowMDAwMDExNzI2IDAwMDAwIG4gCjAwMDAwMTQ1NTggMDAwMDAgbiAKMDAwMDAxNTA2NiAwMDAwMCBuIAowMDAwMDE0NzcwIDAwMDAwIG4gCjAwMDAwMTUzMDIgMDAwMDAgbiAKMDAwMDAyMjcyMyAwMDAwMCBuIAowMDAwMDIyMzQ0IDAwMDAwIG4gCjAwMDAwMjI5NTkgMDAwMDAgbiAKMDAwMDAzMzI4NSAwMDAwMCBuIAowMDAwMDMyOTc4IDAwMDAwIG4gCjAwMDAwMzM1MjEgMDAwMDAgbiAKMDAwMDA0MDk5MiAwMDAwMCBuIAowMDAwMDQwNjM3IDAwMDAwIG4gCjAwMDAwNDEyMjggMDAwMDAgbiAKMDAwMDA0OTg5MyAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDMwIC9Sb290IDE2IDAgUiAvSW5mbyAyOSAwIFIgL0lEIFsgPDQzZjZkMjJmYzFiM2NiZjk1MDhjNTliMWE0NjViYTdjPgo8NDNmNmQyMmZjMWIzY2JmOTUwOGM1OWIxYTQ2NWJhN2M+IF0gPj4Kc3RhcnR4cmVmCjUwMTEwCiUlRU9GCg==", "document_status_id": 2 + }, + { + "id": "00000000-0000-0000-0000-000000000009", + "date_created": "2024-01-01T19:29:08.602237+00:00", + "document_name": "SelfDescription_LegalPerson.json", + "media_type_id": 7, + "document_type_id": 8, + "company_user_id": null, + "document_hash": "81a212e6bc3121779f67abfefe7b586240c094412760a1faeb05ae2d4a30de5a781217cdf1be8b21416861819fa15d306fcb5bc62c62044f673d649e569a1dbb", + "document_content": "ewogICJzZWxmRGVzY3JpcHRpb25DcmVkZW50aWFsIjogewogICAgIkxlZ2FsUGVyc29uIjogewogICAgICAiQGNvbnRleHQiOiBbCiAgICAgICAgImh0dHBzOi8vY2FybGEuZGloLWNsb3VkLmNvbS9kZXYvY29tcGxpYW5jZV9zZXJ2aWNlL2NvbnRleHQtanNvbi9jcmVkZW50aWFsc192MV9jb250ZXh0Lmpzb24iLAogICAgICAgICJodHRwczovL2YxYzgyNzg1LTU1OTgtNDFjNy1hMDgzLTAxYThlMWE4MGUxOS5tb2NrLnBzdG1uLmlvL2N0eHNkIgogICAgICBdLAogICAgICAidHlwZSI6IFsKICAgICAgICAiVmVyaWZpYWJsZUNyZWRlbnRpYWwiCiAgICAgIF0sCiAgICAgICJpZCI6ICJodHRwczovL2NhcmxhLmRpaC1jbG91ZC5jb20vdGVzdC9jb21wbGlhbmNlX3NlcnZpY2UvcGFydGljaXBhbnQvQlBOTDAwMDAwMDAzQ1JIS19wYXJ0aWNpcGFudC5qc29uIiwKICAgICAgImNyZWRlbnRpYWxTdWJqZWN0IjogewogICAgICAgICJ0eXBlIjogIkxlZ2FsUGFydGljaXBhbnQiLAogICAgICAgICJicG4iOiAiQlBOTDAwMDAwMDAzQ1JISyIsCiAgICAgICAgInJlZ2lzdHJhdGlvbk51bWJlciI6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgInR5cGUiOiAidmF0SUQiLAogICAgICAgICAgICAidmFsdWUiOiAiREUwMDAwMDAwMDAiCiAgICAgICAgICB9CiAgICAgICAgXSwKICAgICAgICAiaGVhZHF1YXJ0ZXJBZGRyZXNzIjogewogICAgICAgICAgImNvdW50cnlDb2RlIjogIkRFIgogICAgICAgIH0sCiAgICAgICAgImxlZ2FsQWRkcmVzcyI6IHsKICAgICAgICAgICJjb3VudHJ5Q29kZSI6ICJERSIKICAgICAgICB9LAogICAgICAgICJpZCI6ICJCUE5MMDAwMDAwMDNDUkhLIgogICAgICB9LAogICAgICAiaXNzdWVyIjogImRpZDp3ZWI6b25seV90ZXN0IiwKICAgICAgImlzc3VhbmNlRGF0ZSI6ICIyMDI0LTA0LTI0VDEwOjI1OjQ4WiIsCiAgICAgICJwcm9vZiI6IHsKICAgICAgICAidHlwZSI6ICJKc29uV2ViU2lnbmF0dXJlMjAyMCIsCiAgICAgICAgImNyZWF0ZWQiOiAiMjAyNC0wNC0yNFQxMDoyNTo0OS43MTFaIiwKICAgICAgICAicHJvb2ZQdXJwb3NlIjogImFzc2VydGlvbk1ldGhvZCIsCiAgICAgICAgImp3cyI6ICJleUpoYkdjaU9pSlFVekkxTmlJc0ltSTJOQ0k2Wm1Gc2MyVXNJbU55YVhRaU9sc2lZalkwSWwxOS4uOGFzZm10VnpmWDQ0OHdtUy16SmZfZ190dF9XZFF0eXREcU1LSDNpNU1xU2drZ1Q4eWhLVUxOYzQ2d3dDbnJoZUk5cGRLUGNmZnJoRTVpeHV0WTZ5MV9UYW5hbEJrTk9GTUN3Sjl6VVFtR0FSamcxTE1kMXNPUnZGR3dyanBwOVUtSHlmWEJQT1BIVUJhelJGNVJjLVZyWmZVTGJGbEpNb05mdnV3UTRhejlzazhhdTZleDJLUnppSnVUWVlDUU43M2s1YTNES3hjNEQ2V09VYmJKWGZub3FLMkhEWDBtRzNZTm1sWHA4UEFjN0R2MXFyV1QyR1QzazlRTDB3OFE3QzByQ29zcDdVMnBiZVdpVUZjQTFYUTFucmg1MF9ScHNCbVprMDhCMkVSdEdvaDlhUTFkUGxLdThXQjRDcHZMLVJVWmEtek5mYUFOYlFEY3BoRFVhNEFBdDRrcHo2WlRlQm4zQUxFbWJLcW53Vk1ZU3VHMUpDOFphZkxRSWo5b1IzWS04Z3V6S3RQYTgwa3JJUTBQekZEbnZrVjQ4WjZqTFNRYm5TVDZrWXczVlFMYVF2TGpWYkFTZzBvZUlrTUFRQ250MjdmRTZYZFlobFVxSENxSDZodk5JZko4c0h6VTNTcUstUDdiWmJVSkhmS3pLY0tENVV4eHdwcHBFalBYN0U2clAtenJ1dERBejdEREdMNWo1THpEQjczcXNFbmk3amhWN3pCOTEzdS13bTItcFZPc0RuaDVQUnQ4Y00yZXlKT011Y1M3TE4tQ21mTTctWDk5UVZ5cXBKTURTcFk0YkZhQUoycTJhZjNwUllZV1hLQzh0bmdFZ3l6ek5qbHBHYm5XM19IQmFiYVpPZWF0b3ctOGFmYW0ydTdJWjlmbEJnSGJlTnRraEtrMWciLAogICAgICAgICJ2ZXJpZmljYXRpb25NZXRob2QiOiAiZGlkOndlYjpvbmx5X3Rlc3QiCiAgICAgIH0KICAgIH0KICB9LAogICJjb21wbGlhbmNlQ3JlZGVudGlhbCI6IHsKICAgICJAY29udGV4dCI6IFsKICAgICAgImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIiwKICAgICAgImh0dHBzOi8vZ3gtcmVnaXN0cnkudGVzdC5kaWgtY2xvdWQuY29tL3YxL2FwaS90cnVzdGVkLXNoYXBlLXJlZ2lzdHJ5L3YxL3NoYXBlcy9qc29ubGQvdHJ1c3RmcmFtZXdvcmsjIgogICAgXSwKICAgICJ0eXBlIjogWwogICAgICAiVmVyaWZpYWJsZUNyZWRlbnRpYWwiCiAgICBdLAogICAgImlkIjogImh0dHBzOi8vY2FybGEuZGloLWNsb3VkLmNvbS90ZXN0L2NvbXBsaWFuY2Vfc2VydmljZS9jcmVkZW50aWFsL0JQTkwwMDAwMDAwM0NSSEtfcGFydGljaXBhbnQuanNvbiIsCiAgICAiY3JlZGVudGlhbFN1YmplY3QiOiBbCiAgICAgIHsKICAgICAgICAidHlwZSI6ICJneDpjb21wbGlhbmNlIiwKICAgICAgICAiaWQiOiAiQlBOTDAwMDAwMDAzQ1JISyIsCiAgICAgICAgImludGVncml0eSI6ICJzaGEyNTYtZDhlZWEzOTlkODAxNzkwMWJlNzk5MGQ1YmU1YTU1ODA5NzlhOGI4OWQ2NWMxZWIzODk5NzU2MGNlNzU2OTFmZCIKICAgICAgfQogICAgXSwKICAgICJpc3N1ZXIiOiAiZGlkOndlYjpvbmx5X3Rlc3QiLAogICAgImlzc3VhbmNlRGF0ZSI6ICIyMDI0LTA0LTI0VDEwOjI1OjUxLjE1MloiLAogICAgImV4cGlyYXRpb25EYXRlIjogIjIwMjUtMDQtMjRUMTA6MjU6NTEuMTUyWiIsCiAgICAicHJvb2YiOiB7CiAgICAgICJ0eXBlIjogIkpzb25XZWJTaWduYXR1cmUyMDIwIiwKICAgICAgImNyZWF0ZWQiOiAiMjAyNC0wNC0yNFQxMDoyNTo1MS4zNzNaIiwKICAgICAgInByb29mUHVycG9zZSI6ICJhc3NlcnRpb25NZXRob2QiLAogICAgICAiandzIjogImV5SmhiR2NpT2lKUVV6STFOaUlzSW1JMk5DSTZabUZzYzJVc0ltTnlhWFFpT2xzaVlqWTBJbDE5Li43SXFTNjZoVDhFbjdqZ2U3LUx4dHIxSFZJTHFCSzlUdjJFUEltdWFsTzhEQ1V6dnBVbHlKaTlncVJiNFhDTkMxanl3Slc5ZEwxR1lxUFRQSTJkZG1KSUhGd20zNmREeVlJWHVwdG42VS0zWFEtRGhUYjVkYXBGOFNyQnRFdUJMakNfQnNTR2ZEdXpMUWdXSDdKb0ZkVmJIX2FLZ0Joa3lrSTZRU2xCbGpILXFWSVZadFBPMkVCQzlHQWFCaHpVVmE3RFBxY1hudUcwQVliN0dYNnBmZDdzZ2lNQjdoeWFPZ3lpaG42eFZxR0c5WFk0Nk50b3dxUkZHZGNMQ0pQZ05iSXlmOGdyVHZNSXRaWUJ3N2ppMlJtcWVjR1pXd0Roc2g3Y3RUcDMzdkNkNHFYeEZuU1ZpbFNUY29lOUJDa1llNnlmSDBvdlZPeHJlY2duNXBXME54aDNreEJmX0tselF3bEhfVktCSHhEWjl3ckV1eHI5VE1fZFVDWlhHOFVyOHRPaENhNzNaMklmUXpsaFhMTENZbm1BclY2bl81UGNVZmZjMTBVMk5Ca1hPY0tEVEx1WGg2N3RhNVVxLVoyT2hnS3JIWEt3SXI4aDdtcm9ncXcwMllTSFNSOW1xNXNEdFNMcU9ZTEVHdEFDdC1ycW1Dc3I2VHhIMUduMnR5ZlQxTWZNSUJKSktQT1drRVA1UUhuUnc5Tk4zOE1hN25vVWN0VlQ3N1ExV25wU0NlNlNuTDQyV1p6WUVZbEdpd3VsRFBoTjQ4S3JiM1hRNk1TLWdmSmRmZkJjZFRIeFVPcW9wTW1XdU5sYjd1VHhDaVZJSzl5QVJGOU1NSXZvel9XUm54QWd0aGYtLVphQmoyMVhQLW0xWXVrd1VrUkU3endQTXR1MkgxOFFsVXZxVSIsCiAgICAgICJ2ZXJpZmljYXRpb25NZXRob2QiOiAiZGlkOndlYjpvbmx5X3Rlc3QiCiAgICB9CiAgfQp9", + "document_status_id": 2, + "last_editor_id": "7e85a0b8-0001-ab67-10d1-0ef508201027" } ] \ No newline at end of file diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json index 3402e881ac..228e7a5064 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json @@ -182,5 +182,21 @@ { "user_role_collection_id": "1a24eca5-901f-4191-84a7-4ef09a894575", "user_role_id": "ec3a3005-b59c-4319-a8eb-3228984cd6e5" + }, + { + "user_role_collection_id": "ec428950-8b64-4646-b336-28af869b5d73", + "user_role_id": "a6b6a5b6-d7fe-42af-94ce-35c16b3ae128" + }, + { + "user_role_collection_id": "ec428950-8b64-4646-b336-28af869b5d73", + "user_role_id": "9956fa8d-e454-49ca-a3b1-45e2c106fe59" + }, + { + "user_role_collection_id": "a5b8b1de-7759-4620-9c87-6b6d74fb4fbc", + "user_role_id": "a6b6a5b6-d7fe-42af-94ce-35c16b3ae128" + }, + { + "user_role_collection_id": "a5b8b1de-7759-4620-9c87-6b6d74fb4fbc", + "user_role_id": "9956fa8d-e454-49ca-a3b1-45e2c106fe59" } ] diff --git a/src/portalbackend/PortalBackend.PortalEntities/Enums/DocumentTypeId.cs b/src/portalbackend/PortalBackend.PortalEntities/Enums/DocumentTypeId.cs index 783ae56c77..104d52dc7e 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Enums/DocumentTypeId.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Enums/DocumentTypeId.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/processes/DimUserCreationProcess.Executor/DimUserCreationProcessService.cs b/src/processes/DimUserCreationProcess.Executor/DimUserCreationProcessService.cs index 4dd361e0a1..3a1c589c03 100644 --- a/src/processes/DimUserCreationProcess.Executor/DimUserCreationProcessService.cs +++ b/src/processes/DimUserCreationProcess.Executor/DimUserCreationProcessService.cs @@ -33,7 +33,7 @@ public class DimUserCreationProcessService( public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateDimUser(Guid processId, Guid dimServiceAccountId, CancellationToken cancellationToken) { var serviceAccountRepository = portalRepositories.GetInstance(); - var (isValid, bpn, clientClientId) = await serviceAccountRepository.GetDimServiceAccountData(dimServiceAccountId) + var (isValid, bpn, name) = await serviceAccountRepository.GetDimServiceAccountData(dimServiceAccountId) .ConfigureAwait(ConfigureAwaitOptions.None); if (!isValid) @@ -46,12 +46,13 @@ public class DimUserCreationProcessService( throw new ConflictException("Bpn must not be null"); } - if (string.IsNullOrWhiteSpace(clientClientId)) + if (string.IsNullOrWhiteSpace(name)) { - throw new ConflictException("Service Account Name must not be null"); + throw new ConflictException("Service Account Name must not be empty"); } - await dimService.CreateTechnicalUser(bpn, new TechnicalUserData(processId, $"dim-{clientClientId}"), cancellationToken).ConfigureAwait(false); + var dimName = string.Concat(name.Where(c => !char.IsWhiteSpace(c))); // DIM doesn't accept whitespace chars in name + await dimService.CreateTechnicalUser(bpn, new TechnicalUserData(processId, dimName), cancellationToken).ConfigureAwait(false); return (Enumerable.Repeat(ProcessStepTypeId.AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE, 1), ProcessStepStatusId.DONE, true, null); } } diff --git a/src/processes/Invitation.Executor/DependencyInjection/InvitationSettings.cs b/src/processes/Invitation.Executor/DependencyInjection/InvitationSettings.cs index e830f942ec..1c247b74b6 100644 --- a/src/processes/Invitation.Executor/DependencyInjection/InvitationSettings.cs +++ b/src/processes/Invitation.Executor/DependencyInjection/InvitationSettings.cs @@ -46,6 +46,9 @@ public class InvitationSettings [Required] [DistinctValues("x => x.Index")] public IEnumerable EncryptionConfigs { get; set; } = null!; + + [Required(AllowEmptyStrings = false)] + public string CloseApplicationAddress { get; set; } = null!; } public static class InvitationSettingsExtension diff --git a/src/processes/Invitation.Executor/InvitationProcessService.cs b/src/processes/Invitation.Executor/InvitationProcessService.cs index e98516589a..a2323af1b9 100644 --- a/src/processes/Invitation.Executor/InvitationProcessService.cs +++ b/src/processes/Invitation.Executor/InvitationProcessService.cs @@ -360,6 +360,7 @@ await _idpManagement KeyValuePair.Create("companyName", companyName), KeyValuePair.Create("url", _settings.RegistrationAppAddress), KeyValuePair.Create("passwordResendUrl", _settings.PasswordResendAddress), + KeyValuePair.Create("closeApplicationUrl", _settings.CloseApplicationAddress) }); _mailingProcessCreation.CreateMailProcess(userInformation.Email, template, mailParameters); } diff --git a/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs b/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs index 16ecb5ef80..3487a64d48 100644 --- a/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs +++ b/src/processes/Processes.Worker.Library/IProcessTypeExecutor.cs @@ -1,5 +1,4 @@ /******************************************************************************** - * Copyright (c) 2022 Microsoft and BMW Group AG * Copyright (c) 2022 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional @@ -18,7 +17,6 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; namespace Org.Eclipse.TractusX.Portal.Backend.Processes.Worker.Library; diff --git a/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs b/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs index 4cfb8c5708..53f117c01e 100644 --- a/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs +++ b/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs @@ -59,30 +59,36 @@ public class ServiceAccountCreation( var userRolesRepository = portalRepositories.GetInstance(); var userRoleData = await GetAndValidateUserRoleData(userRolesRepository, userRoleIds).ConfigureAwait(ConfigureAwaitOptions.None); - var serviceAccounts = ImmutableList.CreateBuilder(); + var dimConfigRoles = _settings.DimUserRoles.SelectMany(x => x.UserRoleNames.Select(userRoleName => (x.ClientId, userRoleName))); - var (clientId, enhancedName, serviceAccountData) = await CreateKeycloakServiceAccount(bpns, enhanceTechnicalUserName, enabled, name, description, iamClientAuthMethod, userRoleData).ConfigureAwait(ConfigureAwaitOptions.None); - var serviceAccountId = CreateDatabaseServiceAccount(companyId, UserStatusId.ACTIVE, companyServiceAccountTypeId, CompanyServiceAccountKindId.INTERNAL, name, clientId, description, userRoleData, serviceAccountsRepository, userRolesRepository, setOptionalParameter); - serviceAccounts.Add(new CreatedServiceAccountData( - serviceAccountId, - enhancedName, - description, - UserStatusId.ACTIVE, - clientId, - serviceAccountData, - userRoleData)); + var serviceAccounts = ImmutableList.CreateBuilder(); - var dimRoles = userRoleData - .Join(_settings.DimUserRoles, data => data.ClientClientId, config => config.ClientId, - (data, config) => new { data, config }) - .Where(@t => t.config.UserRoleNames.Contains(@t.data.UserRoleText)) - .Select(@t => t.data) - .ToImmutableList(); + if (userRoleData.ExceptBy(dimConfigRoles, roleData => (roleData.ClientClientId, roleData.UserRoleText)).IfAny( + async roleData => + { + var keycloakRoleData = roleData.ToImmutableList(); + var (clientId, enhancedName, serviceAccountData) = await CreateKeycloakServiceAccount(bpns, enhanceTechnicalUserName, enabled, name, description, iamClientAuthMethod, keycloakRoleData).ConfigureAwait(ConfigureAwaitOptions.None); + var serviceAccountId = CreateDatabaseServiceAccount(companyId, UserStatusId.ACTIVE, companyServiceAccountTypeId, CompanyServiceAccountKindId.INTERNAL, name, clientId, description, keycloakRoleData, serviceAccountsRepository, userRolesRepository, setOptionalParameter); + serviceAccounts.Add(new CreatedServiceAccountData( + serviceAccountId, + enhancedName, + description, + UserStatusId.ACTIVE, + clientId, + serviceAccountData, + keycloakRoleData)); + }, + out var keycloakRolesTask)) + { + await keycloakRolesTask!.ConfigureAwait(ConfigureAwaitOptions.None); + } - var hasExternalServiceAccount = dimRoles.IfAny(roles => + var hasExternalServiceAccount = userRoleData.IntersectBy(dimConfigRoles, roleData => (roleData.ClientClientId, roleData.UserRoleText)).IfAny( + roleData => { + var dimRoleData = roleData.ToImmutableList(); var dimSaName = $"dim-{name}"; - var dimServiceAccountId = CreateDatabaseServiceAccount(companyId, UserStatusId.PENDING, companyServiceAccountTypeId, CompanyServiceAccountKindId.EXTERNAL, dimSaName, null, description, roles, serviceAccountsRepository, userRolesRepository, setOptionalParameter); + var dimServiceAccountId = CreateDatabaseServiceAccount(companyId, UserStatusId.PENDING, companyServiceAccountTypeId, CompanyServiceAccountKindId.EXTERNAL, dimSaName, null, description, dimRoleData, serviceAccountsRepository, userRolesRepository, setOptionalParameter); var processStepRepository = portalRepositories.GetInstance(); if (processData?.ProcessTypeId is not null) { @@ -98,7 +104,7 @@ public class ServiceAccountCreation( processId = processData.ProcessId.Value; } - portalRepositories.GetInstance().CreateDimUserCreationData(serviceAccountId, processId); + portalRepositories.GetInstance().CreateDimUserCreationData(dimServiceAccountId, processId); } serviceAccounts.Add(new CreatedServiceAccountData( @@ -108,7 +114,7 @@ public class ServiceAccountCreation( UserStatusId.PENDING, null, null, - roles)); + dimRoleData)); }); return (hasExternalServiceAccount, serviceAccounts.ToImmutable()); diff --git a/src/registration/Registration.Service/appsettings.json b/src/registration/Registration.Service/appsettings.json index bb32ceaa5a..edff4031b9 100644 --- a/src/registration/Registration.Service/appsettings.json +++ b/src/registration/Registration.Service/appsettings.json @@ -63,7 +63,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Provisioning": { diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs index 10f32a29a4..090d0cb93a 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs @@ -192,14 +192,14 @@ public async Task GetCompanyWithAddressAsync_WithDefaultRequest_GetsExpectedResu .With(x => x.AgreementsData, _fixture.CreateMany(20)) .With(x => x.CompanyIdentifiers, Enumerable.Repeat(new ValueTuple(identifierIdType, companyUniqueIds), 1)) .Create(); - A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId)) + A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(A._, A>._)) .Returns(data); // Act var result = await _logic.GetCompanyWithAddressAsync(applicationId); // Assert - A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId, _options.Value.DocumentTypeIds)).MustHaveHappenedOnceExactly(); result.Should().BeOfType(); result.Should().Match(r => r.CompanyId == data.CompanyId && @@ -238,14 +238,14 @@ public async Task GetCompanyWithAddressAsync_WithDefaultRequest_GetsExpectedResu .With(x => x.CountryDe, default(string?)) .With(x => x.InvitedCompanyUserData, _fixture.CreateMany().Select(id => new InvitedCompanyUserData(id, null, null, null))) .Create(); - A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId)) + A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(A._, A>._)) .Returns(data); // Act var result = await _logic.GetCompanyWithAddressAsync(applicationId); // Assert - A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _applicationRepository.GetCompanyUserRoleWithAddressUntrackedAsync(applicationId, _options.Value.DocumentTypeIds)).MustHaveHappenedOnceExactly(); result.Should().BeOfType(); result.Should().Match(r => r.CompanyId == data.CompanyId && diff --git a/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json b/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json index 4fac7a9735..632ec19dfa 100644 --- a/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/administration/Administration.Service.Tests/appsettings.IntegrationTests.json @@ -40,7 +40,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Provisioning": { diff --git a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs index d92dfe3f3a..0ffc884c67 100644 --- a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs +++ b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs @@ -1192,10 +1192,12 @@ public async Task GetActiveAppRolesAsync_ReturnsExpected() { // Arrange var appId = _fixture.Create(); - var userRole1 = new ActiveAppRoleDetails("TestRole1", [ + var roleId1 = _fixture.Create(); + var roleId2 = _fixture.Create(); + var userRole1 = new ActiveAppRoleDetails(roleId1, "TestRole1", [ new ActiveAppUserRoleDescription("en", "TestRole1 description") ]); - var userRole2 = new ActiveAppRoleDetails("TestRole2", [ + var userRole2 = new ActiveAppRoleDetails(roleId2, "TestRole2", [ new ActiveAppUserRoleDescription("en", "TestRole2 description") ]); var activeAppRoleDetails = (true, true, new[] { @@ -1212,8 +1214,8 @@ public async Task GetActiveAppRolesAsync_ReturnsExpected() // Assert result.Should().HaveCount(2) .And.Satisfy( - x => x.Role == "TestRole1" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole1 description", - x => x.Role == "TestRole2" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole2 description"); + x => x.RoleId == roleId1 && x.Role == "TestRole1" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole1 description", + x => x.RoleId == roleId2 && x.Role == "TestRole2" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole2 description"); A.CallTo(() => _userRolesRepository.GetActiveOfferRolesAsync(appId, OfferTypeId.APP, "de", "en")) .MustHaveHappenedOnceExactly(); } diff --git a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppReleaseBusinessLogicTest.cs b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppReleaseBusinessLogicTest.cs index d8e1802e67..436180017d 100644 --- a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppReleaseBusinessLogicTest.cs +++ b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppReleaseBusinessLogicTest.cs @@ -1252,10 +1252,12 @@ public async Task GetAppProviderRolesAsync_ReturnsExpected() { // Arrange var appId = _fixture.Create(); - var userRole1 = new ActiveAppRoleDetails("TestRole1", [ + var roleId1 = _fixture.Create(); + var roleId2 = _fixture.Create(); + var userRole1 = new ActiveAppRoleDetails(roleId1, "TestRole1", [ new ActiveAppUserRoleDescription("en", "TestRole1 description") ]); - var userRole2 = new ActiveAppRoleDetails("TestRole2", [ + var userRole2 = new ActiveAppRoleDetails(roleId2, "TestRole2", [ new ActiveAppUserRoleDescription("en", "TestRole2 description") ]); var activeAppRoleDetails = (true, true, new[] { @@ -1272,8 +1274,8 @@ public async Task GetAppProviderRolesAsync_ReturnsExpected() // Assert result.Should().HaveCount(2) .And.Satisfy( - x => x.Role == "TestRole1" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole1 description", - x => x.Role == "TestRole2" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole2 description"); + x => x.RoleId == roleId1 && x.Role == "TestRole1" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole1 description", + x => x.RoleId == roleId2 && x.Role == "TestRole2" && x.Descriptions.Count() == 1 && x.Descriptions.Single().Description == "TestRole2 description"); A.CallTo(() => _userRolesRepository.GetOfferProviderRolesAsync(appId, OfferTypeId.APP, _identity.CompanyId, "de", "en")) .MustHaveHappenedOnceExactly(); } diff --git a/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json b/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json index bc1fa85148..1f00b30b42 100644 --- a/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json @@ -28,7 +28,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "ConnectionStrings": { diff --git a/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json b/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json index 34444dda34..a697823515 100644 --- a/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/marketplace/Services.Service.Tests/appsettings.IntegrationTests.json @@ -28,7 +28,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "ConnectionStrings": { diff --git a/tests/notifications/Notifications.Service.Tests/appsettings.IntegrationTests.json b/tests/notifications/Notifications.Service.Tests/appsettings.IntegrationTests.json index b4dc0a8f24..c059467684 100644 --- a/tests/notifications/Notifications.Service.Tests/appsettings.IntegrationTests.json +++ b/tests/notifications/Notifications.Service.Tests/appsettings.IntegrationTests.json @@ -55,7 +55,7 @@ "ValidAudience": "", "ValidateAudience": true, "ValidateLifetime": true, - "ClockSkew": 600000 + "ClockSkew": "00:05:00" } }, "Notifications": { diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs index 1653cf0df5..f8db8b2c39 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs @@ -18,6 +18,7 @@ ********************************************************************************/ using Microsoft.EntityFrameworkCore; +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; @@ -55,7 +56,7 @@ public async Task GetCompanyUserRoleWithAddressUntrackedAsync_WithExistingEntry_ // Act var result = await sut - .GetCompanyUserRoleWithAddressUntrackedAsync(new Guid("4f0146c6-32aa-4bb1-b844-df7e8babdcb2")); + .GetCompanyUserRoleWithAddressUntrackedAsync(new Guid("4f0146c6-32aa-4bb1-b844-df7e8babdcb2"), [DocumentTypeId.ADDITIONAL_DETAILS]); // Assert result.Should().NotBeNull(); @@ -76,10 +77,14 @@ public async Task GetCompanyUserRoleWithAddressUntrackedAsync_WithExistingEntry_ result.AgreementsData.Where(x => x.CompanyRoleId == CompanyRoleId.APP_PROVIDER).Should().HaveCount(1); result.AgreementsData.Where(x => x.CompanyRoleId == CompanyRoleId.ACTIVE_PARTICIPANT).Should().HaveCount(3); - result.InvitedCompanyUserData.Should().BeEmpty(); + result.InvitedCompanyUserData.Should().ContainSingle() + .Which.Should().Match(x => x.UserId == new Guid("8b42e6de-7b59-4217-a63c-198e83d93776") && x.FirstName == "First" && x.LastName == "User" && x.Email == "test@email.com"); - result.CompanyIdentifiers.Should().HaveCount(1); - result.CompanyIdentifiers.First().Should().Match<(UniqueIdentifierId UniqueIdentifierId, string Value)>(identifier => identifier.UniqueIdentifierId == UniqueIdentifierId.VAT_ID && identifier.Value == "DE123456789"); + result.CompanyIdentifiers.Should().ContainSingle() + .Which.Should().Match<(UniqueIdentifierId UniqueIdentifierId, string Value)>(identifier => identifier.UniqueIdentifierId == UniqueIdentifierId.VAT_ID && identifier.Value == "DE123456789"); + + result.DocumentData.Should().ContainSingle() + .Which.Should().Match<(Guid DocumentId, DocumentTypeId DocumentTypeId)>(x => x.DocumentId == new Guid("ec12dc7e-a8fa-4aa5-945a-f7e64be30841") && x.DocumentTypeId == DocumentTypeId.ADDITIONAL_DETAILS); } #endregion GetRegistrationDataUntrackedAsync diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs index 65f77cddcc..5017cb887e 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs @@ -45,7 +45,7 @@ public async Task CompanyRoleCollectionRolesView_GetAll_ReturnsExpected() // Act var result = await sut.CompanyRoleCollectionRolesView.ToListAsync(); - result.Should().HaveCount(46); + result.Should().HaveCount(50); } [Fact] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/documents.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/documents.test.json index ea83ba55e9..12b413e172 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/documents.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/documents.test.json @@ -141,5 +141,27 @@ "document_hash": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", "document_content": "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", "document_status_id": 2 + }, + { + "id": "ec12dc7e-a8fa-4aa5-945a-f7e64be30841", + "date_created": "2023-10-08T08:00:00.000000+00:00", + "document_name": "ApplicationDetails.pdf", + "media_type_id": 6, + "document_type_id": 5, + "company_user_id": "8b42e6de-7b59-4217-a63c-198e83d93776", + "document_hash": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", + "document_content": "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", + "document_status_id": 2 + }, + { + "id": "ec12dc7e-a8fa-4aa5-945a-f7e64be30842", + "date_created": "2023-10-08T08:00:00.000000+00:00", + "document_name": "OtherCertificate.pdf", + "media_type_id": 6, + "document_type_id": 15, + "company_user_id": "8b42e6de-7b59-4217-a63c-198e83d93776", + "document_hash": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", + "document_content": "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", + "document_status_id": 2 } ] \ No newline at end of file diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/invitations.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/invitations.test.json index c0e1e7fd58..81a6a65e60 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/invitations.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/invitations.test.json @@ -26,5 +26,12 @@ "invitation_status_id": 1, "company_application_id": "6b2d1263-c073-4a48-bfaf-704dc154ca9e", "company_user_id": "1dceacb8-c5a5-4573-a77d-e2487ac4a8aa" + }, + { + "id": "e92b54ed-fbbe-4259-9747-efd8613ce61f", + "date_created": "2022-03-24 18:01:33.439000 +00:00", + "invitation_status_id": 1, + "company_application_id": "4f0146c6-32aa-4bb1-b844-df7e8babdcb2", + "company_user_id": "8b42e6de-7b59-4217-a63c-198e83d93776" } ] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs index c8ef51116c..524cec69bf 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs @@ -229,8 +229,8 @@ public async Task GetActiveOfferRolesAsync_ActiveApp_ReturnsExpected() data.IsActive.Should().BeTrue(); data.AppRoleDetails.Should().HaveCount(2) .And.Satisfy( - x => x.Role == "EarthCommerce.AdministratorRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"), - x => x.Role == "EarthCommerce.Advanced.BuyerRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en")); + x => x.RoleId == new Guid("efc20368-9e82-46ff-b88f-6495b9810253") && x.Role == "EarthCommerce.AdministratorRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"), + x => x.RoleId == new Guid("aabcdfeb-6669-4c74-89f0-19cda090873f") && x.Role == "EarthCommerce.Advanced.BuyerRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en")); } #endregion @@ -281,8 +281,8 @@ public async Task GetOfferProviderRolesAsync_ValidAppAndProvider_ReturnsExpected data.IsProvider.Should().BeTrue(); data.AppRoleDetails.Should().HaveCount(2) .And.Satisfy( - x => x.Role == "EarthCommerce.AdministratorRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"), - x => x.Role == "EarthCommerce.Advanced.BuyerRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en")); + x => x.RoleId == new Guid("efc20368-9e82-46ff-b88f-6495b9810253") && x.Role == "EarthCommerce.AdministratorRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en"), + x => x.RoleId == new Guid("aabcdfeb-6669-4c74-89f0-19cda090873f") && x.Role == "EarthCommerce.Advanced.BuyerRC_QAS2" && x.Descriptions.Count() == 2 && x.Descriptions.Any(x => x.LanguageCode == "de") && x.Descriptions.Any(x => x.LanguageCode == "en")); } #endregion diff --git a/tests/processes/DimUserCreationProcess.Executor.Tests/DimUserCreationProcessServiceTests.cs b/tests/processes/DimUserCreationProcess.Executor.Tests/DimUserCreationProcessServiceTests.cs index f64e7fb518..39a8a4e843 100644 --- a/tests/processes/DimUserCreationProcess.Executor.Tests/DimUserCreationProcessServiceTests.cs +++ b/tests/processes/DimUserCreationProcess.Executor.Tests/DimUserCreationProcessServiceTests.cs @@ -60,9 +60,9 @@ public async Task CreateDimUser_WithValid_ReturnsExpected() // Arrange var dimServiceAccountId = Guid.NewGuid(); var processId = Guid.NewGuid(); - var expectedServiceAccountName = "dim-sa-test"; + var expectedServiceAccountName = "dim-sa-testFooBar"; A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) - .Returns((true, Bpn, "sa-test")); + .Returns((true, Bpn, "dim-sa-test Foo Bar")); // Act var result = await _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None); @@ -86,7 +86,7 @@ public async Task CreateDimUser_WithInvalidDimServiceAccountId_ThrowsNotFoundExc var dimServiceAccountId = Guid.NewGuid(); var processId = Guid.NewGuid(); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) - .Returns(default((bool, string?, string?))); + .Returns(default((bool, string?, string))); Task Act() => _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act @@ -107,7 +107,7 @@ public async Task CreateDimUser_WithBpnNotSet_ThrowsConflictException() var dimServiceAccountId = Guid.NewGuid(); var processId = Guid.NewGuid(); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) - .Returns((true, null, null)); + .Returns((true, null, "foo")); Task Act() => _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act @@ -128,14 +128,14 @@ public async Task CreateDimUser_WithValidMissingServiceAccountName_ThrowsConflic var dimServiceAccountId = Guid.NewGuid(); var processId = Guid.NewGuid(); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(A._)) - .Returns((true, Bpn, null)); + .Returns((true, Bpn, " ")); Task Act() => _sut.CreateDimUser(processId, dimServiceAccountId, CancellationToken.None); // Act var ex = await Assert.ThrowsAsync(Act); // Act - ex.Message.Should().Be("Service Account Name must not be null"); + ex.Message.Should().Be("Service Account Name must not be empty"); A.CallTo(() => _serviceAccountRepository.GetDimServiceAccountData(dimServiceAccountId)) .MustHaveHappenedOnceExactly(); A.CallTo(() => _dimService.CreateTechnicalUser(Bpn, A._, A._)) diff --git a/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs b/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs index 287b3f132a..72213be07a 100644 --- a/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs +++ b/tests/provisioning/Provisioning.Library.Tests/Extensions/ServiceAccountCreationTests.cs @@ -39,15 +39,21 @@ public class ServiceAccountCreationTests private const string Bpn = "CAXSDUMMYCATENAZZ"; private readonly string _iamUserId = Guid.NewGuid().ToString(); private readonly Guid _companyId = Guid.NewGuid(); - private readonly Guid _serviceAccountId = Guid.NewGuid(); private readonly Guid _identityId = Guid.NewGuid(); + private readonly Guid _secondId = Guid.NewGuid(); + private readonly string _validClientId; private readonly Guid _validUserRoleId = Guid.NewGuid(); + private readonly string _dimClient; + private readonly string _dimRoleText; + private readonly Guid _dimUserRoleId = Guid.NewGuid(); private readonly Guid _invalidUserRoleId = Guid.NewGuid(); + private readonly Guid _processId = Guid.NewGuid(); + private readonly Guid _processStepId = Guid.NewGuid(); private readonly IServiceAccountRepository _serviceAccountRepository; private readonly IUserRepository _userRepository; private readonly IUserRolesRepository _userRolesRepository; - + private readonly IProcessStepRepository _processStepRepository; private readonly IProvisioningManager _provisioningManager; private readonly IPortalRepositories _portalRepositories; private readonly IProvisioningDBAccess _provisioningDbAccess; @@ -60,9 +66,14 @@ public ServiceAccountCreationTests() .ForEach(b => fixture.Behaviors.Remove(b)); fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _validClientId = fixture.Create(); + _dimClient = fixture.Create(); + _dimRoleText = fixture.Create(); + _serviceAccountRepository = A.Fake(); _userRepository = A.Fake(); _userRolesRepository = A.Fake(); + _processStepRepository = A.Fake(); _provisioningManager = A.Fake(); _portalRepositories = A.Fake(); @@ -71,42 +82,57 @@ public ServiceAccountCreationTests() var settings = new ServiceAccountCreationSettings { ServiceAccountClientPrefix = "sa", - DimUserRoles = [new UserRoleConfig("technical_user_management", ["Identity Wallet Management"])] + DimUserRoles = [new UserRoleConfig(_dimClient, [_dimRoleText])] }; A.CallTo(() => _portalRepositories.GetInstance()).Returns(_serviceAccountRepository); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRepository); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRolesRepository); + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_processStepRepository); _sut = new ServiceAccountCreation(_provisioningManager, _portalRepositories, _provisioningDbAccess, Options.Create(settings)); } + private void ServiceAccountCreationAction(CompanyServiceAccount _) { } + [Fact] public async Task CreateServiceAccountAsync_WithInvalidRole_ThrowsNotFoundException() { // Arrange - var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, new[] { _invalidUserRoleId }); + var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, [_invalidUserRoleId]); Setup(); // Act - async Task Act() => await _sut.CreateServiceAccountAsync(creationData, _companyId, Enumerable.Empty(), CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null)); + async Task Act() => await _sut.CreateServiceAccountAsync(creationData, _companyId, Enumerable.Empty(), CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null), ServiceAccountCreationAction); // Assert var ex = await Assert.ThrowsAsync(Act); ex.Message.Should().Be(ProvisioningServiceErrors.USER_NOT_VALID_USERROLEID.ToString()); - A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(A._, A>._)).MustNotHaveHappened(); - A.CallTo(() => _provisioningManager.AddProtocolMapperAsync(A._)).MustNotHaveHappened(); - A.CallTo(() => _userRolesRepository.DeleteCompanyUserAssignedRoles(A>._)).MustNotHaveHappened(); + + A.CallTo(() => _userRepository.CreateIdentity(A._, A._, A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(A._, A._, A._, A._, A._, A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync(A._, A._, A._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.AddProtocolMapperAsync(A._)) + .MustNotHaveHappened(); A.CallTo(() => _portalRepositories.SaveAsync()).MustNotHaveHappened(); } - [Fact] - public async Task CreateServiceAccountAsync_WithValidData_ReturnsExpected() + [Theory] + [InlineData(false, "testName")] + [InlineData(true, "sa1-testName")] + public async Task CreateServiceAccountAsync_WithValidData_ReturnsExpected(bool enhance, string serviceAccountName) { // Arrange var serviceAccounts = new List(); var identities = new List(); - var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, new[] { _validUserRoleId }); + var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, [_validUserRoleId]); var bpns = new[] { Bpn @@ -114,21 +140,64 @@ public async Task CreateServiceAccountAsync_WithValidData_ReturnsExpected() Setup(serviceAccounts, identities); // Act - var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null)); + var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, enhance, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null), ServiceAccountCreationAction); // Assert - result.ServiceAccounts.Should().ContainSingle(); - var serviceAccount = result.ServiceAccounts.Single(); - serviceAccount.UserRoleData.Should().ContainSingle(x => x.UserRoleId == _validUserRoleId && x.UserRoleText == "UserRole"); - serviceAccount.ServiceAccountData.InternalClientId.Should().Be("internal-sa1"); - serviceAccount.ServiceAccountData.IamUserId.Should().Be(_iamUserId); - serviceAccount.ServiceAccountData.AuthData.IamClientAuthMethod.Should().Be(IamClientAuthMethod.SECRET); - A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(_iamUserId, bpns)).MustHaveHappenedOnceExactly(); - A.CallTo(() => _provisioningManager.AddProtocolMapperAsync("internal-sa1")).MustHaveHappenedOnceExactly(); - A.CallTo(() => _portalRepositories.SaveAsync()).MustNotHaveHappened(); + + result.ServiceAccounts.Should().ContainSingle() + .Which.Should().Match(x => + x.ClientId == "sa1" && + x.Description == "abc" && + x.UserRoleData.SequenceEqual(new[] { new UserRoleData(_validUserRoleId, _validClientId, "UserRole") }) && + x.Name == serviceAccountName && + x.ServiceAccountData != null && + x.ServiceAccountData.InternalClientId == "internal-sa1" && + x.ServiceAccountData.IamUserId == _iamUserId && + x.ServiceAccountData.AuthData.IamClientAuthMethod == IamClientAuthMethod.SECRET + ); + + A.CallTo(() => _userRepository.CreateIdentity(_companyId, UserStatusId.ACTIVE, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, null)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_identityId, "testName", "abc", "sa1", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL, ServiceAccountCreationAction)) + .MustHaveHappenedOnceExactly(); + var expectedRolesIds = new[] { (_identityId, _validUserRoleId) }; + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.IsSameSequenceAs(expectedRolesIds))) + .MustHaveHappenedOnceExactly(); + IEnumerable? userRoles; + A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync( + "sa1", + A.That.Matches(x => + x.IamClientAuthMethod == IamClientAuthMethod.SECRET && + x.Name == serviceAccountName && + x.Description == "abc" && + x.ClientRoles.Count() == 1 && + x.ClientRoles.TryGetValue(_validClientId, out userRoles) && + userRoles.SequenceEqual(new[] { "UserRole" })), + true)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(_iamUserId, bpns)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _provisioningManager.AddProtocolMapperAsync("internal-sa1")) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _userRepository.CreateIdentity(A._, UserStatusId.PENDING, A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(A._, A._, A._, A._, A._, CompanyServiceAccountKindId.EXTERNAL, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.Matches(x => x.Any(y => y.Item2 != _validUserRoleId)))) + .MustNotHaveHappened(); + A.CallTo(() => _processStepRepository.CreateProcess(A._)) + .MustNotHaveHappened(); + A.CallTo(() => _processStepRepository.CreateProcessStep(A._, A._, A._)) + .MustNotHaveHappened(); + A.CallTo(() => _serviceAccountRepository.CreateDimUserCreationData(A._, A._)) + .MustNotHaveHappened(); + A.CallTo(() => _portalRepositories.SaveAsync()) + .MustNotHaveHappened(); serviceAccounts.Should().ContainSingle().Which.Should().Match( x => x.Name == "testName" && - x.ClientClientId == "sa1"); + x.ClientClientId == "sa1" && + x.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL); identities.Should().ContainSingle().Which.Should().Match( x => x.CompanyId == _companyId && x.UserStatusId == UserStatusId.ACTIVE && @@ -136,12 +205,12 @@ public async Task CreateServiceAccountAsync_WithValidData_ReturnsExpected() } [Fact] - public async Task CreateServiceAccountAsync_WithNameSetAndValidData_ReturnsExpected() + public async Task CreateServiceAccountAsync_WithValidDimData_ReturnsExpected() { // Arrange var serviceAccounts = new List(); var identities = new List(); - var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, new[] { _validUserRoleId }); + var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, [_dimUserRoleId]); var bpns = new[] { Bpn @@ -149,48 +218,169 @@ public async Task CreateServiceAccountAsync_WithNameSetAndValidData_ReturnsExpec Setup(serviceAccounts, identities); // Act - var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, true, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null)); + var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null), ServiceAccountCreationAction); // Assert - result.ServiceAccounts.Should().ContainSingle(); - var technicalUser = result.ServiceAccounts.Single(); - technicalUser.UserRoleData.Should().ContainSingle(x => x.UserRoleId == _validUserRoleId && x.UserRoleText == "UserRole"); - technicalUser.ServiceAccountData.InternalClientId.Should().Be("internal-sa1"); - technicalUser.ServiceAccountData.IamUserId.Should().Be(_iamUserId); - technicalUser.ServiceAccountData.AuthData.IamClientAuthMethod.Should().Be(IamClientAuthMethod.SECRET); - A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync(A._, A.That.Matches(x => x.Name == "sa1-testName"), A._)).MustHaveHappenedOnceExactly(); - A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(_iamUserId, bpns)).MustHaveHappenedOnceExactly(); - A.CallTo(() => _provisioningManager.AddProtocolMapperAsync("internal-sa1")).MustHaveHappenedOnceExactly(); - A.CallTo(() => _portalRepositories.SaveAsync()).MustNotHaveHappened(); + result.ServiceAccounts.Should().ContainSingle() + .Which.Should().Match(x => + x.ClientId == null && + x.Description == "abc" && + x.UserRoleData.SequenceEqual(new[] { new UserRoleData(_dimUserRoleId, _dimClient, _dimRoleText) }) && + x.Name == "dim-testName" && + x.ServiceAccountData == null && + x.Status == UserStatusId.PENDING + ); + + A.CallTo(() => _userRepository.CreateIdentity(A._, UserStatusId.ACTIVE, A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(A._, A._, A._, A._, A._, CompanyServiceAccountKindId.INTERNAL, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.Matches(x => x.Any(y => y.Item2 != _dimUserRoleId)))) + .MustNotHaveHappened(); + + A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync(A._, A._, A._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(A._, A>._)) + .MustNotHaveHappened(); + A.CallTo(() => _provisioningManager.AddProtocolMapperAsync(A._)) + .MustNotHaveHappened(); + + A.CallTo(() => _userRepository.CreateIdentity(_companyId, UserStatusId.PENDING, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, null)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_identityId, "dim-testName", "abc", null, CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.EXTERNAL, ServiceAccountCreationAction)) + .MustHaveHappenedOnceExactly(); + var expectedRolesIds = new[] { (_identityId, _dimUserRoleId) }; + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.IsSameSequenceAs(expectedRolesIds))) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _processStepRepository.CreateProcess(ProcessTypeId.DIM_TECHNICAL_USER)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _processStepRepository.CreateProcessStep(ProcessStepTypeId.CREATE_DIM_TECHNICAL_USER, ProcessStepStatusId.TODO, A._)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateDimUserCreationData(_identityId, _processId)) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _portalRepositories.SaveAsync()) + .MustNotHaveHappened(); + serviceAccounts.Should().ContainSingle().Which.Should().Match( - x => x.Name == "testName" && - x.ClientClientId == "sa1"); + x => x.Name == "dim-testName" && + x.ClientClientId == null && + x.CompanyServiceAccountKindId == CompanyServiceAccountKindId.EXTERNAL); identities.Should().ContainSingle().Which.Should().Match( x => x.CompanyId == _companyId && - x.UserStatusId == UserStatusId.ACTIVE && + x.UserStatusId == UserStatusId.PENDING && x.IdentityTypeId == IdentityTypeId.COMPANY_SERVICE_ACCOUNT); } + [Fact] + public async Task CreateServiceAccountAsync_WithValidDataPlus_ReturnsExpected() + { + // Arrange + var serviceAccounts = new List(); + var identities = new List(); + var creationData = new ServiceAccountCreationInfo("testName", "abc", IamClientAuthMethod.SECRET, [_validUserRoleId, _dimUserRoleId]); + var bpns = new[] + { + Bpn + }; + Setup(serviceAccounts, identities); + + // Act + var result = await _sut.CreateServiceAccountAsync(creationData, _companyId, bpns, CompanyServiceAccountTypeId.OWN, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null), ServiceAccountCreationAction); + + // Assert + result.ServiceAccounts.Should().HaveCount(2) + .And.Satisfy( + x => x.ClientId == "sa1" && + x.Description == "abc" && + x.UserRoleData.SequenceEqual(new[] { new UserRoleData(_validUserRoleId, _validClientId, "UserRole") }) && + x.Name == "testName" && + x.ServiceAccountData != null && + x.ServiceAccountData.InternalClientId == "internal-sa1" && + x.ServiceAccountData.IamUserId == _iamUserId && + x.ServiceAccountData.AuthData.IamClientAuthMethod == IamClientAuthMethod.SECRET, + x => x.ClientId == null && + x.Description == "abc" && + x.UserRoleData.SequenceEqual(new[] { new UserRoleData(_dimUserRoleId, _dimClient, _dimRoleText) }) && + x.Name == "dim-testName" && + x.ServiceAccountData == null); + + A.CallTo(() => _userRepository.CreateIdentity(_companyId, UserStatusId.ACTIVE, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, null)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_identityId, "testName", "abc", "sa1", CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.INTERNAL, ServiceAccountCreationAction)) + .MustHaveHappenedOnceExactly(); + var expectedRolesIds = new[] { (_identityId, _validUserRoleId) }; + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.IsSameSequenceAs(expectedRolesIds))) + .MustHaveHappenedOnceExactly(); + IEnumerable? userRoles; + A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync( + "sa1", + A.That.Matches(x => + x.IamClientAuthMethod == IamClientAuthMethod.SECRET && + x.Name == "testName" && + x.Description == "abc" && + x.ClientRoles.Count() == 1 && + x.ClientRoles.TryGetValue(_validClientId, out userRoles) && + userRoles.SequenceEqual(new[] { "UserRole" })), + true)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _provisioningManager.AddBpnAttributetoUserAsync(_iamUserId, bpns)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _provisioningManager.AddProtocolMapperAsync("internal-sa1")) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _userRepository.CreateIdentity(_companyId, UserStatusId.ACTIVE, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, null)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_secondId, "dim-testName", "abc", null, CompanyServiceAccountTypeId.OWN, CompanyServiceAccountKindId.EXTERNAL, ServiceAccountCreationAction)) + .MustHaveHappenedOnceExactly(); + var expectedDimRolesIds = new[] { (_secondId, _dimUserRoleId) }; + A.CallTo(() => _userRolesRepository.CreateIdentityAssignedRoleRange(A>.That.IsSameSequenceAs(expectedDimRolesIds))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _portalRepositories.SaveAsync()) + .MustNotHaveHappened(); + + serviceAccounts.Should().HaveCount(2) + .And.Satisfy( + x => x.Name == "testName" && x.ClientClientId == "sa1" && x.CompanyServiceAccountKindId == CompanyServiceAccountKindId.INTERNAL, + x => x.Name == "dim-testName" && x.ClientClientId == null && x.CompanyServiceAccountKindId == CompanyServiceAccountKindId.EXTERNAL + ); + identities.Should().HaveCount(2) + .And.AllSatisfy(x => x.Should().Match(x => x.CompanyId == _companyId && x.IdentityTypeId == IdentityTypeId.COMPANY_SERVICE_ACCOUNT)) + .And.Satisfy( + x => x.Id == _identityId && x.UserStatusId == UserStatusId.ACTIVE, + x => x.Id == _secondId && x.UserStatusId == UserStatusId.PENDING + ); + } + #region Setup private void Setup(ICollection? serviceAccounts = null, ICollection? identities = null) { A.CallTo(() => _provisioningDbAccess.GetNextClientSequenceAsync()) - .Returns(1); + .Returns(1).Once(); A.CallTo(() => _provisioningManager.SetupCentralServiceAccountClientAsync(A._, A._, A._)) - .Returns(new ServiceAccountData("internal-sa1", _iamUserId, new ClientAuthData(IamClientAuthMethod.SECRET))); + .Returns(new ServiceAccountData("internal-sa1", _iamUserId, new ClientAuthData(IamClientAuthMethod.SECRET))).Once(); - A.CallTo(() => _userRepository.CreateIdentity(_companyId, A._, IdentityTypeId.COMPANY_SERVICE_ACCOUNT, A>._)) - .Invokes((Guid companyId, UserStatusId userStatusId, IdentityTypeId identityTypeId, Action? setOptionalFields) => + A.CallTo(() => _userRepository.CreateIdentity(A._, A._, A._, A>._)) + .ReturnsLazily((Guid companyId, UserStatusId userStatusId, IdentityTypeId identityTypeId, Action? setOptionalFields) => { - var identity = new Identity(Guid.NewGuid(), DateTimeOffset.UtcNow, companyId, userStatusId, identityTypeId); + var identity = new Identity(_identityId, DateTimeOffset.UtcNow, companyId, userStatusId, identityTypeId); setOptionalFields?.Invoke(identity); identities?.Add(identity); - }) - .Returns(new Identity(_identityId, default, default, default, default)); - A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(_identityId, A._, A._, A._, A._, A._, A>._)) - .Invokes((Guid identityId, string name, string description, string clientClientId, CompanyServiceAccountTypeId companyServiceAccountTypeId, CompanyServiceAccountKindId companyServiceAccountKindId, Action? setOptionalParameters) => + return identity; + }).Once() + .Then.ReturnsLazily((Guid companyId, UserStatusId userStatusId, IdentityTypeId identityTypeId, Action? setOptionalFields) => + { + var identity = new Identity(_secondId, DateTimeOffset.UtcNow, companyId, userStatusId, identityTypeId); + setOptionalFields?.Invoke(identity); + identities?.Add(identity); + return identity; + }).Once(); + + A.CallTo(() => _serviceAccountRepository.CreateCompanyServiceAccount(A._, A._, A._, A._, A._, A._, A>._)) + .ReturnsLazily((Guid identityId, string name, string description, string clientClientId, CompanyServiceAccountTypeId companyServiceAccountTypeId, CompanyServiceAccountKindId companyServiceAccountKindId, Action? setOptionalParameters) => { var sa = new CompanyServiceAccount( identityId, @@ -203,13 +393,26 @@ private void Setup(ICollection? serviceAccounts = null, I }; setOptionalParameters?.Invoke(sa); serviceAccounts?.Add(sa); - }) - .Returns(new CompanyServiceAccount(_serviceAccountId, null!, null!, default, default)); + return sa; + }); - A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Matches(x => x.Count(y => y == _validUserRoleId) == 1))) - .Returns(new[] { new UserRoleData(_validUserRoleId, Guid.NewGuid().ToString(), "UserRole") }.ToAsyncEnumerable()); - A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Matches(x => x.Count(y => y == _invalidUserRoleId) == 1))) + A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Contains(_validUserRoleId))) + .Returns(new[] { new UserRoleData(_validUserRoleId, _validClientId, "UserRole") }.ToAsyncEnumerable()); + A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Contains(_dimUserRoleId))) + .Returns(new[] { new UserRoleData(_dimUserRoleId, _dimClient, _dimRoleText) }.ToAsyncEnumerable()); + A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.Contains(_invalidUserRoleId))) .Returns(Enumerable.Empty().ToAsyncEnumerable()); + A.CallTo(() => _userRolesRepository.GetUserRoleDataUntrackedAsync(A>.That.IsSameSequenceAs(new[] { _validUserRoleId, _dimUserRoleId }))) + .Returns(new UserRoleData[] + { + new(_validUserRoleId, _validClientId, "UserRole"), + new(_dimUserRoleId, _dimClient, _dimRoleText) + }.ToAsyncEnumerable()); + + A.CallTo(() => _processStepRepository.CreateProcess(A._)) + .ReturnsLazily((ProcessTypeId processTypeId) => new Process(_processId, processTypeId, Guid.NewGuid())).Once(); + A.CallTo(() => _processStepRepository.CreateProcessStep(A._, A._, A._)) + .ReturnsLazily((ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid processId) => new ProcessStep(_processStepId, processStepTypeId, processStepStatusId, processId, DateTimeOffset.UtcNow)).Once(); } #endregion From 7f178ef0f7e2c1340a6c2f067d2b7eb839d0c948 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Thu, 23 May 2024 13:13:43 +0200 Subject: [PATCH 13/24] feat(serviceaccounts): include pending serviceaccounts and add userstatus to result (#765) --- .../IServiceAccountBusinessLogic.cs | 3 ++- .../ServiceAccountBusinessLogic.cs | 19 ++++++++++--- .../Controllers/ServiceAccountController.cs | 6 +++-- .../ServiceAccountConnectorOfferData.cs | 1 + .../Models/CompanyServiceAccountData.cs | 1 + .../Repositories/IServiceAccountRepository.cs | 2 +- .../Repositories/ServiceAccountRepository.cs | 5 ++-- .../ServiceAccountBusinessLogicTests.cs | 16 +++++++---- .../ServiceAccountControllerTests.cs | 19 ++++++++----- .../ServiceAccountRespotitoryTests.cs | 27 ++++++++++--------- 10 files changed, 67 insertions(+), 32 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/IServiceAccountBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/IServiceAccountBusinessLogic.cs index a42ec3326b..29126427cf 100644 --- a/src/administration/Administration.Service/BusinessLogic/IServiceAccountBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/IServiceAccountBusinessLogic.cs @@ -21,6 +21,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Dim.Library.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Models; namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLogic; @@ -32,7 +33,7 @@ public interface IServiceAccountBusinessLogic Task GetOwnCompanyServiceAccountDetailsAsync(Guid serviceAccountId); Task UpdateOwnCompanyServiceAccountDetailsAsync(Guid serviceAccountId, ServiceAccountEditableDetails serviceAccountDetails); Task ResetOwnCompanyServiceAccountSecretAsync(Guid serviceAccountId); - Task> GetOwnCompanyServiceAccountsDataAsync(int page, int size, string? clientId, bool? isOwner, bool filterForInactive); + Task> GetOwnCompanyServiceAccountsDataAsync(int page, int size, string? clientId, bool? isOwner, bool filterForInactive, IEnumerable? userStatusIds); IAsyncEnumerable GetServiceAccountRolesAsync(string? languageShortName); Task HandleServiceAccountCreationCallback(Guid processId, AuthenticationDetail callbackData); } diff --git a/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs index 74a7884796..174ad1080d 100644 --- a/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs @@ -183,6 +183,7 @@ public async Task GetOwnCompanyServiceAccountD iamClientAuthMethod, result.UserRoleDatas, result.CompanyServiceAccountTypeId, + result.Status, secret, result.ConnectorData, result.OfferSubscriptionData, @@ -311,12 +312,24 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAs result.OfferSubscriptionId); } - public Task> GetOwnCompanyServiceAccountsDataAsync(int page, int size, string? clientId, bool? isOwner, bool filterForInactive) => - Pagination.CreateResponseAsync( + public Task> GetOwnCompanyServiceAccountsDataAsync(int page, int size, string? clientId, bool? isOwner, bool filterForInactive, IEnumerable? userStatusIds) + { + IEnumerable filterUserStatusIds; + if (userStatusIds?.Any() ?? false) + { + filterUserStatusIds = userStatusIds; + } + else + { + filterUserStatusIds = filterForInactive ? [UserStatusId.INACTIVE] : [UserStatusId.ACTIVE, UserStatusId.PENDING]; + } + + return Pagination.CreateResponseAsync( page, size, 15, - portalRepositories.GetInstance().GetOwnCompanyServiceAccountsUntracked(_identityData.CompanyId, clientId, isOwner, filterForInactive ? UserStatusId.INACTIVE : UserStatusId.ACTIVE)); + portalRepositories.GetInstance().GetOwnCompanyServiceAccountsUntracked(_identityData.CompanyId, clientId, isOwner, filterUserStatusIds)); + } public IAsyncEnumerable GetServiceAccountRolesAsync(string? languageShortName) => portalRepositories.GetInstance().GetServiceAccountRolesAsync(_identityData.CompanyId, _settings.ClientId, languageShortName ?? Constants.DefaultLanguage); diff --git a/src/administration/Administration.Service/Controllers/ServiceAccountController.cs b/src/administration/Administration.Service/Controllers/ServiceAccountController.cs index b6bd8d7178..069706ed26 100644 --- a/src/administration/Administration.Service/Controllers/ServiceAccountController.cs +++ b/src/administration/Administration.Service/Controllers/ServiceAccountController.cs @@ -26,6 +26,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.Web; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Models; using Org.Eclipse.TractusX.Portal.Backend.Web.Identity; @@ -162,6 +163,7 @@ public Task ResetServiceAccountCredentials([FromRoute] Gu /// isOwner either true or false /// clientId is string clientclientid /// isUserStatusActive is True or False + /// userStatus is ACTIVE, INACTIVE, PENDING or DELETED (optional, multiple values allowed) /// Returns the specific number of service account data for the given page. /// Example: GET: api/administration/serviceaccount/owncompany/serviceaccounts /// Returns the specific number of service account data for the given page. @@ -170,8 +172,8 @@ public Task ResetServiceAccountCredentials([FromRoute] Gu [Authorize(Policy = PolicyTypes.ValidCompany)] [Route("owncompany/serviceaccounts")] [ProducesResponseType(typeof(Pagination.Response), StatusCodes.Status200OK)] - public Task> GetServiceAccountsData([FromQuery] int page, [FromQuery] int size, [FromQuery] bool? isOwner, [FromQuery] string? clientId, [FromQuery] bool filterForInactive) => - _logic.GetOwnCompanyServiceAccountsDataAsync(page, size, clientId, isOwner, filterForInactive); + public Task> GetServiceAccountsData([FromQuery] int page, [FromQuery] int size, [FromQuery] bool? isOwner, [FromQuery] string? clientId, [FromQuery] bool filterForInactive = false, [FromQuery] IEnumerable? userStatus = null) => + _logic.GetOwnCompanyServiceAccountsDataAsync(page, size, clientId, isOwner, filterForInactive, userStatus); /// /// Get all service account roles diff --git a/src/administration/Administration.Service/Models/ServiceAccountConnectorOfferData.cs b/src/administration/Administration.Service/Models/ServiceAccountConnectorOfferData.cs index 1416aea89a..ed8e4224da 100644 --- a/src/administration/Administration.Service/Models/ServiceAccountConnectorOfferData.cs +++ b/src/administration/Administration.Service/Models/ServiceAccountConnectorOfferData.cs @@ -33,6 +33,7 @@ public record ServiceAccountConnectorOfferData( [property: JsonPropertyName("authenticationType")] IamClientAuthMethod IamClientAuthMethod, [property: JsonPropertyName("roles")] IEnumerable UserRoleDatas, [property: JsonPropertyName("companyServiceAccountTypeId")] CompanyServiceAccountTypeId CompanyServiceAccountTypeId, + [property: JsonPropertyName("status")] UserStatusId UserStatusId, [property: JsonPropertyName("secret")] string? Secret, [property: JsonPropertyName("connector")] ConnectorResponseData? Connector, [property: JsonPropertyName("offer")] OfferResponseData? Offer, diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyServiceAccountData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyServiceAccountData.cs index 94672c4ed5..b02924c9db 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyServiceAccountData.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyServiceAccountData.cs @@ -28,6 +28,7 @@ public record CompanyServiceAccountData( [property: JsonPropertyName("clientId")] string? ClientId, [property: JsonPropertyName("name")] string Name, [property: JsonPropertyName("serviceAccountType")] CompanyServiceAccountTypeId CompanyServiceAccountTypeId, + [property: JsonPropertyName("status")] UserStatusId UserStatusId, [property: JsonPropertyName("isOwner")] bool IsOwner, [property: JsonPropertyName("isProvider")] bool IsProvider, [property: JsonPropertyName("offerSubscriptionId")] Guid? OfferSubscriptionId, diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs index 368502d740..1e1c7577f2 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IServiceAccountRepository.cs @@ -38,7 +38,7 @@ CompanyServiceAccount CreateCompanyServiceAccount(Guid identityId, Task GetOwnCompanyServiceAccountWithIamClientIdAsync(Guid serviceAccountId, Guid userCompanyId); Task<(IEnumerable UserRoleIds, Guid? ConnectorId, string? ClientClientId, ConnectorStatusId? statusId, OfferSubscriptionStatusId? OfferStatusId)> GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(Guid serviceAccountId, Guid companyId); Task GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(Guid serviceAccountId, Guid companyId); - Func?>> GetOwnCompanyServiceAccountsUntracked(Guid userCompanyId, string? clientId, bool? isOwner, UserStatusId userStatusId); + Func?>> GetOwnCompanyServiceAccountsUntracked(Guid userCompanyId, string? clientId, bool? isOwner, IEnumerable userStatusIds); Task CheckActiveServiceAccountExistsForCompanyAsync(Guid technicalUserId, Guid companyId); public Task<(Guid IdentityId, Guid CompanyId)> GetServiceAccountDataByClientId(string clientId); void CreateDimCompanyServiceAccount(Guid serviceAccountId, string authenticationServiceUrl, byte[] secret, byte[] initializationVector, int encryptionMode); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs index 22c8c7c3e2..0778583eff 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs @@ -159,7 +159,7 @@ public void AttachAndModifyCompanyServiceAccount( serviceAccount.DimCompanyServiceAccount.EncryptionMode))) .SingleOrDefaultAsync(); - public Func?>> GetOwnCompanyServiceAccountsUntracked(Guid userCompanyId, string? clientId, bool? isOwner, UserStatusId userStatusId) => + public Func?>> GetOwnCompanyServiceAccountsUntracked(Guid userCompanyId, string? clientId, bool? isOwner, IEnumerable userStatusIds) => (skip, take) => Pagination.CreateSourceQueryAsync( skip, take, @@ -175,7 +175,7 @@ public void AttachAndModifyCompanyServiceAccount( (isOwner.HasValue ? isOwner.Value && x.IsOwner || !isOwner.Value && x.IsProvider : x.IsOwner || x.IsProvider) && - x.ServiceAccount.Identity!.UserStatusId == userStatusId && + userStatusIds.Contains(x.ServiceAccount.Identity!.UserStatusId) && (clientId == null || EF.Functions.ILike(x.ServiceAccount.ClientClientId!, $"%{clientId.EscapeForILike()}%"))) .GroupBy(x => x.ServiceAccount.Identity!.UserStatusId), x => x.OrderBy(x => x.ServiceAccount.Name), @@ -184,6 +184,7 @@ public void AttachAndModifyCompanyServiceAccount( x.ServiceAccount.ClientClientId, x.ServiceAccount.Name, x.ServiceAccount.CompanyServiceAccountTypeId, + x.ServiceAccount.Identity!.UserStatusId, x.IsOwner, x.IsProvider, x.ServiceAccount.OfferSubscriptionId, diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs index 25a74b070b..2b99abbd23 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs @@ -455,24 +455,30 @@ public async Task UpdateOwnCompanyServiceAccountDetailsAsync_WithExternalService #region GetOwnCompanyServiceAccountsDataAsync [Theory] - [InlineData(UserStatusId.ACTIVE, false)] - [InlineData(UserStatusId.INACTIVE, true)] - public async Task GetOwnCompanyServiceAccountsDataAsync_GetsExpectedData(UserStatusId userStatusId, bool isUserInactive) + [InlineData(new[] { UserStatusId.INACTIVE, UserStatusId.DELETED, UserStatusId.ACTIVE }, false, new[] { UserStatusId.INACTIVE, UserStatusId.DELETED, UserStatusId.ACTIVE })] + [InlineData(new[] { UserStatusId.DELETED, UserStatusId.PENDING, UserStatusId.ACTIVE }, true, new[] { UserStatusId.DELETED, UserStatusId.PENDING, UserStatusId.ACTIVE })] + [InlineData(new UserStatusId[] { }, false, new UserStatusId[] { UserStatusId.ACTIVE, UserStatusId.PENDING })] + [InlineData(new UserStatusId[] { }, true, new UserStatusId[] { UserStatusId.INACTIVE })] + [InlineData(null, false, new[] { UserStatusId.ACTIVE, UserStatusId.PENDING })] + [InlineData(null, true, new[] { UserStatusId.INACTIVE })] + public async Task GetOwnCompanyServiceAccountsDataAsync_GetsExpectedData(IEnumerable? userStatusIds, bool isUserInactive, IEnumerable expectedStatusIds) { // Arrange var data = _fixture.CreateMany(15); - A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountsUntracked(ValidCompanyId, null, null, userStatusId)) + A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountsUntracked(A._, A._, A._, A>._)) .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); // Act - var result = await sut.GetOwnCompanyServiceAccountsDataAsync(1, 10, null, null, isUserInactive); + var result = await sut.GetOwnCompanyServiceAccountsDataAsync(1, 10, null, null, isUserInactive, userStatusIds); // Assert result.Should().NotBeNull(); result.Content.Should().HaveCount(5); + A.CallTo(() => _serviceAccountRepository.GetOwnCompanyServiceAccountsUntracked(ValidCompanyId, null, null, A>.That.IsSameSequenceAs(expectedStatusIds))) + .MustHaveHappenedOnceExactly(); } #endregion diff --git a/tests/administration/Administration.Service.Tests/Controllers/ServiceAccountControllerTests.cs b/tests/administration/Administration.Service.Tests/Controllers/ServiceAccountControllerTests.cs index 7e9cc0b934..685090c971 100644 --- a/tests/administration/Administration.Service.Tests/Controllers/ServiceAccountControllerTests.cs +++ b/tests/administration/Administration.Service.Tests/Controllers/ServiceAccountControllerTests.cs @@ -17,7 +17,6 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -using Microsoft.AspNetCore.Mvc; using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLogic; using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Controllers; using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; @@ -27,6 +26,7 @@ using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Identities; using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Models; using Org.Eclipse.TractusX.Portal.Backend.Tests.Shared.Extensions; +using System.Collections.Immutable; namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Tests.Controllers; @@ -106,19 +106,26 @@ public async Task GetServiceAccountDetails_CallsExpected() } - [Fact] - public async Task GetServiceAccountsData_CallsExpected() + [Theory] + [InlineData(true, true)] + [InlineData(true, false)] + [InlineData(false, true)] + [InlineData(false, false)] + public async Task GetServiceAccountsData_CallsExpected(bool filterInactive, bool withStatusIds) { //Arrange var paginationResponse = new Pagination.Response(new Pagination.Metadata(15, 1, 1, 15), _fixture.CreateMany(5)); - A.CallTo(() => _logic.GetOwnCompanyServiceAccountsDataAsync(0, 15, null, null, true)) + IEnumerable? userStatusIds = withStatusIds + ? _fixture.CreateMany().ToImmutableArray() + : null; + A.CallTo(() => _logic.GetOwnCompanyServiceAccountsDataAsync(0, 15, null, null, filterInactive, userStatusIds)) .Returns(paginationResponse); //Act - var result = await _controller.GetServiceAccountsData(0, 15, null, null, true); + var result = await _controller.GetServiceAccountsData(0, 15, null, null, filterInactive, userStatusIds); //Assert - A.CallTo(() => _logic.GetOwnCompanyServiceAccountsDataAsync(0, 15, null, null, true)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _logic.GetOwnCompanyServiceAccountsDataAsync(0, 15, null, null, filterInactive, userStatusIds)).MustHaveHappenedOnceExactly(); Assert.IsType>(result); result.Content.Should().HaveCount(5); } diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs index 3e8b637445..3b6ae1b9af 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs @@ -229,7 +229,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_ReturnsExpectedResult(in var newvalidCompanyId = new Guid("41fd2ab8-71cd-4546-9bef-a388d91b2542"); var (sut, _) = await CreateSut(); // Act - var result = await sut.GetOwnCompanyServiceAccountsUntracked(newvalidCompanyId, null, null, UserStatusId.ACTIVE)(page, size); + var result = await sut.GetOwnCompanyServiceAccountsUntracked(newvalidCompanyId, null, null, [UserStatusId.ACTIVE])(page, size); // Assert result.Should().NotBeNull(); @@ -250,7 +250,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithClientIdAndOwner_Ret var (sut, _) = await CreateSut(); // Act - var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, "sa-cl5-custodian-2", true, UserStatusId.ACTIVE)(0, 10); + var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, "sa-cl5-custodian-2", true, [UserStatusId.ACTIVE])(0, 10); // Assert result!.Count.Should().Be(1); @@ -265,12 +265,14 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithOwnerTrue_ReturnsExp var (sut, _) = await CreateSut().ConfigureAwait(false); // Act - var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, null, true, UserStatusId.ACTIVE)(0, 10).ConfigureAwait(false); + var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, null, true, [UserStatusId.ACTIVE])(0, 10).ConfigureAwait(false); // Assert result!.Count.Should().Be(15); result.Data.Should().HaveCount(10) - .And.AllSatisfy(x => x.CompanyServiceAccountTypeId.Should().Be(CompanyServiceAccountTypeId.OWN)) + .And.AllSatisfy(x => x.Should().Match(y => + y.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.OWN && + y.UserStatusId == UserStatusId.ACTIVE)) .And.BeInAscendingOrder(x => x.Name) .And.Satisfy( x => x.ServiceAccountId == new Guid("7e85a0b8-0001-ab67-10d1-0ef508201029"), @@ -292,7 +294,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithOwnerFalse_ReturnsEx var (sut, _) = await CreateSut().ConfigureAwait(false); // Act - var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, null, false, UserStatusId.ACTIVE)(0, 10).ConfigureAwait(false); + var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, null, false, [UserStatusId.ACTIVE])(0, 10).ConfigureAwait(false); // Assert result!.Count.Should().Be(1); @@ -308,7 +310,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithClientIdAndProvider_ var (sut, _) = await CreateSut(); // Act - var result = await sut.GetOwnCompanyServiceAccountsUntracked(new("41fd2ab8-71cd-4546-9bef-a388d91b2543"), "sa-x-2", false, UserStatusId.ACTIVE)(0, 10); + var result = await sut.GetOwnCompanyServiceAccountsUntracked(new("41fd2ab8-71cd-4546-9bef-a388d91b2543"), "sa-x-2", false, [UserStatusId.ACTIVE])(0, 10); // Assert result!.Count.Should().Be(1); @@ -323,7 +325,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithOnlyClientId_Returns var (sut, _) = await CreateSut(); // Act - var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, "sa-cl5-custodian-2", null, UserStatusId.ACTIVE)(0, 10); + var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, "sa-cl5-custodian-2", null, [UserStatusId.ACTIVE])(0, 10); // Assert result!.Count.Should().Be(1); @@ -338,7 +340,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithSearch_ReturnsExpect var (sut, _) = await CreateSut(); // Act - var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, "sa-cl", null, UserStatusId.ACTIVE)(0, 10); + var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, "sa-cl", null, [UserStatusId.ACTIVE])(0, 10); // Assert result!.Count.Should().Be(13); @@ -352,15 +354,16 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithUserStatusId_InActiv var (sut, _) = await CreateSut(); // Act - var result = await sut.GetOwnCompanyServiceAccountsUntracked(new Guid("729e0af2-6723-4a7f-85a1-833d84b39bdf"), null, null, UserStatusId.INACTIVE)(0, 10); + var result = await sut.GetOwnCompanyServiceAccountsUntracked(new Guid("729e0af2-6723-4a7f-85a1-833d84b39bdf"), null, null, [UserStatusId.INACTIVE])(0, 10); // Assert result!.Count.Should().Be(1); result.Data.Should().HaveCount(1) .And.Satisfy(x => - x.ServiceAccountId == new Guid("38c92162-6328-40ce-80f3-22e3f3e9b94d") - && x.ClientId == "sa-x-inactive" - && x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.MANAGED); + x.ServiceAccountId == new Guid("38c92162-6328-40ce-80f3-22e3f3e9b94d") && + x.ClientId == "sa-x-inactive" && + x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.MANAGED && + x.UserStatusId == UserStatusId.INACTIVE); } #endregion From fa3c2d207cecb09debc2ab691c6940eed9986c02 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Thu, 23 May 2024 14:31:40 +0200 Subject: [PATCH 14/24] fix(serviceAccounts): fix error "Sequence contains more than one element" (#766) --- .../Repositories/ServiceAccountRepository.cs | 2 +- .../ServiceAccountRespotitoryTests.cs | 51 ++++++++++++++++--- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs index 0778583eff..fe1272e8da 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs @@ -177,7 +177,7 @@ public void AttachAndModifyCompanyServiceAccount( : x.IsOwner || x.IsProvider) && userStatusIds.Contains(x.ServiceAccount.Identity!.UserStatusId) && (clientId == null || EF.Functions.ILike(x.ServiceAccount.ClientClientId!, $"%{clientId.EscapeForILike()}%"))) - .GroupBy(x => x.ServiceAccount.Identity!.UserStatusId), + .GroupBy(x => x.ServiceAccount.Identity!.IdentityTypeId), x => x.OrderBy(x => x.ServiceAccount.Name), x => new CompanyServiceAccountData( x.ServiceAccount.Id, diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs index 3b6ae1b9af..6152c9bbc6 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs @@ -232,14 +232,16 @@ public async Task GetOwnCompanyServiceAccountsUntracked_ReturnsExpectedResult(in var result = await sut.GetOwnCompanyServiceAccountsUntracked(newvalidCompanyId, null, null, [UserStatusId.ACTIVE])(page, size); // Assert - result.Should().NotBeNull(); - result!.Count.Should().Be(count); - result.Data.Should().HaveCount(expected); + result.Should().NotBeNull() + .And.Match>(x => + x.Count == count && + x.Data.Count() == expected); if (expected > 0) { - result.Data.First().CompanyServiceAccountTypeId.Should().Be(CompanyServiceAccountTypeId.MANAGED); - result.Data.First().IsOwner.Should().BeTrue(); - result.Data.First().IsProvider.Should().BeFalse(); + result!.Data.First().Should().Match(y => + y.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.MANAGED && + y.IsOwner && + !y.IsProvider); } } @@ -268,6 +270,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithOwnerTrue_ReturnsExp var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, null, true, [UserStatusId.ACTIVE])(0, 10).ConfigureAwait(false); // Assert + result.Should().NotBeNull(); result!.Count.Should().Be(15); result.Data.Should().HaveCount(10) .And.AllSatisfy(x => x.Should().Match(y => @@ -297,6 +300,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithOwnerFalse_ReturnsEx var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, null, false, [UserStatusId.ACTIVE])(0, 10).ConfigureAwait(false); // Assert + result.Should().NotBeNull(); result!.Count.Should().Be(1); result.Data.Should().HaveCount(1) .And.Satisfy(x => x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.MANAGED @@ -313,6 +317,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithClientIdAndProvider_ var result = await sut.GetOwnCompanyServiceAccountsUntracked(new("41fd2ab8-71cd-4546-9bef-a388d91b2543"), "sa-x-2", false, [UserStatusId.ACTIVE])(0, 10); // Assert + result.Should().NotBeNull(); result!.Count.Should().Be(1); result.Data.Should().HaveCount(1) .And.Satisfy(x => x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.MANAGED); @@ -328,6 +333,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithOnlyClientId_Returns var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, "sa-cl5-custodian-2", null, [UserStatusId.ACTIVE])(0, 10); // Assert + result.Should().NotBeNull(); result!.Count.Should().Be(1); result.Data.Should().HaveCount(1) .And.Satisfy(x => x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.OWN); @@ -343,6 +349,7 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithSearch_ReturnsExpect var result = await sut.GetOwnCompanyServiceAccountsUntracked(_validCompanyId, "sa-cl", null, [UserStatusId.ACTIVE])(0, 10); // Assert + result.Should().NotBeNull(); result!.Count.Should().Be(13); result.Data.Should().HaveCount(10); } @@ -357,15 +364,43 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithUserStatusId_InActiv var result = await sut.GetOwnCompanyServiceAccountsUntracked(new Guid("729e0af2-6723-4a7f-85a1-833d84b39bdf"), null, null, [UserStatusId.INACTIVE])(0, 10); // Assert + result.Should().NotBeNull(); result!.Count.Should().Be(1); - result.Data.Should().HaveCount(1) - .And.Satisfy(x => + result.Data.Should().ContainSingle() + .Which.Should().Match(x => x.ServiceAccountId == new Guid("38c92162-6328-40ce-80f3-22e3f3e9b94d") && x.ClientId == "sa-x-inactive" && x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.MANAGED && x.UserStatusId == UserStatusId.INACTIVE); } + [Fact] + public async Task GetOwnCompanyServiceAccountsUntracked_WithMultipleStatus_ReturnsExpectedResult() + { + // Arrange + var (sut, _) = await CreateSut(); + + // Act + var result = await sut.GetOwnCompanyServiceAccountsUntracked(new("729e0af2-6723-4a7f-85a1-833d84b39bdf"), null, null, [UserStatusId.ACTIVE, UserStatusId.INACTIVE, UserStatusId.PENDING, UserStatusId.DELETED])(0, 10); + + // Assert + result.Should().NotBeNull(); + result!.Data.DistinctBy(x => x.UserStatusId).Should().HaveCountGreaterThan(1); + } + + [Fact] + public async Task GetOwnCompanyServiceAccountsUntracked_WithInvalidCompanyId_ReturnsNull() + { + // Arrange + var (sut, _) = await CreateSut(); + + // Act + var result = await sut.GetOwnCompanyServiceAccountsUntracked(new Guid("deadbeef-dead-beef-dead-beefdeadbeef"), null, null, [UserStatusId.ACTIVE, UserStatusId.INACTIVE, UserStatusId.PENDING, UserStatusId.DELETED])(0, 10); + + // Assert + result.Should().BeNull(); + } + #endregion #region CheckActiveServiceAccountExistsForCompanyAsync From bd2bedd175d175d5bb859cd32e5bff4ec713383d Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Thu, 23 May 2024 16:28:42 +0200 Subject: [PATCH 15/24] feat(serviceaccount): get serviceaccounts with userstatusid != DELETED (#768) --- .../Repositories/ServiceAccountRepository.cs | 2 +- .../ServiceAccountRespotitoryTests.cs | 40 ++++++++++++++----- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs index fe1272e8da..2f10d7d662 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs @@ -116,7 +116,7 @@ public void AttachAndModifyCompanyServiceAccount( .AsNoTracking() .Where(serviceAccount => serviceAccount.Id == serviceAccountId && - serviceAccount.Identity!.UserStatusId == UserStatusId.ACTIVE && + serviceAccount.Identity!.UserStatusId != UserStatusId.DELETED && (serviceAccount.CompaniesLinkedServiceAccount!.Owners == companyId || serviceAccount.CompaniesLinkedServiceAccount!.Provider == companyId)) .Select(serviceAccount => new CompanyServiceAccountDetailedData( serviceAccount.Id, diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs index 6152c9bbc6..30b792dde6 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/ServiceAccountRespotitoryTests.cs @@ -74,9 +74,8 @@ public async Task CreateCompanyServiceAccount_ReturnsExpectedResult() result.CompanyServiceAccountTypeId.Should().Be(CompanyServiceAccountTypeId.MANAGED); result.ClientClientId.Should().Be("sa1"); changeTracker.HasChanges().Should().BeTrue(); - changedEntries.Should().NotBeEmpty(); - changedEntries.Should().HaveCount(1); - changedEntries.Single().Entity.Should().BeOfType().Which.OfferSubscriptionId.Should().Be(_validSubscriptionId); + changedEntries.Should().ContainSingle() + .Which.Entity.Should().BeOfType().Which.OfferSubscriptionId.Should().Be(_validSubscriptionId); } #endregion @@ -169,10 +168,13 @@ public async Task GetOwnCompanyServiceAccountDetailedDataUntrackedAsync_ReturnsE var result = await sut.GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(_validServiceAccountId, _validCompanyId); // Assert - result.Should().NotBeNull(); - result!.CompanyServiceAccountTypeId.Should().Be(CompanyServiceAccountTypeId.OWN); - result.CompanyLastEditorData!.CompanyName.Should().Be("CX-Test-Access"); - result.CompanyLastEditorData.Name.Should().Be("CX Admin"); + result.Should().NotBeNull() + .And.Match(x => + x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.OWN && + x.Status == UserStatusId.ACTIVE && + x.CompanyLastEditorData != null && + x.CompanyLastEditorData.CompanyName == "CX-Test-Access" && + x.CompanyLastEditorData.Name == "CX Admin"); } [Fact] @@ -216,9 +218,27 @@ public async Task GetOwnCompanyServiceAccountDetailedDataUntrackedAsync_WithInva result.Should().BeNull(); } + [Fact] + public async Task GetOwnCompanyServiceAccountDetailedDataUntrackedAsync_WithInactiveStatus_ReturnsExpected() + { + // Arrange + var (sut, _) = await CreateSut(); + Guid companyServiceAccountId = new("38c92162-6328-40ce-80f3-22e3f3e9b94d"); + Guid companyId = new("729e0af2-6723-4a7f-85a1-833d84b39bdf"); + // Act + var result = await sut.GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(companyServiceAccountId, companyId); + + // Assert + result.Should().NotBeNull() + .And.Match(x => + x.ClientClientId == "sa-x-inactive" && + x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.MANAGED && + x.Status == UserStatusId.INACTIVE); + } + #endregion - #region GetOwnCompanyServiceAccountDetailedDataUntrackedAsync + #region GetOwnCompanyServiceAccountsUntracked [Theory] [InlineData(3, 0, 10, 3)] @@ -335,8 +355,8 @@ public async Task GetOwnCompanyServiceAccountsUntracked_WithOnlyClientId_Returns // Assert result.Should().NotBeNull(); result!.Count.Should().Be(1); - result.Data.Should().HaveCount(1) - .And.Satisfy(x => x.CompanyServiceAccountTypeId == CompanyServiceAccountTypeId.OWN); + result.Data.Should().ContainSingle() + .Which.CompanyServiceAccountTypeId.Should().Be(CompanyServiceAccountTypeId.OWN); } [Fact] From ef231e2f048accd74a4ff04e6b0385e4a84e1bc7 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Thu, 23 May 2024 16:33:52 +0200 Subject: [PATCH 16/24] feat(registration): add process to decline own companies registration (#757) * synchronously process all db-entities and create processes to asynchronously process all related entities in keycloak within the same transaction. * feat: added unit tests and migrations Ref: CPLP-3548 --------- Co-authored-by: VPrasannaK94 --- src/Portal.Backend.sln | 62 +- .../IRegistrationBusinessLogic.cs | 25 +- .../IdentityProviderBusinessLogic.cs | 16 - .../RegistrationBusinessLogic.cs | 43 +- .../Controllers/RegistrationController.cs | 85 +- .../Offers.Library/Service/OfferService.cs | 15 +- .../Models/CompanyApplicationWithStatus.cs | 43 +- .../Repositories/ApplicationRepository.cs | 57 +- .../Repositories/IApplicationRepository.cs | 1 + .../IIdentityProviderRepository.cs | 3 + .../Repositories/IIdentityRepository.cs | 1 - .../IOfferSubscriptionsRepository.cs | 2 +- .../Repositories/IProcessStepRepository.cs | 1 + .../Repositories/IUserRepository.cs | 3 + .../IdentityProviderRepository.cs | 17 + .../Repositories/IdentityRepository.cs | 10 - .../OfferSubscriptionsRepository.cs | 6 +- .../Repositories/ProcessStepRepository.cs | 12 +- .../Repositories/UserRepository.cs | 12 + ..._CPLP-3548-declineRegistration.Designer.cs | 10129 ++++++++++++++++ ...517135403_CPLP-3548-declineRegistration.cs | 345 + .../PortalDbContextModelSnapshot.cs | 166 +- .../Seeder/BatchInsertSeeder.cs | 1 + .../Entities/CompanyUser.cs | 1 + .../Entities/CompanyUserAssignedProcess.cs | 36 + .../Entities/IdentityProvider.cs | 2 +- .../IdentityProviderAssignedProcess.cs | 36 + .../Entities/NetworkRegistration.cs | 2 +- .../Entities/OfferSubscription.cs | 3 +- .../Entities/Process.cs | 2 + .../Enums/ProcessStepTypeId.cs | 16 +- .../Enums/ProcessTypeId.cs | 4 +- .../PortalDbContext.cs | 28 +- ...entityProviderProvisioning.Executor.csproj | 36 + .../IdentityProviderProvisioningExtensions.cs | 35 + ...ProviderProvisioningProcessTypeExecutor.cs | 163 + .../Processes.Worker/Processes.Worker.csproj | 2 + src/processes/Processes.Worker/Program.cs | 9 +- .../UserProvisioning.Executor.csproj | 36 + .../UserProvisioningExtension.cs | 33 + .../UserProvisioningProcessTypeExecutor.cs | 134 + .../IProvisioningManager.cs | 2 + .../ProvisioningManager.cs | 12 + .../IRegistrationBusinessLogic.cs | 1 + .../RegistrationBusinessLogic.cs | 153 + .../Controllers/RegistrationController.cs | 21 + .../IdentityProviderBusinessLogicTests.cs | 12 +- .../InvitationBusinessLogicTests.cs | 16 +- .../RegistrationBusinessLogicTest.cs | 235 +- .../Controllers/RegistrationControllerTest.cs | 56 + .../Service/OfferServiceTests.cs | 9 +- .../Service/OfferSubscriptionServiceTests.cs | 7 +- .../ServiceBusinessLogicTests.cs | 7 +- .../ApplicationRepositoryTests.cs | 63 + .../CompanyIdpViewTests.cs | 2 +- .../IdentityProviderRepositoryTests.cs | 65 +- .../Data/iam_identity_providers.test.json | 4 + .../Data/identity_assigned_roles.test.json | 7 +- ...tity_provider_assigned_processes.test.json | 6 + .../Seeder/Data/identity_providers.test.json | 7 + .../Seeder/Data/processes.test.json | 6 + .../Setup/TestDbFixture.cs | 6 +- ...ProviderProvisioning.Executor.Tests.csproj | 47 + ...ntityProviderProvisioningExtensionsTest.cs | 50 + ...derProvisioningProcessTypeExecutorTests.cs | 205 + .../Using.cs | 24 + .../UserProvisioning.Executor.Tests.csproj | 47 + .../UserProvisioningExtensionsTest.cs | 48 + ...serProvisioningProcessTypeExecutorTests.cs | 194 + .../UserProvisioning.Executor.Tests/Using.cs | 24 + .../ProvisioningManagerTests.cs | 57 +- .../RegistrationBusinessLogicTest.cs | 672 +- .../Controller/RegistrationControllerTest.cs | 14 + 73 files changed, 13380 insertions(+), 332 deletions(-) create mode 100644 src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.Designer.cs create mode 100644 src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.cs create mode 100644 src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyUserAssignedProcess.cs create mode 100644 src/portalbackend/PortalBackend.PortalEntities/Entities/IdentityProviderAssignedProcess.cs create mode 100644 src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioning.Executor.csproj create mode 100644 src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioningExtensions.cs create mode 100644 src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioningProcessTypeExecutor.cs create mode 100644 src/processes/UserProvisioning.Executor/UserProvisioning.Executor.csproj create mode 100644 src/processes/UserProvisioning.Executor/UserProvisioningExtension.cs create mode 100644 src/processes/UserProvisioning.Executor/UserProvisioningProcessTypeExecutor.cs create mode 100644 tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_provider_assigned_processes.test.json create mode 100644 tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioning.Executor.Tests.csproj create mode 100644 tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioningExtensionsTest.cs create mode 100644 tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioningProcessTypeExecutorTests.cs create mode 100644 tests/processes/IdentityProviderProvisioning.Executor.Tests/Using.cs create mode 100644 tests/processes/UserProvisioning.Executor.Tests/UserProvisioning.Executor.Tests.csproj create mode 100644 tests/processes/UserProvisioning.Executor.Tests/UserProvisioningExtensionsTest.cs create mode 100644 tests/processes/UserProvisioning.Executor.Tests/UserProvisioningProcessTypeExecutorTests.cs create mode 100644 tests/processes/UserProvisioning.Executor.Tests/Using.cs diff --git a/src/Portal.Backend.sln b/src/Portal.Backend.sln index b80c37926c..d14470b9fb 100644 --- a/src/Portal.Backend.sln +++ b/src/Portal.Backend.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.1.32407.343 MinimumVisualStudioVersion = 10.0.40219.1 @@ -274,6 +274,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DimUserCreationProcess.Exec EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DimUserCreationProcess.Executor.Tests", "..\tests\processes\DimUserCreationProcess.Executor.Tests\DimUserCreationProcess.Executor.Tests.csproj", "{143433B2-2792-4C5F-A3C2-E5C91D68E30D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IdentityProviderProvisioning.Executor", "processes\IdentityProviderProvisioning.Executor\IdentityProviderProvisioning.Executor.csproj", "{9636BEC8-6929-4852-8DC8-8B41609630A3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserProvisioning.Executor", "processes\UserProvisioning.Executor\UserProvisioning.Executor.csproj", "{E5494227-BDFE-41F2-A12F-54292D76C29F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IdentityProviderProvisioning.Executor.Tests", "..\tests\processes\IdentityProviderProvisioning.Executor.Tests\IdentityProviderProvisioning.Executor.Tests.csproj", "{CD76A7FF-D003-41DE-9442-F9AB223C6051}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserProvisioning.Executor.Tests", "..\tests\processes\UserProvisioning.Executor.Tests\UserProvisioning.Executor.Tests.csproj", "{0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1738,6 +1746,54 @@ Global {143433B2-2792-4C5F-A3C2-E5C91D68E30D}.Release|x64.Build.0 = Release|Any CPU {143433B2-2792-4C5F-A3C2-E5C91D68E30D}.Release|x86.ActiveCfg = Release|Any CPU {143433B2-2792-4C5F-A3C2-E5C91D68E30D}.Release|x86.Build.0 = Release|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Debug|x64.ActiveCfg = Debug|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Debug|x64.Build.0 = Debug|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Debug|x86.ActiveCfg = Debug|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Debug|x86.Build.0 = Debug|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Release|Any CPU.Build.0 = Release|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Release|x64.ActiveCfg = Release|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Release|x64.Build.0 = Release|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Release|x86.ActiveCfg = Release|Any CPU + {9636BEC8-6929-4852-8DC8-8B41609630A3}.Release|x86.Build.0 = Release|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Debug|x64.ActiveCfg = Debug|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Debug|x64.Build.0 = Debug|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Debug|x86.ActiveCfg = Debug|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Debug|x86.Build.0 = Debug|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Release|Any CPU.Build.0 = Release|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Release|x64.ActiveCfg = Release|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Release|x64.Build.0 = Release|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Release|x86.ActiveCfg = Release|Any CPU + {E5494227-BDFE-41F2-A12F-54292D76C29F}.Release|x86.Build.0 = Release|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Debug|x64.ActiveCfg = Debug|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Debug|x64.Build.0 = Debug|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Debug|x86.ActiveCfg = Debug|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Debug|x86.Build.0 = Debug|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Release|Any CPU.Build.0 = Release|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Release|x64.ActiveCfg = Release|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Release|x64.Build.0 = Release|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Release|x86.ActiveCfg = Release|Any CPU + {CD76A7FF-D003-41DE-9442-F9AB223C6051}.Release|x86.Build.0 = Release|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Debug|x64.ActiveCfg = Debug|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Debug|x64.Build.0 = Debug|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Debug|x86.ActiveCfg = Debug|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Debug|x86.Build.0 = Debug|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Release|Any CPU.Build.0 = Release|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Release|x64.ActiveCfg = Release|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Release|x64.Build.0 = Release|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Release|x86.ActiveCfg = Release|Any CPU + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1746,6 +1802,8 @@ Global SolutionGuid = {2EB6265F-323A-4BF3-969E-003D64A14B64} EndGlobalSection GlobalSection(NestedProjects) = preSolution + {0CBCC851-99A1-4005-9BBA-E6A20A0AEDAA} = {323C198D-A8C6-4EB0-8B79-72624275E35F} + {CD76A7FF-D003-41DE-9442-F9AB223C6051} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {A43B5ACA-1209-46E9-84DB-A48553ED623E} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {A5BEDD89-7280-466E-8D14-EC5E177AAD07} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {5E80DEEA-B254-425C-8220-27EEF47C10BD} = {323C198D-A8C6-4EB0-8B79-72624275E35F} @@ -1868,5 +1926,7 @@ Global {C8E23437-963C-4277-8A65-FDE330C20AAC} = {323C198D-A8C6-4EB0-8B79-72624275E35F} {AD692510-23BA-4021-A44D-DE480A771C23} = {282CEF03-292F-4A49-83C6-997567D0FF5F} {143433B2-2792-4C5F-A3C2-E5C91D68E30D} = {323C198D-A8C6-4EB0-8B79-72624275E35F} + {9636BEC8-6929-4852-8DC8-8B41609630A3} = {282CEF03-292F-4A49-83C6-997567D0FF5F} + {E5494227-BDFE-41F2-A12F-54292D76C29F} = {282CEF03-292F-4A49-83C6-997567D0FF5F} EndGlobalSection EndGlobal diff --git a/src/administration/Administration.Service/BusinessLogic/IRegistrationBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/IRegistrationBusinessLogic.cs index a23ab22067..1d69686213 100644 --- a/src/administration/Administration.Service/BusinessLogic/IRegistrationBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/IRegistrationBusinessLogic.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 @@ -107,4 +106,28 @@ public interface IRegistrationBusinessLogic /// the response data /// cancellation token Task ProcessIssuerMembershipResponseAsync(IssuerResponseData data, CancellationToken cancellationToken); + + /// + /// Retrigger the DeleteIdpSharedRealm ProcessStepType + /// + /// Id of the Process + Task RetriggerDeleteIdpSharedRealm(Guid processId); + + /// + /// Retrigger the DeleteIdpSharedServiceAccount ProcessStepType + /// + /// Id of the Process + Task RetriggerDeleteIdpSharedServiceAccount(Guid processId); + + /// + /// Retrigger the DeleteCentralIdentityProvider ProcessStepType + /// + /// Id of the Process + Task RetriggerDeleteCentralIdentityProvider(Guid processId); + + /// + /// Retrigger the DeleteCentralUser ProcessStepType + /// + /// Id of the Process + Task RetriggerDeleteCentralUser(Guid processId); } diff --git a/src/administration/Administration.Service/BusinessLogic/IdentityProviderBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/IdentityProviderBusinessLogic.cs index 6462cca6b3..fccb1642f0 100644 --- a/src/administration/Administration.Service/BusinessLogic/IdentityProviderBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/IdentityProviderBusinessLogic.cs @@ -376,24 +376,11 @@ public async ValueTask DeleteCompanyIdentityProviderAsync(Guid identityProviderI { await DeleteManagedIdpLinks(identityProviderId, alias, ownerCompanyName, identityProviderRepository).ConfigureAwait(ConfigureAwaitOptions.None); } - else - { - await DeleteOwnCompanyIdpLinks(identityProviderId, identityProviderRepository).ConfigureAwait(ConfigureAwaitOptions.None); - } identityProviderRepository.DeleteIdentityProvider(identityProviderId); await _portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); } - private async Task DeleteOwnCompanyIdpLinks(Guid identityProviderId, IIdentityProviderRepository identityProviderRepository) - { - var companyId = _identityData.CompanyId; - var companyUserIds = await identityProviderRepository.GetIdpLinkedCompanyUserIds(identityProviderId, companyId).ToListAsync(); - - identityProviderRepository.DeleteCompanyIdentityProvider(companyId, identityProviderId); - _portalRepositories.GetInstance().RemoveCompanyUserAssignedIdentityProviders(companyUserIds.Select(id => (id, identityProviderId))); - } - private async Task DeleteManagedIdpLinks(Guid identityProviderId, string? alias, string ownerCompanyName, IIdentityProviderRepository identityProviderRepository) { var roleIds = await _mailingProcessCreation.GetRoleData(_settings.DeleteIdpRoles).ConfigureAwait(ConfigureAwaitOptions.None); @@ -417,9 +404,6 @@ private async Task DeleteManagedIdpLinks(Guid identityProviderId, string? alias, await DeleteKeycloakUsers(data.Identities.Select(i => i.IdentityId)); } - identityProviderRepository.DeleteCompanyIdentityProvider(data.CompanyId, identityProviderId); - userRepository.RemoveCompanyUserAssignedIdentityProviders(data.Identities.Where(x => x.IsLinkedCompanyUser).Select(x => (x.IdentityId, identityProviderId))); - foreach (var userData in data.Identities.Where(i => i is { IsInUserRoles: true, Userdata.UserMail: not null }).Select(i => i.Userdata)) { var userName = string.Join(" ", new[] { userData.FirstName, userData.LastName }.Where(item => !string.IsNullOrWhiteSpace(item))); diff --git a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs index abd7a95014..4b453d2f21 100644 --- a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs @@ -36,6 +36,7 @@ using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Org.Eclipse.TractusX.Portal.Backend.Processes.ApplicationChecklist.Library; +using Org.Eclipse.TractusX.Portal.Backend.Processes.Library; using Org.Eclipse.TractusX.Portal.Backend.Processes.Mailing.Library; using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library; using Org.Eclipse.TractusX.Portal.Backend.Registration.Common; @@ -491,14 +492,18 @@ public async Task DeclineRegistrationVerification(Guid applicationId, string com await _provisioningManager.DeleteSharedIdpRealmAsync(idpAlias).ConfigureAwait(false); } - identityProviderRepository.DeleteCompanyIdentityProvider(companyId, idpId); if (idpType is IdentityProviderTypeId.OWN or IdentityProviderTypeId.SHARED) { await _provisioningManager.DeleteCentralIdentityProviderAsync(idpAlias).ConfigureAwait(ConfigureAwaitOptions.None); identityProviderRepository.DeleteIamIdentityProvider(idpAlias); identityProviderRepository.DeleteIdentityProvider(idpId); } - userRepository.RemoveCompanyUserAssignedIdentityProviders(linkedUserIds.Select(userId => (userId, idpId))); + else + { + // a managed identityprovider is just unlinked from company and users + identityProviderRepository.DeleteCompanyIdentityProvider(companyId, idpId); + userRepository.RemoveCompanyUserAssignedIdentityProviders(linkedUserIds.Select(userId => (userId, idpId))); + } } _portalRepositories.GetInstance().AttachAndModifyCompanyApplication(applicationId, application => @@ -631,4 +636,38 @@ private async Task GetApplicationIdByBpn(IssuerResponseData data, Cancella return result.Single(); } + + public Task RetriggerDeleteIdpSharedRealm(Guid processId) => RetriggerProcessStepInternal(processId, ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_REALM); + + /// + public Task RetriggerDeleteIdpSharedServiceAccount(Guid processId) => RetriggerProcessStepInternal(processId, ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT); + + /// + public Task RetriggerDeleteCentralIdentityProvider(Guid processId) => RetriggerProcessStepInternal(processId, ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER); + + public Task RetriggerDeleteCentralUser(Guid processId) => RetriggerProcessStepInternal(processId, ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_USER); + + private async Task RetriggerProcessStepInternal(Guid processId, ProcessStepTypeId stepToTrigger) + { + var (processType, nextStep) = stepToTrigger switch + { + ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_REALM => (ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, ProcessStepTypeId.DELETE_IDP_SHARED_REALM), + ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT => (ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT), + ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER => (ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER), + ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_USER => (ProcessTypeId.USER_PROVISIONING, ProcessStepTypeId.DELETE_CENTRAL_USER), + _ => throw new UnexpectedConditionException($"Step {stepToTrigger} is not retriggerable") + }; + + var (validProcessId, processData) = await _portalRepositories.GetInstance().IsValidProcess(processId, processType, Enumerable.Repeat(stepToTrigger, 1)).ConfigureAwait(false); + if (!validProcessId) + { + throw new NotFoundException($"process {processId} does not exist"); + } + + var context = processData.CreateManualProcessData(stepToTrigger, _portalRepositories, () => $"processId {processId}"); + + context.ScheduleProcessSteps(Enumerable.Repeat(nextStep, 1)); + context.FinalizeProcessStep(); + await _portalRepositories.SaveAsync().ConfigureAwait(false); + } } diff --git a/src/administration/Administration.Service/Controllers/RegistrationController.cs b/src/administration/Administration.Service/Controllers/RegistrationController.cs index 43cafed1b9..abe8ff82bc 100644 --- a/src/administration/Administration.Service/Controllers/RegistrationController.cs +++ b/src/administration/Administration.Service/Controllers/RegistrationController.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 @@ -477,4 +476,88 @@ public async Task ProcessIssuerMembershipResponse([FromBody] Is await _logic.ProcessIssuerMembershipResponseAsync(responseData, cancellationToken).ConfigureAwait(false); return NoContent(); } + + /// + /// Retriggers the last failed step + /// + /// Id of the process that should be triggered + /// NoContent + /// Example: POST: api/administration/registration/{processId}/retrigger-delete-idpSharedRealm + /// Empty response on success. + /// No Process found for the processId + [HttpPost] + [Authorize(Roles = "decline_new_partner")] + [Authorize(Policy = PolicyTypes.CompanyUser)] + [Route("{processId}/retrigger-delete-idpSharedRealm")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] + public async Task RetriggerDeleteIdpSharedRealm([FromRoute] Guid processId) + { + await _logic.RetriggerDeleteIdpSharedRealm(processId).ConfigureAwait(false); + return NoContent(); + } + + /// + /// Retriggers the last failed step + /// + /// Id of the process that should be triggered + /// NoContent + /// Example: POST: api/administration/registration/{processId}/retrigger-delete-idpSharedServiceAccount + /// Empty response on success. + /// No Process found for the processId + [HttpPost] + [Authorize(Roles = "decline_new_partner")] + [Authorize(Policy = PolicyTypes.CompanyUser)] + [Route("{processId}/retrigger-delete-idpSharedServiceAccount")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] + public async Task RetriggerDeleteIdpSharedServiceAccount([FromRoute] Guid processId) + { + await _logic.RetriggerDeleteIdpSharedServiceAccount(processId).ConfigureAwait(false); + return NoContent(); + } + + /// + /// Retriggers the last failed step + /// + /// Id of the process that should be triggered + /// NoContent + /// Example: POST: api/administration/registration/{processId}/retrigger-delete-centralIdentityProvider + /// Empty response on success. + /// No Process found for the processId + [HttpPost] + [Authorize(Roles = "decline_new_partner")] + [Authorize(Policy = PolicyTypes.CompanyUser)] + [Route("{processId}/retrigger-delete-centralIdentityProvider")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] + public async Task RetriggerDeleteCentralIdentityProvider([FromRoute] Guid processId) + { + await _logic.RetriggerDeleteCentralIdentityProvider(processId).ConfigureAwait(false); + return NoContent(); + } + + /// + /// Retriggers the last failed step + /// + /// Id of the process that should be triggered + /// NoContent + /// Example: POST: api/administration/registration/{processId}/retrigger-delete-centraluser + /// Empty response on success. + /// No Process found for the processId + [HttpPost] + [Authorize(Roles = "decline_new_partner")] + [Authorize(Policy = PolicyTypes.CompanyUser)] + [Route("{processId}/retrigger-delete-centraluser")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] + public async Task RetriggerDeleteCentralUser([FromRoute] Guid processId) + { + await _logic.RetriggerDeleteCentralUser(processId).ConfigureAwait(false); + return NoContent(); + } } diff --git a/src/marketplace/Offers.Library/Service/OfferService.cs b/src/marketplace/Offers.Library/Service/OfferService.cs index d56dfba2c1..892630e5ce 100644 --- a/src/marketplace/Offers.Library/Service/OfferService.cs +++ b/src/marketplace/Offers.Library/Service/OfferService.cs @@ -74,7 +74,7 @@ public OfferService(IPortalRepositories portalRepositories, /// public async Task CreateOfferSubscriptionAgreementConsentAsync(Guid subscriptionId, Guid agreementId, ConsentStatusId consentStatusId, OfferTypeId offerTypeId) { - var (companyId, offerSubscription, companyUserId) = await GetOfferSubscriptionCompanyAndUserAsync(subscriptionId, offerTypeId).ConfigureAwait(ConfigureAwaitOptions.None); + var (companyId, offerSubscriptionId, companyUserId) = await GetOfferSubscriptionCompanyAndUserAsync(subscriptionId, offerTypeId).ConfigureAwait(ConfigureAwaitOptions.None); if (!await _portalRepositories.GetInstance() .CheckAgreementExistsForSubscriptionAsync(agreementId, subscriptionId, offerTypeId).ConfigureAwait(ConfigureAwaitOptions.None)) @@ -83,7 +83,7 @@ public async Task CreateOfferSubscriptionAgreementConsentAsync(Guid subscr } var consent = _portalRepositories.GetInstance().CreateConsent(agreementId, companyId, companyUserId, consentStatusId); - _portalRepositories.GetInstance().CreateConsentAssignedOfferSubscription(consent.Id, offerSubscription.Id); + _portalRepositories.GetInstance().CreateConsentAssignedOfferSubscription(consent.Id, offerSubscriptionId); await _portalRepositories.SaveAsync(); return consent.Id; @@ -92,7 +92,7 @@ public async Task CreateOfferSubscriptionAgreementConsentAsync(Guid subscr /// public async Task CreateOrUpdateOfferSubscriptionAgreementConsentAsync(Guid subscriptionId, IEnumerable offerAgreementConsentData, OfferTypeId offerTypeId) { - var (companyId, offerSubscription, companyUserId) = await GetOfferSubscriptionCompanyAndUserAsync(subscriptionId, offerTypeId).ConfigureAwait(ConfigureAwaitOptions.None); + var (companyId, offerSubscriptionId, companyUserId) = await GetOfferSubscriptionCompanyAndUserAsync(subscriptionId, offerTypeId).ConfigureAwait(ConfigureAwaitOptions.None); if (!await _portalRepositories .GetInstance() @@ -118,11 +118,11 @@ public async Task CreateOrUpdateOfferSubscriptionAgreementConsentAsync(Guid subs foreach (var consentData in offerAgreementConsentData.ExceptBy(offerSubscriptionConsents.Select(x => x.AgreementId), consentData => consentData.AgreementId)) { var consent = _portalRepositories.GetInstance().CreateConsent(consentData.AgreementId, companyId, companyUserId, consentData.ConsentStatusId); - consentAssignedOfferSubscriptionRepository.CreateConsentAssignedOfferSubscription(consent.Id, offerSubscription.Id); + consentAssignedOfferSubscriptionRepository.CreateConsentAssignedOfferSubscription(consent.Id, offerSubscriptionId); } } - private async Task<(Guid CompanyId, OfferSubscription OfferSubscription, Guid CompanyUserId)> GetOfferSubscriptionCompanyAndUserAsync(Guid subscriptionId, OfferTypeId offerTypeId) + private async Task<(Guid CompanyId, Guid OfferSubscriptionId, Guid CompanyUserId)> GetOfferSubscriptionCompanyAndUserAsync(Guid subscriptionId, OfferTypeId offerTypeId) { var result = await _portalRepositories.GetInstance() .GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync(subscriptionId, _identityData.IdentityId, offerTypeId) @@ -131,12 +131,11 @@ public async Task CreateOrUpdateOfferSubscriptionAgreementConsentAsync(Guid subs { throw new ControllerArgumentException("Company or CompanyUser not assigned correctly.", nameof(_identityData.IdentityId)); } - var (companyId, offerSubscription) = result; - if (offerSubscription is null) + if (!result.IsValidOfferSubscription) { throw new NotFoundException($"Invalid OfferSubscription {subscriptionId} for OfferType {offerTypeId}"); } - return (companyId, offerSubscription, _identityData.IdentityId); + return (result.CompanyId, subscriptionId, _identityData.IdentityId); } /// diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyApplicationWithStatus.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyApplicationWithStatus.cs index 04751ab5dd..c6a5ec1197 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyApplicationWithStatus.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyApplicationWithStatus.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,15 +21,17 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models { - public record CompanyApplicationWithStatus - ( + public record CompanyApplicationWithStatus( Guid ApplicationId, CompanyApplicationStatusId ApplicationStatus, CompanyApplicationTypeId ApplicationType, IEnumerable ApplicationChecklist ); - public record ApplicationChecklistData(ApplicationChecklistEntryTypeId TypeId, ApplicationChecklistEntryStatusId StatusId); + public record ApplicationChecklistData( + ApplicationChecklistEntryTypeId TypeId, + ApplicationChecklistEntryStatusId StatusId + ); public record CompanyApplicationDeclineData( Guid ApplicationId, @@ -39,4 +40,38 @@ public record CompanyApplicationDeclineData( string CompanyName, IEnumerable Users ); + + public record ApplicationDeclineData( + IEnumerable IdentityProviderStatusDatas, + string CompanyName, + CompanyApplicationStatusId CompanyApplicationStatusId, + IEnumerable InvitationsStatusDatas, + IEnumerable CompanyUserStatusDatas, + IEnumerable DocumentStatusDatas + ); + + public record IdentityProviderStatusData( + Guid IdentityProviderId, + IdentityProviderTypeId IdentityProviderTypeId + ); + + public record InvitationsStatusData( + Guid InvitationId, + InvitationStatusId InvitationStatusId + ); + + public record CompanyUserStatusData( + Guid CompanyUserId, + string? FirstName, + string? LastName, + string? Email, + UserStatusId UserStatusId, + IEnumerable IdentityAssignedRoleIds + ); + + public record IdpData( + Guid IdentityProviderId, + string IamAlias, + IdentityProviderTypeId IdentityProviderTypeId + ); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs index d98c77f9d7..aef436272d 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs @@ -510,15 +510,6 @@ public Task IsValidApplicationForCompany(Guid applicationId, Guid companyI ))) .SingleOrDefaultAsync(); - public Task<(bool Exists, Guid CompanyId, CompanyApplicationStatusId CompanyApplicationStatusId)> GetCompanyIdForSubmittedApplication(Guid applicationId) => - portalDbContext.CompanyApplications - .Where(a => a.Id == applicationId) - .Select(a => new ValueTuple( - true, - a.CompanyId, - a.ApplicationStatusId)) - .SingleOrDefaultAsync(); - public Task<(bool Exists, string? Did, string? Bpn)> GetDidAndBpnForApplicationId(Guid applicationId) => portalDbContext.CompanyApplications .Where(ca => ca.Id == applicationId) @@ -535,4 +526,52 @@ public Task IsValidApplicationForCompany(Guid applicationId, Guid companyI true, ca.Company!.CompanyWalletData!.Did)) .SingleOrDefaultAsync(); + + public Task<(bool IsValidApplicationId, bool IsValidCompany, ApplicationDeclineData? ApplicationDeclineData)> GetDeclineApplicationDataForApplicationId(Guid applicationId, Guid companyId, IEnumerable companyApplicationStatusIds) => + portalDbContext.CompanyApplications + .AsNoTracking() + .AsSplitQuery() + .Where(application => application.Id == applicationId && companyApplicationStatusIds.Contains(application.ApplicationStatusId)) + .Select(application => new + { + IsValidCompany = application.CompanyId == companyId, + Application = application, + application.Company, + application.Company!.Identities + }) + .Select(x => new ValueTuple( + true, + x.IsValidCompany, + x.IsValidCompany + ? new ApplicationDeclineData( + x.Company!.IdentityProviders + .Select(x => new IdentityProviderStatusData( + x.Id, + x.IdentityProviderTypeId)), + x.Company.Name, + x.Application.ApplicationStatusId, + x.Application.Invitations + .Where(invitation => invitation.InvitationStatusId != InvitationStatusId.DECLINED) + .Select(invitation => new InvitationsStatusData( + invitation.Id, + invitation.InvitationStatusId)), + x.Identities + .Where(identity => + identity.IdentityTypeId == IdentityTypeId.COMPANY_USER && + identity.UserStatusId != UserStatusId.DELETED) + .Select(identity => new CompanyUserStatusData( + identity.Id, + identity.CompanyUser!.Firstname, + identity.CompanyUser.Lastname, + identity.CompanyUser.Email, + identity.UserStatusId, + identity.IdentityAssignedRoles.Select(iar => iar.UserRoleId))), + x.Identities.SelectMany(identity => + identity.CompanyUser!.Documents + .Where(document => document.DocumentStatusId != DocumentStatusId.INACTIVE) + .Select(document => new DocumentStatusData( + document.Id, + document.DocumentStatusId)))) + : null)) + .SingleOrDefaultAsync(); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs index 9e6e942f9a..c6571d5944 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IApplicationRepository.cs @@ -103,4 +103,5 @@ public interface IApplicationRepository Task<(bool Exists, string? Holder, string? BusinessPartnerNumber, WalletInformation? WalletInformation)> GetBpnlCredentialIformationByApplicationId(Guid applicationId); Task<(bool Exists, string? Did, string? Bpn)> GetDidAndBpnForApplicationId(Guid applicationId); Task<(bool Exists, string? Did)> GetDidForApplicationId(Guid applicationId); + Task<(bool IsValidApplicationId, bool IsValidCompany, ApplicationDeclineData? ApplicationDeclineData)> GetDeclineApplicationDataForApplicationId(Guid applicationId, Guid companyId, IEnumerable companyApplicationStatusIds); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityProviderRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityProviderRepository.cs index c16fe86a55..1d288aa6dc 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityProviderRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityProviderRepository.cs @@ -35,6 +35,7 @@ public interface IIdentityProviderRepository void AttachAndModifyIamIdentityProvider(string idpAlias, Action? initialize, Action modify); CompanyIdentityProvider CreateCompanyIdentityProvider(Guid companyId, Guid identityProviderId); void DeleteCompanyIdentityProvider(Guid companyId, Guid identityProviderId); + void DeleteCompanyIdentityProviderRange(IEnumerable<(Guid CompanyId, Guid IdentityProviderId)> companyIdentityProviderIds); void CreateCompanyIdentityProviders(IEnumerable<(Guid CompanyId, Guid IdentityProviderId)> companyIdIdentityProviderIds); Task GetSharedIdentityProviderIamAliasDataUntrackedAsync(Guid companyId); Task<(string? Alias, bool IsValidUser)> GetIdpCategoryIdByUserIdAsync(Guid companyUserId, Guid userCompanyId); @@ -59,4 +60,6 @@ public interface IIdentityProviderRepository IAsyncEnumerable GetIdpLinkedCompanyUserIds(Guid identityProviderId, Guid companyId); IAsyncEnumerable<(Guid CompanyId, CompanyStatusId CompanyStatusId, bool HasMoreIdentityProviders, IEnumerable<(Guid IdentityId, bool IsLinkedCompanyUser, (string? UserMail, string? FirstName, string? LastName) Userdata, bool IsInUserRoles, IEnumerable UserRoleIds)> Identities)> GetManagedIdpLinkedData(Guid identityProviderId, IEnumerable userRoleIds); IAsyncEnumerable<(string Email, string? FirstName, string? LastName)> GetCompanyUserEmailForIdpWithoutOwnerAndRoleId(IEnumerable userRoleIds, Guid identityProviderId); + Task GetIdentityProviderDataForProcessIdAsync(Guid processId); + void CreateIdentityProviderAssignedProcessRange(IEnumerable<(Guid IdentityProviderId, Guid ProcessId)> identityProviderProcessIds); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityRepository.cs index 5b00b65e53..20d88e1366 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityRepository.cs @@ -26,5 +26,4 @@ public interface IIdentityRepository Task GetActiveCompanyIdByIdentityId(Guid identityId); Task<(IdentityTypeId IdentityTypeId, Guid CompanyId)> GetActiveIdentityDataByIdentityId(Guid identityId); Task<(Guid IdentityId, IdentityTypeId IdentityTypeId, Guid CompanyId)> GetActiveIdentityDataByUserEntityId(string userEntityId); - IAsyncEnumerable<(string Email, string? FirstName, string? LastName)> GetCompanyUserEmailForIdentityIdsWithoutOwnerAndRoleId(IEnumerable userRoleIds, IEnumerable identityIds); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs index 54dc4ee6bd..f13e63de6d 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs @@ -52,7 +52,7 @@ public interface IOfferSubscriptionsRepository Task<(OfferSubscriptionStatusId OfferSubscriptionStatusId, bool IsSubscribingCompany, bool IsValidSubscriptionId, IEnumerable ConnectorIds, IEnumerable ServiceAccounts)> GetCompanyAssignedOfferSubscriptionDataForCompanyUserAsync(Guid subscriptionId, Guid userCompanyId); - Task<(Guid companyId, OfferSubscription? offerSubscription)> GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync(Guid subscriptionId, Guid userId, OfferTypeId offerTypeId); + Task<(Guid CompanyId, bool IsValidOfferSubscription)> GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync(Guid subscriptionId, Guid userId, OfferTypeId offerTypeId); /// /// Gets the subscription detail data for the given id and user diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IProcessStepRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IProcessStepRepository.cs index 164463f30f..3334fd7df4 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IProcessStepRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IProcessStepRepository.cs @@ -29,6 +29,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositorie public interface IProcessStepRepository { Process CreateProcess(ProcessTypeId processTypeId); + IEnumerable CreateProcessRange(IEnumerable processTypeIds); ProcessStep CreateProcessStep(ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid processId); IEnumerable CreateProcessStepRange(IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus); void AttachAndModifyProcessStep(Guid processStepId, Action? initialize, Action modify); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IUserRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IUserRepository.cs index fc8894a8d3..7e258ce840 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IUserRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IUserRepository.cs @@ -131,4 +131,7 @@ public interface IUserRepository void AttachAndModifyUserAssignedIdentityProvider(Guid companyUserId, Guid identityProviderId, Action? initialize, Action modify); Task<(bool Exists, string? RecipientMail)> GetUserMailData(Guid companyUserId); Task CheckUserExists(Guid companyUserId); + void CreateCompanyUserAssignedProcessRange(IEnumerable<(Guid CompanyUserId, Guid ProcessId)> companyUserProcessIds); + Task GetCompanyUserIdForProcessIdAsync(Guid processId); + void DeleteCompanyUserAssignedProcess(Guid companyUserId, Guid processId); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityProviderRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityProviderRepository.cs index 0f8c2e64e6..43d7149a19 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityProviderRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityProviderRepository.cs @@ -66,6 +66,9 @@ public CompanyIdentityProvider CreateCompanyIdentityProvider(Guid companyId, Gui public void DeleteCompanyIdentityProvider(Guid companyId, Guid identityProviderId) => _context.Remove(new CompanyIdentityProvider(companyId, identityProviderId)); + public void DeleteCompanyIdentityProviderRange(IEnumerable<(Guid CompanyId, Guid IdentityProviderId)> companyIdentityProviderIds) => + _context.RemoveRange(companyIdentityProviderIds.Select(x => new CompanyIdentityProvider(x.CompanyId, x.IdentityProviderId))); + public void CreateCompanyIdentityProviders(IEnumerable<(Guid CompanyId, Guid IdentityProviderId)> companyIdIdentityProviderIds) => _context.CompanyIdentityProviders .AddRange(companyIdIdentityProviderIds.Select(x => new CompanyIdentityProvider( @@ -343,4 +346,18 @@ public IAsyncEnumerable GetIdpLinkedCompanyUserIds(Guid identityProviderId x.Email != null) .Select(x => new ValueTuple(x.Email!, x.Firstname, x.Lastname)) .ToAsyncEnumerable(); + + /// + public Task GetIdentityProviderDataForProcessIdAsync(Guid processId) => + _context.IdentityProviderAssignedProcesses + .AsNoTracking() + .Where(ipap => ipap.ProcessId == processId) + .Select(ipap => new IdpData( + ipap.IdentityProviderId, + ipap.IdentityProvider!.IamIdentityProvider!.IamIdpAlias, + ipap.IdentityProvider.IdentityProviderTypeId)) + .SingleOrDefaultAsync(); + + public void CreateIdentityProviderAssignedProcessRange(IEnumerable<(Guid IdentityProviderId, Guid ProcessId)> identityProviderProcessIds) => + _context.AddRange(identityProviderProcessIds.Select(x => new IdentityProviderAssignedProcess(x.IdentityProviderId, x.ProcessId))); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityRepository.cs index a7314bb6c7..56365ed7cd 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityRepository.cs @@ -51,14 +51,4 @@ public Task GetActiveCompanyIdByIdentityId(Guid identityId) => x.IdentityTypeId, x.CompanyId)) .SingleOrDefaultAsync(); - - /// - public IAsyncEnumerable<(string Email, string? FirstName, string? LastName)> GetCompanyUserEmailForIdentityIdsWithoutOwnerAndRoleId(IEnumerable userRoleIds, IEnumerable identityIds) => - _context.CompanyUsers - .Where(x => - identityIds.Contains(x.Id) && - x.Identity!.IdentityAssignedRoles.Select(u => u.UserRoleId).Any(u => userRoleIds.Any(ur => ur == u)) && - x.Email != null) - .Select(x => new ValueTuple(x.Email!, x.Firstname, x.Lastname)) - .ToAsyncEnumerable(); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs index ac73f4818a..9eae7e9e8a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs @@ -115,13 +115,13 @@ public OfferSubscription CreateOfferSubscription(Guid offerId, Guid companyId, O )) .SingleOrDefaultAsync(); - public Task<(Guid companyId, OfferSubscription? offerSubscription)> GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync(Guid subscriptionId, Guid userId, OfferTypeId offerTypeId) => + public Task<(Guid CompanyId, bool IsValidOfferSubscription)> GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync(Guid subscriptionId, Guid userId, OfferTypeId offerTypeId) => _context.CompanyUsers .Where(user => user.Id == userId) .Select(user => user.Identity!.Company) - .Select(company => new ValueTuple( + .Select(company => new ValueTuple( company!.Id, - company.OfferSubscriptions.SingleOrDefault(os => os.Id == subscriptionId && os.Offer!.OfferTypeId == offerTypeId) + company.OfferSubscriptions.Any(os => os.Id == subscriptionId && os.Offer!.OfferTypeId == offerTypeId) )) .SingleOrDefaultAsync(); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ProcessStepRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ProcessStepRepository.cs index 4573d830ac..44fb7aa917 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ProcessStepRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ProcessStepRepository.cs @@ -22,6 +22,7 @@ using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; +using System.Collections.Immutable; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; @@ -41,12 +42,19 @@ public ProcessStepRepository(PortalDbContext portalDbContext) public Process CreateProcess(ProcessTypeId processTypeId) => _context.Add(new Process(Guid.NewGuid(), processTypeId, Guid.NewGuid())).Entity; + public IEnumerable CreateProcessRange(IEnumerable processTypeIds) + { + var processes = processTypeIds.Select(x => new Process(Guid.NewGuid(), x, Guid.NewGuid())).ToImmutableList(); + _context.AddRange(processes); + return processes; + } + public ProcessStep CreateProcessStep(ProcessStepTypeId processStepTypeId, ProcessStepStatusId processStepStatusId, Guid processId) => _context.Add(new ProcessStep(Guid.NewGuid(), processStepTypeId, processStepStatusId, processId, DateTimeOffset.UtcNow)).Entity; public IEnumerable CreateProcessStepRange(IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus) { - var processSteps = processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, DateTimeOffset.UtcNow)).ToList(); + var processSteps = processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, DateTimeOffset.UtcNow)).ToImmutableList(); _context.AddRange(processSteps); return processSteps; } @@ -67,7 +75,7 @@ public void AttachAndModifyProcessSteps(IEnumerable<(Guid ProcessStepId, Action< var step = new ProcessStep(data.ProcessStepId, default, default, Guid.Empty, default); data.Initialize?.Invoke(step); return (Step: step, data.Modify); - }).ToList(); + }).ToImmutableList(); _context.AttachRange(stepModifyData.Select(data => data.Step)); stepModifyData.ForEach(data => { diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs index cfdc2d6c95..52c6e3195e 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs @@ -535,4 +535,16 @@ public IAsyncEnumerable GetNextIdentitiesForNetworkRegistration(Guid netwo .Select(x => x.Id) .Take(2) .ToAsyncEnumerable(); + + public void CreateCompanyUserAssignedProcessRange(IEnumerable<(Guid CompanyUserId, Guid ProcessId)> companyUserProcessIds) => + _dbContext.AddRange(companyUserProcessIds.Select(x => new CompanyUserAssignedProcess(x.CompanyUserId, x.ProcessId))); + + public Task GetCompanyUserIdForProcessIdAsync(Guid processId) => + _dbContext.CompanyUserAssignedProcesses + .Where(cuap => cuap.ProcessId == processId) + .Select(cuap => cuap.CompanyUserId) + .SingleOrDefaultAsync(); + + public void DeleteCompanyUserAssignedProcess(Guid companyUserId, Guid processId) => + _dbContext.Remove(new CompanyUserAssignedProcess(companyUserId, processId)); } diff --git a/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.Designer.cs b/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.Designer.cs new file mode 100644 index 0000000000..37bc98806c --- /dev/null +++ b/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.Designer.cs @@ -0,0 +1,10129 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +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("20240517135403_CPLP-3548-declineRegistration")] + partial class CPLP3548declineRegistration + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("portal") + .UseCollation("en_US.utf8") + .HasAnnotation("ProductVersion", "8.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditAppSubscriptionDetail20221118", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AppInstanceId") + .HasColumnType("uuid") + .HasColumnName("app_instance_id"); + + b.Property("AppSubscriptionUrl") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("app_subscription_url"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferSubscriptionId") + .HasColumnType("uuid") + .HasColumnName("offer_subscription_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_app_subscription_detail20221118"); + + b.ToTable("audit_app_subscription_detail20221118", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditAppSubscriptionDetail20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AppInstanceId") + .HasColumnType("uuid") + .HasColumnName("app_instance_id"); + + b.Property("AppSubscriptionUrl") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("app_subscription_url"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferSubscriptionId") + .HasColumnType("uuid") + .HasColumnName("offer_subscription_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_app_subscription_detail20231115"); + + b.ToTable("audit_app_subscription_detail20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCertificateManagement20240416", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_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("Id") + .HasColumnType("uuid") + .HasColumnName("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("AuditV1Id") + .HasName("pk_audit_certificate_management20240416"); + + b.ToTable("audit_certificate_management20240416", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanyApplication20221005", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("ApplicationStatusId") + .HasColumnType("integer") + .HasColumnName("application_status_id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_application20221005"); + + b.ToTable("audit_company_application20221005", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanyApplication20230214", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("ApplicationStatusId") + .HasColumnType("integer") + .HasColumnName("application_status_id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("ChecklistProcessId") + .HasColumnType("uuid") + .HasColumnName("checklist_process_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_application20230214"); + + b.ToTable("audit_company_application20230214", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanyApplication20230824", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("ApplicationStatusId") + .HasColumnType("integer") + .HasColumnName("application_status_id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("ChecklistProcessId") + .HasColumnType("uuid") + .HasColumnName("checklist_process_id"); + + b.Property("CompanyApplicationTypeId") + .HasColumnType("integer") + .HasColumnName("company_application_type_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OnboardingServiceProviderId") + .HasColumnType("uuid") + .HasColumnName("onboarding_service_provider_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_application20230824"); + + b.ToTable("audit_company_application20230824", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanyApplication20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("ApplicationStatusId") + .HasColumnType("integer") + .HasColumnName("application_status_id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("ChecklistProcessId") + .HasColumnType("uuid") + .HasColumnName("checklist_process_id"); + + b.Property("CompanyApplicationTypeId") + .HasColumnType("integer") + .HasColumnName("company_application_type_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OnboardingServiceProviderId") + .HasColumnType("uuid") + .HasColumnName("onboarding_service_provider_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_application20231115"); + + b.ToTable("audit_company_application20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanyAssignedRole2023316", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyRoleId") + .HasColumnType("integer") + .HasColumnName("company_role_id"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_assigned_role2023316"); + + b.ToTable("audit_company_assigned_role2023316", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanySsiDetail20230621", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanySsiDetailStatusId") + .HasColumnType("integer") + .HasColumnName("company_ssi_detail_status_id"); + + b.Property("CreatorUserId") + .HasColumnType("uuid") + .HasColumnName("creator_user_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DocumentId") + .HasColumnType("uuid") + .HasColumnName("document_id"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiry_date"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("VerifiedCredentialExternalTypeUseCaseDetailId") + .HasColumnType("uuid") + .HasColumnName("verified_credential_external_type_use_case_detail_id"); + + b.Property("VerifiedCredentialTypeId") + .HasColumnType("integer") + .HasColumnName("verified_credential_type_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_ssi_detail20230621"); + + b.ToTable("audit_company_ssi_detail20230621", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanySsiDetail20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanySsiDetailStatusId") + .HasColumnType("integer") + .HasColumnName("company_ssi_detail_status_id"); + + b.Property("CreatorUserId") + .HasColumnType("uuid") + .HasColumnName("creator_user_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DocumentId") + .HasColumnType("uuid") + .HasColumnName("document_id"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiry_date"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("VerifiedCredentialExternalTypeUseCaseDetailId") + .HasColumnType("uuid") + .HasColumnName("verified_credential_external_type_use_case_detail_id"); + + b.Property("VerifiedCredentialTypeId") + .HasColumnType("integer") + .HasColumnName("verified_credential_type_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_ssi_detail20231115"); + + b.ToTable("audit_company_ssi_detail20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanyUser20221005", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyUserStatusId") + .HasColumnType("integer") + .HasColumnName("company_user_status_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Email") + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("Firstname") + .HasColumnType("text") + .HasColumnName("firstname"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("Lastlogin") + .HasColumnType("bytea") + .HasColumnName("lastlogin"); + + b.Property("Lastname") + .HasColumnType("text") + .HasColumnName("lastname"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_user20221005"); + + b.ToTable("audit_company_user20221005", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanyUser20230522", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Email") + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("Firstname") + .HasColumnType("text") + .HasColumnName("firstname"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("Lastlogin") + .HasColumnType("bytea") + .HasColumnName("lastlogin"); + + b.Property("Lastname") + .HasColumnType("text") + .HasColumnName("lastname"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_user20230523"); + + b.ToTable("audit_company_user20230523", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditCompanyUserAssignedRole20221018", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("UserRoleId") + .HasColumnType("uuid") + .HasColumnName("user_role_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_company_user_assigned_role20221018"); + + b.ToTable("audit_company_user_assigned_role20221018", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditConnector20230405", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("ConnectorUrl") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("connector_url"); + + b.Property("DapsRegistrationSuccessful") + .HasColumnType("boolean") + .HasColumnName("daps_registration_successful"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("HostId") + .HasColumnType("uuid") + .HasColumnName("host_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("LocationId") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character varying(2)") + .HasColumnName("location_id"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("ProviderId") + .HasColumnType("uuid") + .HasColumnName("provider_id"); + + b.Property("SelfDescriptionDocumentId") + .HasColumnType("uuid") + .HasColumnName("self_description_document_id"); + + b.Property("SelfDescriptionMessage") + .HasColumnType("text") + .HasColumnName("self_description_message"); + + b.Property("StatusId") + .HasColumnType("integer") + .HasColumnName("status_id"); + + b.Property("TypeId") + .HasColumnType("integer") + .HasColumnName("type_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_connector20230405"); + + b.ToTable("audit_connector20230405", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditConnector20230503", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyServiceAccountId") + .HasColumnType("uuid") + .HasColumnName("company_service_account_id"); + + b.Property("ConnectorUrl") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("connector_url"); + + b.Property("DapsRegistrationSuccessful") + .HasColumnType("boolean") + .HasColumnName("daps_registration_successful"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("HostId") + .HasColumnType("uuid") + .HasColumnName("host_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("LocationId") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character varying(2)") + .HasColumnName("location_id"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("ProviderId") + .HasColumnType("uuid") + .HasColumnName("provider_id"); + + b.Property("SelfDescriptionDocumentId") + .HasColumnType("uuid") + .HasColumnName("self_description_document_id"); + + b.Property("SelfDescriptionMessage") + .HasColumnType("text") + .HasColumnName("self_description_message"); + + b.Property("StatusId") + .HasColumnType("integer") + .HasColumnName("status_id"); + + b.Property("TypeId") + .HasColumnType("integer") + .HasColumnName("type_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_connector20230503"); + + b.ToTable("audit_connector20230503", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditConnector20230803", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyServiceAccountId") + .HasColumnType("uuid") + .HasColumnName("company_service_account_id"); + + b.Property("ConnectorUrl") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("connector_url"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("HostId") + .HasColumnType("uuid") + .HasColumnName("host_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("LocationId") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character varying(2)") + .HasColumnName("location_id"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("ProviderId") + .HasColumnType("uuid") + .HasColumnName("provider_id"); + + b.Property("SelfDescriptionDocumentId") + .HasColumnType("uuid") + .HasColumnName("self_description_document_id"); + + b.Property("SelfDescriptionMessage") + .HasColumnType("text") + .HasColumnName("self_description_message"); + + b.Property("StatusId") + .HasColumnType("integer") + .HasColumnName("status_id"); + + b.Property("TypeId") + .HasColumnType("integer") + .HasColumnName("type_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_connector20230803"); + + b.ToTable("audit_connector20230803", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditConnector20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyServiceAccountId") + .HasColumnType("uuid") + .HasColumnName("company_service_account_id"); + + b.Property("ConnectorUrl") + .HasColumnType("text") + .HasColumnName("connector_url"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("HostId") + .HasColumnType("uuid") + .HasColumnName("host_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("LocationId") + .HasColumnType("text") + .HasColumnName("location_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("ProviderId") + .HasColumnType("uuid") + .HasColumnName("provider_id"); + + b.Property("SelfDescriptionDocumentId") + .HasColumnType("uuid") + .HasColumnName("self_description_document_id"); + + b.Property("SelfDescriptionMessage") + .HasColumnType("text") + .HasColumnName("self_description_message"); + + b.Property("StatusId") + .HasColumnType("integer") + .HasColumnName("status_id"); + + b.Property("TypeId") + .HasColumnType("integer") + .HasColumnName("type_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_connector20231115"); + + b.ToTable("audit_connector20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditConsent20230412", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AgreementId") + .HasColumnType("uuid") + .HasColumnName("agreement_id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("Comment") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("comment"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("ConsentStatusId") + .HasColumnType("integer") + .HasColumnName("consent_status_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DocumentId") + .HasColumnType("uuid") + .HasColumnName("document_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("Target") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("target"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_consent20230412"); + + b.ToTable("audit_consent20230412", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditConsent20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AgreementId") + .HasColumnType("uuid") + .HasColumnName("agreement_id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("Comment") + .HasColumnType("text") + .HasColumnName("comment"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("ConsentStatusId") + .HasColumnType("integer") + .HasColumnName("consent_status_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DocumentId") + .HasColumnType("uuid") + .HasColumnName("document_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("Target") + .HasColumnType("text") + .HasColumnName("target"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_consent20231115"); + + b.ToTable("audit_consent20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditDocument20231108", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DocumentContent") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("document_content"); + + b.Property("DocumentHash") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("document_hash"); + + b.Property("DocumentName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("document_name"); + + b.Property("DocumentStatusId") + .HasColumnType("integer") + .HasColumnName("document_status_id"); + + b.Property("DocumentTypeId") + .HasColumnType("integer") + .HasColumnName("document_type_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("MediaTypeId") + .HasColumnType("integer") + .HasColumnName("media_type_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_document20231108"); + + b.ToTable("audit_document20231108", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditDocument20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DocumentContent") + .HasColumnType("bytea") + .HasColumnName("document_content"); + + b.Property("DocumentHash") + .HasColumnType("bytea") + .HasColumnName("document_hash"); + + b.Property("DocumentName") + .HasColumnType("text") + .HasColumnName("document_name"); + + b.Property("DocumentStatusId") + .HasColumnType("integer") + .HasColumnName("document_status_id"); + + b.Property("DocumentTypeId") + .HasColumnType("integer") + .HasColumnName("document_type_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("MediaTypeId") + .HasColumnType("integer") + .HasColumnName("media_type_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_document20231115"); + + b.ToTable("audit_document20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditIdentity20230526", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("IdentityTypeId") + .HasColumnType("integer") + .HasColumnName("identity_type_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("UserEntityId") + .HasMaxLength(36) + .HasColumnType("character varying(36)") + .HasColumnName("user_entity_id"); + + b.Property("UserStatusId") + .HasColumnType("integer") + .HasColumnName("user_status_id") + .HasAnnotation("Relational:JsonPropertyName", "user_status_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_identity20230526"); + + b.ToTable("audit_identity20230526", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditIdentity20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("IdentityTypeId") + .HasColumnType("integer") + .HasColumnName("identity_type_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("UserEntityId") + .HasColumnType("text") + .HasColumnName("user_entity_id"); + + b.Property("UserStatusId") + .HasColumnType("integer") + .HasColumnName("user_status_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_identity20231115"); + + b.ToTable("audit_identity20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditIdentityAssignedRole20230522", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("IdentityId") + .HasColumnType("uuid") + .HasColumnName("identity_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("UserRoleId") + .HasColumnType("uuid") + .HasColumnName("user_role_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_identity_assigned_role20230522"); + + b.ToTable("audit_identity_assigned_role20230522", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditOffer20230119", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("ContactEmail") + .HasColumnType("text") + .HasColumnName("contact_email"); + + b.Property("ContactNumber") + .HasColumnType("text") + .HasColumnName("contact_number"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DateReleased") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_released"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("MarketingUrl") + .HasColumnType("text") + .HasColumnName("marketing_url"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("OfferStatusId") + .HasColumnType("integer") + .HasColumnName("offer_status_id"); + + b.Property("OfferTypeId") + .HasColumnType("integer") + .HasColumnName("offer_type_id"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("text") + .HasColumnName("provider"); + + b.Property("ProviderCompanyId") + .HasColumnType("uuid") + .HasColumnName("provider_company_id"); + + b.Property("SalesManagerId") + .HasColumnType("uuid") + .HasColumnName("sales_manager_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_offer20230119"); + + b.ToTable("audit_offer20230119", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditOffer20230406", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("ContactEmail") + .HasColumnType("text") + .HasColumnName("contact_email"); + + b.Property("ContactNumber") + .HasColumnType("text") + .HasColumnName("contact_number"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DateReleased") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_released"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("LicenseTypeId") + .HasColumnType("integer") + .HasColumnName("license_type_id"); + + b.Property("MarketingUrl") + .HasColumnType("text") + .HasColumnName("marketing_url"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("OfferStatusId") + .HasColumnType("integer") + .HasColumnName("offer_status_id"); + + b.Property("OfferTypeId") + .HasColumnType("integer") + .HasColumnName("offer_type_id"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("text") + .HasColumnName("provider"); + + b.Property("ProviderCompanyId") + .HasColumnType("uuid") + .HasColumnName("provider_company_id"); + + b.Property("SalesManagerId") + .HasColumnType("uuid") + .HasColumnName("sales_manager_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_offer20230406"); + + b.ToTable("audit_offer20230406", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditOffer20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("ContactEmail") + .HasColumnType("text") + .HasColumnName("contact_email"); + + b.Property("ContactNumber") + .HasColumnType("text") + .HasColumnName("contact_number"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DateReleased") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_released"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("LicenseTypeId") + .HasColumnType("integer") + .HasColumnName("license_type_id"); + + b.Property("MarketingUrl") + .HasColumnType("text") + .HasColumnName("marketing_url"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("OfferStatusId") + .HasColumnType("integer") + .HasColumnName("offer_status_id"); + + b.Property("OfferTypeId") + .HasColumnType("integer") + .HasColumnName("offer_type_id"); + + b.Property("Provider") + .HasColumnType("text") + .HasColumnName("provider"); + + b.Property("ProviderCompanyId") + .HasColumnType("uuid") + .HasColumnName("provider_company_id"); + + b.Property("SalesManagerId") + .HasColumnType("uuid") + .HasColumnName("sales_manager_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_offer20231115"); + + b.ToTable("audit_offer20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditOfferSubscription20221005", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("DisplayName") + .HasColumnType("text") + .HasColumnName("display_name"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("OfferSubscriptionStatusId") + .HasColumnType("integer") + .HasColumnName("offer_subscription_status_id"); + + b.Property("RequesterId") + .HasColumnType("uuid") + .HasColumnName("requester_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_offer_subscription20221005"); + + b.ToTable("audit_offer_subscription20221005", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditOfferSubscription20230317", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("DisplayName") + .HasColumnType("text") + .HasColumnName("display_name"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("OfferSubscriptionStatusId") + .HasColumnType("integer") + .HasColumnName("offer_subscription_status_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("RequesterId") + .HasColumnType("uuid") + .HasColumnName("requester_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_offer_subscription20230317"); + + b.ToTable("audit_offer_subscription20230317", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditOfferSubscription20231013", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("DisplayName") + .HasColumnType("text") + .HasColumnName("display_name"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("OfferSubscriptionStatusId") + .HasColumnType("integer") + .HasColumnName("offer_subscription_status_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("RequesterId") + .HasColumnType("uuid") + .HasColumnName("requester_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_offer_subscription20231013"); + + b.ToTable("audit_offer_subscription20231013", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditOfferSubscription20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("DisplayName") + .HasColumnType("text") + .HasColumnName("display_name"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("OfferSubscriptionStatusId") + .HasColumnType("integer") + .HasColumnName("offer_subscription_status_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("RequesterId") + .HasColumnType("uuid") + .HasColumnName("requester_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_offer_subscription20231115"); + + b.ToTable("audit_offer_subscription20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditProviderCompanyDetail20230614", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("AutoSetupCallbackUrl") + .HasColumnType("text") + .HasColumnName("auto_setup_callback_url"); + + b.Property("AutoSetupUrl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("auto_setup_url"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_provider_company_detail20230614"); + + b.ToTable("audit_provider_company_detail20230614", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditProviderCompanyDetail20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("AutoSetupCallbackUrl") + .HasColumnType("text") + .HasColumnName("auto_setup_callback_url"); + + b.Property("AutoSetupUrl") + .HasColumnType("text") + .HasColumnName("auto_setup_url"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_provider_company_detail20231115"); + + b.ToTable("audit_provider_company_detail20231115", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditUserRole20221017", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("UserRoleText") + .IsRequired() + .HasColumnType("text") + .HasColumnName("user_role"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_user_role20221017"); + + b.ToTable("audit_user_role20221017", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.AuditEntities.AuditUserRole20231115", b => + { + b.Property("AuditV1Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("audit_v1id"); + + b.Property("AuditV1DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("audit_v1date_last_changed"); + + b.Property("AuditV1LastEditorId") + .HasColumnType("uuid") + .HasColumnName("audit_v1last_editor_id"); + + b.Property("AuditV1OperationId") + .HasColumnType("integer") + .HasColumnName("audit_v1operation_id"); + + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("UserRoleText") + .HasColumnType("text") + .HasColumnName("user_role"); + + b.HasKey("AuditV1Id") + .HasName("pk_audit_user_role20231115"); + + 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") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("City") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("city"); + + b.Property("CountryAlpha2Code") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("country_alpha2code") + .HasAnnotation("Relational:JsonPropertyName", "country_alpha2code"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Region") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("region"); + + b.Property("Streetadditional") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("streetadditional"); + + b.Property("Streetname") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("streetname"); + + b.Property("Streetnumber") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("streetnumber"); + + b.Property("Zipcode") + .HasMaxLength(12) + .HasColumnType("character varying(12)") + .HasColumnName("zipcode"); + + b.HasKey("Id") + .HasName("pk_addresses"); + + b.HasIndex("CountryAlpha2Code") + .HasDatabaseName("ix_addresses_country_alpha2code"); + + b.ToTable("addresses", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Agreement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AgreementCategoryId") + .HasColumnType("integer") + .HasColumnName("agreement_category_id"); + + b.Property("AgreementLink") + .HasColumnType("text") + .HasColumnName("agreement_link"); + + b.Property("AgreementStatusId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1) + .HasColumnName("agreement_status_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DocumentId") + .HasColumnType("uuid") + .HasColumnName("document_id"); + + b.Property("IssuerCompanyId") + .HasColumnType("uuid") + .HasColumnName("issuer_company_id"); + + b.Property("Mandatory") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true) + .HasColumnName("mandatory"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("UseCaseId") + .HasColumnType("uuid") + .HasColumnName("use_case_id"); + + b.HasKey("Id") + .HasName("pk_agreements"); + + b.HasIndex("AgreementCategoryId") + .HasDatabaseName("ix_agreements_agreement_category_id"); + + b.HasIndex("AgreementStatusId") + .HasDatabaseName("ix_agreements_agreement_status_id"); + + b.HasIndex("DocumentId") + .HasDatabaseName("ix_agreements_document_id"); + + b.HasIndex("IssuerCompanyId") + .HasDatabaseName("ix_agreements_issuer_company_id"); + + b.HasIndex("UseCaseId") + .HasDatabaseName("ix_agreements_use_case_id"); + + b.ToTable("agreements", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementAssignedCompanyRole", b => + { + b.Property("AgreementId") + .HasColumnType("uuid") + .HasColumnName("agreement_id"); + + b.Property("CompanyRoleId") + .HasColumnType("integer") + .HasColumnName("company_role_id"); + + b.HasKey("AgreementId", "CompanyRoleId") + .HasName("pk_agreement_assigned_company_roles"); + + b.HasIndex("CompanyRoleId") + .HasDatabaseName("ix_agreement_assigned_company_roles_company_role_id"); + + b.ToTable("agreement_assigned_company_roles", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementAssignedOffer", b => + { + b.Property("AgreementId") + .HasColumnType("uuid") + .HasColumnName("agreement_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.HasKey("AgreementId", "OfferId") + .HasName("pk_agreement_assigned_offers"); + + b.HasIndex("OfferId") + .HasDatabaseName("ix_agreement_assigned_offers_offer_id"); + + b.ToTable("agreement_assigned_offers", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementAssignedOfferType", b => + { + b.Property("AgreementId") + .HasColumnType("uuid") + .HasColumnName("agreement_id"); + + b.Property("OfferTypeId") + .HasColumnType("integer") + .HasColumnName("offer_type_id"); + + b.HasKey("AgreementId", "OfferTypeId") + .HasName("pk_agreement_assigned_offer_types"); + + b.HasIndex("OfferTypeId") + .HasDatabaseName("ix_agreement_assigned_offer_types_offer_type_id"); + + b.ToTable("agreement_assigned_offer_types", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementCategory", 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_agreement_categories"); + + b.ToTable("agreement_categories", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "CX_FRAME_CONTRACT" + }, + new + { + Id = 2, + Label = "APP_CONTRACT" + }, + new + { + Id = 3, + Label = "DATA_CONTRACT" + }, + new + { + Id = 4, + Label = "SERVICE_CONTRACT" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementStatus", 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_agreement_statuses"); + + b.ToTable("agreement_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "ACTIVE" + }, + new + { + Id = 2, + Label = "INACTIVE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppAssignedUseCase", b => + { + b.Property("AppId") + .HasColumnType("uuid") + .HasColumnName("app_id"); + + b.Property("UseCaseId") + .HasColumnType("uuid") + .HasColumnName("use_case_id"); + + b.HasKey("AppId", "UseCaseId") + .HasName("pk_app_assigned_use_cases"); + + b.HasIndex("UseCaseId") + .HasDatabaseName("ix_app_assigned_use_cases_use_case_id"); + + b.ToTable("app_assigned_use_cases", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AppId") + .HasColumnType("uuid") + .HasColumnName("app_id"); + + b.Property("IamClientId") + .HasColumnType("uuid") + .HasColumnName("iam_client_id"); + + b.HasKey("Id") + .HasName("pk_app_instances"); + + b.HasIndex("AppId") + .HasDatabaseName("ix_app_instances_app_id"); + + b.HasIndex("IamClientId") + .HasDatabaseName("ix_app_instances_iam_client_id"); + + b.ToTable("app_instances", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstanceAssignedCompanyServiceAccount", b => + { + b.Property("AppInstanceId") + .HasColumnType("uuid") + .HasColumnName("app_instance_id"); + + b.Property("CompanyServiceAccountId") + .HasColumnType("uuid") + .HasColumnName("company_service_account_id"); + + b.HasKey("AppInstanceId", "CompanyServiceAccountId") + .HasName("pk_app_instance_assigned_service_accounts"); + + b.HasIndex("CompanyServiceAccountId") + .HasDatabaseName("ix_app_instance_assigned_service_accounts_company_service_acco"); + + b.ToTable("app_instance_assigned_service_accounts", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstanceSetup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AppId") + .HasColumnType("uuid") + .HasColumnName("app_id"); + + b.Property("InstanceUrl") + .HasColumnType("text") + .HasColumnName("instance_url"); + + b.Property("IsSingleInstance") + .HasColumnType("boolean") + .HasColumnName("is_single_instance"); + + b.HasKey("Id") + .HasName("pk_app_instance_setups"); + + b.HasIndex("AppId") + .IsUnique() + .HasDatabaseName("ix_app_instance_setups_app_id"); + + b.ToTable("app_instance_setups", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppLanguage", b => + { + b.Property("AppId") + .HasColumnType("uuid") + .HasColumnName("app_id"); + + b.Property("LanguageShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("language_short_name"); + + b.HasKey("AppId", "LanguageShortName") + .HasName("pk_app_languages"); + + b.HasIndex("LanguageShortName") + .HasDatabaseName("ix_app_languages_language_short_name"); + + b.ToTable("app_languages", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppSubscriptionDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AppInstanceId") + .HasColumnType("uuid") + .HasColumnName("app_instance_id"); + + b.Property("AppSubscriptionUrl") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("app_subscription_url"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferSubscriptionId") + .HasColumnType("uuid") + .HasColumnName("offer_subscription_id"); + + b.HasKey("Id") + .HasName("pk_app_subscription_details"); + + b.HasIndex("AppInstanceId") + .HasDatabaseName("ix_app_subscription_details_app_instance_id"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_app_subscription_details_last_editor_id"); + + b.HasIndex("OfferSubscriptionId") + .IsUnique() + .HasDatabaseName("ix_app_subscription_details_offer_subscription_id"); + + b.ToTable("app_subscription_details", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_APPSUBSCRIPTIONDETAIL"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_APPSUBSCRIPTIONDETAIL"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_APPSUBSCRIPTIONDETAIL", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_APPSUBSCRIPTIONDETAIL\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_APPSUBSCRIPTIONDETAIL$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_app_subscription_detail20231115\" (\"id\", \"offer_subscription_id\", \"app_instance_id\", \"app_subscription_url\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"offer_subscription_id\", \r\n NEW.\"app_instance_id\", \r\n NEW.\"app_subscription_url\", \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_APPSUBSCRIPTIONDETAIL$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_APPSUBSCRIPTIONDETAIL AFTER INSERT\r\nON \"portal\".\"app_subscription_details\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_APPSUBSCRIPTIONDETAIL\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_APPSUBSCRIPTIONDETAIL", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_APPSUBSCRIPTIONDETAIL\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_APPSUBSCRIPTIONDETAIL$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_app_subscription_detail20231115\" (\"id\", \"offer_subscription_id\", \"app_instance_id\", \"app_subscription_url\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"offer_subscription_id\", \r\n NEW.\"app_instance_id\", \r\n NEW.\"app_subscription_url\", \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_APPSUBSCRIPTIONDETAIL$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_APPSUBSCRIPTIONDETAIL AFTER UPDATE\r\nON \"portal\".\"app_subscription_details\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_APPSUBSCRIPTIONDETAIL\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ApplicationChecklistEntry", b => + { + b.Property("ApplicationId") + .HasColumnType("uuid") + .HasColumnName("application_id"); + + b.Property("ApplicationChecklistEntryTypeId") + .HasColumnType("integer") + .HasColumnName("application_checklist_entry_type_id"); + + b.Property("ApplicationChecklistEntryStatusId") + .HasColumnType("integer") + .HasColumnName("application_checklist_entry_status_id"); + + b.Property("Comment") + .HasColumnType("text") + .HasColumnName("comment"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.HasKey("ApplicationId", "ApplicationChecklistEntryTypeId") + .HasName("pk_application_checklist"); + + b.HasIndex("ApplicationChecklistEntryStatusId") + .HasDatabaseName("ix_application_checklist_application_checklist_entry_status_id"); + + b.HasIndex("ApplicationChecklistEntryTypeId") + .HasDatabaseName("ix_application_checklist_application_checklist_entry_type_id"); + + b.ToTable("application_checklist", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ApplicationChecklistEntryStatus", 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_application_checklist_statuses"); + + b.ToTable("application_checklist_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "TO_DO" + }, + new + { + Id = 2, + Label = "IN_PROGRESS" + }, + new + { + Id = 3, + Label = "DONE" + }, + new + { + Id = 4, + Label = "FAILED" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ApplicationChecklistEntryType", 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_application_checklist_types"); + + b.ToTable("application_checklist_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "REGISTRATION_VERIFICATION" + }, + new + { + Id = 2, + Label = "BUSINESS_PARTNER_NUMBER" + }, + new + { + Id = 3, + Label = "IDENTITY_WALLET" + }, + new + { + Id = 4, + Label = "BPNL_CREDENTIAL" + }, + new + { + Id = 5, + Label = "MEMBERSHIP_CREDENTIAL" + }, + new + { + Id = 6, + Label = "CLEARING_HOUSE" + }, + new + { + Id = 7, + Label = "SELF_DESCRIPTION_LP" + }, + new + { + Id = 8, + Label = "APPLICATION_ACTIVATION" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AuditOperation", 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_audit_operation"); + + b.ToTable("audit_operation", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "INSERT" + }, + new + { + Id = 2, + Label = "UPDATE" + }, + new + { + Id = 3, + Label = "DELETE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.BpdmIdentifier", 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_bpdm_identifiers"); + + b.ToTable("bpdm_identifiers", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "EU_VAT_ID_DE" + }, + new + { + Id = 2, + Label = "CH_UID" + }, + new + { + Id = 3, + Label = "EU_VAT_ID_FR" + }, + new + { + Id = 4, + Label = "FR_SIREN" + }, + new + { + Id = 5, + Label = "EU_VAT_ID_AT" + }, + new + { + Id = 6, + Label = "DE_BNUM" + }, + new + { + Id = 7, + Label = "CZ_ICO" + }, + new + { + Id = 8, + Label = "EU_VAT_ID_CZ" + }, + new + { + Id = 9, + Label = "EU_VAT_ID_PL" + }, + new + { + Id = 10, + Label = "EU_VAT_ID_BE" + }, + new + { + Id = 11, + Label = "EU_VAT_ID_CH" + }, + new + { + Id = 12, + Label = "EU_VAT_ID_DK" + }, + new + { + Id = 13, + Label = "EU_VAT_ID_ES" + }, + new + { + Id = 14, + Label = "EU_VAT_ID_GB" + }, + new + { + Id = 15, + Label = "EU_VAT_ID_NO" + }, + new + { + Id = 16, + Label = "BE_ENT_NO" + }, + new + { + Id = 17, + Label = "CVR_DK" + }, + new + { + Id = 18, + Label = "ID_CRN" + }, + new + { + Id = 19, + Label = "NO_ORGID" + }, + new + { + Id = 20, + Label = "LEI_ID" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddressId") + .HasColumnType("uuid") + .HasColumnName("address_id"); + + b.Property("BusinessPartnerNumber") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("business_partner_number"); + + b.Property("CompanyStatusId") + .HasColumnType("integer") + .HasColumnName("company_status_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DidDocumentLocation") + .HasColumnType("text") + .HasColumnName("did_document_location"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("SelfDescriptionDocumentId") + .HasColumnType("uuid") + .HasColumnName("self_description_document_id"); + + b.Property("Shortname") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("shortname"); + + b.HasKey("Id") + .HasName("pk_companies"); + + b.HasIndex("AddressId") + .HasDatabaseName("ix_companies_address_id"); + + b.HasIndex("CompanyStatusId") + .HasDatabaseName("ix_companies_company_status_id"); + + b.HasIndex("SelfDescriptionDocumentId") + .HasDatabaseName("ix_companies_self_description_document_id"); + + b.ToTable("companies", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ApplicationStatusId") + .HasColumnType("integer") + .HasColumnName("application_status_id"); + + b.Property("ChecklistProcessId") + .HasColumnType("uuid") + .HasColumnName("checklist_process_id"); + + b.Property("CompanyApplicationTypeId") + .HasColumnType("integer") + .HasColumnName("company_application_type_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OnboardingServiceProviderId") + .HasColumnType("uuid") + .HasColumnName("onboarding_service_provider_id"); + + b.HasKey("Id") + .HasName("pk_company_applications"); + + b.HasIndex("ApplicationStatusId") + .HasDatabaseName("ix_company_applications_application_status_id"); + + b.HasIndex("ChecklistProcessId") + .IsUnique() + .HasDatabaseName("ix_company_applications_checklist_process_id"); + + b.HasIndex("CompanyApplicationTypeId") + .HasDatabaseName("ix_company_applications_company_application_type_id"); + + b.HasIndex("CompanyId") + .HasDatabaseName("ix_company_applications_company_id"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_company_applications_last_editor_id"); + + b.HasIndex("OnboardingServiceProviderId") + .HasDatabaseName("ix_company_applications_onboarding_service_provider_id"); + + b.ToTable("company_applications", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_COMPANYAPPLICATION"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_COMPANYAPPLICATION"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_COMPANYAPPLICATION", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYAPPLICATION\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_COMPANYAPPLICATION$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_company_application20231115\" (\"id\", \"date_created\", \"date_last_changed\", \"application_status_id\", \"company_id\", \"checklist_process_id\", \"company_application_type_id\", \"onboarding_service_provider_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"date_created\", \r\n NEW.\"date_last_changed\", \r\n NEW.\"application_status_id\", \r\n NEW.\"company_id\", \r\n NEW.\"checklist_process_id\", \r\n NEW.\"company_application_type_id\", \r\n NEW.\"onboarding_service_provider_id\", \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_COMPANYAPPLICATION$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_COMPANYAPPLICATION AFTER INSERT\r\nON \"portal\".\"company_applications\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYAPPLICATION\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_COMPANYAPPLICATION", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYAPPLICATION\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_COMPANYAPPLICATION$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_company_application20231115\" (\"id\", \"date_created\", \"date_last_changed\", \"application_status_id\", \"company_id\", \"checklist_process_id\", \"company_application_type_id\", \"onboarding_service_provider_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"date_created\", \r\n NEW.\"date_last_changed\", \r\n NEW.\"application_status_id\", \r\n NEW.\"company_id\", \r\n NEW.\"checklist_process_id\", \r\n NEW.\"company_application_type_id\", \r\n NEW.\"onboarding_service_provider_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_COMPANYAPPLICATION$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_COMPANYAPPLICATION AFTER UPDATE\r\nON \"portal\".\"company_applications\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYAPPLICATION\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplicationStatus", 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_application_statuses"); + + b.ToTable("company_application_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "CREATED" + }, + new + { + Id = 2, + Label = "ADD_COMPANY_DATA" + }, + new + { + Id = 3, + Label = "INVITE_USER" + }, + new + { + Id = 4, + Label = "SELECT_COMPANY_ROLE" + }, + new + { + Id = 5, + Label = "UPLOAD_DOCUMENTS" + }, + new + { + Id = 6, + Label = "VERIFY" + }, + new + { + Id = 7, + Label = "SUBMITTED" + }, + new + { + Id = 8, + Label = "CONFIRMED" + }, + new + { + Id = 9, + Label = "DECLINED" + }, + new + { + Id = 10, + Label = "CANCELLED_BY_CUSTOMER" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplicationType", 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_application_types"); + + b.ToTable("company_application_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "INTERNAL" + }, + new + { + Id = 2, + Label = "EXTERNAL" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyAssignedRole", b => + { + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyRoleId") + .HasColumnType("integer") + .HasColumnName("company_role_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.HasKey("CompanyId", "CompanyRoleId") + .HasName("pk_company_assigned_roles"); + + b.HasIndex("CompanyRoleId") + .HasDatabaseName("ix_company_assigned_roles_company_role_id"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_company_assigned_roles_last_editor_id"); + + b.ToTable("company_assigned_roles", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_COMPANYASSIGNEDROLE"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_COMPANYASSIGNEDROLE"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_COMPANYASSIGNEDROLE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYASSIGNEDROLE\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_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 1, \r\n CURRENT_TIMESTAMP, \r\n NEW.\"last_editor_id\";\r\nRETURN NEW;\r\nEND;\r\n$LC_TRIGGER_AFTER_INSERT_COMPANYASSIGNEDROLE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_COMPANYASSIGNEDROLE AFTER INSERT\r\nON \"portal\".\"company_assigned_roles\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYASSIGNEDROLE\"();") + .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 => + { + 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.CompanyIdentifier", b => + { + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("UniqueIdentifierId") + .HasColumnType("integer") + .HasColumnName("unique_identifier_id"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text") + .HasColumnName("value"); + + b.HasKey("CompanyId", "UniqueIdentifierId") + .HasName("pk_company_identifiers"); + + b.HasIndex("UniqueIdentifierId") + .HasDatabaseName("ix_company_identifiers_unique_identifier_id"); + + b.ToTable("company_identifiers", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyIdentityProvider", b => + { + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("IdentityProviderId") + .HasColumnType("uuid") + .HasColumnName("identity_provider_id"); + + b.HasKey("CompanyId", "IdentityProviderId") + .HasName("pk_company_identity_providers"); + + b.HasIndex("IdentityProviderId") + .HasDatabaseName("ix_company_identity_providers_identity_provider_id"); + + b.ToTable("company_identity_providers", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyInvitation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ApplicationId") + .HasColumnType("uuid") + .HasColumnName("application_id"); + + b.Property("ClientId") + .HasColumnType("text") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .HasColumnType("bytea") + .HasColumnName("client_secret"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("EncryptionMode") + .HasColumnType("integer") + .HasColumnName("encryption_mode"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("first_name"); + + b.Property("IdpName") + .HasColumnType("text") + .HasColumnName("idp_name"); + + b.Property("InitializationVector") + .HasColumnType("bytea") + .HasColumnName("initialization_vector"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("last_name"); + + b.Property("OrganisationName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("organisation_name"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("ServiceAccountUserId") + .HasColumnType("text") + .HasColumnName("service_account_user_id"); + + b.Property("UserName") + .HasColumnType("text") + .HasColumnName("user_name"); + + b.HasKey("Id") + .HasName("pk_company_invitations"); + + b.HasIndex("ApplicationId") + .IsUnique() + .HasDatabaseName("ix_company_invitations_application_id"); + + b.HasIndex("ProcessId") + .IsUnique() + .HasDatabaseName("ix_company_invitations_process_id"); + + b.ToTable("company_invitations", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRole", 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_roles"); + + b.ToTable("company_roles", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "ACTIVE_PARTICIPANT" + }, + new + { + Id = 2, + Label = "APP_PROVIDER" + }, + new + { + Id = 3, + Label = "SERVICE_PROVIDER" + }, + new + { + Id = 4, + Label = "OPERATOR" + }, + new + { + Id = 5, + Label = "ONBOARDING_SERVICE_PROVIDER" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRoleAssignedRoleCollection", b => + { + b.Property("CompanyRoleId") + .HasColumnType("integer") + .HasColumnName("company_role_id"); + + b.Property("UserRoleCollectionId") + .HasColumnType("uuid") + .HasColumnName("user_role_collection_id"); + + b.HasKey("CompanyRoleId") + .HasName("pk_company_role_assigned_role_collections"); + + b.HasIndex("UserRoleCollectionId") + .IsUnique() + .HasDatabaseName("ix_company_role_assigned_role_collections_user_role_collection"); + + b.ToTable("company_role_assigned_role_collections", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRoleDescription", b => + { + b.Property("CompanyRoleId") + .HasColumnType("integer") + .HasColumnName("company_role_id"); + + b.Property("LanguageShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("language_short_name"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("description"); + + b.HasKey("CompanyRoleId", "LanguageShortName") + .HasName("pk_company_role_descriptions"); + + b.HasIndex("LanguageShortName") + .HasDatabaseName("ix_company_role_descriptions_language_short_name"); + + b.ToTable("company_role_descriptions", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRoleRegistrationData", b => + { + b.Property("CompanyRoleId") + .HasColumnType("integer") + .HasColumnName("company_role_id"); + + b.Property("IsRegistrationRole") + .HasColumnType("boolean") + .HasColumnName("is_registration_role"); + + b.HasKey("CompanyRoleId") + .HasName("pk_company_role_registration_data"); + + b.ToTable("company_role_registration_data", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccount", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ClientClientId") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("client_client_id"); + + b.Property("CompanyServiceAccountKindId") + .HasColumnType("integer") + .HasColumnName("company_service_account_kind_id"); + + b.Property("CompanyServiceAccountTypeId") + .HasColumnType("integer") + .HasColumnName("company_service_account_type_id"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("OfferSubscriptionId") + .HasColumnType("uuid") + .HasColumnName("offer_subscription_id"); + + b.HasKey("Id") + .HasName("pk_company_service_accounts"); + + b.HasIndex("ClientClientId") + .HasDatabaseName("ix_company_service_accounts_client_client_id") + .HasFilter("client_client_id is not null AND company_service_account_kind_id = 1"); + + b.HasIndex("CompanyServiceAccountKindId") + .HasDatabaseName("ix_company_service_accounts_company_service_account_kind_id"); + + b.HasIndex("CompanyServiceAccountTypeId") + .HasDatabaseName("ix_company_service_accounts_company_service_account_type_id"); + + b.HasIndex("OfferSubscriptionId") + .HasDatabaseName("ix_company_service_accounts_offer_subscription_id"); + + b.ToTable("company_service_accounts", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccountKind", 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_service_account_kindes"); + + b.ToTable("company_service_account_kindes", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "INTERNAL" + }, + new + { + Id = 2, + Label = "EXTERNAL" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccountType", 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_service_account_types"); + + b.ToTable("company_service_account_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "MANAGED" + }, + new + { + Id = 2, + Label = "OWN" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanySsiDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanySsiDetailStatusId") + .HasColumnType("integer") + .HasColumnName("company_ssi_detail_status_id"); + + b.Property("CreatorUserId") + .HasColumnType("uuid") + .HasColumnName("creator_user_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DocumentId") + .HasColumnType("uuid") + .HasColumnName("document_id"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiry_date"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("VerifiedCredentialExternalTypeUseCaseDetailId") + .HasColumnType("uuid") + .HasColumnName("verified_credential_external_type_use_case_detail_id"); + + b.Property("VerifiedCredentialTypeId") + .HasColumnType("integer") + .HasColumnName("verified_credential_type_id"); + + b.HasKey("Id") + .HasName("pk_company_ssi_details"); + + b.HasIndex("CompanyId") + .HasDatabaseName("ix_company_ssi_details_company_id"); + + b.HasIndex("CompanySsiDetailStatusId") + .HasDatabaseName("ix_company_ssi_details_company_ssi_detail_status_id"); + + b.HasIndex("CreatorUserId") + .HasDatabaseName("ix_company_ssi_details_creator_user_id"); + + b.HasIndex("DocumentId") + .IsUnique() + .HasDatabaseName("ix_company_ssi_details_document_id"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_company_ssi_details_last_editor_id"); + + b.HasIndex("VerifiedCredentialExternalTypeUseCaseDetailId") + .HasDatabaseName("ix_company_ssi_details_verified_credential_external_type_use_c"); + + b.HasIndex("VerifiedCredentialTypeId") + .HasDatabaseName("ix_company_ssi_details_verified_credential_type_id"); + + b.ToTable("company_ssi_details", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_COMPANYSSIDETAIL"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_COMPANYSSIDETAIL"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_COMPANYSSIDETAIL", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYSSIDETAIL\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_COMPANYSSIDETAIL$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_company_ssi_detail20231115\" (\"id\", \"company_id\", \"verified_credential_type_id\", \"company_ssi_detail_status_id\", \"document_id\", \"date_created\", \"creator_user_id\", \"expiry_date\", \"verified_credential_external_type_use_case_detail_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.\"company_id\", \r\n NEW.\"verified_credential_type_id\", \r\n NEW.\"company_ssi_detail_status_id\", \r\n NEW.\"document_id\", \r\n NEW.\"date_created\", \r\n NEW.\"creator_user_id\", \r\n NEW.\"expiry_date\", \r\n NEW.\"verified_credential_external_type_use_case_detail_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_COMPANYSSIDETAIL$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_COMPANYSSIDETAIL AFTER INSERT\r\nON \"portal\".\"company_ssi_details\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYSSIDETAIL\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_COMPANYSSIDETAIL", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYSSIDETAIL\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_COMPANYSSIDETAIL$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_company_ssi_detail20231115\" (\"id\", \"company_id\", \"verified_credential_type_id\", \"company_ssi_detail_status_id\", \"document_id\", \"date_created\", \"creator_user_id\", \"expiry_date\", \"verified_credential_external_type_use_case_detail_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.\"company_id\", \r\n NEW.\"verified_credential_type_id\", \r\n NEW.\"company_ssi_detail_status_id\", \r\n NEW.\"document_id\", \r\n NEW.\"date_created\", \r\n NEW.\"creator_user_id\", \r\n NEW.\"expiry_date\", \r\n NEW.\"verified_credential_external_type_use_case_detail_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_COMPANYSSIDETAIL$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_COMPANYSSIDETAIL AFTER UPDATE\r\nON \"portal\".\"company_ssi_details\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYSSIDETAIL\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanySsiDetailStatus", 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_ssi_detail_statuses"); + + b.ToTable("company_ssi_detail_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "PENDING" + }, + new + { + Id = 2, + Label = "ACTIVE" + }, + new + { + Id = 3, + Label = "INACTIVE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyStatus", 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_statuses"); + + b.ToTable("company_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "PENDING" + }, + new + { + Id = 2, + Label = "ACTIVE" + }, + new + { + Id = 3, + Label = "REJECTED" + }, + new + { + Id = 4, + Label = "INACTIVE" + }, + new + { + Id = 5, + Label = "DELETED" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Email") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("email"); + + b.Property("Firstname") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("firstname"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("Lastlogin") + .HasColumnType("bytea") + .HasColumnName("lastlogin"); + + b.Property("Lastname") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("lastname"); + + b.HasKey("Id") + .HasName("pk_company_users"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_company_users_last_editor_id"); + + b.ToTable("company_users", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_COMPANYUSER"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_COMPANYUSER"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_COMPANYUSER", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYUSER\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_COMPANYUSER$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_company_user20230523\" (\"id\", \"email\", \"firstname\", \"lastlogin\", \"lastname\", \"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.\"email\", \r\n NEW.\"firstname\", \r\n NEW.\"lastlogin\", \r\n NEW.\"lastname\", \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_COMPANYUSER$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_COMPANYUSER AFTER INSERT\r\nON \"portal\".\"company_users\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_COMPANYUSER\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_COMPANYUSER", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYUSER\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_COMPANYUSER$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_company_user20230523\" (\"id\", \"email\", \"firstname\", \"lastlogin\", \"lastname\", \"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.\"email\", \r\n NEW.\"firstname\", \r\n NEW.\"lastlogin\", \r\n NEW.\"lastname\", \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_COMPANYUSER$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_COMPANYUSER AFTER UPDATE\r\nON \"portal\".\"company_users\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_COMPANYUSER\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedAppFavourite", b => + { + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("AppId") + .HasColumnType("uuid") + .HasColumnName("app_id"); + + b.HasKey("CompanyUserId", "AppId") + .HasName("pk_company_user_assigned_app_favourites"); + + b.HasIndex("AppId") + .HasDatabaseName("ix_company_user_assigned_app_favourites_app_id"); + + b.ToTable("company_user_assigned_app_favourites", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedBusinessPartner", b => + { + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("BusinessPartnerNumber") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("business_partner_number"); + + b.HasKey("CompanyUserId", "BusinessPartnerNumber") + .HasName("pk_company_user_assigned_business_partners"); + + b.ToTable("company_user_assigned_business_partners", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedIdentityProvider", b => + { + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("IdentityProviderId") + .HasColumnType("uuid") + .HasColumnName("identity_provider_id"); + + b.Property("ProviderId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("provider_id"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("user_name"); + + b.HasKey("CompanyUserId", "IdentityProviderId") + .HasName("pk_company_user_assigned_identity_providers"); + + b.HasIndex("IdentityProviderId") + .HasDatabaseName("ix_company_user_assigned_identity_providers_identity_provider_"); + + b.ToTable("company_user_assigned_identity_providers", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedProcess", b => + { + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.HasKey("CompanyUserId", "ProcessId") + .HasName("pk_company_user_assigned_processes"); + + b.HasIndex("CompanyUserId") + .IsUnique() + .HasDatabaseName("ix_company_user_assigned_processes_company_user_id"); + + b.HasIndex("ProcessId") + .IsUnique() + .HasDatabaseName("ix_company_user_assigned_processes_process_id"); + + b.ToTable("company_user_assigned_processes", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyWalletData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AuthenticationServiceUrl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("authentication_service_url"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("client_secret"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("Did") + .IsRequired() + .HasColumnType("text") + .HasColumnName("did"); + + b.Property("DidDocument") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("did_document"); + + b.Property("EncryptionMode") + .HasColumnType("integer") + .HasColumnName("encryption_mode"); + + b.Property("InitializationVector") + .HasColumnType("bytea") + .HasColumnName("initialization_vector"); + + b.HasKey("Id") + .HasName("pk_company_wallet_datas"); + + b.HasIndex("CompanyId") + .IsUnique() + .HasDatabaseName("ix_company_wallet_datas_company_id"); + + b.ToTable("company_wallet_datas", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Connector", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CompanyServiceAccountId") + .HasColumnType("uuid") + .HasColumnName("company_service_account_id"); + + b.Property("ConnectorUrl") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("connector_url"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("HostId") + .HasColumnType("uuid") + .HasColumnName("host_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("LocationId") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("location_id"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("ProviderId") + .HasColumnType("uuid") + .HasColumnName("provider_id"); + + b.Property("SelfDescriptionDocumentId") + .HasColumnType("uuid") + .HasColumnName("self_description_document_id"); + + b.Property("SelfDescriptionMessage") + .HasColumnType("text") + .HasColumnName("self_description_message"); + + b.Property("StatusId") + .HasColumnType("integer") + .HasColumnName("status_id"); + + b.Property("TypeId") + .HasColumnType("integer") + .HasColumnName("type_id"); + + b.HasKey("Id") + .HasName("pk_connectors"); + + b.HasIndex("CompanyServiceAccountId") + .IsUnique() + .HasDatabaseName("ix_connectors_company_service_account_id"); + + b.HasIndex("HostId") + .HasDatabaseName("ix_connectors_host_id"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_connectors_last_editor_id"); + + b.HasIndex("LocationId") + .HasDatabaseName("ix_connectors_location_id"); + + b.HasIndex("ProviderId") + .HasDatabaseName("ix_connectors_provider_id"); + + b.HasIndex("SelfDescriptionDocumentId") + .IsUnique() + .HasDatabaseName("ix_connectors_self_description_document_id"); + + b.HasIndex("StatusId") + .HasDatabaseName("ix_connectors_status_id"); + + b.HasIndex("TypeId") + .HasDatabaseName("ix_connectors_type_id"); + + b.ToTable("connectors", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_CONNECTOR"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_CONNECTOR"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_CONNECTOR", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_CONNECTOR\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_CONNECTOR$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_connector20231115\" (\"id\", \"name\", \"connector_url\", \"type_id\", \"status_id\", \"provider_id\", \"host_id\", \"self_description_document_id\", \"location_id\", \"self_description_message\", \"date_last_changed\", \"company_service_account_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"name\", \r\n NEW.\"connector_url\", \r\n NEW.\"type_id\", \r\n NEW.\"status_id\", \r\n NEW.\"provider_id\", \r\n NEW.\"host_id\", \r\n NEW.\"self_description_document_id\", \r\n NEW.\"location_id\", \r\n NEW.\"self_description_message\", \r\n NEW.\"date_last_changed\", \r\n NEW.\"company_service_account_id\", \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_CONNECTOR$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_CONNECTOR AFTER INSERT\r\nON \"portal\".\"connectors\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_CONNECTOR\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_CONNECTOR", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_CONNECTOR\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_CONNECTOR$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_connector20231115\" (\"id\", \"name\", \"connector_url\", \"type_id\", \"status_id\", \"provider_id\", \"host_id\", \"self_description_document_id\", \"location_id\", \"self_description_message\", \"date_last_changed\", \"company_service_account_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"name\", \r\n NEW.\"connector_url\", \r\n NEW.\"type_id\", \r\n NEW.\"status_id\", \r\n NEW.\"provider_id\", \r\n NEW.\"host_id\", \r\n NEW.\"self_description_document_id\", \r\n NEW.\"location_id\", \r\n NEW.\"self_description_message\", \r\n NEW.\"date_last_changed\", \r\n NEW.\"company_service_account_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_CONNECTOR$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_CONNECTOR AFTER UPDATE\r\nON \"portal\".\"connectors\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_CONNECTOR\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConnectorAssignedOfferSubscription", b => + { + b.Property("ConnectorId") + .HasColumnType("uuid") + .HasColumnName("connector_id"); + + b.Property("OfferSubscriptionId") + .HasColumnType("uuid") + .HasColumnName("offer_subscription_id"); + + b.HasKey("ConnectorId", "OfferSubscriptionId") + .HasName("pk_connector_assigned_offer_subscriptions"); + + b.HasIndex("OfferSubscriptionId") + .HasDatabaseName("ix_connector_assigned_offer_subscriptions_offer_subscription_id"); + + b.ToTable("connector_assigned_offer_subscriptions", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConnectorStatus", 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_connector_statuses"); + + b.ToTable("connector_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "PENDING" + }, + new + { + Id = 2, + Label = "ACTIVE" + }, + new + { + Id = 3, + Label = "INACTIVE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConnectorType", 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_connector_types"); + + b.ToTable("connector_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "COMPANY_CONNECTOR" + }, + new + { + Id = 2, + Label = "CONNECTOR_AS_A_SERVICE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Consent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AgreementId") + .HasColumnType("uuid") + .HasColumnName("agreement_id"); + + b.Property("Comment") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("comment"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("ConsentStatusId") + .HasColumnType("integer") + .HasColumnName("consent_status_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DocumentId") + .HasColumnType("uuid") + .HasColumnName("document_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("Target") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("target"); + + b.HasKey("Id") + .HasName("pk_consents"); + + b.HasIndex("AgreementId") + .HasDatabaseName("ix_consents_agreement_id"); + + b.HasIndex("CompanyId") + .HasDatabaseName("ix_consents_company_id"); + + b.HasIndex("CompanyUserId") + .HasDatabaseName("ix_consents_company_user_id"); + + b.HasIndex("ConsentStatusId") + .HasDatabaseName("ix_consents_consent_status_id"); + + b.HasIndex("DocumentId") + .HasDatabaseName("ix_consents_document_id"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_consents_last_editor_id"); + + b.ToTable("consents", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_CONSENT"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_CONSENT"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_CONSENT", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_CONSENT\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_CONSENT$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_consent20231115\" (\"id\", \"date_created\", \"comment\", \"consent_status_id\", \"target\", \"agreement_id\", \"company_id\", \"document_id\", \"company_user_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"date_created\", \r\n NEW.\"comment\", \r\n NEW.\"consent_status_id\", \r\n NEW.\"target\", \r\n NEW.\"agreement_id\", \r\n NEW.\"company_id\", \r\n NEW.\"document_id\", \r\n NEW.\"company_user_id\", \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_CONSENT$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_CONSENT AFTER INSERT\r\nON \"portal\".\"consents\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_CONSENT\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_CONSENT", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_CONSENT\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_CONSENT$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_consent20231115\" (\"id\", \"date_created\", \"comment\", \"consent_status_id\", \"target\", \"agreement_id\", \"company_id\", \"document_id\", \"company_user_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"date_created\", \r\n NEW.\"comment\", \r\n NEW.\"consent_status_id\", \r\n NEW.\"target\", \r\n NEW.\"agreement_id\", \r\n NEW.\"company_id\", \r\n NEW.\"document_id\", \r\n NEW.\"company_user_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_CONSENT$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_CONSENT AFTER UPDATE\r\nON \"portal\".\"consents\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_CONSENT\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConsentAssignedOffer", b => + { + b.Property("ConsentId") + .HasColumnType("uuid") + .HasColumnName("consent_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.HasKey("ConsentId", "OfferId") + .HasName("pk_consent_assigned_offers"); + + b.HasIndex("OfferId") + .HasDatabaseName("ix_consent_assigned_offers_offer_id"); + + b.ToTable("consent_assigned_offers", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConsentAssignedOfferSubscription", b => + { + b.Property("ConsentId") + .HasColumnType("uuid") + .HasColumnName("consent_id"); + + b.Property("OfferSubscriptionId") + .HasColumnType("uuid") + .HasColumnName("offer_subscription_id"); + + b.HasKey("ConsentId", "OfferSubscriptionId") + .HasName("pk_consent_assigned_offer_subscriptions"); + + b.HasIndex("OfferSubscriptionId") + .HasDatabaseName("ix_consent_assigned_offer_subscriptions_offer_subscription_id"); + + b.ToTable("consent_assigned_offer_subscriptions", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConsentStatus", 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_consent_statuses"); + + b.ToTable("consent_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "ACTIVE" + }, + new + { + Id = 2, + Label = "INACTIVE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Country", b => + { + b.Property("Alpha2Code") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("alpha2code") + .IsFixedLength() + .HasAnnotation("Relational:JsonPropertyName", "alpha2code"); + + b.Property("Alpha3Code") + .HasMaxLength(3) + .HasColumnType("character(3)") + .HasColumnName("alpha3code") + .IsFixedLength() + .HasAnnotation("Relational:JsonPropertyName", "alpha3code"); + + b.HasKey("Alpha2Code") + .HasName("pk_countries"); + + b.ToTable("countries", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CountryAssignedIdentifier", b => + { + b.Property("CountryAlpha2Code") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("country_alpha2code") + .HasAnnotation("Relational:JsonPropertyName", "country_alpha2code"); + + b.Property("UniqueIdentifierId") + .HasColumnType("integer") + .HasColumnName("unique_identifier_id"); + + b.Property("BpdmIdentifierId") + .HasColumnType("integer") + .HasColumnName("bpdm_identifier_id"); + + b.HasKey("CountryAlpha2Code", "UniqueIdentifierId") + .HasName("pk_country_assigned_identifiers"); + + b.HasIndex("BpdmIdentifierId") + .HasDatabaseName("ix_country_assigned_identifiers_bpdm_identifier_id"); + + b.HasIndex("UniqueIdentifierId") + .HasDatabaseName("ix_country_assigned_identifiers_unique_identifier_id"); + + b.ToTable("country_assigned_identifiers", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CountryLongName", b => + { + b.Property("Alpha2Code") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("alpha2code") + .HasAnnotation("Relational:JsonPropertyName", "alpha2code"); + + b.Property("ShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("short_name"); + + b.Property("LongName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("long_name"); + + b.HasKey("Alpha2Code", "ShortName") + .HasName("pk_country_long_names"); + + b.HasIndex("ShortName") + .HasDatabaseName("ix_country_long_names_short_name"); + + b.ToTable("country_long_names", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DimCompanyServiceAccount", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AuthenticationServiceUrl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("authentication_service_url"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("client_secret"); + + b.Property("EncryptionMode") + .HasColumnType("integer") + .HasColumnName("encryption_mode"); + + b.Property("InitializationVector") + .HasColumnType("bytea") + .HasColumnName("initialization_vector"); + + b.HasKey("Id") + .HasName("pk_dim_company_service_accounts"); + + b.ToTable("dim_company_service_accounts", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DimUserCreationData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("ServiceAccountId") + .HasColumnType("uuid") + .HasColumnName("service_account_id"); + + b.HasKey("Id") + .HasName("pk_dim_user_creation_data"); + + b.HasIndex("ProcessId") + .IsUnique() + .HasDatabaseName("ix_dim_user_creation_data_process_id"); + + b.HasIndex("ServiceAccountId") + .IsUnique() + .HasDatabaseName("ix_dim_user_creation_data_service_account_id"); + + b.ToTable("dim_user_creation_data", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DocumentContent") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("document_content"); + + b.Property("DocumentHash") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("document_hash"); + + b.Property("DocumentName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("document_name"); + + b.Property("DocumentStatusId") + .HasColumnType("integer") + .HasColumnName("document_status_id"); + + b.Property("DocumentTypeId") + .HasColumnType("integer") + .HasColumnName("document_type_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("MediaTypeId") + .HasColumnType("integer") + .HasColumnName("media_type_id"); + + b.HasKey("Id") + .HasName("pk_documents"); + + b.HasIndex("CompanyUserId") + .HasDatabaseName("ix_documents_company_user_id"); + + b.HasIndex("DocumentStatusId") + .HasDatabaseName("ix_documents_document_status_id"); + + b.HasIndex("DocumentTypeId") + .HasDatabaseName("ix_documents_document_type_id"); + + b.HasIndex("MediaTypeId") + .HasDatabaseName("ix_documents_media_type_id"); + + b.ToTable("documents", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_DOCUMENT"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_DOCUMENT"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_DOCUMENT", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_DOCUMENT\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_DOCUMENT$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_document20231115\" (\"id\", \"date_created\", \"document_hash\", \"document_content\", \"document_name\", \"media_type_id\", \"document_type_id\", \"document_status_id\", \"company_user_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.\"date_created\", \r\n NEW.\"document_hash\", \r\n NEW.\"document_content\", \r\n NEW.\"document_name\", \r\n NEW.\"media_type_id\", \r\n NEW.\"document_type_id\", \r\n NEW.\"document_status_id\", \r\n NEW.\"company_user_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_DOCUMENT$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_DOCUMENT AFTER INSERT\r\nON \"portal\".\"documents\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_DOCUMENT\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_DOCUMENT", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_DOCUMENT\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_DOCUMENT$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_document20231115\" (\"id\", \"date_created\", \"document_hash\", \"document_content\", \"document_name\", \"media_type_id\", \"document_type_id\", \"document_status_id\", \"company_user_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.\"date_created\", \r\n NEW.\"document_hash\", \r\n NEW.\"document_content\", \r\n NEW.\"document_name\", \r\n NEW.\"media_type_id\", \r\n NEW.\"document_type_id\", \r\n NEW.\"document_status_id\", \r\n NEW.\"company_user_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_DOCUMENT$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_DOCUMENT AFTER UPDATE\r\nON \"portal\".\"documents\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_DOCUMENT\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DocumentStatus", 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_document_status"); + + b.ToTable("document_status", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "PENDING" + }, + new + { + Id = 2, + Label = "LOCKED" + }, + new + { + Id = 3, + Label = "INACTIVE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DocumentType", 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_document_types"); + + b.ToTable("document_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "CX_FRAME_CONTRACT" + }, + new + { + Id = 2, + Label = "COMMERCIAL_REGISTER_EXTRACT" + }, + new + { + Id = 3, + Label = "APP_CONTRACT" + }, + new + { + Id = 4, + Label = "CONFORMITY_APPROVAL_REGISTRATION" + }, + new + { + Id = 5, + Label = "ADDITIONAL_DETAILS" + }, + new + { + Id = 6, + Label = "APP_LEADIMAGE" + }, + new + { + Id = 7, + Label = "APP_IMAGE" + }, + new + { + Id = 8, + Label = "SELF_DESCRIPTION" + }, + new + { + Id = 9, + Label = "APP_TECHNICAL_INFORMATION" + }, + new + { + Id = 10, + Label = "CONFORMITY_APPROVAL_CONNECTOR" + }, + new + { + Id = 11, + Label = "CONFORMITY_APPROVAL_BUSINESS_APPS" + }, + new + { + Id = 12, + Label = "CONFORMITY_APPROVAL_SERVICES" + }, + new + { + Id = 13, + Label = "SERVICE_LEADIMAGE" + }, + new + { + Id = 14, + Label = "PRESENTATION" + }, + new + { + Id = 15, + Label = "COMPANY_CERTIFICATE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IamClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ClientClientId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("client_client_id"); + + b.HasKey("Id") + .HasName("pk_iam_clients"); + + b.HasIndex("ClientClientId") + .IsUnique() + .HasDatabaseName("ix_iam_clients_client_client_id"); + + b.ToTable("iam_clients", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IamIdentityProvider", b => + { + b.Property("IamIdpAlias") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("iam_idp_alias"); + + b.Property("IdentityProviderId") + .HasColumnType("uuid") + .HasColumnName("identity_provider_id"); + + b.Property("MetadataUrl") + .HasColumnType("text") + .HasColumnName("metadata_url"); + + b.HasKey("IamIdpAlias") + .HasName("pk_iam_identity_providers"); + + b.HasIndex("IdentityProviderId") + .IsUnique() + .HasDatabaseName("ix_iam_identity_providers_identity_provider_id"); + + b.ToTable("iam_identity_providers", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("IdentityTypeId") + .HasColumnType("integer") + .HasColumnName("identity_type_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("UserEntityId") + .HasMaxLength(36) + .HasColumnType("character varying(36)") + .HasColumnName("user_entity_id"); + + b.Property("UserStatusId") + .HasColumnType("integer") + .HasColumnName("user_status_id") + .HasAnnotation("Relational:JsonPropertyName", "user_status_id"); + + b.HasKey("Id") + .HasName("pk_identities"); + + b.HasIndex("CompanyId") + .HasDatabaseName("ix_identities_company_id"); + + b.HasIndex("IdentityTypeId") + .HasDatabaseName("ix_identities_identity_type_id"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_identities_last_editor_id"); + + b.HasIndex("UserEntityId") + .IsUnique() + .HasDatabaseName("ix_identities_user_entity_id"); + + b.HasIndex("UserStatusId") + .HasDatabaseName("ix_identities_user_status_id"); + + b.ToTable("identities", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_IDENTITY"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_IDENTITY"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_IDENTITY", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_IDENTITY\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_IDENTITY$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_identity20231115\" (\"id\", \"date_created\", \"company_id\", \"user_status_id\", \"user_entity_id\", \"identity_type_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.\"date_created\", \r\n NEW.\"company_id\", \r\n NEW.\"user_status_id\", \r\n NEW.\"user_entity_id\", \r\n NEW.\"identity_type_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_IDENTITY$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_IDENTITY AFTER INSERT\r\nON \"portal\".\"identities\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_IDENTITY\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_IDENTITY", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_IDENTITY\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_IDENTITY$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_identity20231115\" (\"id\", \"date_created\", \"company_id\", \"user_status_id\", \"user_entity_id\", \"identity_type_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.\"date_created\", \r\n NEW.\"company_id\", \r\n NEW.\"user_status_id\", \r\n NEW.\"user_entity_id\", \r\n NEW.\"identity_type_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_IDENTITY$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_IDENTITY AFTER UPDATE\r\nON \"portal\".\"identities\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_IDENTITY\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityAssignedRole", b => + { + b.Property("IdentityId") + .HasColumnType("uuid") + .HasColumnName("identity_id"); + + b.Property("UserRoleId") + .HasColumnType("uuid") + .HasColumnName("user_role_id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.HasKey("IdentityId", "UserRoleId") + .HasName("pk_identity_assigned_roles"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_identity_assigned_roles_last_editor_id"); + + b.HasIndex("UserRoleId") + .HasDatabaseName("ix_identity_assigned_roles_user_role_id"); + + b.ToTable("identity_assigned_roles", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_IDENTITYASSIGNEDROLE"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_IDENTITYASSIGNEDROLE"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_IDENTITYASSIGNEDROLE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_IDENTITYASSIGNEDROLE\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_IDENTITYASSIGNEDROLE$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_identity_assigned_role20230522\" (\"identity_id\", \"user_role_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"identity_id\", \r\n NEW.\"user_role_id\", \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_IDENTITYASSIGNEDROLE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_IDENTITYASSIGNEDROLE AFTER INSERT\r\nON \"portal\".\"identity_assigned_roles\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_IDENTITYASSIGNEDROLE\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_IDENTITYASSIGNEDROLE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_IDENTITYASSIGNEDROLE\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_IDENTITYASSIGNEDROLE$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_identity_assigned_role20230522\" (\"identity_id\", \"user_role_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"identity_id\", \r\n NEW.\"user_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_IDENTITYASSIGNEDROLE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_IDENTITYASSIGNEDROLE AFTER UPDATE\r\nON \"portal\".\"identity_assigned_roles\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_IDENTITYASSIGNEDROLE\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("IdentityProviderCategoryId") + .HasColumnType("integer") + .HasColumnName("identity_provider_category_id"); + + b.Property("IdentityProviderTypeId") + .HasColumnType("integer") + .HasColumnName("identity_provider_type_id"); + + b.Property("OwnerId") + .HasColumnType("uuid") + .HasColumnName("owner_id"); + + b.HasKey("Id") + .HasName("pk_identity_providers"); + + b.HasIndex("IdentityProviderCategoryId") + .HasDatabaseName("ix_identity_providers_identity_provider_category_id"); + + b.HasIndex("IdentityProviderTypeId") + .HasDatabaseName("ix_identity_providers_identity_provider_type_id"); + + b.HasIndex("OwnerId") + .HasDatabaseName("ix_identity_providers_owner_id"); + + b.ToTable("identity_providers", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderAssignedProcess", b => + { + b.Property("IdentityProviderId") + .HasColumnType("uuid") + .HasColumnName("identity_provider_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.HasKey("IdentityProviderId", "ProcessId") + .HasName("pk_identity_provider_assigned_processes"); + + b.HasIndex("IdentityProviderId") + .IsUnique() + .HasDatabaseName("ix_identity_provider_assigned_processes_identity_provider_id"); + + b.HasIndex("ProcessId") + .IsUnique() + .HasDatabaseName("ix_identity_provider_assigned_processes_process_id"); + + b.ToTable("identity_provider_assigned_processes", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderCategory", 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_identity_provider_categories"); + + b.ToTable("identity_provider_categories", "portal"); + + b.HasData( + new + { + Id = 2, + Label = "KEYCLOAK_OIDC" + }, + new + { + Id = 3, + Label = "KEYCLOAK_SAML" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderType", 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_identity_provider_types"); + + b.ToTable("identity_provider_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "OWN" + }, + new + { + Id = 2, + Label = "MANAGED" + }, + new + { + Id = 3, + Label = "SHARED" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityType", 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_identity_type"); + + b.ToTable("identity_type", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "COMPANY_USER" + }, + new + { + Id = 2, + Label = "COMPANY_SERVICE_ACCOUNT" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityUserStatus", 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_identity_user_statuses"); + + b.ToTable("identity_user_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "ACTIVE" + }, + new + { + Id = 2, + Label = "INACTIVE" + }, + new + { + Id = 3, + Label = "DELETED" + }, + new + { + Id = 4, + Label = "PENDING" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Invitation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CompanyApplicationId") + .HasColumnType("uuid") + .HasColumnName("company_application_id"); + + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("InvitationStatusId") + .HasColumnType("integer") + .HasColumnName("invitation_status_id"); + + b.HasKey("Id") + .HasName("pk_invitations"); + + b.HasIndex("CompanyApplicationId") + .HasDatabaseName("ix_invitations_company_application_id"); + + b.HasIndex("CompanyUserId") + .HasDatabaseName("ix_invitations_company_user_id"); + + b.HasIndex("InvitationStatusId") + .HasDatabaseName("ix_invitations_invitation_status_id"); + + b.ToTable("invitations", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.InvitationStatus", 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_invitation_statuses"); + + b.ToTable("invitation_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "CREATED" + }, + new + { + Id = 2, + Label = "PENDING" + }, + new + { + Id = 3, + Label = "ACCEPTED" + }, + new + { + Id = 4, + Label = "DECLINED" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", b => + { + b.Property("ShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("short_name") + .IsFixedLength(); + + b.HasKey("ShortName") + .HasName("pk_languages"); + + b.ToTable("languages", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.LanguageLongName", b => + { + b.Property("ShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("short_name") + .IsFixedLength(); + + b.Property("LanguageShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("language_short_name") + .IsFixedLength(); + + b.Property("LongName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("long_name"); + + b.HasKey("ShortName", "LanguageShortName") + .HasName("pk_language_long_names"); + + b.HasIndex("LanguageShortName") + .HasDatabaseName("ix_language_long_names_language_short_name"); + + b.ToTable("language_long_names", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.LicenseType", 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_license_types"); + + b.ToTable("license_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "COTS" + }, + new + { + Id = 2, + Label = "FOSS" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.MailingInformation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("EncryptionMode") + .HasColumnType("integer") + .HasColumnName("encryption_mode"); + + b.Property("InitializationVector") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("initialization_vector"); + + b.Property("MailParameters") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("mail_parameters"); + + b.Property("MailingStatusId") + .HasColumnType("integer") + .HasColumnName("mailing_status_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("Template") + .IsRequired() + .HasColumnType("text") + .HasColumnName("template"); + + b.HasKey("Id") + .HasName("pk_mailing_informations"); + + b.HasIndex("MailingStatusId") + .HasDatabaseName("ix_mailing_informations_mailing_status_id"); + + b.HasIndex("ProcessId") + .IsUnique() + .HasDatabaseName("ix_mailing_informations_process_id"); + + b.ToTable("mailing_informations", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.MailingStatus", 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_mailing_statuses"); + + b.ToTable("mailing_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "PENDING" + }, + new + { + Id = 2, + Label = "SENT" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.MediaType", 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_media_types"); + + b.ToTable("media_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "JPEG" + }, + new + { + Id = 2, + Label = "GIF" + }, + new + { + Id = 3, + Label = "PNG" + }, + new + { + Id = 4, + Label = "SVG" + }, + new + { + Id = 5, + Label = "TIFF" + }, + new + { + Id = 6, + Label = "PDF" + }, + new + { + Id = 7, + Label = "JSON" + }, + new + { + Id = 8, + Label = "PEM" + }, + new + { + Id = 9, + Label = "CA_CERT" + }, + new + { + Id = 10, + Label = "PKX_CER" + }, + new + { + Id = 11, + Label = "OCTET" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NetworkRegistration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ApplicationId") + .HasColumnType("uuid") + .HasColumnName("application_id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("external_id"); + + b.Property("OnboardingServiceProviderId") + .HasColumnType("uuid") + .HasColumnName("onboarding_service_provider_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.HasKey("Id") + .HasName("pk_network_registrations"); + + b.HasIndex("ApplicationId") + .IsUnique() + .HasDatabaseName("ix_network_registrations_application_id"); + + b.HasIndex("CompanyId") + .IsUnique() + .HasDatabaseName("ix_network_registrations_company_id"); + + b.HasIndex("OnboardingServiceProviderId") + .HasDatabaseName("ix_network_registrations_onboarding_service_provider_id"); + + b.HasIndex("ProcessId") + .IsUnique() + .HasDatabaseName("ix_network_registrations_process_id"); + + b.HasIndex("ExternalId", "OnboardingServiceProviderId") + .IsUnique() + .HasDatabaseName("ix_network_registrations_external_id_onboarding_service_provid"); + + b.ToTable("network_registrations", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Content") + .HasColumnType("text") + .HasColumnName("content"); + + b.Property("CreatorUserId") + .HasColumnType("uuid") + .HasColumnName("creator_user_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("Done") + .HasColumnType("boolean") + .HasColumnName("done"); + + b.Property("DueDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("due_date"); + + b.Property("IsRead") + .HasColumnType("boolean") + .HasColumnName("is_read"); + + b.Property("NotificationTypeId") + .HasColumnType("integer") + .HasColumnName("notification_type_id"); + + b.Property("ReceiverUserId") + .HasColumnType("uuid") + .HasColumnName("receiver_user_id"); + + b.HasKey("Id") + .HasName("pk_notifications"); + + b.HasIndex("CreatorUserId") + .HasDatabaseName("ix_notifications_creator_user_id"); + + b.HasIndex("NotificationTypeId") + .HasDatabaseName("ix_notifications_notification_type_id"); + + b.HasIndex("ReceiverUserId") + .HasDatabaseName("ix_notifications_receiver_user_id"); + + b.ToTable("notifications", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationTopic", 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_notification_topic"); + + b.ToTable("notification_topic", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "INFO" + }, + new + { + Id = 2, + Label = "ACTION" + }, + new + { + Id = 3, + Label = "OFFER" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationType", 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_notification_type"); + + b.ToTable("notification_type", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "INFO" + }, + new + { + Id = 2, + Label = "ACTION" + }, + new + { + Id = 3, + Label = "WELCOME" + }, + new + { + Id = 4, + Label = "WELCOME_USE_CASES" + }, + new + { + Id = 5, + Label = "WELCOME_SERVICE_PROVIDER" + }, + new + { + Id = 6, + Label = "WELCOME_CONNECTOR_REGISTRATION" + }, + new + { + Id = 7, + Label = "WELCOME_APP_MARKETPLACE" + }, + new + { + Id = 8, + Label = "APP_SUBSCRIPTION_REQUEST" + }, + new + { + Id = 9, + Label = "APP_SUBSCRIPTION_ACTIVATION" + }, + new + { + Id = 10, + Label = "CONNECTOR_REGISTERED" + }, + new + { + Id = 11, + Label = "APP_RELEASE_REQUEST" + }, + new + { + Id = 12, + Label = "TECHNICAL_USER_CREATION" + }, + new + { + Id = 13, + Label = "SERVICE_REQUEST" + }, + new + { + Id = 14, + Label = "SERVICE_ACTIVATION" + }, + new + { + Id = 15, + Label = "APP_ROLE_ADDED" + }, + new + { + Id = 16, + Label = "APP_RELEASE_APPROVAL" + }, + new + { + Id = 17, + Label = "SERVICE_RELEASE_REQUEST" + }, + new + { + Id = 18, + Label = "SERVICE_RELEASE_APPROVAL" + }, + new + { + Id = 19, + Label = "APP_RELEASE_REJECTION" + }, + new + { + Id = 20, + Label = "SERVICE_RELEASE_REJECTION" + }, + new + { + Id = 21, + Label = "ROLE_UPDATE_CORE_OFFER" + }, + new + { + Id = 22, + Label = "ROLE_UPDATE_APP_OFFER" + }, + new + { + Id = 23, + Label = "SUBSCRIPTION_URL_UPDATE" + }, + new + { + Id = 24, + Label = "CREDENTIAL_APPROVAL" + }, + new + { + Id = 25, + Label = "CREDENTIAL_REJECTED" + }, + new + { + Id = 26, + Label = "CREDENTIAL_EXPIRY" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationTypeAssignedTopic", b => + { + b.Property("NotificationTypeId") + .HasColumnType("integer") + .HasColumnName("notification_type_id"); + + b.Property("NotificationTopicId") + .HasColumnType("integer") + .HasColumnName("notification_topic_id"); + + b.HasKey("NotificationTypeId", "NotificationTopicId") + .HasName("pk_notification_type_assigned_topics"); + + b.HasIndex("NotificationTopicId") + .HasDatabaseName("ix_notification_type_assigned_topics_notification_topic_id"); + + b.HasIndex("NotificationTypeId") + .IsUnique() + .HasDatabaseName("ix_notification_type_assigned_topics_notification_type_id"); + + b.ToTable("notification_type_assigned_topics", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ContactEmail") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("contact_email"); + + b.Property("ContactNumber") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("contact_number"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("DateReleased") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_released"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("LicenseTypeId") + .HasColumnType("integer") + .HasColumnName("license_type_id"); + + b.Property("MarketingUrl") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("marketing_url"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("OfferStatusId") + .HasColumnType("integer") + .HasColumnName("offer_status_id"); + + b.Property("OfferTypeId") + .HasColumnType("integer") + .HasColumnName("offer_type_id"); + + b.Property("Provider") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("provider"); + + b.Property("ProviderCompanyId") + .HasColumnType("uuid") + .HasColumnName("provider_company_id"); + + b.Property("SalesManagerId") + .HasColumnType("uuid") + .HasColumnName("sales_manager_id"); + + b.HasKey("Id") + .HasName("pk_offers"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_offers_last_editor_id"); + + b.HasIndex("LicenseTypeId") + .HasDatabaseName("ix_offers_license_type_id"); + + b.HasIndex("OfferStatusId") + .HasDatabaseName("ix_offers_offer_status_id"); + + b.HasIndex("OfferTypeId") + .HasDatabaseName("ix_offers_offer_type_id"); + + b.HasIndex("ProviderCompanyId") + .HasDatabaseName("ix_offers_provider_company_id"); + + b.HasIndex("SalesManagerId") + .HasDatabaseName("ix_offers_sales_manager_id"); + + b.ToTable("offers", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_OFFER"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_OFFER"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_OFFER", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_OFFER\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_OFFER$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_offer20231115\" (\"id\", \"name\", \"date_created\", \"date_released\", \"marketing_url\", \"contact_email\", \"contact_number\", \"provider\", \"offer_type_id\", \"sales_manager_id\", \"provider_company_id\", \"offer_status_id\", \"license_type_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.\"name\", \r\n NEW.\"date_created\", \r\n NEW.\"date_released\", \r\n NEW.\"marketing_url\", \r\n NEW.\"contact_email\", \r\n NEW.\"contact_number\", \r\n NEW.\"provider\", \r\n NEW.\"offer_type_id\", \r\n NEW.\"sales_manager_id\", \r\n NEW.\"provider_company_id\", \r\n NEW.\"offer_status_id\", \r\n NEW.\"license_type_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_OFFER$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_OFFER AFTER INSERT\r\nON \"portal\".\"offers\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_OFFER\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_OFFER", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_OFFER\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_OFFER$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_offer20231115\" (\"id\", \"name\", \"date_created\", \"date_released\", \"marketing_url\", \"contact_email\", \"contact_number\", \"provider\", \"offer_type_id\", \"sales_manager_id\", \"provider_company_id\", \"offer_status_id\", \"license_type_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.\"name\", \r\n NEW.\"date_created\", \r\n NEW.\"date_released\", \r\n NEW.\"marketing_url\", \r\n NEW.\"contact_email\", \r\n NEW.\"contact_number\", \r\n NEW.\"provider\", \r\n NEW.\"offer_type_id\", \r\n NEW.\"sales_manager_id\", \r\n NEW.\"provider_company_id\", \r\n NEW.\"offer_status_id\", \r\n NEW.\"license_type_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_OFFER$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_OFFER AFTER UPDATE\r\nON \"portal\".\"offers\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_OFFER\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferAssignedDocument", b => + { + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("DocumentId") + .HasColumnType("uuid") + .HasColumnName("document_id"); + + b.HasKey("OfferId", "DocumentId") + .HasName("pk_offer_assigned_documents"); + + b.HasIndex("DocumentId") + .HasDatabaseName("ix_offer_assigned_documents_document_id"); + + b.ToTable("offer_assigned_documents", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferAssignedLicense", b => + { + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("OfferLicenseId") + .HasColumnType("uuid") + .HasColumnName("offer_license_id"); + + b.HasKey("OfferId", "OfferLicenseId") + .HasName("pk_offer_assigned_licenses"); + + b.HasIndex("OfferLicenseId") + .HasDatabaseName("ix_offer_assigned_licenses_offer_license_id"); + + b.ToTable("offer_assigned_licenses", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferAssignedPrivacyPolicy", b => + { + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("PrivacyPolicyId") + .HasColumnType("integer") + .HasColumnName("privacy_policy_id"); + + b.HasKey("OfferId", "PrivacyPolicyId") + .HasName("pk_offer_assigned_privacy_policies"); + + b.HasIndex("PrivacyPolicyId") + .HasDatabaseName("ix_offer_assigned_privacy_policies_privacy_policy_id"); + + b.ToTable("offer_assigned_privacy_policies", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferDescription", b => + { + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("LanguageShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("language_short_name"); + + b.Property("DescriptionLong") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description_long"); + + b.Property("DescriptionShort") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("description_short"); + + b.HasKey("OfferId", "LanguageShortName") + .HasName("pk_offer_descriptions"); + + b.HasIndex("LanguageShortName") + .HasDatabaseName("ix_offer_descriptions_language_short_name"); + + b.ToTable("offer_descriptions", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferLicense", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Licensetext") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("licensetext"); + + b.HasKey("Id") + .HasName("pk_offer_licenses"); + + b.ToTable("offer_licenses", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferStatus", 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_offer_statuses"); + + b.ToTable("offer_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "CREATED" + }, + new + { + Id = 2, + Label = "IN_REVIEW" + }, + new + { + Id = 3, + Label = "ACTIVE" + }, + new + { + Id = 4, + Label = "INACTIVE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("Description") + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("description"); + + b.Property("DisplayName") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("display_name"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("OfferSubscriptionStatusId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1) + .HasColumnName("offer_subscription_status_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("RequesterId") + .HasColumnType("uuid") + .HasColumnName("requester_id"); + + b.HasKey("Id") + .HasName("pk_offer_subscriptions"); + + b.HasIndex("CompanyId") + .HasDatabaseName("ix_offer_subscriptions_company_id"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_offer_subscriptions_last_editor_id"); + + b.HasIndex("OfferId") + .HasDatabaseName("ix_offer_subscriptions_offer_id"); + + b.HasIndex("OfferSubscriptionStatusId") + .HasDatabaseName("ix_offer_subscriptions_offer_subscription_status_id"); + + b.HasIndex("ProcessId") + .IsUnique() + .HasDatabaseName("ix_offer_subscriptions_process_id"); + + b.HasIndex("RequesterId") + .HasDatabaseName("ix_offer_subscriptions_requester_id"); + + b.ToTable("offer_subscriptions", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_OFFERSUBSCRIPTION"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_OFFERSUBSCRIPTION"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_OFFERSUBSCRIPTION", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_OFFERSUBSCRIPTION\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_OFFERSUBSCRIPTION$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_offer_subscription20231115\" (\"id\", \"company_id\", \"offer_id\", \"offer_subscription_status_id\", \"display_name\", \"description\", \"requester_id\", \"last_editor_id\", \"process_id\", \"date_created\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"company_id\", \r\n NEW.\"offer_id\", \r\n NEW.\"offer_subscription_status_id\", \r\n NEW.\"display_name\", \r\n NEW.\"description\", \r\n NEW.\"requester_id\", \r\n NEW.\"last_editor_id\", \r\n NEW.\"process_id\", \r\n NEW.\"date_created\", \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_OFFERSUBSCRIPTION$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_OFFERSUBSCRIPTION AFTER INSERT\r\nON \"portal\".\"offer_subscriptions\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_OFFERSUBSCRIPTION\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_OFFERSUBSCRIPTION", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_OFFERSUBSCRIPTION\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_OFFERSUBSCRIPTION$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_offer_subscription20231115\" (\"id\", \"company_id\", \"offer_id\", \"offer_subscription_status_id\", \"display_name\", \"description\", \"requester_id\", \"last_editor_id\", \"process_id\", \"date_created\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"company_id\", \r\n NEW.\"offer_id\", \r\n NEW.\"offer_subscription_status_id\", \r\n NEW.\"display_name\", \r\n NEW.\"description\", \r\n NEW.\"requester_id\", \r\n NEW.\"last_editor_id\", \r\n NEW.\"process_id\", \r\n NEW.\"date_created\", \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_OFFERSUBSCRIPTION$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_OFFERSUBSCRIPTION AFTER UPDATE\r\nON \"portal\".\"offer_subscriptions\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_OFFERSUBSCRIPTION\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscriptionProcessData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("OfferSubscriptionId") + .HasColumnType("uuid") + .HasColumnName("offer_subscription_id"); + + b.Property("OfferUrl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("offer_url"); + + b.HasKey("Id") + .HasName("pk_offer_subscriptions_process_datas"); + + b.HasIndex("OfferSubscriptionId") + .IsUnique() + .HasDatabaseName("ix_offer_subscriptions_process_datas_offer_subscription_id"); + + b.ToTable("offer_subscriptions_process_datas", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscriptionStatus", 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_offer_subscription_statuses"); + + b.ToTable("offer_subscription_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "PENDING" + }, + new + { + Id = 2, + Label = "ACTIVE" + }, + new + { + Id = 3, + Label = "INACTIVE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferTag", b => + { + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("Name") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("tag_name") + .HasAnnotation("Relational:JsonPropertyName", "tag_name"); + + b.HasKey("OfferId", "Name") + .HasName("pk_offer_tags"); + + b.ToTable("offer_tags", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferType", 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_offer_types"); + + b.ToTable("offer_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "APP" + }, + new + { + Id = 2, + Label = "CORE_COMPONENT" + }, + new + { + Id = 3, + Label = "SERVICE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OnboardingServiceProviderDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AuthUrl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("auth_url"); + + b.Property("CallbackUrl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("callback_url"); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("client_secret"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("EncryptionMode") + .HasColumnType("integer") + .HasColumnName("encryption_mode"); + + b.Property("InitializationVector") + .HasColumnType("bytea") + .HasColumnName("initialization_vector"); + + b.HasKey("Id") + .HasName("pk_onboarding_service_provider_details"); + + b.HasIndex("CompanyId") + .IsUnique() + .HasDatabaseName("ix_onboarding_service_provider_details_company_id"); + + b.ToTable("onboarding_service_provider_details", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.PrivacyPolicy", 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_privacy_policies"); + + b.ToTable("privacy_policies", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "COMPANY_DATA" + }, + new + { + Id = 2, + Label = "USER_DATA" + }, + new + { + Id = 3, + Label = "LOCATION" + }, + new + { + Id = 4, + Label = "BROWSER_HISTORY" + }, + new + { + Id = 5, + Label = "NONE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LockExpiryDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("lock_expiry_date"); + + b.Property("ProcessTypeId") + .HasColumnType("integer") + .HasColumnName("process_type_id"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("uuid") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_processes"); + + b.HasIndex("ProcessTypeId") + .HasDatabaseName("ix_processes_process_type_id"); + + b.ToTable("processes", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessStep", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.Property("ProcessStepStatusId") + .HasColumnType("integer") + .HasColumnName("process_step_status_id"); + + b.Property("ProcessStepTypeId") + .HasColumnType("integer") + .HasColumnName("process_step_type_id"); + + b.HasKey("Id") + .HasName("pk_process_steps"); + + b.HasIndex("ProcessId") + .HasDatabaseName("ix_process_steps_process_id"); + + b.HasIndex("ProcessStepStatusId") + .HasDatabaseName("ix_process_steps_process_step_status_id"); + + b.HasIndex("ProcessStepTypeId") + .HasDatabaseName("ix_process_steps_process_step_type_id"); + + b.ToTable("process_steps", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessStepStatus", 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_process_step_statuses"); + + b.ToTable("process_step_statuses", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "TODO" + }, + new + { + Id = 2, + Label = "DONE" + }, + new + { + Id = 3, + Label = "SKIPPED" + }, + new + { + Id = 4, + Label = "FAILED" + }, + new + { + Id = 5, + Label = "DUPLICATE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessStepType", 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_process_step_types"); + + b.ToTable("process_step_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "VERIFY_REGISTRATION" + }, + new + { + Id = 2, + Label = "CREATE_BUSINESS_PARTNER_NUMBER_PUSH" + }, + new + { + Id = 3, + Label = "CREATE_BUSINESS_PARTNER_NUMBER_PULL" + }, + new + { + Id = 4, + Label = "CREATE_BUSINESS_PARTNER_NUMBER_MANUAL" + }, + new + { + Id = 5, + Label = "CREATE_IDENTITY_WALLET" + }, + new + { + Id = 6, + Label = "RETRIGGER_IDENTITY_WALLET" + }, + new + { + Id = 7, + Label = "START_CLEARING_HOUSE" + }, + new + { + Id = 8, + Label = "RETRIGGER_CLEARING_HOUSE" + }, + new + { + Id = 9, + Label = "END_CLEARING_HOUSE" + }, + new + { + Id = 10, + Label = "START_SELF_DESCRIPTION_LP" + }, + new + { + Id = 11, + Label = "RETRIGGER_SELF_DESCRIPTION_LP" + }, + new + { + Id = 12, + Label = "ACTIVATE_APPLICATION" + }, + new + { + Id = 13, + Label = "RETRIGGER_BUSINESS_PARTNER_NUMBER_PUSH" + }, + new + { + Id = 14, + Label = "RETRIGGER_BUSINESS_PARTNER_NUMBER_PULL" + }, + new + { + Id = 15, + Label = "OVERRIDE_BUSINESS_PARTNER_NUMBER" + }, + new + { + Id = 16, + Label = "TRIGGER_OVERRIDE_CLEARING_HOUSE" + }, + new + { + Id = 17, + Label = "START_OVERRIDE_CLEARING_HOUSE" + }, + new + { + Id = 18, + Label = "FINISH_SELF_DESCRIPTION_LP" + }, + new + { + Id = 19, + Label = "DECLINE_APPLICATION" + }, + new + { + Id = 20, + Label = "CREATE_DIM_WALLET" + }, + new + { + Id = 21, + Label = "AWAIT_DIM_RESPONSE" + }, + new + { + Id = 22, + Label = "RETRIGGER_CREATE_DIM_WALLET" + }, + new + { + Id = 23, + Label = "VALIDATE_DID_DOCUMENT" + }, + new + { + Id = 24, + Label = "RETRIGGER_VALIDATE_DID_DOCUMENT" + }, + new + { + Id = 25, + Label = "REQUEST_BPN_CREDENTIAL" + }, + new + { + Id = 26, + Label = "STORED_BPN_CREDENTIAL" + }, + new + { + Id = 27, + Label = "REQUEST_MEMBERSHIP_CREDENTIAL" + }, + new + { + Id = 28, + Label = "STORED_MEMBERSHIP_CREDENTIAL" + }, + new + { + Id = 29, + Label = "TRANSMIT_BPN_DID" + }, + new + { + Id = 30, + Label = "RETRIGGER_TRANSMIT_DID_BPN" + }, + new + { + Id = 100, + Label = "TRIGGER_PROVIDER" + }, + new + { + Id = 101, + Label = "START_AUTOSETUP" + }, + new + { + Id = 102, + Label = "OFFERSUBSCRIPTION_CLIENT_CREATION" + }, + new + { + Id = 103, + Label = "SINGLE_INSTANCE_SUBSCRIPTION_DETAILS_CREATION" + }, + new + { + Id = 104, + Label = "OFFERSUBSCRIPTION_TECHNICALUSER_CREATION" + }, + new + { + Id = 105, + Label = "ACTIVATE_SUBSCRIPTION" + }, + new + { + Id = 106, + Label = "TRIGGER_PROVIDER_CALLBACK" + }, + new + { + Id = 107, + Label = "RETRIGGER_PROVIDER" + }, + new + { + Id = 108, + Label = "RETRIGGER_OFFERSUBSCRIPTION_CLIENT_CREATION" + }, + new + { + Id = 109, + Label = "RETRIGGER_OFFERSUBSCRIPTION_TECHNICALUSER_CREATION" + }, + new + { + Id = 110, + Label = "RETRIGGER_PROVIDER_CALLBACK" + }, + new + { + Id = 111, + Label = "TRIGGER_ACTIVATE_SUBSCRIPTION" + }, + new + { + Id = 112, + Label = "OFFERSUBSCRIPTION_CREATE_DIM_TECHNICAL_USER" + }, + new + { + Id = 113, + 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" + }, + new + { + Id = 201, + Label = "RETRIGGER_SYNCHRONIZE_USER" + }, + new + { + Id = 202, + Label = "TRIGGER_CALLBACK_OSP_SUBMITTED" + }, + new + { + Id = 203, + Label = "TRIGGER_CALLBACK_OSP_APPROVED" + }, + new + { + Id = 204, + Label = "TRIGGER_CALLBACK_OSP_DECLINED" + }, + new + { + Id = 205, + Label = "RETRIGGER_CALLBACK_OSP_SUBMITTED" + }, + new + { + Id = 206, + Label = "RETRIGGER_CALLBACK_OSP_APPROVED" + }, + new + { + Id = 207, + Label = "RETRIGGER_CALLBACK_OSP_DECLINED" + }, + new + { + Id = 208, + Label = "MANUAL_DECLINE_OSP" + }, + new + { + Id = 209, + Label = "REMOVE_KEYCLOAK_USERS" + }, + new + { + Id = 210, + Label = "RETRIGGER_REMOVE_KEYCLOAK_USERS" + }, + new + { + Id = 301, + Label = "SEND_MAIL" + }, + new + { + Id = 302, + Label = "RETRIGGER_SEND_MAIL" + }, + new + { + Id = 400, + Label = "INVITATION_CREATE_CENTRAL_IDP" + }, + new + { + Id = 401, + Label = "INVITATION_CREATE_SHARED_IDP_SERVICE_ACCOUNT" + }, + new + { + Id = 402, + Label = "INVITATION_ADD_REALM_ROLE" + }, + new + { + Id = 403, + Label = "INVITATION_CREATE_SHARED_REALM" + }, + new + { + Id = 404, + Label = "INVITATION_CREATE_CENTRAL_IDP_ORG_MAPPER" + }, + new + { + Id = 405, + Label = "INVITATION_UPDATE_CENTRAL_IDP_URLS" + }, + new + { + Id = 406, + Label = "INVITATION_CREATE_SHARED_CLIENT" + }, + new + { + Id = 407, + Label = "INVITATION_ENABLE_CENTRAL_IDP" + }, + new + { + Id = 408, + Label = "INVITATION_CREATE_DATABASE_IDP" + }, + new + { + Id = 409, + Label = "INVITATION_CREATE_USER" + }, + new + { + Id = 410, + Label = "RETRIGGER_INVITATION_CREATE_CENTRAL_IDP" + }, + new + { + Id = 411, + Label = "RETRIGGER_INVITATION_CREATE_SHARED_IDP_SERVICE_ACCOUNT" + }, + new + { + Id = 412, + Label = "RETRIGGER_INVITATION_ADD_REALM_ROLE" + }, + new + { + Id = 413, + Label = "RETRIGGER_INVITATION_CREATE_SHARED_REALM" + }, + new + { + Id = 414, + Label = "RETRIGGER_INVITATION_CREATE_CENTRAL_IDP_ORG_MAPPER" + }, + new + { + Id = 415, + Label = "RETRIGGER_INVITATION_UPDATE_CENTRAL_IDP_URLS" + }, + new + { + Id = 416, + Label = "RETRIGGER_INVITATION_CREATE_SHARED_CLIENT" + }, + new + { + Id = 417, + Label = "RETRIGGER_INVITATION_ENABLE_CENTRAL_IDP" + }, + new + { + Id = 418, + Label = "RETRIGGER_INVITATION_CREATE_USER" + }, + new + { + Id = 419, + Label = "RETRIGGER_INVITATION_CREATE_DATABASE_IDP" + }, + new + { + Id = 500, + Label = "CREATE_DIM_TECHNICAL_USER" + }, + new + { + Id = 501, + Label = "RETRIGGER_CREATE_DIM_TECHNICAL_USER" + }, + new + { + Id = 600, + Label = "DELETE_CENTRAL_USER" + }, + new + { + Id = 601, + Label = "RETRIGGER_DELETE_CENTRAL_USER" + }, + new + { + Id = 602, + Label = "DELETE_COMPANYUSER_ASSIGNED_PROCESS" + }, + new + { + Id = 700, + Label = "DELETE_IDP_SHARED_REALM" + }, + new + { + Id = 701, + Label = "RETRIGGER_DELETE_IDP_SHARED_REALM" + }, + new + { + Id = 702, + Label = "DELETE_IDP_SHARED_SERVICEACCOUNT" + }, + new + { + Id = 703, + Label = "RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT" + }, + new + { + Id = 704, + Label = "DELETE_CENTRAL_IDENTITY_PROVIDER" + }, + new + { + Id = 705, + Label = "RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER" + }, + new + { + Id = 706, + Label = "DELETE_IDENTITY_PROVIDER" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessType", 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_process_types"); + + b.ToTable("process_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "APPLICATION_CHECKLIST" + }, + new + { + Id = 3, + Label = "OFFER_SUBSCRIPTION" + }, + new + { + Id = 4, + Label = "PARTNER_REGISTRATION" + }, + new + { + Id = 5, + Label = "MAILING" + }, + new + { + Id = 6, + Label = "INVITATION" + }, + new + { + Id = 7, + Label = "DIM_TECHNICAL_USER" + }, + new + { + Id = 8, + Label = "USER_PROVISIONING" + }, + new + { + Id = 9, + Label = "IDENTITYPROVIDER_PROVISIONING" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProviderCompanyDetail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AutoSetupCallbackUrl") + .HasColumnType("text") + .HasColumnName("auto_setup_callback_url"); + + b.Property("AutoSetupUrl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("auto_setup_url"); + + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_created"); + + b.Property("DateLastChanged") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_last_changed"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.HasKey("Id") + .HasName("pk_provider_company_details"); + + b.HasIndex("CompanyId") + .IsUnique() + .HasDatabaseName("ix_provider_company_details_company_id"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_provider_company_details_last_editor_id"); + + b.ToTable("provider_company_details", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_PROVIDERCOMPANYDETAIL"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_PROVIDERCOMPANYDETAIL"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_PROVIDERCOMPANYDETAIL", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_PROVIDERCOMPANYDETAIL\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_PROVIDERCOMPANYDETAIL$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_provider_company_detail20231115\" (\"id\", \"date_created\", \"auto_setup_url\", \"auto_setup_callback_url\", \"company_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.\"date_created\", \r\n NEW.\"auto_setup_url\", \r\n NEW.\"auto_setup_callback_url\", \r\n NEW.\"company_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_PROVIDERCOMPANYDETAIL$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_PROVIDERCOMPANYDETAIL AFTER INSERT\r\nON \"portal\".\"provider_company_details\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_PROVIDERCOMPANYDETAIL\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_PROVIDERCOMPANYDETAIL", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_PROVIDERCOMPANYDETAIL\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_PROVIDERCOMPANYDETAIL$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_provider_company_detail20231115\" (\"id\", \"date_created\", \"auto_setup_url\", \"auto_setup_callback_url\", \"company_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.\"date_created\", \r\n NEW.\"auto_setup_url\", \r\n NEW.\"auto_setup_callback_url\", \r\n NEW.\"company_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_PROVIDERCOMPANYDETAIL$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_PROVIDERCOMPANYDETAIL AFTER UPDATE\r\nON \"portal\".\"provider_company_details\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_PROVIDERCOMPANYDETAIL\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ServiceDetail", b => + { + b.Property("ServiceId") + .HasColumnType("uuid") + .HasColumnName("service_id"); + + b.Property("ServiceTypeId") + .HasColumnType("integer") + .HasColumnName("service_type_id"); + + b.HasKey("ServiceId", "ServiceTypeId") + .HasName("pk_service_details"); + + b.HasIndex("ServiceTypeId") + .HasDatabaseName("ix_service_details_service_type_id"); + + b.ToTable("service_details", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ServiceType", 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_service_types"); + + b.ToTable("service_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "DATASPACE_SERVICE" + }, + new + { + Id = 2, + Label = "CONSULTANCY_SERVICE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.TechnicalUserProfile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.HasKey("Id") + .HasName("pk_technical_user_profiles"); + + b.HasIndex("OfferId") + .HasDatabaseName("ix_technical_user_profiles_offer_id"); + + b.ToTable("technical_user_profiles", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.TechnicalUserProfileAssignedUserRole", b => + { + b.Property("TechnicalUserProfileId") + .HasColumnType("uuid") + .HasColumnName("technical_user_profile_id"); + + b.Property("UserRoleId") + .HasColumnType("uuid") + .HasColumnName("user_role_id"); + + b.HasKey("TechnicalUserProfileId", "UserRoleId") + .HasName("pk_technical_user_profile_assigned_user_roles"); + + b.HasIndex("UserRoleId") + .HasDatabaseName("ix_technical_user_profile_assigned_user_roles_user_role_id"); + + b.ToTable("technical_user_profile_assigned_user_roles", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UniqueIdentifier", 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_unique_identifiers"); + + b.ToTable("unique_identifiers", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "COMMERCIAL_REG_NUMBER" + }, + new + { + Id = 2, + Label = "VAT_ID" + }, + new + { + Id = 3, + Label = "LEI_CODE" + }, + new + { + Id = 4, + Label = "VIES" + }, + new + { + Id = 5, + Label = "EORI" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UseCase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("name"); + + b.Property("Shortname") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("shortname"); + + b.HasKey("Id") + .HasName("pk_use_cases"); + + b.ToTable("use_cases", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UseCaseDescription", b => + { + b.Property("UseCaseId") + .HasColumnType("uuid") + .HasColumnName("use_case_id"); + + b.Property("LanguageShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("language_short_name"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text") + .HasColumnName("description"); + + b.HasKey("UseCaseId", "LanguageShortName") + .HasName("pk_use_case_descriptions"); + + b.HasIndex("LanguageShortName") + .HasDatabaseName("ix_use_case_descriptions_language_short_name"); + + b.ToTable("use_case_descriptions", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("LastEditorId") + .HasColumnType("uuid") + .HasColumnName("last_editor_id"); + + b.Property("OfferId") + .HasColumnType("uuid") + .HasColumnName("offer_id"); + + b.Property("UserRoleText") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("user_role") + .HasAnnotation("Relational:JsonPropertyName", "user_role"); + + b.HasKey("Id") + .HasName("pk_user_roles"); + + b.HasIndex("LastEditorId") + .HasDatabaseName("ix_user_roles_last_editor_id"); + + b.HasIndex("OfferId") + .HasDatabaseName("ix_user_roles_offer_id"); + + b.ToTable("user_roles", "portal", t => + { + t.HasTrigger("LC_TRIGGER_AFTER_INSERT_USERROLE"); + + t.HasTrigger("LC_TRIGGER_AFTER_UPDATE_USERROLE"); + }); + + b + .HasAnnotation("LC_TRIGGER_AFTER_INSERT_USERROLE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_INSERT_USERROLE\"() RETURNS trigger as $LC_TRIGGER_AFTER_INSERT_USERROLE$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_user_role20231115\" (\"id\", \"user_role\", \"offer_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"user_role\", \r\n NEW.\"offer_id\", \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_USERROLE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_INSERT_USERROLE AFTER INSERT\r\nON \"portal\".\"user_roles\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_INSERT_USERROLE\"();") + .HasAnnotation("LC_TRIGGER_AFTER_UPDATE_USERROLE", "CREATE FUNCTION \"portal\".\"LC_TRIGGER_AFTER_UPDATE_USERROLE\"() RETURNS trigger as $LC_TRIGGER_AFTER_UPDATE_USERROLE$\r\nBEGIN\r\n INSERT INTO \"portal\".\"audit_user_role20231115\" (\"id\", \"user_role\", \"offer_id\", \"last_editor_id\", \"audit_v1id\", \"audit_v1operation_id\", \"audit_v1date_last_changed\", \"audit_v1last_editor_id\") SELECT NEW.\"id\", \r\n NEW.\"user_role\", \r\n NEW.\"offer_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_USERROLE$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_AFTER_UPDATE_USERROLE AFTER UPDATE\r\nON \"portal\".\"user_roles\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"portal\".\"LC_TRIGGER_AFTER_UPDATE_USERROLE\"();"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleAssignedCollection", b => + { + b.Property("UserRoleId") + .HasColumnType("uuid") + .HasColumnName("user_role_id"); + + b.Property("UserRoleCollectionId") + .HasColumnType("uuid") + .HasColumnName("user_role_collection_id"); + + b.HasKey("UserRoleId", "UserRoleCollectionId") + .HasName("pk_user_role_assigned_collections"); + + b.HasIndex("UserRoleCollectionId") + .HasDatabaseName("ix_user_role_assigned_collections_user_role_collection_id"); + + b.ToTable("user_role_assigned_collections", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("pk_user_role_collections"); + + b.ToTable("user_role_collections", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleCollectionDescription", b => + { + b.Property("UserRoleCollectionId") + .HasColumnType("uuid") + .HasColumnName("user_role_collection_id"); + + b.Property("LanguageShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("language_short_name"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("description"); + + b.HasKey("UserRoleCollectionId", "LanguageShortName") + .HasName("pk_user_role_collection_descriptions"); + + b.HasIndex("LanguageShortName") + .HasDatabaseName("ix_user_role_collection_descriptions_language_short_name"); + + b.ToTable("user_role_collection_descriptions", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleDescription", b => + { + b.Property("UserRoleId") + .HasColumnType("uuid") + .HasColumnName("user_role_id"); + + b.Property("LanguageShortName") + .HasMaxLength(2) + .HasColumnType("character(2)") + .HasColumnName("language_short_name"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("description"); + + b.HasKey("UserRoleId", "LanguageShortName") + .HasName("pk_user_role_descriptions"); + + b.HasIndex("LanguageShortName") + .HasDatabaseName("ix_user_role_descriptions_language_short_name"); + + b.ToTable("user_role_descriptions", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialExternalType", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id"); + + b.Property("Label") + .IsRequired() + .HasColumnType("text") + .HasColumnName("label"); + + b.HasKey("Id") + .HasName("pk_verified_credential_external_types"); + + b.ToTable("verified_credential_external_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "TRACEABILITY_CREDENTIAL" + }, + new + { + Id = 2, + Label = "PCF_CREDENTIAL" + }, + new + { + Id = 3, + Label = "BEHAVIOR_TWIN_CREDENTIAL" + }, + new + { + Id = 4, + Label = "VEHICLE_DISMANTLE" + }, + new + { + Id = 5, + Label = "SUSTAINABILITY_CREDENTIAL" + }, + new + { + Id = 6, + Label = "Quality_Credential" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialExternalTypeUseCaseDetailVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("Expiry") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiry"); + + b.Property("Template") + .HasColumnType("text") + .HasColumnName("template"); + + b.Property("ValidFrom") + .HasColumnType("timestamp with time zone") + .HasColumnName("valid_from"); + + b.Property("VerifiedCredentialExternalTypeId") + .HasColumnType("integer") + .HasColumnName("verified_credential_external_type_id"); + + b.Property("Version") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_verified_credential_external_type_use_case_detail_versions"); + + b.HasIndex("VerifiedCredentialExternalTypeId", "Version") + .IsUnique() + .HasDatabaseName("ix_verified_credential_external_type_use_case_detail_versions_"); + + b.ToTable("verified_credential_external_type_use_case_detail_versions", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialType", 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_verified_credential_types"); + + b.ToTable("verified_credential_types", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "TRACEABILITY_FRAMEWORK" + }, + new + { + Id = 2, + Label = "PCF_FRAMEWORK" + }, + new + { + Id = 3, + Label = "BEHAVIOR_TWIN_FRAMEWORK" + }, + new + { + Id = 4, + Label = "DISMANTLER_CERTIFICATE" + }, + new + { + Id = 5, + Label = "SUSTAINABILITY_FRAMEWORK" + }, + new + { + Id = 6, + Label = "FRAMEWORK_AGREEMENT_QUALITY" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedExternalType", b => + { + b.Property("VerifiedCredentialTypeId") + .HasColumnType("integer") + .HasColumnName("verified_credential_type_id"); + + b.Property("VerifiedCredentialExternalTypeId") + .HasColumnType("integer") + .HasColumnName("verified_credential_external_type_id"); + + b.HasKey("VerifiedCredentialTypeId", "VerifiedCredentialExternalTypeId") + .HasName("pk_verified_credential_type_assigned_external_types"); + + b.HasIndex("VerifiedCredentialExternalTypeId") + .HasDatabaseName("ix_verified_credential_type_assigned_external_types_verified_c"); + + b.HasIndex("VerifiedCredentialTypeId") + .IsUnique() + .HasDatabaseName("ix_verified_credential_type_assigned_external_types_verified_c1"); + + b.ToTable("verified_credential_type_assigned_external_types", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedKind", b => + { + b.Property("VerifiedCredentialTypeId") + .HasColumnType("integer") + .HasColumnName("verified_credential_type_id"); + + b.Property("VerifiedCredentialTypeKindId") + .HasColumnType("integer") + .HasColumnName("verified_credential_type_kind_id"); + + b.HasKey("VerifiedCredentialTypeId", "VerifiedCredentialTypeKindId") + .HasName("pk_verified_credential_type_assigned_kinds"); + + b.HasIndex("VerifiedCredentialTypeId") + .HasDatabaseName("ix_verified_credential_type_assigned_kinds_verified_credential"); + + b.HasIndex("VerifiedCredentialTypeKindId") + .HasDatabaseName("ix_verified_credential_type_assigned_kinds_verified_credential1"); + + b.ToTable("verified_credential_type_assigned_kinds", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedUseCase", b => + { + b.Property("VerifiedCredentialTypeId") + .HasColumnType("integer") + .HasColumnName("verified_credential_type_id"); + + b.Property("UseCaseId") + .HasColumnType("uuid") + .HasColumnName("use_case_id"); + + b.HasKey("VerifiedCredentialTypeId", "UseCaseId") + .HasName("pk_verified_credential_type_assigned_use_cases"); + + b.HasIndex("UseCaseId") + .IsUnique() + .HasDatabaseName("ix_verified_credential_type_assigned_use_cases_use_case_id"); + + b.HasIndex("VerifiedCredentialTypeId") + .IsUnique() + .HasDatabaseName("ix_verified_credential_type_assigned_use_cases_verified_creden"); + + b.ToTable("verified_credential_type_assigned_use_cases", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeKind", 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_verified_credential_type_kinds"); + + b.ToTable("verified_credential_type_kinds", "portal"); + + b.HasData( + new + { + Id = 1, + Label = "USE_CASE" + }, + new + { + Id = 2, + Label = "CERTIFICATE" + }); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Views.AgreementView", b => + { + b.Property("AgreementCompanyRole") + .IsRequired() + .HasColumnType("text") + .HasColumnName("agreement_company_role"); + + b.Property("AgreementId") + .HasColumnType("uuid") + .HasColumnName("agreement_id"); + + b.Property("AgreementName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("agreement_name"); + + b.Property("AgreementStatus") + .IsRequired() + .HasColumnType("text") + .HasColumnName("agreement_status"); + + b.Property("Mandatory") + .HasColumnType("boolean") + .HasColumnName("mandatory"); + + b.ToTable((string)null); + + b.ToView("agreement_view", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Views.CompaniesLinkedServiceAccount", b => + { + b.Property("ServiceAccountId") + .HasColumnType("uuid") + .HasColumnName("service_account_id"); + + b.Property("Owners") + .HasColumnType("uuid") + .HasColumnName("owners"); + + b.Property("Provider") + .HasColumnType("uuid") + .HasColumnName("provider"); + + b.HasKey("ServiceAccountId"); + + b.ToTable((string)null); + + b.ToView("company_linked_service_accounts", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Views.CompanyConnectorView", b => + { + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("company_name"); + + b.Property("ConnectorStatus") + .IsRequired() + .HasColumnType("text") + .HasColumnName("connector_status"); + + b.Property("ConnectorUrl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("connector_url"); + + b.ToTable((string)null); + + b.ToView("company_connector_view", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Views.CompanyIdpView", b => + { + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("company_name"); + + b.Property("IdpAlias") + .IsRequired() + .HasColumnType("text") + .HasColumnName("idp_alias"); + + b.ToTable((string)null); + + b.ToView("company_idp_view", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Views.CompanyRoleCollectionRolesView", b => + { + b.Property("ClientName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("client_name"); + + b.Property("CollectionName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("collection_name"); + + b.Property("UserRole") + .IsRequired() + .HasColumnType("text") + .HasColumnName("user_role"); + + b.ToTable((string)null); + + b.ToView("companyrole_collectionroles_view", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Views.CompanyUsersView", b => + { + b.Property("CompanyId") + .HasColumnType("uuid") + .HasColumnName("company_id"); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("company_name"); + + b.Property("FirstName") + .HasColumnType("text") + .HasColumnName("first_name"); + + b.Property("LastName") + .HasColumnType("text") + .HasColumnName("last_name"); + + b.Property("UserEmail") + .HasColumnType("text") + .HasColumnName("user_email"); + + b.Property("UserStatus") + .IsRequired() + .HasColumnType("text") + .HasColumnName("user_status"); + + b.ToTable((string)null); + + b.ToView("company_users_view", "portal"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Views.OfferSubscriptionView", b => + { + b.Property("AppInstance") + .HasColumnType("uuid") + .HasColumnName("app_instance"); + + b.Property("Connector") + .HasColumnType("uuid") + .HasColumnName("connector"); + + b.Property("OfferTypeId") + .HasColumnType("integer") + .HasColumnName("offer_type_id"); + + b.Property("SubscriptionId") + .HasColumnType("uuid") + .HasColumnName("subscription_id"); + + b.Property("TechnicalUser") + .HasColumnType("uuid") + .HasColumnName("technical_user"); + + b.ToTable((string)null); + + 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") + .WithMany("Addresses") + .HasForeignKey("CountryAlpha2Code") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_addresses_countries_country_alpha2code"); + + b.Navigation("Country"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Agreement", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementCategory", "AgreementCategory") + .WithMany("Agreements") + .HasForeignKey("AgreementCategoryId") + .IsRequired() + .HasConstraintName("fk_agreements_agreement_categories_agreement_category_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementStatus", null) + .WithMany("Agreements") + .HasForeignKey("AgreementStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_agreements_agreement_statuses_agreement_status_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", "Document") + .WithMany("Agreements") + .HasForeignKey("DocumentId") + .HasConstraintName("fk_agreements_documents_document_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "IssuerCompany") + .WithMany("Agreements") + .HasForeignKey("IssuerCompanyId") + .IsRequired() + .HasConstraintName("fk_agreements_companies_issuer_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UseCase", "UseCase") + .WithMany("Agreements") + .HasForeignKey("UseCaseId") + .HasConstraintName("fk_agreements_use_cases_use_case_id"); + + b.Navigation("AgreementCategory"); + + b.Navigation("Document"); + + b.Navigation("IssuerCompany"); + + b.Navigation("UseCase"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementAssignedCompanyRole", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Agreement", "Agreement") + .WithMany("AgreementAssignedCompanyRoles") + .HasForeignKey("AgreementId") + .IsRequired() + .HasConstraintName("fk_agreement_assigned_company_roles_agreements_agreement_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRole", "CompanyRole") + .WithMany("AgreementAssignedCompanyRoles") + .HasForeignKey("CompanyRoleId") + .IsRequired() + .HasConstraintName("fk_agreement_assigned_company_roles_company_roles_company_role"); + + b.Navigation("Agreement"); + + b.Navigation("CompanyRole"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementAssignedOffer", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Agreement", "Agreement") + .WithMany("AgreementAssignedOffers") + .HasForeignKey("AgreementId") + .IsRequired() + .HasConstraintName("fk_agreement_assigned_offers_agreements_agreement_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany("AgreementAssignedOffers") + .HasForeignKey("OfferId") + .IsRequired() + .HasConstraintName("fk_agreement_assigned_offers_offers_offer_id"); + + b.Navigation("Agreement"); + + b.Navigation("Offer"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementAssignedOfferType", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Agreement", "Agreement") + .WithMany("AgreementAssignedOfferTypes") + .HasForeignKey("AgreementId") + .IsRequired() + .HasConstraintName("fk_agreement_assigned_offer_types_agreements_agreement_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferType", "OfferType") + .WithMany("AgreementAssignedOfferTypes") + .HasForeignKey("OfferTypeId") + .IsRequired() + .HasConstraintName("fk_agreement_assigned_offer_types_offer_types_offer_type_id"); + + b.Navigation("Agreement"); + + b.Navigation("OfferType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppAssignedUseCase", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "App") + .WithMany() + .HasForeignKey("AppId") + .IsRequired() + .HasConstraintName("fk_app_assigned_use_cases_offers_app_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UseCase", "UseCase") + .WithMany() + .HasForeignKey("UseCaseId") + .IsRequired() + .HasConstraintName("fk_app_assigned_use_cases_use_cases_use_case_id"); + + b.Navigation("App"); + + b.Navigation("UseCase"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstance", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "App") + .WithMany("AppInstances") + .HasForeignKey("AppId") + .OnDelete(DeleteBehavior.SetNull) + .IsRequired() + .HasConstraintName("fk_app_instances_offers_app_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IamClient", "IamClient") + .WithMany("AppInstances") + .HasForeignKey("IamClientId") + .OnDelete(DeleteBehavior.SetNull) + .IsRequired() + .HasConstraintName("fk_app_instances_iam_clients_iam_client_id"); + + b.Navigation("App"); + + b.Navigation("IamClient"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstanceAssignedCompanyServiceAccount", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstance", "AppInstance") + .WithMany("ServiceAccounts") + .HasForeignKey("AppInstanceId") + .IsRequired() + .HasConstraintName("fk_app_instance_assigned_service_accounts_app_instances_app_in"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccount", "CompanyServiceAccount") + .WithMany("AppInstances") + .HasForeignKey("CompanyServiceAccountId") + .IsRequired() + .HasConstraintName("fk_app_instance_assigned_service_accounts_company_service_acco"); + + b.Navigation("AppInstance"); + + b.Navigation("CompanyServiceAccount"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstanceSetup", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "App") + .WithOne("AppInstanceSetup") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstanceSetup", "AppId") + .IsRequired() + .HasConstraintName("fk_app_instance_setups_offers_app_id"); + + b.Navigation("App"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppLanguage", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "App") + .WithMany() + .HasForeignKey("AppId") + .IsRequired() + .HasConstraintName("fk_app_languages_offers_app_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") + .WithMany() + .HasForeignKey("LanguageShortName") + .IsRequired() + .HasConstraintName("fk_app_languages_languages_language_short_name"); + + b.Navigation("App"); + + b.Navigation("Language"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppSubscriptionDetail", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstance", "AppInstance") + .WithMany("AppSubscriptionDetails") + .HasForeignKey("AppInstanceId") + .HasConstraintName("fk_app_subscription_details_app_instances_app_instance_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_app_subscription_details_identities_last_editor_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscription", "OfferSubscription") + .WithOne("AppSubscriptionDetail") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppSubscriptionDetail", "OfferSubscriptionId") + .IsRequired() + .HasConstraintName("fk_app_subscription_details_offer_subscriptions_offer_subscrip"); + + b.Navigation("AppInstance"); + + b.Navigation("LastEditor"); + + b.Navigation("OfferSubscription"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ApplicationChecklistEntry", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ApplicationChecklistEntryStatus", "ApplicationChecklistEntryStatus") + .WithMany("ApplicationChecklistEntries") + .HasForeignKey("ApplicationChecklistEntryStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_application_checklist_application_checklist_statuses_applic"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ApplicationChecklistEntryType", "ApplicationChecklistEntryType") + .WithMany("ApplicationChecklistEntries") + .HasForeignKey("ApplicationChecklistEntryTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_application_checklist_application_checklist_types_applicati"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplication", "Application") + .WithMany("ApplicationChecklistEntries") + .HasForeignKey("ApplicationId") + .IsRequired() + .HasConstraintName("fk_application_checklist_company_applications_application_id"); + + b.Navigation("Application"); + + b.Navigation("ApplicationChecklistEntryStatus"); + + b.Navigation("ApplicationChecklistEntryType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Address", "Address") + .WithMany("Companies") + .HasForeignKey("AddressId") + .HasConstraintName("fk_companies_addresses_address_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyStatus", "CompanyStatus") + .WithMany("Companies") + .HasForeignKey("CompanyStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_companies_company_statuses_company_status_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", "SelfDescriptionDocument") + .WithMany("Companies") + .HasForeignKey("SelfDescriptionDocumentId") + .HasConstraintName("fk_companies_documents_self_description_document_id"); + + b.Navigation("Address"); + + b.Navigation("CompanyStatus"); + + b.Navigation("SelfDescriptionDocument"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplication", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplicationStatus", "ApplicationStatus") + .WithMany("CompanyApplications") + .HasForeignKey("ApplicationStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_applications_company_application_statuses_applicati"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "ChecklistProcess") + .WithOne("CompanyApplication") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplication", "ChecklistProcessId") + .HasConstraintName("fk_company_applications_processes_checklist_process_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplicationType", "CompanyApplicationType") + .WithMany("CompanyApplications") + .HasForeignKey("CompanyApplicationTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_applications_company_application_types_company_appl"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany("CompanyApplications") + .HasForeignKey("CompanyId") + .IsRequired() + .HasConstraintName("fk_company_applications_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_company_applications_identities_last_editor_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "OnboardingServiceProvider") + .WithMany("ProvidedApplications") + .HasForeignKey("OnboardingServiceProviderId") + .HasConstraintName("fk_company_applications_companies_onboarding_service_provider_"); + + b.Navigation("ApplicationStatus"); + + b.Navigation("ChecklistProcess"); + + b.Navigation("Company"); + + b.Navigation("CompanyApplicationType"); + + b.Navigation("LastEditor"); + + b.Navigation("OnboardingServiceProvider"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyAssignedRole", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany("CompanyAssignedRoles") + .HasForeignKey("CompanyId") + .IsRequired() + .HasConstraintName("fk_company_assigned_roles_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRole", "CompanyRole") + .WithMany("CompanyAssignedRoles") + .HasForeignKey("CompanyRoleId") + .IsRequired() + .HasConstraintName("fk_company_assigned_roles_company_roles_company_role_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_company_assigned_roles_identities_last_editor_id"); + + b.Navigation("Company"); + + b.Navigation("CompanyRole"); + + b.Navigation("LastEditor"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyAssignedUseCase", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany("CompanyAssignedUseCase") + .HasForeignKey("CompanyId") + .IsRequired() + .HasConstraintName("fk_company_assigned_use_cases_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UseCase", "UseCase") + .WithMany("CompanyAssignedUseCase") + .HasForeignKey("UseCaseId") + .IsRequired() + .HasConstraintName("fk_company_assigned_use_cases_use_cases_use_case_id"); + + b.Navigation("Company"); + + b.Navigation("UseCase"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyIdentifier", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany("CompanyIdentifiers") + .HasForeignKey("CompanyId") + .IsRequired() + .HasConstraintName("fk_company_identifiers_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UniqueIdentifier", "UniqueIdentifier") + .WithMany("CompanyIdentifiers") + .HasForeignKey("UniqueIdentifierId") + .IsRequired() + .HasConstraintName("fk_company_identifiers_unique_identifiers_unique_identifier_id"); + + b.Navigation("Company"); + + b.Navigation("UniqueIdentifier"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyIdentityProvider", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_identity_providers_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", "IdentityProvider") + .WithMany("CompanyIdentityProviders") + .HasForeignKey("IdentityProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_identity_providers_identity_providers_identity_prov"); + + b.Navigation("Company"); + + b.Navigation("IdentityProvider"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyInvitation", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplication", "Application") + .WithOne("CompanyInvitation") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyInvitation", "ApplicationId") + .HasConstraintName("fk_company_invitations_company_applications_application_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithOne("CompanyInvitation") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyInvitation", "ProcessId") + .IsRequired() + .HasConstraintName("fk_company_invitations_processes_process_id"); + + b.Navigation("Application"); + + b.Navigation("Process"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRoleAssignedRoleCollection", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRole", "CompanyRole") + .WithOne("CompanyRoleAssignedRoleCollection") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRoleAssignedRoleCollection", "CompanyRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_role_assigned_role_collections_company_roles_compan"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleCollection", "UserRoleCollection") + .WithOne("CompanyRoleAssignedRoleCollection") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRoleAssignedRoleCollection", "UserRoleCollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_role_assigned_role_collections_user_role_collection"); + + b.Navigation("CompanyRole"); + + b.Navigation("UserRoleCollection"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRoleDescription", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRole", "CompanyRole") + .WithMany("CompanyRoleDescriptions") + .HasForeignKey("CompanyRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_role_descriptions_company_roles_company_role_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") + .WithMany("CompanyRoleDescriptions") + .HasForeignKey("LanguageShortName") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_role_descriptions_languages_language_short_name"); + + b.Navigation("CompanyRole"); + + b.Navigation("Language"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRoleRegistrationData", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRole", "CompanyRole") + .WithOne("CompanyRoleRegistrationData") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRoleRegistrationData", "CompanyRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_role_registration_data_company_roles_company_role_id"); + + b.Navigation("CompanyRole"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccount", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccountKind", "CompanyServiceAccountKind") + .WithMany("CompanyServiceAccounts") + .HasForeignKey("CompanyServiceAccountKindId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_service_accounts_company_service_account_kindes_com"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccountType", "CompanyServiceAccountType") + .WithMany("CompanyServiceAccounts") + .HasForeignKey("CompanyServiceAccountTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_service_accounts_company_service_account_types_comp"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "Identity") + .WithOne("CompanyServiceAccount") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccount", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_service_accounts_identities_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscription", "OfferSubscription") + .WithMany("CompanyServiceAccounts") + .HasForeignKey("OfferSubscriptionId") + .HasConstraintName("fk_company_service_accounts_offer_subscriptions_offer_subscrip"); + + b.Navigation("CompanyServiceAccountKind"); + + b.Navigation("CompanyServiceAccountType"); + + b.Navigation("Identity"); + + b.Navigation("OfferSubscription"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanySsiDetail", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany("CompanySsiDetails") + .HasForeignKey("CompanyId") + .IsRequired() + .HasConstraintName("fk_company_ssi_details_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanySsiDetailStatus", "CompanySsiDetailStatus") + .WithMany("CompanySsiDetails") + .HasForeignKey("CompanySsiDetailStatusId") + .IsRequired() + .HasConstraintName("fk_company_ssi_details_company_ssi_detail_statuses_company_ssi"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CreatorUser") + .WithMany("CompanySsiDetails") + .HasForeignKey("CreatorUserId") + .IsRequired() + .HasConstraintName("fk_company_ssi_details_company_users_creator_user_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", "Document") + .WithOne("CompanySsiDetail") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanySsiDetail", "DocumentId") + .IsRequired() + .HasConstraintName("fk_company_ssi_details_documents_document_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_company_ssi_details_identities_last_editor_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialExternalTypeUseCaseDetailVersion", "VerifiedCredentialExternalTypeUseCaseDetailVersion") + .WithMany("CompanySsiDetails") + .HasForeignKey("VerifiedCredentialExternalTypeUseCaseDetailId") + .HasConstraintName("fk_company_ssi_details_verified_credential_external_type_use_c"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialType", "VerifiedCredentialType") + .WithMany("CompanySsiDetails") + .HasForeignKey("VerifiedCredentialTypeId") + .IsRequired() + .HasConstraintName("fk_company_ssi_details_verified_credential_types_verified_cred"); + + b.Navigation("Company"); + + b.Navigation("CompanySsiDetailStatus"); + + b.Navigation("CreatorUser"); + + b.Navigation("Document"); + + b.Navigation("LastEditor"); + + b.Navigation("VerifiedCredentialExternalTypeUseCaseDetailVersion"); + + b.Navigation("VerifiedCredentialType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "Identity") + .WithOne("CompanyUser") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_users_identities_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_company_users_identities_last_editor_id"); + + b.Navigation("Identity"); + + b.Navigation("LastEditor"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedAppFavourite", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "App") + .WithMany() + .HasForeignKey("AppId") + .IsRequired() + .HasConstraintName("fk_company_user_assigned_app_favourites_offers_app_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CompanyUser") + .WithMany() + .HasForeignKey("CompanyUserId") + .IsRequired() + .HasConstraintName("fk_company_user_assigned_app_favourites_company_users_company_"); + + b.Navigation("App"); + + b.Navigation("CompanyUser"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedBusinessPartner", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CompanyUser") + .WithMany("CompanyUserAssignedBusinessPartners") + .HasForeignKey("CompanyUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_user_assigned_business_partners_company_users_compa"); + + b.Navigation("CompanyUser"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedIdentityProvider", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CompanyUser") + .WithMany("CompanyUserAssignedIdentityProviders") + .HasForeignKey("CompanyUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_user_assigned_identity_providers_company_users_comp"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", "IdentityProvider") + .WithMany("CompanyUserAssignedIdentityProviders") + .HasForeignKey("IdentityProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_user_assigned_identity_providers_identity_providers"); + + b.Navigation("CompanyUser"); + + b.Navigation("IdentityProvider"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedProcess", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CompanyUser") + .WithOne("CompanyUserAssignedProcess") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedProcess", "CompanyUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_user_assigned_processes_company_users_company_user_"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithOne("CompanyUserAssignedProcess") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedProcess", "ProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_user_assigned_processes_processes_process_id"); + + b.Navigation("CompanyUser"); + + b.Navigation("Process"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyWalletData", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithOne("CompanyWalletData") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyWalletData", "CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_wallet_datas_companies_company_id"); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Connector", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccount", "CompanyServiceAccount") + .WithOne("Connector") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Connector", "CompanyServiceAccountId") + .HasConstraintName("fk_connectors_company_service_accounts_company_service_account"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Host") + .WithMany("HostedConnectors") + .HasForeignKey("HostId") + .HasConstraintName("fk_connectors_companies_host_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_connectors_identities_last_editor_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Country", "Location") + .WithMany("Connectors") + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_connectors_countries_location_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Provider") + .WithMany("ProvidedConnectors") + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_connectors_companies_provider_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", "SelfDescriptionDocument") + .WithOne("Connector") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Connector", "SelfDescriptionDocumentId") + .HasConstraintName("fk_connectors_documents_self_description_document_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConnectorStatus", "Status") + .WithMany("Connectors") + .HasForeignKey("StatusId") + .IsRequired() + .HasConstraintName("fk_connectors_connector_statuses_status_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConnectorType", "Type") + .WithMany("Connectors") + .HasForeignKey("TypeId") + .IsRequired() + .HasConstraintName("fk_connectors_connector_types_type_id"); + + b.Navigation("CompanyServiceAccount"); + + b.Navigation("Host"); + + b.Navigation("LastEditor"); + + b.Navigation("Location"); + + b.Navigation("Provider"); + + b.Navigation("SelfDescriptionDocument"); + + b.Navigation("Status"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConnectorAssignedOfferSubscription", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Connector", "Connector") + .WithMany("ConnectorAssignedOfferSubscriptions") + .HasForeignKey("ConnectorId") + .IsRequired() + .HasConstraintName("fk_connector_assigned_offer_subscriptions_connectors_connector"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscription", "OfferSubscription") + .WithMany("ConnectorAssignedOfferSubscriptions") + .HasForeignKey("OfferSubscriptionId") + .IsRequired() + .HasConstraintName("fk_connector_assigned_offer_subscriptions_offer_subscriptions_"); + + b.Navigation("Connector"); + + b.Navigation("OfferSubscription"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Consent", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Agreement", "Agreement") + .WithMany("Consents") + .HasForeignKey("AgreementId") + .IsRequired() + .HasConstraintName("fk_consents_agreements_agreement_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany("Consents") + .HasForeignKey("CompanyId") + .IsRequired() + .HasConstraintName("fk_consents_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CompanyUser") + .WithMany("Consents") + .HasForeignKey("CompanyUserId") + .IsRequired() + .HasConstraintName("fk_consents_company_users_company_user_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConsentStatus", "ConsentStatus") + .WithMany("Consents") + .HasForeignKey("ConsentStatusId") + .IsRequired() + .HasConstraintName("fk_consents_consent_statuses_consent_status_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", "Document") + .WithMany("Consents") + .HasForeignKey("DocumentId") + .HasConstraintName("fk_consents_documents_document_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_consents_identities_last_editor_id"); + + b.Navigation("Agreement"); + + b.Navigation("Company"); + + b.Navigation("CompanyUser"); + + b.Navigation("ConsentStatus"); + + b.Navigation("Document"); + + b.Navigation("LastEditor"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConsentAssignedOffer", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Consent", "Consent") + .WithMany("ConsentAssignedOffers") + .HasForeignKey("ConsentId") + .IsRequired() + .HasConstraintName("fk_consent_assigned_offers_consents_consent_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany("ConsentAssignedOffers") + .HasForeignKey("OfferId") + .IsRequired() + .HasConstraintName("fk_consent_assigned_offers_offers_offer_id"); + + b.Navigation("Consent"); + + b.Navigation("Offer"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConsentAssignedOfferSubscription", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Consent", "Consent") + .WithMany("ConsentAssignedOfferSubscriptions") + .HasForeignKey("ConsentId") + .IsRequired() + .HasConstraintName("fk_consent_assigned_offer_subscriptions_consents_consent_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscription", "OfferSubscription") + .WithMany("ConsentAssignedOfferSubscriptions") + .HasForeignKey("OfferSubscriptionId") + .IsRequired() + .HasConstraintName("fk_consent_assigned_offer_subscriptions_offer_subscriptions_of"); + + b.Navigation("Consent"); + + b.Navigation("OfferSubscription"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CountryAssignedIdentifier", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.BpdmIdentifier", "BpdmIdentifier") + .WithMany("CountryAssignedIdentifiers") + .HasForeignKey("BpdmIdentifierId") + .HasConstraintName("fk_country_assigned_identifiers_bpdm_identifiers_bpdm_identifi"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Country", "Country") + .WithMany("CountryAssignedIdentifiers") + .HasForeignKey("CountryAlpha2Code") + .IsRequired() + .HasConstraintName("fk_country_assigned_identifiers_countries_country_alpha2code"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UniqueIdentifier", "UniqueIdentifier") + .WithMany("CountryAssignedIdentifiers") + .HasForeignKey("UniqueIdentifierId") + .IsRequired() + .HasConstraintName("fk_country_assigned_identifiers_unique_identifiers_unique_iden"); + + b.Navigation("BpdmIdentifier"); + + b.Navigation("Country"); + + b.Navigation("UniqueIdentifier"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CountryLongName", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Country", "Country") + .WithMany("CountryLongNames") + .HasForeignKey("Alpha2Code") + .IsRequired() + .HasConstraintName("fk_country_long_names_countries_alpha2code"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") + .WithMany("CountryLongNames") + .HasForeignKey("ShortName") + .IsRequired() + .HasConstraintName("fk_country_long_names_languages_short_name"); + + b.Navigation("Country"); + + b.Navigation("Language"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DimCompanyServiceAccount", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccount", "CompanyServiceAccount") + .WithOne("DimCompanyServiceAccount") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DimCompanyServiceAccount", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_dim_company_service_accounts_company_service_accounts_id"); + + b.Navigation("CompanyServiceAccount"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DimUserCreationData", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithOne("DimUserCreationData") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DimUserCreationData", "ProcessId") + .IsRequired() + .HasConstraintName("fk_dim_user_creation_data_processes_process_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccount", "ServiceAccount") + .WithOne("DimUserCreationData") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DimUserCreationData", "ServiceAccountId") + .IsRequired() + .HasConstraintName("fk_dim_user_creation_data_company_service_accounts_service_acc"); + + b.Navigation("Process"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CompanyUser") + .WithMany("Documents") + .HasForeignKey("CompanyUserId") + .HasConstraintName("fk_documents_company_users_company_user_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DocumentStatus", "DocumentStatus") + .WithMany("Documents") + .HasForeignKey("DocumentStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_documents_document_status_document_status_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DocumentType", "DocumentType") + .WithMany("Documents") + .HasForeignKey("DocumentTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_documents_document_types_document_type_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.MediaType", "MediaType") + .WithMany("Documents") + .HasForeignKey("MediaTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_documents_media_types_media_type_id"); + + b.Navigation("CompanyUser"); + + b.Navigation("DocumentStatus"); + + b.Navigation("DocumentType"); + + b.Navigation("MediaType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IamIdentityProvider", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", "IdentityProvider") + .WithOne("IamIdentityProvider") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IamIdentityProvider", "IdentityProviderId") + .IsRequired() + .HasConstraintName("fk_iam_identity_providers_identity_providers_identity_provider"); + + b.Navigation("IdentityProvider"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany("Identities") + .HasForeignKey("CompanyId") + .IsRequired() + .HasConstraintName("fk_identities_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityType", "IdentityType") + .WithMany("Identities") + .HasForeignKey("IdentityTypeId") + .IsRequired() + .HasConstraintName("fk_identities_identity_type_identity_type_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_identities_identities_last_editor_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityUserStatus", "IdentityStatus") + .WithMany("Identities") + .HasForeignKey("UserStatusId") + .IsRequired() + .HasConstraintName("fk_identities_identity_user_statuses_user_status_id"); + + b.Navigation("Company"); + + b.Navigation("IdentityStatus"); + + b.Navigation("IdentityType"); + + b.Navigation("LastEditor"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityAssignedRole", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "Identity") + .WithMany("IdentityAssignedRoles") + .HasForeignKey("IdentityId") + .IsRequired() + .HasConstraintName("fk_identity_assigned_roles_identities_identity_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_identity_assigned_roles_identities_last_editor_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRole", "UserRole") + .WithMany("IdentityAssignedRoles") + .HasForeignKey("UserRoleId") + .IsRequired() + .HasConstraintName("fk_identity_assigned_roles_user_roles_user_role_id"); + + b.Navigation("Identity"); + + b.Navigation("LastEditor"); + + b.Navigation("UserRole"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderCategory", "IdentityProviderCategory") + .WithMany("IdentityProviders") + .HasForeignKey("IdentityProviderCategoryId") + .IsRequired() + .HasConstraintName("fk_identity_providers_identity_provider_categories_identity_pr"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderType", "IdentityProviderType") + .WithMany("IdentityProviders") + .HasForeignKey("IdentityProviderTypeId") + .IsRequired() + .HasConstraintName("fk_identity_providers_identity_provider_types_identity_provide"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Owner") + .WithMany("OwnedIdentityProviders") + .HasForeignKey("OwnerId") + .IsRequired() + .HasConstraintName("fk_identity_providers_companies_owner_id"); + + b.Navigation("IdentityProviderCategory"); + + b.Navigation("IdentityProviderType"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderAssignedProcess", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", "IdentityProvider") + .WithOne("IdentityProviderAssignedProcess") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderAssignedProcess", "IdentityProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_identity_provider_assigned_processes_identity_providers_ide"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithOne("IdentityProviderAssignedProcess") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderAssignedProcess", "ProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_identity_provider_assigned_processes_processes_process_id"); + + b.Navigation("IdentityProvider"); + + b.Navigation("Process"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Invitation", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplication", "CompanyApplication") + .WithMany("Invitations") + .HasForeignKey("CompanyApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_invitations_company_applications_company_application_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CompanyUser") + .WithMany("Invitations") + .HasForeignKey("CompanyUserId") + .IsRequired() + .HasConstraintName("fk_invitations_company_users_company_user_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.InvitationStatus", "InvitationStatus") + .WithMany("Invitations") + .HasForeignKey("InvitationStatusId") + .IsRequired() + .HasConstraintName("fk_invitations_invitation_statuses_invitation_status_id"); + + b.Navigation("CompanyApplication"); + + b.Navigation("CompanyUser"); + + b.Navigation("InvitationStatus"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.LanguageLongName", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "LongNameLanguage") + .WithMany("LanguageLongNameLanguages") + .HasForeignKey("LanguageShortName") + .IsRequired() + .HasConstraintName("fk_language_long_names_languages_language_short_name"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") + .WithMany("LanguageLongNames") + .HasForeignKey("ShortName") + .IsRequired() + .HasConstraintName("fk_language_long_names_languages_short_name"); + + b.Navigation("Language"); + + b.Navigation("LongNameLanguage"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.MailingInformation", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.MailingStatus", "MailingStatus") + .WithMany("MailingInformations") + .HasForeignKey("MailingStatusId") + .IsRequired() + .HasConstraintName("fk_mailing_informations_mailing_statuses_mailing_status_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithOne("MailingInformation") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.MailingInformation", "ProcessId") + .IsRequired() + .HasConstraintName("fk_mailing_informations_processes_process_id"); + + b.Navigation("MailingStatus"); + + b.Navigation("Process"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NetworkRegistration", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplication", "CompanyApplication") + .WithOne("NetworkRegistration") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NetworkRegistration", "ApplicationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_network_registrations_company_applications_application_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithOne("NetworkRegistration") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NetworkRegistration", "CompanyId") + .IsRequired() + .HasConstraintName("fk_network_registrations_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "OnboardingServiceProvider") + .WithMany("OnboardedNetworkRegistrations") + .HasForeignKey("OnboardingServiceProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_network_registrations_companies_onboarding_service_provider"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithOne("NetworkRegistration") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NetworkRegistration", "ProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_network_registrations_processes_process_id"); + + b.Navigation("Company"); + + b.Navigation("CompanyApplication"); + + b.Navigation("OnboardingServiceProvider"); + + b.Navigation("Process"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Notification", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "Creator") + .WithMany("CreatedNotifications") + .HasForeignKey("CreatorUserId") + .HasConstraintName("fk_notifications_identities_creator_user_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationType", "NotificationType") + .WithMany("Notifications") + .HasForeignKey("NotificationTypeId") + .IsRequired() + .HasConstraintName("fk_notifications_notification_type_notification_type_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "Receiver") + .WithMany("Notifications") + .HasForeignKey("ReceiverUserId") + .IsRequired() + .HasConstraintName("fk_notifications_company_users_receiver_user_id"); + + b.Navigation("Creator"); + + b.Navigation("NotificationType"); + + b.Navigation("Receiver"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationTypeAssignedTopic", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationTopic", "NotificationTopic") + .WithMany("NotificationTypeAssignedTopics") + .HasForeignKey("NotificationTopicId") + .IsRequired() + .HasConstraintName("fk_notification_type_assigned_topics_notification_topic_notifi"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationType", "NotificationType") + .WithOne("NotificationTypeAssignedTopic") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationTypeAssignedTopic", "NotificationTypeId") + .IsRequired() + .HasConstraintName("fk_notification_type_assigned_topics_notification_type_notific"); + + b.Navigation("NotificationTopic"); + + b.Navigation("NotificationType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_offers_identities_last_editor_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.LicenseType", "LicenseType") + .WithMany("Offers") + .HasForeignKey("LicenseTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_offers_license_types_license_type_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferStatus", "OfferStatus") + .WithMany("Offers") + .HasForeignKey("OfferStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_offers_offer_statuses_offer_status_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferType", "OfferType") + .WithMany("Offers") + .HasForeignKey("OfferTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_offers_offer_types_offer_type_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "ProviderCompany") + .WithMany("ProvidedOffers") + .HasForeignKey("ProviderCompanyId") + .HasConstraintName("fk_offers_companies_provider_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "SalesManager") + .WithMany("SalesManagerOfOffers") + .HasForeignKey("SalesManagerId") + .HasConstraintName("fk_offers_company_users_sales_manager_id"); + + b.Navigation("LastEditor"); + + b.Navigation("LicenseType"); + + b.Navigation("OfferStatus"); + + b.Navigation("OfferType"); + + b.Navigation("ProviderCompany"); + + b.Navigation("SalesManager"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferAssignedDocument", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", "Document") + .WithMany() + .HasForeignKey("DocumentId") + .IsRequired() + .HasConstraintName("fk_offer_assigned_documents_documents_document_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany() + .HasForeignKey("OfferId") + .IsRequired() + .HasConstraintName("fk_offer_assigned_documents_offers_offer_id"); + + b.Navigation("Document"); + + b.Navigation("Offer"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferAssignedLicense", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany() + .HasForeignKey("OfferId") + .IsRequired() + .HasConstraintName("fk_offer_assigned_licenses_offers_offer_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferLicense", "OfferLicense") + .WithMany() + .HasForeignKey("OfferLicenseId") + .IsRequired() + .HasConstraintName("fk_offer_assigned_licenses_offer_licenses_offer_license_id"); + + b.Navigation("Offer"); + + b.Navigation("OfferLicense"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferAssignedPrivacyPolicy", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany("OfferAssignedPrivacyPolicies") + .HasForeignKey("OfferId") + .IsRequired() + .HasConstraintName("fk_offer_assigned_privacy_policies_offers_offer_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.PrivacyPolicy", "PrivacyPolicy") + .WithMany("OfferAssignedPrivacyPolicies") + .HasForeignKey("PrivacyPolicyId") + .IsRequired() + .HasConstraintName("fk_offer_assigned_privacy_policies_privacy_policies_privacy_po"); + + b.Navigation("Offer"); + + b.Navigation("PrivacyPolicy"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferDescription", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") + .WithMany("AppDescriptions") + .HasForeignKey("LanguageShortName") + .IsRequired() + .HasConstraintName("fk_offer_descriptions_languages_language_short_name"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany("OfferDescriptions") + .HasForeignKey("OfferId") + .IsRequired() + .HasConstraintName("fk_offer_descriptions_offers_offer_id"); + + b.Navigation("Language"); + + b.Navigation("Offer"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscription", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithMany("OfferSubscriptions") + .HasForeignKey("CompanyId") + .IsRequired() + .HasConstraintName("fk_offer_subscriptions_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_offer_subscriptions_identities_last_editor_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany("OfferSubscriptions") + .HasForeignKey("OfferId") + .IsRequired() + .HasConstraintName("fk_offer_subscriptions_offers_offer_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscriptionStatus", "OfferSubscriptionStatus") + .WithMany("OfferSubscriptions") + .HasForeignKey("OfferSubscriptionStatusId") + .IsRequired() + .HasConstraintName("fk_offer_subscriptions_offer_subscription_statuses_offer_subsc"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithOne("OfferSubscription") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscription", "ProcessId") + .HasConstraintName("fk_offer_subscriptions_processes_process_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "Requester") + .WithMany("RequestedSubscriptions") + .HasForeignKey("RequesterId") + .IsRequired() + .HasConstraintName("fk_offer_subscriptions_company_users_requester_id"); + + b.Navigation("Company"); + + b.Navigation("LastEditor"); + + b.Navigation("Offer"); + + b.Navigation("OfferSubscriptionStatus"); + + b.Navigation("Process"); + + b.Navigation("Requester"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscriptionProcessData", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscription", "OfferSubscription") + .WithOne("OfferSubscriptionProcessData") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscriptionProcessData", "OfferSubscriptionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_offer_subscriptions_process_datas_offer_subscriptions_offer"); + + b.Navigation("OfferSubscription"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferTag", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany("Tags") + .HasForeignKey("OfferId") + .IsRequired() + .HasConstraintName("fk_offer_tags_offers_offer_id"); + + b.Navigation("Offer"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OnboardingServiceProviderDetail", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithOne("OnboardingServiceProviderDetail") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OnboardingServiceProviderDetail", "CompanyId") + .IsRequired() + .HasConstraintName("fk_onboarding_service_provider_details_companies_company_id"); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessType", "ProcessType") + .WithMany("Processes") + .HasForeignKey("ProcessTypeId") + .IsRequired() + .HasConstraintName("fk_processes_process_types_process_type_id"); + + b.Navigation("ProcessType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessStep", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithMany("ProcessSteps") + .HasForeignKey("ProcessId") + .IsRequired() + .HasConstraintName("fk_process_steps_processes_process_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessStepStatus", "ProcessStepStatus") + .WithMany("ProcessSteps") + .HasForeignKey("ProcessStepStatusId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_process_steps_process_step_statuses_process_step_status_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessStepType", "ProcessStepType") + .WithMany("ProcessSteps") + .HasForeignKey("ProcessStepTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_process_steps_process_step_types_process_step_type_id"); + + b.Navigation("Process"); + + b.Navigation("ProcessStepStatus"); + + b.Navigation("ProcessStepType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProviderCompanyDetail", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") + .WithOne("ProviderCompanyDetail") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProviderCompanyDetail", "CompanyId") + .IsRequired() + .HasConstraintName("fk_provider_company_details_companies_company_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_provider_company_details_identities_last_editor_id"); + + b.Navigation("Company"); + + b.Navigation("LastEditor"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ServiceDetail", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Service") + .WithMany("ServiceDetails") + .HasForeignKey("ServiceId") + .IsRequired() + .HasConstraintName("fk_service_details_offers_service_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ServiceType", "ServiceType") + .WithMany("ServiceDetails") + .HasForeignKey("ServiceTypeId") + .IsRequired() + .HasConstraintName("fk_service_details_service_types_service_type_id"); + + b.Navigation("Service"); + + b.Navigation("ServiceType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.TechnicalUserProfile", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany("TechnicalUserProfiles") + .HasForeignKey("OfferId") + .IsRequired() + .HasConstraintName("fk_technical_user_profiles_offers_offer_id"); + + b.Navigation("Offer"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.TechnicalUserProfileAssignedUserRole", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.TechnicalUserProfile", "TechnicalUserProfile") + .WithMany("TechnicalUserProfileAssignedUserRoles") + .HasForeignKey("TechnicalUserProfileId") + .IsRequired() + .HasConstraintName("fk_technical_user_profile_assigned_user_roles_technical_user_p"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRole", "UserRole") + .WithMany("TechnicalUserProfileAssignedUserRole") + .HasForeignKey("UserRoleId") + .IsRequired() + .HasConstraintName("fk_technical_user_profile_assigned_user_roles_user_roles_user_"); + + b.Navigation("TechnicalUserProfile"); + + b.Navigation("UserRole"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UseCaseDescription", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") + .WithMany("UseCases") + .HasForeignKey("LanguageShortName") + .IsRequired() + .HasConstraintName("fk_use_case_descriptions_languages_language_short_name"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UseCase", "UseCase") + .WithMany("UseCaseDescriptions") + .HasForeignKey("UseCaseId") + .IsRequired() + .HasConstraintName("fk_use_case_descriptions_use_cases_use_case_id"); + + b.Navigation("Language"); + + b.Navigation("UseCase"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRole", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", "LastEditor") + .WithMany() + .HasForeignKey("LastEditorId") + .HasConstraintName("fk_user_roles_identities_last_editor_id"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", "Offer") + .WithMany("UserRoles") + .HasForeignKey("OfferId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_roles_offers_offer_id"); + + b.Navigation("LastEditor"); + + b.Navigation("Offer"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleAssignedCollection", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleCollection", "UserRoleCollection") + .WithMany() + .HasForeignKey("UserRoleCollectionId") + .IsRequired() + .HasConstraintName("fk_user_role_assigned_collections_user_role_collections_user_r"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRole", "UserRole") + .WithMany() + .HasForeignKey("UserRoleId") + .IsRequired() + .HasConstraintName("fk_user_role_assigned_collections_user_roles_user_role_id"); + + b.Navigation("UserRole"); + + b.Navigation("UserRoleCollection"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleCollectionDescription", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") + .WithMany() + .HasForeignKey("LanguageShortName") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_role_collection_descriptions_languages_language_short_"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleCollection", "UserRoleCollection") + .WithMany("UserRoleCollectionDescriptions") + .HasForeignKey("UserRoleCollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_role_collection_descriptions_user_role_collections_use"); + + b.Navigation("Language"); + + b.Navigation("UserRoleCollection"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleDescription", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", "Language") + .WithMany("UserRoleDescriptions") + .HasForeignKey("LanguageShortName") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_role_descriptions_languages_language_short_name"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRole", "UserRole") + .WithMany("UserRoleDescriptions") + .HasForeignKey("UserRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_role_descriptions_user_roles_user_role_id"); + + b.Navigation("Language"); + + b.Navigation("UserRole"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialExternalTypeUseCaseDetailVersion", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialExternalType", "VerifiedCredentialExternalType") + .WithMany("VerifiedCredentialExternalTypeUseCaseDetailVersions") + .HasForeignKey("VerifiedCredentialExternalTypeId") + .IsRequired() + .HasConstraintName("fk_verified_credential_external_type_use_case_detail_versions_"); + + b.Navigation("VerifiedCredentialExternalType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedExternalType", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialExternalType", "VerifiedCredentialExternalType") + .WithMany("VerifiedCredentialTypeAssignedExternalTypes") + .HasForeignKey("VerifiedCredentialExternalTypeId") + .IsRequired() + .HasConstraintName("fk_verified_credential_type_assigned_external_types_verified_c"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialType", "VerifiedCredentialType") + .WithOne("VerifiedCredentialTypeAssignedExternalType") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedExternalType", "VerifiedCredentialTypeId") + .IsRequired() + .HasConstraintName("fk_verified_credential_type_assigned_external_types_verified_c1"); + + b.Navigation("VerifiedCredentialExternalType"); + + b.Navigation("VerifiedCredentialType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedKind", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialType", "VerifiedCredentialType") + .WithOne("VerifiedCredentialTypeAssignedKind") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedKind", "VerifiedCredentialTypeId") + .IsRequired() + .HasConstraintName("fk_verified_credential_type_assigned_kinds_verified_credential"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeKind", "VerifiedCredentialTypeKind") + .WithMany("VerifiedCredentialTypeAssignedKinds") + .HasForeignKey("VerifiedCredentialTypeKindId") + .IsRequired() + .HasConstraintName("fk_verified_credential_type_assigned_kinds_verified_credential1"); + + b.Navigation("VerifiedCredentialType"); + + b.Navigation("VerifiedCredentialTypeKind"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedUseCase", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UseCase", "UseCase") + .WithOne("VerifiedCredentialAssignedUseCase") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedUseCase", "UseCaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_verified_credential_type_assigned_use_cases_use_cases_use_c"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialType", "VerifiedCredentialType") + .WithOne("VerifiedCredentialTypeAssignedUseCase") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeAssignedUseCase", "VerifiedCredentialTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_verified_credential_type_assigned_use_cases_verified_creden"); + + b.Navigation("UseCase"); + + b.Navigation("VerifiedCredentialType"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Views.CompaniesLinkedServiceAccount", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccount", "CompanyServiceAccount") + .WithOne("CompaniesLinkedServiceAccount") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Views.CompaniesLinkedServiceAccount", "ServiceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_linked_service_accounts_company_service_accounts_co"); + + 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"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Agreement", b => + { + b.Navigation("AgreementAssignedCompanyRoles"); + + b.Navigation("AgreementAssignedOfferTypes"); + + b.Navigation("AgreementAssignedOffers"); + + b.Navigation("Consents"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementCategory", b => + { + b.Navigation("Agreements"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AgreementStatus", b => + { + b.Navigation("Agreements"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.AppInstance", b => + { + b.Navigation("AppSubscriptionDetails"); + + b.Navigation("ServiceAccounts"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ApplicationChecklistEntryStatus", b => + { + b.Navigation("ApplicationChecklistEntries"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ApplicationChecklistEntryType", b => + { + b.Navigation("ApplicationChecklistEntries"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.BpdmIdentifier", b => + { + b.Navigation("CountryAssignedIdentifiers"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", b => + { + b.Navigation("Agreements"); + + b.Navigation("CompanyApplications"); + + b.Navigation("CompanyAssignedRoles"); + + b.Navigation("CompanyAssignedUseCase"); + + b.Navigation("CompanyCertificates"); + + b.Navigation("CompanyIdentifiers"); + + b.Navigation("CompanySsiDetails"); + + b.Navigation("CompanyWalletData"); + + b.Navigation("Consents"); + + b.Navigation("HostedConnectors"); + + b.Navigation("Identities"); + + b.Navigation("NetworkRegistration"); + + b.Navigation("OfferSubscriptions"); + + b.Navigation("OnboardedNetworkRegistrations"); + + b.Navigation("OnboardingServiceProviderDetail"); + + b.Navigation("OwnedIdentityProviders"); + + b.Navigation("ProvidedApplications"); + + b.Navigation("ProvidedConnectors"); + + b.Navigation("ProvidedOffers"); + + b.Navigation("ProviderCompanyDetail"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplication", b => + { + b.Navigation("ApplicationChecklistEntries"); + + b.Navigation("CompanyInvitation"); + + b.Navigation("Invitations"); + + b.Navigation("NetworkRegistration"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplicationStatus", b => + { + b.Navigation("CompanyApplications"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplicationType", b => + { + b.Navigation("CompanyApplications"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyRole", b => + { + b.Navigation("AgreementAssignedCompanyRoles"); + + b.Navigation("CompanyAssignedRoles"); + + b.Navigation("CompanyRoleAssignedRoleCollection"); + + b.Navigation("CompanyRoleDescriptions"); + + b.Navigation("CompanyRoleRegistrationData"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccount", b => + { + b.Navigation("AppInstances"); + + b.Navigation("CompaniesLinkedServiceAccount"); + + b.Navigation("Connector"); + + b.Navigation("DimCompanyServiceAccount"); + + b.Navigation("DimUserCreationData"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccountKind", b => + { + b.Navigation("CompanyServiceAccounts"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyServiceAccountType", b => + { + b.Navigation("CompanyServiceAccounts"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanySsiDetailStatus", b => + { + b.Navigation("CompanySsiDetails"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyStatus", b => + { + b.Navigation("Companies"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", b => + { + b.Navigation("CompanySsiDetails"); + + b.Navigation("CompanyUserAssignedBusinessPartners"); + + b.Navigation("CompanyUserAssignedIdentityProviders"); + + b.Navigation("CompanyUserAssignedProcess"); + + b.Navigation("Consents"); + + b.Navigation("Documents"); + + b.Navigation("Invitations"); + + b.Navigation("Notifications"); + + b.Navigation("RequestedSubscriptions"); + + b.Navigation("SalesManagerOfOffers"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Connector", b => + { + b.Navigation("ConnectorAssignedOfferSubscriptions"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConnectorStatus", b => + { + b.Navigation("Connectors"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConnectorType", b => + { + b.Navigation("Connectors"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Consent", b => + { + b.Navigation("ConsentAssignedOfferSubscriptions"); + + b.Navigation("ConsentAssignedOffers"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ConsentStatus", b => + { + b.Navigation("Consents"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Country", b => + { + b.Navigation("Addresses"); + + b.Navigation("Connectors"); + + b.Navigation("CountryAssignedIdentifiers"); + + b.Navigation("CountryLongNames"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document", b => + { + b.Navigation("Agreements"); + + b.Navigation("Companies"); + + b.Navigation("CompanyCertificates"); + + b.Navigation("CompanySsiDetail"); + + b.Navigation("Connector"); + + b.Navigation("Consents"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DocumentStatus", b => + { + b.Navigation("Documents"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.DocumentType", b => + { + b.Navigation("Documents"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IamClient", b => + { + b.Navigation("AppInstances"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Identity", b => + { + b.Navigation("CompanyServiceAccount"); + + b.Navigation("CompanyUser"); + + b.Navigation("CreatedNotifications"); + + b.Navigation("IdentityAssignedRoles"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", b => + { + b.Navigation("CompanyIdentityProviders"); + + b.Navigation("CompanyUserAssignedIdentityProviders"); + + b.Navigation("IamIdentityProvider"); + + b.Navigation("IdentityProviderAssignedProcess"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderCategory", b => + { + b.Navigation("IdentityProviders"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderType", b => + { + b.Navigation("IdentityProviders"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityType", b => + { + b.Navigation("Identities"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityUserStatus", b => + { + b.Navigation("Identities"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.InvitationStatus", b => + { + b.Navigation("Invitations"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Language", b => + { + b.Navigation("AppDescriptions"); + + b.Navigation("CompanyCertificateTypeDescriptions"); + + b.Navigation("CompanyRoleDescriptions"); + + b.Navigation("CountryLongNames"); + + b.Navigation("LanguageLongNameLanguages"); + + b.Navigation("LanguageLongNames"); + + b.Navigation("UseCases"); + + b.Navigation("UserRoleDescriptions"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.LicenseType", b => + { + b.Navigation("Offers"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.MailingStatus", b => + { + b.Navigation("MailingInformations"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.MediaType", b => + { + b.Navigation("Documents"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationTopic", b => + { + b.Navigation("NotificationTypeAssignedTopics"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.NotificationType", b => + { + b.Navigation("NotificationTypeAssignedTopic"); + + b.Navigation("Notifications"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Offer", b => + { + b.Navigation("AgreementAssignedOffers"); + + b.Navigation("AppInstanceSetup"); + + b.Navigation("AppInstances"); + + b.Navigation("ConsentAssignedOffers"); + + b.Navigation("OfferAssignedPrivacyPolicies"); + + b.Navigation("OfferDescriptions"); + + b.Navigation("OfferSubscriptions"); + + b.Navigation("ServiceDetails"); + + b.Navigation("Tags"); + + b.Navigation("TechnicalUserProfiles"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferStatus", b => + { + b.Navigation("Offers"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscription", b => + { + b.Navigation("AppSubscriptionDetail"); + + b.Navigation("CompanyServiceAccounts"); + + b.Navigation("ConnectorAssignedOfferSubscriptions"); + + b.Navigation("ConsentAssignedOfferSubscriptions"); + + b.Navigation("OfferSubscriptionProcessData"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferSubscriptionStatus", b => + { + b.Navigation("OfferSubscriptions"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.OfferType", b => + { + b.Navigation("AgreementAssignedOfferTypes"); + + b.Navigation("Offers"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.PrivacyPolicy", b => + { + b.Navigation("OfferAssignedPrivacyPolicies"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", b => + { + b.Navigation("CompanyApplication"); + + b.Navigation("CompanyInvitation"); + + b.Navigation("CompanyUserAssignedProcess"); + + b.Navigation("DimUserCreationData"); + + b.Navigation("IdentityProviderAssignedProcess"); + + b.Navigation("MailingInformation"); + + b.Navigation("NetworkRegistration"); + + b.Navigation("OfferSubscription"); + + b.Navigation("ProcessSteps"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessStepStatus", b => + { + b.Navigation("ProcessSteps"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessStepType", b => + { + b.Navigation("ProcessSteps"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ProcessType", b => + { + b.Navigation("Processes"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.ServiceType", b => + { + b.Navigation("ServiceDetails"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.TechnicalUserProfile", b => + { + b.Navigation("TechnicalUserProfileAssignedUserRoles"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UniqueIdentifier", b => + { + b.Navigation("CompanyIdentifiers"); + + b.Navigation("CountryAssignedIdentifiers"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UseCase", b => + { + b.Navigation("Agreements"); + + b.Navigation("CompanyAssignedUseCase"); + + b.Navigation("UseCaseDescriptions"); + + b.Navigation("VerifiedCredentialAssignedUseCase"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRole", b => + { + b.Navigation("IdentityAssignedRoles"); + + b.Navigation("TechnicalUserProfileAssignedUserRole"); + + b.Navigation("UserRoleDescriptions"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.UserRoleCollection", b => + { + b.Navigation("CompanyRoleAssignedRoleCollection"); + + b.Navigation("UserRoleCollectionDescriptions"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialExternalType", b => + { + b.Navigation("VerifiedCredentialExternalTypeUseCaseDetailVersions"); + + b.Navigation("VerifiedCredentialTypeAssignedExternalTypes"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialExternalTypeUseCaseDetailVersion", b => + { + b.Navigation("CompanySsiDetails"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialType", b => + { + b.Navigation("CompanySsiDetails"); + + b.Navigation("VerifiedCredentialTypeAssignedExternalType"); + + b.Navigation("VerifiedCredentialTypeAssignedKind"); + + b.Navigation("VerifiedCredentialTypeAssignedUseCase"); + }); + + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.VerifiedCredentialTypeKind", b => + { + b.Navigation("VerifiedCredentialTypeAssignedKinds"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.cs b/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.cs new file mode 100644 index 0000000000..b83bac1eb9 --- /dev/null +++ b/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.cs @@ -0,0 +1,345 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.Migrations.Migrations +{ + /// + public partial class CPLP3548declineRegistration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_company_identity_providers_companies_company_id", + schema: "portal", + table: "company_identity_providers"); + + migrationBuilder.DropForeignKey( + name: "fk_company_identity_providers_identity_providers_identity_prov", + schema: "portal", + table: "company_identity_providers"); + + migrationBuilder.DropForeignKey( + name: "fk_company_user_assigned_identity_providers_company_users_comp", + schema: "portal", + table: "company_user_assigned_identity_providers"); + + migrationBuilder.DropForeignKey( + name: "fk_company_user_assigned_identity_providers_identity_providers", + schema: "portal", + table: "company_user_assigned_identity_providers"); + + migrationBuilder.CreateTable( + name: "company_user_assigned_processes", + schema: "portal", + columns: table => new + { + company_user_id = table.Column(type: "uuid", nullable: false), + process_id = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_company_user_assigned_processes", x => new { x.company_user_id, x.process_id }); + table.ForeignKey( + name: "fk_company_user_assigned_processes_company_users_company_user_", + column: x => x.company_user_id, + principalSchema: "portal", + principalTable: "company_users", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_company_user_assigned_processes_processes_process_id", + column: x => x.process_id, + principalSchema: "portal", + principalTable: "processes", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "identity_provider_assigned_processes", + schema: "portal", + columns: table => new + { + identity_provider_id = table.Column(type: "uuid", nullable: false), + process_id = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_identity_provider_assigned_processes", x => new { x.identity_provider_id, x.process_id }); + table.ForeignKey( + name: "fk_identity_provider_assigned_processes_identity_providers_ide", + column: x => x.identity_provider_id, + principalSchema: "portal", + principalTable: "identity_providers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_identity_provider_assigned_processes_processes_process_id", + column: x => x.process_id, + principalSchema: "portal", + principalTable: "processes", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.InsertData( + schema: "portal", + table: "process_step_types", + columns: new[] { "id", "label" }, + values: new object[,] + { + { 600, "DELETE_CENTRAL_USER" }, + { 601, "RETRIGGER_DELETE_CENTRAL_USER" }, + { 602, "DELETE_COMPANYUSER_ASSIGNED_PROCESS" }, + { 700, "DELETE_IDP_SHARED_REALM" }, + { 701, "RETRIGGER_DELETE_IDP_SHARED_REALM" }, + { 702, "DELETE_IDP_SHARED_SERVICEACCOUNT" }, + { 703, "RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT" }, + { 704, "DELETE_CENTRAL_IDENTITY_PROVIDER" }, + { 705, "RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER" }, + { 706, "DELETE_IDENTITY_PROVIDER" } + }); + + migrationBuilder.InsertData( + schema: "portal", + table: "process_types", + columns: new[] { "id", "label" }, + values: new object[,] + { + { 8, "USER_PROVISIONING" }, + { 9, "IDENTITYPROVIDER_PROVISIONING" } + }); + + migrationBuilder.CreateIndex( + name: "ix_company_user_assigned_processes_company_user_id", + schema: "portal", + table: "company_user_assigned_processes", + column: "company_user_id", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_company_user_assigned_processes_process_id", + schema: "portal", + table: "company_user_assigned_processes", + column: "process_id", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_identity_provider_assigned_processes_identity_provider_id", + schema: "portal", + table: "identity_provider_assigned_processes", + column: "identity_provider_id", + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_identity_provider_assigned_processes_process_id", + schema: "portal", + table: "identity_provider_assigned_processes", + column: "process_id", + unique: true); + + migrationBuilder.AddForeignKey( + name: "fk_company_identity_providers_companies_company_id", + schema: "portal", + table: "company_identity_providers", + column: "company_id", + principalSchema: "portal", + principalTable: "companies", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "fk_company_identity_providers_identity_providers_identity_prov", + schema: "portal", + table: "company_identity_providers", + column: "identity_provider_id", + principalSchema: "portal", + principalTable: "identity_providers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "fk_company_user_assigned_identity_providers_company_users_comp", + schema: "portal", + table: "company_user_assigned_identity_providers", + column: "company_user_id", + principalSchema: "portal", + principalTable: "company_users", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "fk_company_user_assigned_identity_providers_identity_providers", + schema: "portal", + table: "company_user_assigned_identity_providers", + column: "identity_provider_id", + principalSchema: "portal", + principalTable: "identity_providers", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_company_identity_providers_companies_company_id", + schema: "portal", + table: "company_identity_providers"); + + migrationBuilder.DropForeignKey( + name: "fk_company_identity_providers_identity_providers_identity_prov", + schema: "portal", + table: "company_identity_providers"); + + migrationBuilder.DropForeignKey( + name: "fk_company_user_assigned_identity_providers_company_users_comp", + schema: "portal", + table: "company_user_assigned_identity_providers"); + + migrationBuilder.DropForeignKey( + name: "fk_company_user_assigned_identity_providers_identity_providers", + schema: "portal", + table: "company_user_assigned_identity_providers"); + + migrationBuilder.DropTable( + name: "company_user_assigned_processes", + schema: "portal"); + + migrationBuilder.DropTable( + name: "identity_provider_assigned_processes", + schema: "portal"); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 600); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 601); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 602); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 700); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 701); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 702); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 703); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 704); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 705); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_step_types", + keyColumn: "id", + keyValue: 706); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_types", + keyColumn: "id", + keyValue: 8); + + migrationBuilder.DeleteData( + schema: "portal", + table: "process_types", + keyColumn: "id", + keyValue: 9); + + migrationBuilder.AddForeignKey( + name: "fk_company_identity_providers_companies_company_id", + schema: "portal", + table: "company_identity_providers", + column: "company_id", + principalSchema: "portal", + principalTable: "companies", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "fk_company_identity_providers_identity_providers_identity_prov", + schema: "portal", + table: "company_identity_providers", + column: "identity_provider_id", + principalSchema: "portal", + principalTable: "identity_providers", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "fk_company_user_assigned_identity_providers_company_users_comp", + schema: "portal", + table: "company_user_assigned_identity_providers", + column: "company_user_id", + principalSchema: "portal", + principalTable: "company_users", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "fk_company_user_assigned_identity_providers_identity_providers", + schema: "portal", + table: "company_user_assigned_identity_providers", + column: "identity_provider_id", + principalSchema: "portal", + principalTable: "identity_providers", + principalColumn: "id"); + } + } +} diff --git a/src/portalbackend/PortalBackend.Migrations/Migrations/PortalDbContextModelSnapshot.cs b/src/portalbackend/PortalBackend.Migrations/Migrations/PortalDbContextModelSnapshot.cs index 7d11540ed0..fcce8b44d8 100644 --- a/src/portalbackend/PortalBackend.Migrations/Migrations/PortalDbContextModelSnapshot.cs +++ b/src/portalbackend/PortalBackend.Migrations/Migrations/PortalDbContextModelSnapshot.cs @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2024 Contributors to the Eclipse Foundation + * Copyright (c) 2022 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -36,7 +36,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder .HasDefaultSchema("portal") .UseCollation("en_US.utf8") - .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("ProductVersion", "8.0.5") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -4075,6 +4075,30 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("company_user_assigned_identity_providers", "portal"); }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedProcess", b => + { + b.Property("CompanyUserId") + .HasColumnType("uuid") + .HasColumnName("company_user_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.HasKey("CompanyUserId", "ProcessId") + .HasName("pk_company_user_assigned_processes"); + + b.HasIndex("CompanyUserId") + .IsUnique() + .HasDatabaseName("ix_company_user_assigned_processes_company_user_id"); + + b.HasIndex("ProcessId") + .IsUnique() + .HasDatabaseName("ix_company_user_assigned_processes_process_id"); + + b.ToTable("company_user_assigned_processes", "portal"); + }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyWalletData", b => { b.Property("Id") @@ -4994,6 +5018,30 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("identity_providers", "portal"); }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderAssignedProcess", b => + { + b.Property("IdentityProviderId") + .HasColumnType("uuid") + .HasColumnName("identity_provider_id"); + + b.Property("ProcessId") + .HasColumnType("uuid") + .HasColumnName("process_id"); + + b.HasKey("IdentityProviderId", "ProcessId") + .HasName("pk_identity_provider_assigned_processes"); + + b.HasIndex("IdentityProviderId") + .IsUnique() + .HasDatabaseName("ix_identity_provider_assigned_processes_identity_provider_id"); + + b.HasIndex("ProcessId") + .IsUnique() + .HasDatabaseName("ix_identity_provider_assigned_processes_process_id"); + + b.ToTable("identity_provider_assigned_processes", "portal"); + }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderCategory", b => { b.Property("Id") @@ -6836,6 +6884,56 @@ protected override void BuildModel(ModelBuilder modelBuilder) { Id = 501, Label = "RETRIGGER_CREATE_DIM_TECHNICAL_USER" + }, + new + { + Id = 600, + Label = "DELETE_CENTRAL_USER" + }, + new + { + Id = 601, + Label = "RETRIGGER_DELETE_CENTRAL_USER" + }, + new + { + Id = 602, + Label = "DELETE_COMPANYUSER_ASSIGNED_PROCESS" + }, + new + { + Id = 700, + Label = "DELETE_IDP_SHARED_REALM" + }, + new + { + Id = 701, + Label = "RETRIGGER_DELETE_IDP_SHARED_REALM" + }, + new + { + Id = 702, + Label = "DELETE_IDP_SHARED_SERVICEACCOUNT" + }, + new + { + Id = 703, + Label = "RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT" + }, + new + { + Id = 704, + Label = "DELETE_CENTRAL_IDENTITY_PROVIDER" + }, + new + { + Id = 705, + Label = "RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER" + }, + new + { + Id = 706, + Label = "DELETE_IDENTITY_PROVIDER" }); }); @@ -6886,6 +6984,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) { Id = 7, Label = "DIM_TECHNICAL_USER" + }, + new + { + Id = 8, + Label = "USER_PROVISIONING" + }, + new + { + Id = 9, + Label = "IDENTITYPROVIDER_PROVISIONING" }); }); @@ -8148,12 +8256,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") .WithMany() .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) .IsRequired() .HasConstraintName("fk_company_identity_providers_companies_company_id"); b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", "IdentityProvider") .WithMany("CompanyIdentityProviders") .HasForeignKey("IdentityProviderId") + .OnDelete(DeleteBehavior.Cascade) .IsRequired() .HasConstraintName("fk_company_identity_providers_identity_providers_identity_prov"); @@ -8383,12 +8493,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CompanyUser") .WithMany("CompanyUserAssignedIdentityProviders") .HasForeignKey("CompanyUserId") + .OnDelete(DeleteBehavior.Cascade) .IsRequired() .HasConstraintName("fk_company_user_assigned_identity_providers_company_users_comp"); b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", "IdentityProvider") .WithMany("CompanyUserAssignedIdentityProviders") .HasForeignKey("IdentityProviderId") + .OnDelete(DeleteBehavior.Cascade) .IsRequired() .HasConstraintName("fk_company_user_assigned_identity_providers_identity_providers"); @@ -8397,6 +8509,27 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("IdentityProvider"); }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedProcess", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUser", "CompanyUser") + .WithOne("CompanyUserAssignedProcess") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedProcess", "CompanyUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_user_assigned_processes_company_users_company_user_"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithOne("CompanyUserAssignedProcess") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyUserAssignedProcess", "ProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_company_user_assigned_processes_processes_process_id"); + + b.Navigation("CompanyUser"); + + b.Navigation("Process"); + }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyWalletData", b => { b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Company", "Company") @@ -8791,6 +8924,27 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Owner"); }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderAssignedProcess", b => + { + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProvider", "IdentityProvider") + .WithOne("IdentityProviderAssignedProcess") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderAssignedProcess", "IdentityProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_identity_provider_assigned_processes_identity_providers_ide"); + + b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Process", "Process") + .WithOne("IdentityProviderAssignedProcess") + .HasForeignKey("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderAssignedProcess", "ProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_identity_provider_assigned_processes_processes_process_id"); + + b.Navigation("IdentityProvider"); + + b.Navigation("Process"); + }); + modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Invitation", b => { b.HasOne("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.CompanyApplication", "CompanyApplication") @@ -9623,6 +9777,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("CompanyUserAssignedIdentityProviders"); + b.Navigation("CompanyUserAssignedProcess"); + b.Navigation("Consents"); b.Navigation("Documents"); @@ -9722,6 +9878,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("CompanyUserAssignedIdentityProviders"); b.Navigation("IamIdentityProvider"); + + b.Navigation("IdentityProviderAssignedProcess"); }); modelBuilder.Entity("Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.IdentityProviderCategory", b => @@ -9861,8 +10019,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("CompanyInvitation"); + b.Navigation("CompanyUserAssignedProcess"); + b.Navigation("DimUserCreationData"); + b.Navigation("IdentityProviderAssignedProcess"); + b.Navigation("MailingInformation"); b.Navigation("NetworkRegistration"); diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/BatchInsertSeeder.cs b/src/portalbackend/PortalBackend.Migrations/Seeder/BatchInsertSeeder.cs index f3354c0e75..203a50c3dd 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/BatchInsertSeeder.cs +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/BatchInsertSeeder.cs @@ -84,6 +84,7 @@ public async Task ExecuteAsync(CancellationToken cancellationToken) await SeedTable("company_certificate_type_assigned_statuses", x => new { x.CompanyCertificateTypeId, x.CompanyCertificateTypeStatusId }, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); await SeedTable("company_certificate_type_descriptions", x => new { x.CompanyCertificateTypeId, x.LanguageShortName }, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); await SeedTable("identity_assigned_roles", x => new { x.IdentityId, x.UserRoleId }, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); + await SeedTable("identity_provider_assigned_processes", x => new { x.IdentityProviderId, x.ProcessId }, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); await SeedTable("consent_assigned_offers", x => new { x.OfferId, x.ConsentId }, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); await SeedTable("consent_assigned_offer_subscriptions", x => new { x.OfferSubscriptionId, x.ConsentId }, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); await SeedTable("connector_assigned_offer_subscriptions", x => new { x.ConnectorId, x.OfferSubscriptionId }, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); diff --git a/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyUser.cs b/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyUser.cs index 76a98b98e9..c15900d71f 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyUser.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyUser.cs @@ -66,6 +66,7 @@ public CompanyUser(Guid id) public virtual Identity? Identity { get; set; } public virtual Identity? LastEditor { get; private set; } + public virtual CompanyUserAssignedProcess? CompanyUserAssignedProcess { get; set; } public virtual ICollection Consents { get; private set; } public virtual ICollection Documents { get; private set; } public virtual ICollection Invitations { get; private set; } diff --git a/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyUserAssignedProcess.cs b/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyUserAssignedProcess.cs new file mode 100644 index 0000000000..440beb080c --- /dev/null +++ b/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyUserAssignedProcess.cs @@ -0,0 +1,36 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; + +public class CompanyUserAssignedProcess +{ + public CompanyUserAssignedProcess(Guid companyUserId, Guid processId) + { + CompanyUserId = companyUserId; + ProcessId = processId; + } + + public Guid CompanyUserId { get; private set; } + public Guid ProcessId { get; private set; } + + // Navigation properties + public virtual CompanyUser? CompanyUser { get; private set; } + public virtual Process? Process { get; private set; } +} diff --git a/src/portalbackend/PortalBackend.PortalEntities/Entities/IdentityProvider.cs b/src/portalbackend/PortalBackend.PortalEntities/Entities/IdentityProvider.cs index fdda79bd3c..c8dbe6144a 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Entities/IdentityProvider.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Entities/IdentityProvider.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 @@ -56,6 +55,7 @@ public IdentityProvider(Guid id, IdentityProviderCategoryId identityProviderCate public virtual IamIdentityProvider? IamIdentityProvider { get; set; } public virtual IdentityProviderType? IdentityProviderType { get; set; } public virtual Company? Owner { get; set; } + public virtual IdentityProviderAssignedProcess? IdentityProviderAssignedProcess { get; set; } public virtual ICollection Companies { get; private set; } public virtual ICollection CompanyIdentityProviders { get; private set; } public virtual ICollection CompanyUserAssignedIdentityProviders { get; private set; } diff --git a/src/portalbackend/PortalBackend.PortalEntities/Entities/IdentityProviderAssignedProcess.cs b/src/portalbackend/PortalBackend.PortalEntities/Entities/IdentityProviderAssignedProcess.cs new file mode 100644 index 0000000000..cd0d3410e0 --- /dev/null +++ b/src/portalbackend/PortalBackend.PortalEntities/Entities/IdentityProviderAssignedProcess.cs @@ -0,0 +1,36 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; + +public class IdentityProviderAssignedProcess +{ + public IdentityProviderAssignedProcess(Guid identityProviderId, Guid processId) + { + IdentityProviderId = identityProviderId; + ProcessId = processId; + } + + public Guid IdentityProviderId { get; private set; } + public Guid ProcessId { get; private set; } + + // Navigation properties + public virtual IdentityProvider? IdentityProvider { get; private set; } + public virtual Process? Process { get; private set; } +} diff --git a/src/portalbackend/PortalBackend.PortalEntities/Entities/NetworkRegistration.cs b/src/portalbackend/PortalBackend.PortalEntities/Entities/NetworkRegistration.cs index bd5ea84e44..34bded051c 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Entities/NetworkRegistration.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Entities/NetworkRegistration.cs @@ -1,5 +1,4 @@ /******************************************************************************** - * Copyright (c) 2023 BMW Group AG * Copyright (c) 2023 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional @@ -60,5 +59,6 @@ public NetworkRegistration(Guid id, string externalId, Guid companyId, Guid proc public virtual Company? OnboardingServiceProvider { get; private set; } public virtual CompanyApplication? CompanyApplication { get; private set; } + public virtual Process? Process { get; private set; } } diff --git a/src/portalbackend/PortalBackend.PortalEntities/Entities/OfferSubscription.cs b/src/portalbackend/PortalBackend.PortalEntities/Entities/OfferSubscription.cs index 3032ff2be7..8c1343451e 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Entities/OfferSubscription.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Entities/OfferSubscription.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 @@ -122,7 +121,7 @@ public OfferSubscription(Guid id, Guid offerId, Guid companyId, OfferSubscriptio /// /// Assigned Process. /// - public virtual Process? Process { get; private set; } + public virtual Process? Process { get; set; } /// /// Requester diff --git a/src/portalbackend/PortalBackend.PortalEntities/Entities/Process.cs b/src/portalbackend/PortalBackend.PortalEntities/Entities/Process.cs index c3a8ac3f66..1b18db5ccb 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Entities/Process.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Entities/Process.cs @@ -55,5 +55,7 @@ public Process(Guid id, ProcessTypeId processTypeId, Guid version) : this() public virtual MailingInformation? MailingInformation { get; set; } public virtual CompanyInvitation? CompanyInvitation { get; set; } public virtual DimUserCreationData? DimUserCreationData { get; set; } + public virtual CompanyUserAssignedProcess? CompanyUserAssignedProcess { get; set; } + public virtual IdentityProviderAssignedProcess? IdentityProviderAssignedProcess { get; set; } public virtual ICollection ProcessSteps { get; private set; } } diff --git a/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessStepTypeId.cs b/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessStepTypeId.cs index 795f86ebbf..b8a72cdac8 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessStepTypeId.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessStepTypeId.cs @@ -112,5 +112,19 @@ public enum ProcessStepTypeId // DIM_TECHNICAL_USER CREATE_DIM_TECHNICAL_USER = 500, - RETRIGGER_CREATE_DIM_TECHNICAL_USER = 501 + RETRIGGER_CREATE_DIM_TECHNICAL_USER = 501, + + // USER_PROVISIONING + DELETE_CENTRAL_USER = 600, + RETRIGGER_DELETE_CENTRAL_USER = 601, + DELETE_COMPANYUSER_ASSIGNED_PROCESS = 602, + + // IDENTITYPROVIDER_PPROVISIONING + DELETE_IDP_SHARED_REALM = 700, + RETRIGGER_DELETE_IDP_SHARED_REALM = 701, + DELETE_IDP_SHARED_SERVICEACCOUNT = 702, + RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT = 703, + DELETE_CENTRAL_IDENTITY_PROVIDER = 704, + RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER = 705, + DELETE_IDENTITY_PROVIDER = 706, } diff --git a/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessTypeId.cs b/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessTypeId.cs index 8b03d721ad..9531fd0bf0 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessTypeId.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Enums/ProcessTypeId.cs @@ -26,5 +26,7 @@ public enum ProcessTypeId PARTNER_REGISTRATION = 4, MAILING = 5, INVITATION = 6, - DIM_TECHNICAL_USER = 7 + DIM_TECHNICAL_USER = 7, + USER_PROVISIONING = 8, + IDENTITYPROVIDER_PROVISIONING = 9 } diff --git a/src/portalbackend/PortalBackend.PortalEntities/PortalDbContext.cs b/src/portalbackend/PortalBackend.PortalEntities/PortalDbContext.cs index dc40505e0a..96df8a3aa2 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/PortalDbContext.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/PortalDbContext.cs @@ -129,6 +129,7 @@ public PortalDbContext(DbContextOptions options, IAuditHandler public virtual DbSet CompanyUserAssignedAppFavourites { get; set; } = default!; public virtual DbSet CompanyUserAssignedBusinessPartners { get; set; } = default!; public virtual DbSet CompanyUserAssignedIdentityProviders { get; set; } = default!; + public virtual DbSet CompanyUserAssignedProcesses { get; set; } = default!; public virtual DbSet Connectors { get; set; } = default!; public virtual DbSet ConnectorAssignedOfferSubscriptions { get; set; } = default!; public virtual DbSet ConnectorStatuses { get; set; } = default!; @@ -150,6 +151,7 @@ public PortalDbContext(DbContextOptions options, IAuditHandler public virtual DbSet Identities { get; set; } = default!; public virtual DbSet IdentityAssignedRoles { get; set; } = default!; public virtual DbSet IdentityProviders { get; set; } = default!; + public virtual DbSet IdentityProviderAssignedProcesses { get; set; } = default!; public virtual DbSet IdentityProviderTypes { get; set; } = default!; public virtual DbSet IdentityProviderCategories { get; set; } = default!; public virtual DbSet IdentityUserStatuses { get; set; } = default!; @@ -552,12 +554,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) j => j .HasOne(pt => pt.IdentityProvider!) .WithMany() - .HasForeignKey(pt => pt.IdentityProviderId) - .OnDelete(DeleteBehavior.ClientSetNull), + .HasForeignKey(pt => pt.IdentityProviderId), j => j .HasOne(pt => pt.Company!) .WithMany() - .OnDelete(DeleteBehavior.ClientSetNull) .HasForeignKey(pt => pt.CompanyId), j => { @@ -857,6 +857,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) entity.ToTable("company_users"); }); + modelBuilder.Entity() + .HasKey(e => new { e.CompanyUserId, e.ProcessId }); + modelBuilder.Entity(entity => { entity.HasOne(x => x.Identity) @@ -1051,6 +1054,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.ClientSetNull); }); + modelBuilder.Entity() + .HasKey(e => new { e.IdentityProviderId, e.ProcessId }); + modelBuilder.Entity() .HasData( Enum.GetValues(typeof(IdentityProviderTypeId)) @@ -1548,20 +1554,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .HasForeignKey(x => x.ApplicationId); }); - modelBuilder.Entity(entity => - { - entity.HasKey(e => new { e.CompanyUserId, e.IdentityProviderId }); - - entity.HasOne(e => e.CompanyUser) - .WithMany(e => e.CompanyUserAssignedIdentityProviders) - .HasForeignKey(e => e.CompanyUserId) - .OnDelete(DeleteBehavior.ClientSetNull); - - entity.HasOne(e => e.IdentityProvider) - .WithMany(e => e.CompanyUserAssignedIdentityProviders) - .HasForeignKey(e => e.IdentityProviderId) - .OnDelete(DeleteBehavior.ClientSetNull); - }); + modelBuilder.Entity() + .HasKey(e => new { e.CompanyUserId, e.IdentityProviderId }); modelBuilder.Entity() .HasAuditV1Triggers(); diff --git a/src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioning.Executor.csproj b/src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioning.Executor.csproj new file mode 100644 index 0000000000..6030e08d8e --- /dev/null +++ b/src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioning.Executor.csproj @@ -0,0 +1,36 @@ + + + + Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor + Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor + net8.0 + enable + enable + + + + + + + + + + + \ No newline at end of file diff --git a/src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioningExtensions.cs b/src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioningExtensions.cs new file mode 100644 index 0000000000..53cede396a --- /dev/null +++ b/src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioningExtensions.cs @@ -0,0 +1,35 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; + +namespace Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor; + +public static class IdentityProviderProvisioningExtensions +{ + public static IEnumerable? GetIdentityProviderProvisioningRetriggerStep(this ProcessStepTypeId processStepTypeId) => + processStepTypeId switch + { + ProcessStepTypeId.DELETE_IDP_SHARED_REALM => [ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_REALM], + ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT => [ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT], + ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER => [ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER], + _ => throw new UnexpectedConditionException($"ProcessStepTypeId {processStepTypeId} is not supported for Process IdentityProviderProvisioning") + }; +} diff --git a/src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioningProcessTypeExecutor.cs b/src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioningProcessTypeExecutor.cs new file mode 100644 index 0000000000..d78a7e39c3 --- /dev/null +++ b/src/processes/IdentityProviderProvisioning.Executor/IdentityProviderProvisioningProcessTypeExecutor.cs @@ -0,0 +1,163 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.Keycloak.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Processes.Worker.Library; +using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library; +using System.Collections.Immutable; + +namespace Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor; + +public class IdentityProviderProvisioningProcessTypeExecutor : IProcessTypeExecutor +{ + private readonly IPortalRepositories _portalRepositories; + private readonly IProvisioningManager _provisioningManager; + + private static readonly IEnumerable ExecutableProcessSteps = + [ + ProcessStepTypeId.DELETE_IDP_SHARED_REALM, + ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT, + ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, + ProcessStepTypeId.DELETE_IDENTITY_PROVIDER, + ]; + + private IdpData? _idpData = null; + + public IdentityProviderProvisioningProcessTypeExecutor(IPortalRepositories portalRepositories, IProvisioningManager provisioningManager) + { + _portalRepositories = portalRepositories; + _provisioningManager = provisioningManager; + } + + public ProcessTypeId GetProcessTypeId() => ProcessTypeId.IDENTITYPROVIDER_PROVISIONING; + public bool IsExecutableStepTypeId(ProcessStepTypeId processStepTypeId) => ExecutableProcessSteps.Contains(processStepTypeId); + public IEnumerable GetExecutableStepTypeIds() => ExecutableProcessSteps; + public ValueTask IsLockRequested(ProcessStepTypeId processStepTypeId) => ValueTask.FromResult(false); + + public async ValueTask InitializeProcess(Guid processId, IEnumerable processStepTypeIds) + { + var idpData = await _portalRepositories.GetInstance().GetIdentityProviderDataForProcessIdAsync(processId).ConfigureAwait(ConfigureAwaitOptions.None); + + if (idpData == null) + { + throw new ConflictException($"process {processId} does not exist or is not associated with an Identity Provider"); + } + _idpData = idpData; + return new IProcessTypeExecutor.InitializationResult(false, null); + } + + public async ValueTask ExecuteProcessStep(ProcessStepTypeId processStepTypeId, IEnumerable processStepTypeIds, CancellationToken cancellationToken) + { + if (_idpData == null) + { + throw new UnexpectedConditionException("IdentityProvider data should never be empty here"); + } + + IEnumerable? nextStepTypeIds; + ProcessStepStatusId stepStatusId; + bool modified; + string? processMessage; + + try + { + (nextStepTypeIds, stepStatusId, modified, processMessage) = processStepTypeId switch + { + ProcessStepTypeId.DELETE_IDP_SHARED_REALM => await DeleteSharedRealmAsync(_idpData).ConfigureAwait(ConfigureAwaitOptions.None), + ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT => await DeleteIdpSharedServiceAccount(_idpData).ConfigureAwait(ConfigureAwaitOptions.None), + ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER => await DeleteCentralIdentityProvider(_idpData.IamAlias).ConfigureAwait(ConfigureAwaitOptions.None), + ProcessStepTypeId.DELETE_IDENTITY_PROVIDER => DeleteIdentityProvider(_idpData.IdentityProviderId), + _ => (null, ProcessStepStatusId.TODO, false, null) + }; + } + catch (Exception ex) when (ex is not SystemException) + { + (stepStatusId, processMessage, nextStepTypeIds) = ProcessError(ex, processStepTypeId); + modified = true; + } + return new IProcessTypeExecutor.StepExecutionResult(modified, stepStatusId, nextStepTypeIds, null, processMessage); + } + + private static (ProcessStepStatusId StatusId, string? ProcessMessage, IEnumerable? nextSteps) ProcessError(Exception ex, ProcessStepTypeId processStepTypeId) + { + return ex switch + { + ServiceException { IsRecoverable: true } => (ProcessStepStatusId.TODO, ex.Message, null), + _ => (ProcessStepStatusId.FAILED, ex.Message, processStepTypeId.GetIdentityProviderProvisioningRetriggerStep()) + }; + } + + private async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> DeleteSharedRealmAsync(IdpData idpData) + { + if (idpData.IdentityProviderTypeId != IdentityProviderTypeId.SHARED) + { + return ([ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER], ProcessStepStatusId.SKIPPED, false, $"IdentityProvider {idpData.IamAlias} is not a shared idp"); + } + try + { + await _provisioningManager.DeleteSharedRealmAsync(idpData.IamAlias).ConfigureAwait(ConfigureAwaitOptions.None); + return ([ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT], ProcessStepStatusId.DONE, false, null); + } + catch (KeycloakEntityNotFoundException) + { + return ([ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT], ProcessStepStatusId.SKIPPED, false, $"Shared Idp realm {idpData.IamAlias} not found"); + } + } + + private async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> DeleteIdpSharedServiceAccount(IdpData idpData) + { + if (idpData.IdentityProviderTypeId != IdentityProviderTypeId.SHARED) + { + return ([ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER], ProcessStepStatusId.SKIPPED, false, $"IdentityProvider {idpData.IamAlias} is not a shared idp"); + } + try + { + await _provisioningManager.DeleteIdpSharedServiceAccount(idpData.IamAlias).ConfigureAwait(ConfigureAwaitOptions.None); + return ([ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER], ProcessStepStatusId.DONE, false, null); + } + catch (KeycloakEntityNotFoundException) + { + return ([ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER], ProcessStepStatusId.SKIPPED, false, $"Shared Idp admin-serviceaccount for realm {idpData.IamAlias} not found"); + } + } + + private async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> DeleteCentralIdentityProvider(string alias) + { + try + { + await _provisioningManager.DeleteCentralIdentityProviderAsync(alias).ConfigureAwait(ConfigureAwaitOptions.None); + return ([ProcessStepTypeId.DELETE_IDENTITY_PROVIDER], ProcessStepStatusId.DONE, false, null); + } + catch (KeycloakEntityNotFoundException) + { + return ([ProcessStepTypeId.DELETE_IDENTITY_PROVIDER], ProcessStepStatusId.SKIPPED, false, $"Central IdentityProvider {alias} not found"); + } + } + + private (IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage) DeleteIdentityProvider(Guid identityProviderId) + { + var identityProviderRepository = _portalRepositories.GetInstance(); + identityProviderRepository.DeleteIdentityProvider(identityProviderId); + return (null, ProcessStepStatusId.DONE, true, null); + } +} diff --git a/src/processes/Processes.Worker/Processes.Worker.csproj b/src/processes/Processes.Worker/Processes.Worker.csproj index 8b5922fc9d..4025f56740 100644 --- a/src/processes/Processes.Worker/Processes.Worker.csproj +++ b/src/processes/Processes.Worker/Processes.Worker.csproj @@ -52,6 +52,8 @@ + + diff --git a/src/processes/Processes.Worker/Program.cs b/src/processes/Processes.Worker/Program.cs index ea042d86e1..440c5dec5c 100644 --- a/src/processes/Processes.Worker/Program.cs +++ b/src/processes/Processes.Worker/Program.cs @@ -31,17 +31,20 @@ using Org.Eclipse.TractusX.Portal.Backend.Processes.ApplicationChecklist.Config; using Org.Eclipse.TractusX.Portal.Backend.Processes.ApplicationChecklist.Executor; using Org.Eclipse.TractusX.Portal.Backend.Processes.DimUserCreationProcess.Executor.DependencyInjection; +using Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor; using Org.Eclipse.TractusX.Portal.Backend.Processes.Invitation.Executor.DependencyInjection; using Org.Eclipse.TractusX.Portal.Backend.Processes.Mailing.Executor.DependencyInjection; using Org.Eclipse.TractusX.Portal.Backend.Processes.Mailing.Library.DependencyInjection; using Org.Eclipse.TractusX.Portal.Backend.Processes.NetworkRegistration.Executor.DependencyInjection; using Org.Eclipse.TractusX.Portal.Backend.Processes.OfferSubscription.Executor.DependencyInjection; using Org.Eclipse.TractusX.Portal.Backend.Processes.ProcessIdentity.DependencyInjection; +using Org.Eclipse.TractusX.Portal.Backend.Processes.UserProvisioning.Executor; using Org.Eclipse.TractusX.Portal.Backend.Processes.Worker.Library; using Serilog; LoggingExtensions.EnsureInitialized(); Log.Information("Building worker"); +var isDevelopment = false; try { var host = Host @@ -65,7 +68,9 @@ .AddMailingProcessExecutor() .AddInvitationProcessExecutor(hostContext.Configuration) .AddMailingProcessCreation(hostContext.Configuration.GetSection("MailingProcessCreation")) - .AddDimUserCreationProcessExecutor(hostContext.Configuration.GetSection("ApplicationChecklist")); + .AddDimUserCreationProcessExecutor(hostContext.Configuration.GetSection("ApplicationChecklist")) + .AddTransient() + .AddTransient(); if (hostContext.HostingEnvironment.IsDevelopment()) { @@ -77,11 +82,13 @@ { FlurlUntrustedCertExceptionHandler.ConfigureExceptions(urlsToTrust); } + isDevelopment = true; } }) .AddLogging() .Build(); Log.Information("Building worker completed"); + FlurlErrorHandler.ConfigureErrorHandler(host.Services.GetRequiredService>(), isDevelopment); using var tokenSource = new CancellationTokenSource(); Console.CancelKeyPress += (s, e) => diff --git a/src/processes/UserProvisioning.Executor/UserProvisioning.Executor.csproj b/src/processes/UserProvisioning.Executor/UserProvisioning.Executor.csproj new file mode 100644 index 0000000000..696f9ce7f1 --- /dev/null +++ b/src/processes/UserProvisioning.Executor/UserProvisioning.Executor.csproj @@ -0,0 +1,36 @@ + + + + Org.Eclipse.TractusX.Portal.Backend.Processes.UserProvisioning.Executor + Org.Eclipse.TractusX.Portal.Backend.Processes.UserProvisioning.Executor + net8.0 + enable + enable + + + + + + + + + + + \ No newline at end of file diff --git a/src/processes/UserProvisioning.Executor/UserProvisioningExtension.cs b/src/processes/UserProvisioning.Executor/UserProvisioningExtension.cs new file mode 100644 index 0000000000..3b75b16a91 --- /dev/null +++ b/src/processes/UserProvisioning.Executor/UserProvisioningExtension.cs @@ -0,0 +1,33 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; + +namespace Org.Eclipse.TractusX.Portal.Backend.Processes.UserProvisioning.Executor; + +public static class UserProvisioningExtensisons +{ + public static IEnumerable? GetUserProvisioningRetriggerStep(this ProcessStepTypeId processStepTypeId) => + processStepTypeId switch + { + ProcessStepTypeId.DELETE_CENTRAL_USER => [ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_USER], + _ => throw new UnexpectedConditionException($"ProcessStepTypeId {processStepTypeId} is not supported for Process UserProvisioning") + }; +} diff --git a/src/processes/UserProvisioning.Executor/UserProvisioningProcessTypeExecutor.cs b/src/processes/UserProvisioning.Executor/UserProvisioningProcessTypeExecutor.cs new file mode 100644 index 0000000000..1a6a60c1a8 --- /dev/null +++ b/src/processes/UserProvisioning.Executor/UserProvisioningProcessTypeExecutor.cs @@ -0,0 +1,134 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.Keycloak.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Processes.Worker.Library; +using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library; +using System.Collections.Immutable; + +namespace Org.Eclipse.TractusX.Portal.Backend.Processes.UserProvisioning.Executor; + +public class UserProvisioningProcessTypeExecutor : IProcessTypeExecutor +{ + private readonly IPortalRepositories _portalRepositories; + private readonly IProvisioningManager _provisioningManager; + + private static readonly IEnumerable ExecutableProcessSteps = + [ + ProcessStepTypeId.DELETE_CENTRAL_USER, + ProcessStepTypeId.DELETE_COMPANYUSER_ASSIGNED_PROCESS, + ]; + + private Guid _userId = Guid.Empty; + private Guid _processId = Guid.Empty; + + public UserProvisioningProcessTypeExecutor(IPortalRepositories portalRepositories, IProvisioningManager provisioningManager) + { + _portalRepositories = portalRepositories; + _provisioningManager = provisioningManager; + } + + public ProcessTypeId GetProcessTypeId() => ProcessTypeId.USER_PROVISIONING; + public bool IsExecutableStepTypeId(ProcessStepTypeId processStepTypeId) => ExecutableProcessSteps.Contains(processStepTypeId); + public IEnumerable GetExecutableStepTypeIds() => ExecutableProcessSteps; + public ValueTask IsLockRequested(ProcessStepTypeId processStepTypeId) => ValueTask.FromResult(false); + + public async ValueTask InitializeProcess(Guid processId, IEnumerable processStepTypeIds) + { + var userId = await _portalRepositories.GetInstance().GetCompanyUserIdForProcessIdAsync(processId).ConfigureAwait(ConfigureAwaitOptions.None); + + if (userId == Guid.Empty) + { + throw new ConflictException($"process {processId} does not exist or is not associated with an CompanyUser"); + } + _userId = userId; + _processId = processId; + return new IProcessTypeExecutor.InitializationResult(false, null); + } + + public async ValueTask ExecuteProcessStep(ProcessStepTypeId processStepTypeId, IEnumerable processStepTypeIds, CancellationToken cancellationToken) + { + if (_userId == Guid.Empty) + { + throw new UnexpectedConditionException("UserId should never be empty here"); + } + if (_processId == Guid.Empty) + { + throw new UnexpectedConditionException("ProcessId should never be empty here"); + } + + IEnumerable? nextStepTypeIds; + ProcessStepStatusId stepStatusId; + bool modified; + string? processMessage; + + try + { + (nextStepTypeIds, stepStatusId, modified, processMessage) = processStepTypeId switch + { + ProcessStepTypeId.DELETE_CENTRAL_USER => await DeleteCentralUser(_userId).ConfigureAwait(ConfigureAwaitOptions.None), + ProcessStepTypeId.DELETE_COMPANYUSER_ASSIGNED_PROCESS => DeleteCompanyUserAssignedProcess(_userId, _processId), + _ => (null, ProcessStepStatusId.TODO, false, null) + }; + } + catch (Exception ex) when (ex is not SystemException) + { + (stepStatusId, processMessage, nextStepTypeIds) = ProcessError(ex, processStepTypeId); + modified = true; + } + return new IProcessTypeExecutor.StepExecutionResult(modified, stepStatusId, nextStepTypeIds, null, processMessage); + } + + private static (ProcessStepStatusId StatusId, string? ProcessMessage, IEnumerable? nextSteps) ProcessError(Exception ex, ProcessStepTypeId processStepTypeId) + { + return ex switch + { + ServiceException { IsRecoverable: true } => (ProcessStepStatusId.TODO, ex.Message, null), + _ => (ProcessStepStatusId.FAILED, ex.Message, processStepTypeId.GetUserProvisioningRetriggerStep()) + }; + } + + private async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> DeleteCentralUser(Guid companyUserId) + { + var userId = await _provisioningManager.GetUserByUserName(companyUserId.ToString()).ConfigureAwait(ConfigureAwaitOptions.None); + if (userId == null) + { + return ([ProcessStepTypeId.DELETE_COMPANYUSER_ASSIGNED_PROCESS], ProcessStepStatusId.SKIPPED, false, $"User {companyUserId} not found by username"); + } + try + { + await _provisioningManager.DeleteCentralRealmUserAsync(userId).ConfigureAwait(ConfigureAwaitOptions.None); + return ([ProcessStepTypeId.DELETE_COMPANYUSER_ASSIGNED_PROCESS], ProcessStepStatusId.DONE, false, null); + } + catch (KeycloakEntityNotFoundException) + { + return ([ProcessStepTypeId.DELETE_COMPANYUSER_ASSIGNED_PROCESS], ProcessStepStatusId.SKIPPED, false, $"User {userId} not found"); + } + } + + private (IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage) DeleteCompanyUserAssignedProcess(Guid companyUserId, Guid processId) + { + _portalRepositories.GetInstance().DeleteCompanyUserAssignedProcess(companyUserId, processId); + return ([], ProcessStepStatusId.DONE, true, null); + } +} diff --git a/src/provisioning/Provisioning.Library/IProvisioningManager.cs b/src/provisioning/Provisioning.Library/IProvisioningManager.cs index 237b2f2d59..39435fa187 100644 --- a/src/provisioning/Provisioning.Library/IProvisioningManager.cs +++ b/src/provisioning/Provisioning.Library/IProvisioningManager.cs @@ -70,4 +70,6 @@ public interface IProvisioningManager ValueTask UpdateSharedRealmTheme(string alias, string loginTheme); Task GetUserByUserName(string userName); Task GetIdentityProviderDisplayName(string alias); + Task DeleteSharedRealmAsync(string alias); + Task DeleteIdpSharedServiceAccount(string alias); } diff --git a/src/provisioning/Provisioning.Library/ProvisioningManager.cs b/src/provisioning/Provisioning.Library/ProvisioningManager.cs index 934b224ace..34827707f1 100644 --- a/src/provisioning/Provisioning.Library/ProvisioningManager.cs +++ b/src/provisioning/Provisioning.Library/ProvisioningManager.cs @@ -275,6 +275,18 @@ private async Task GetSharedKeycloakClient(string realm) return _factory.CreateKeycloakClient("shared", clientId, secret); } + public async Task DeleteSharedRealmAsync(string alias) + { + var deleteSharedKeycloak = await GetSharedKeycloakClient(alias).ConfigureAwait(false); + await deleteSharedKeycloak.DeleteRealmAsync(alias).ConfigureAwait(false); + } + + public async Task DeleteIdpSharedServiceAccount(string alias) + { + var sharedKeycloak = _factory.CreateKeycloakClient("shared"); + await DeleteSharedIdpServiceAccountAsync(sharedKeycloak, alias); + } + private static T Clone(T cloneObject) where T : class => JsonSerializer.Deserialize(JsonSerializer.Serialize(cloneObject))!; diff --git a/src/registration/Registration.Service/BusinessLogic/IRegistrationBusinessLogic.cs b/src/registration/Registration.Service/BusinessLogic/IRegistrationBusinessLogic.cs index 87df54925c..a81735150d 100644 --- a/src/registration/Registration.Service/BusinessLogic/IRegistrationBusinessLogic.cs +++ b/src/registration/Registration.Service/BusinessLogic/IRegistrationBusinessLogic.cs @@ -57,5 +57,6 @@ public interface IRegistrationBusinessLogic IAsyncEnumerable GetCompanyRoles(string? languageShortName = null); Task> GetCompanyIdentifiers(string alpha2Code); Task<(string fileName, byte[] content, string mediaType)> GetRegistrationDocumentAsync(Guid documentId); + Task DeclineApplicationRegistrationAsync(Guid applicationId); } } diff --git a/src/registration/Registration.Service/BusinessLogic/RegistrationBusinessLogic.cs b/src/registration/Registration.Service/BusinessLogic/RegistrationBusinessLogic.cs index f160ada9af..fb6ecb0002 100644 --- a/src/registration/Registration.Service/BusinessLogic/RegistrationBusinessLogic.cs +++ b/src/registration/Registration.Service/BusinessLogic/RegistrationBusinessLogic.cs @@ -22,6 +22,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Bpdm.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.Linq; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration; using Org.Eclipse.TractusX.Portal.Backend.Framework.Web; @@ -921,4 +922,156 @@ public async Task> GetCompanyIdentifiers(strin return (documentDetails.FileName, documentDetails.Content, documentDetails.MediaTypeId.MapToMediaType()); } + public async Task DeclineApplicationRegistrationAsync(Guid applicationId) + { + var (isValidApplicationId, isValidCompany, declineData) = await _portalRepositories.GetInstance() + .GetDeclineApplicationDataForApplicationId(applicationId, _identityData.CompanyId, _settings.ApplicationDeclineStatusIds) + .ConfigureAwait(ConfigureAwaitOptions.None); + + if (!isValidApplicationId) + { + throw new NotFoundException($"Application {applicationId} does not exits"); + } + + if (!isValidCompany) + { + throw new ForbiddenException($"User is not allowed to decline this application"); + } + + if (declineData == null) + { + throw new UnexpectedConditionException("ApplicationDeclineData should never be null here"); + } + + DeclineApplication(applicationId); + DeleteCompany(_identityData.CompanyId); + DeclineInvitations(declineData.InvitationsStatusDatas); + DeactivateDocuments(declineData.DocumentStatusDatas); + ScheduleDeleteIdentityProviders(_identityData.CompanyId, declineData.IdentityProviderStatusDatas); + ScheduleDeleteCompanyUsers(declineData.CompanyUserStatusDatas); + CreateDeclineApplicationEmailProcesses(declineData.CompanyUserStatusDatas.Select(x => (x.FirstName, x.LastName, x.Email)), declineData.CompanyName); + await _portalRepositories.SaveAsync().ConfigureAwait(false); + } + + private void DeclineApplication(Guid applicationId) => + _portalRepositories.GetInstance() + .AttachAndModifyCompanyApplication(applicationId, application => + { + application.ApplicationStatusId = CompanyApplicationStatusId.DECLINED; + application.DateLastChanged = DateTimeOffset.UtcNow; + }); + + private void DeleteCompany(Guid companyId) => + _portalRepositories.GetInstance() + .AttachAndModifyCompany( + companyId, + null, + company => company.CompanyStatusId = CompanyStatusId.DELETED); + + private void DeclineInvitations(IEnumerable invitationsStatusDatas) => + _portalRepositories.GetInstance() + .AttachAndModifyInvitations( + invitationsStatusDatas.Select(data => new ValueTuple?, Action>( + data.InvitationId, + invitation => invitation.InvitationStatusId = data.InvitationStatusId, + invitation => invitation.InvitationStatusId = InvitationStatusId.DECLINED))); + + private void DeactivateDocuments(IEnumerable documentStatusDatas) => + _portalRepositories.GetInstance() + .AttachAndModifyDocuments( + documentStatusDatas.Select(data => new ValueTuple?, Action>( + data.DocumentId, + document => document.DocumentStatusId = data.StatusId, + document => document.DocumentStatusId = DocumentStatusId.INACTIVE))); + + private void ScheduleDeleteIdentityProviders(Guid companyId, IEnumerable identityProviderStatusDatas) + { + var identityProviderRepository = _portalRepositories.GetInstance(); + var processStepRepository = _portalRepositories.GetInstance(); + + identityProviderStatusDatas + .Where(data => data.IdentityProviderTypeId == IdentityProviderTypeId.MANAGED) + .IfAny(managed => + { + identityProviderRepository.DeleteCompanyIdentityProviderRange(managed.Select(x => (companyId, x.IdentityProviderId))); + }); + + identityProviderStatusDatas + .Where(data => data.IdentityProviderTypeId == IdentityProviderTypeId.SHARED || data.IdentityProviderTypeId == IdentityProviderTypeId.OWN) + .IfAny(notManaged => + { + var processDatas = notManaged + .Zip(processStepRepository.CreateProcessRange(Enumerable.Repeat(ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, notManaged.Count()))) + .Select(x => ( + x.First.IdentityProviderTypeId, + x.First.IdentityProviderId, + ProcessId: x.Second.Id + )) + .ToImmutableList(); + + processStepRepository.CreateProcessStepRange( + processDatas.Select(x => ( + x.IdentityProviderTypeId switch + { + IdentityProviderTypeId.SHARED => ProcessStepTypeId.DELETE_IDP_SHARED_REALM, + IdentityProviderTypeId.OWN => ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, + _ => throw new UnexpectedConditionException("IdentityProviderTypeId should allways be shared or own here") + }, + ProcessStepStatusId.TODO, + x.ProcessId))); + + identityProviderRepository.CreateIdentityProviderAssignedProcessRange( + processDatas.Select(x => ( + x.IdentityProviderId, + x.ProcessId))); + }); + } + + private void ScheduleDeleteCompanyUsers(IEnumerable companyUserDatas) + { + _portalRepositories.GetInstance() + .AttachAndModifyIdentities( + companyUserDatas + .Select(data => new ValueTuple?, Action>( + data.CompanyUserId, + identity => identity.UserStatusId = data.UserStatusId, + identity => + { + identity.UserStatusId = UserStatusId.DELETED; + }))); + + _portalRepositories.GetInstance() + .DeleteCompanyUserAssignedRoles( + companyUserDatas.SelectMany(data => data.IdentityAssignedRoleIds.Select(roleId => (data.CompanyUserId, roleId)))); + + var processStepRepository = _portalRepositories.GetInstance(); + var processIds = processStepRepository + .CreateProcessRange(Enumerable.Repeat(ProcessTypeId.USER_PROVISIONING, companyUserDatas.Count())) + .Select(x => x.Id) + .ToImmutableList(); + processStepRepository.CreateProcessStepRange( + processIds.Select(processId => (ProcessStepTypeId.DELETE_CENTRAL_USER, ProcessStepStatusId.TODO, processId))); + _portalRepositories.GetInstance() + .CreateCompanyUserAssignedProcessRange( + companyUserDatas.Select(x => x.CompanyUserId).Zip(processIds)); + } + + private void CreateDeclineApplicationEmailProcesses(IEnumerable<(string? FirstName, string? LastName, string? Email)> emailData, string companyName) + { + foreach (var (FirstName, LastName, Email) in emailData) + { + var userName = string.Join(" ", new[] { FirstName, LastName }.Where(item => !string.IsNullOrWhiteSpace(item))); + + if (string.IsNullOrWhiteSpace(Email)) + { + throw new ConflictException($"user {userName} has no assigned email"); + } + var mailParameters = ImmutableDictionary.CreateRange(new[] + { + KeyValuePair.Create("userName", !string.IsNullOrWhiteSpace(userName) ? userName : Email), + KeyValuePair.Create("companyName", companyName) + }); + _mailingProcessCreation.CreateMailProcess(Email, "EmailRegistrationDeclineTemplate", mailParameters); + } + } } diff --git a/src/registration/Registration.Service/Controllers/RegistrationController.cs b/src/registration/Registration.Service/Controllers/RegistrationController.cs index 2a8401cde1..a863ee9b11 100644 --- a/src/registration/Registration.Service/Controllers/RegistrationController.cs +++ b/src/registration/Registration.Service/Controllers/RegistrationController.cs @@ -491,5 +491,26 @@ public async Task GetRegistrationDocumentAsync([FromRoute] Guid do var (fileName, content, mediaType) = await _registrationBusinessLogic.GetRegistrationDocumentAsync(documentId); return File(content, mediaType, fileName); } + + /// + /// Declines the registration verification for the application with the given id + /// + /// Id of the application that should be declined + /// + /// Example: POST: /api/registration/application/{applicationId}/declineregistration + /// + /// Successfully declined the application + /// Application ID not found. + [HttpPost] + [Authorize(Roles = "decline_new_partner")] + [Authorize(Policy = PolicyTypes.CompanyUser)] + [Route("applications/{applicationId}/declineregistration")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] + public async Task DeclineApplicationRegistrationAsync([FromRoute] Guid applicationId) + { + await _registrationBusinessLogic.DeclineApplicationRegistrationAsync(applicationId).ConfigureAwait(false); + return NoContent(); + } } } diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/IdentityProviderBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/IdentityProviderBusinessLogicTests.cs index 2f6446c71e..5b1bba1af8 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/IdentityProviderBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/IdentityProviderBusinessLogicTests.cs @@ -802,10 +802,9 @@ public async Task DeleteCompanyIdentityProviderAsync_WithSharedKeycloakValid_Cal A.CallTo(() => _provisioningManager.IsCentralIdentityProviderEnabled("other-alias")).MustHaveHappenedOnceExactly(); A.CallTo(() => _provisioningManager.DeleteSharedIdpRealmAsync("test")).MustHaveHappenedOnceExactly(); A.CallTo(() => _provisioningManager.DeleteCentralIdentityProviderAsync("test")).MustHaveHappenedOnceExactly(); - A.CallTo(() => _userRepository.RemoveCompanyUserAssignedIdentityProviders(A>.That.Matches(x => x.Count() == 3))) - .MustHaveHappenedOnceExactly(); + A.CallTo(() => _userRepository.RemoveCompanyUserAssignedIdentityProviders(A>._)).MustNotHaveHappened(); A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); - A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(_companyId, identityProviderId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(_companyId, identityProviderId)).MustNotHaveHappened(); A.CallTo(() => _identityProviderRepository.DeleteIamIdentityProvider("test")).MustHaveHappenedOnceExactly(); A.CallTo(() => _identityProviderRepository.DeleteIdentityProvider(identityProviderId)).MustHaveHappenedOnceExactly(); } @@ -841,9 +840,8 @@ public async Task DeleteCompanyIdentityProviderAsync_WithValid_CallsExpected() A.CallTo(() => _provisioningManager.DeleteSharedIdpRealmAsync("test")).MustNotHaveHappened(); A.CallTo(() => _provisioningManager.DeleteCentralIdentityProviderAsync("test")).MustHaveHappenedOnceExactly(); A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); - A.CallTo(() => _userRepository.RemoveCompanyUserAssignedIdentityProviders(A>.That.Matches(x => x.Count() == 3))) - .MustHaveHappenedOnceExactly(); - A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(_companyId, identityProviderId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _userRepository.RemoveCompanyUserAssignedIdentityProviders(A>._)).MustNotHaveHappened(); + A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(A._, A._)).MustNotHaveHappened(); A.CallTo(() => _identityProviderRepository.DeleteIamIdentityProvider("test")).MustHaveHappenedOnceExactly(); A.CallTo(() => _identityProviderRepository.DeleteIdentityProvider(identityProviderId)).MustHaveHappenedOnceExactly(); } @@ -901,7 +899,7 @@ public async Task DeleteCompanyIdentityProviderAsync_WithManagedIdp_ExecutesExpe A.CallTo(() => _provisioningManager.DeleteSharedIdpRealmAsync("test")).MustNotHaveHappened(); A.CallTo(() => _provisioningManager.DeleteCentralIdentityProviderAsync("test")).MustHaveHappenedOnceExactly(); A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); - A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(company.Id, identityProviderId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(company.Id, identityProviderId)).MustNotHaveHappened(); A.CallTo(() => _identityProviderRepository.DeleteIamIdentityProvider("test")).MustHaveHappenedOnceExactly(); A.CallTo(() => _identityProviderRepository.DeleteIdentityProvider(identityProviderId)).MustHaveHappenedOnceExactly(); A.CallTo(() => _mailingProcessCreation.CreateMailProcess("test@example.org", "DeleteManagedIdp", A>._)) diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/InvitationBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/InvitationBusinessLogicTests.cs index 803ffed699..d36048f7d1 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/InvitationBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/InvitationBusinessLogicTests.cs @@ -123,7 +123,7 @@ public async Task RetriggerCreateCentralIdp_CallsExpected() var stepToTrigger = ProcessStepTypeId.RETRIGGER_INVITATION_CREATE_CENTRAL_IDP; var processStepTypeId = ProcessStepTypeId.INVITATION_CREATE_CENTRAL_IDP; var processSteps = new List(); - var process = _fixture.Build().With(x => x.LockExpiryDate, (DateTimeOffset?)null).Create(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); var processStepId = Guid.NewGuid(); SetupFakesForRetrigger(processSteps); var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); @@ -168,7 +168,7 @@ public async Task RetriggerCreateSharedIdpServiceAccount_CallsExpected() var stepToTrigger = ProcessStepTypeId.RETRIGGER_INVITATION_CREATE_SHARED_IDP_SERVICE_ACCOUNT; var processStepTypeId = ProcessStepTypeId.INVITATION_CREATE_SHARED_IDP_SERVICE_ACCOUNT; var processSteps = new List(); - var process = _fixture.Build().With(x => x.LockExpiryDate, (DateTimeOffset?)null).Create(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); var processStepId = Guid.NewGuid(); SetupFakesForRetrigger(processSteps); var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); @@ -213,7 +213,7 @@ public async Task RetriggerUpdateCentralIdpUrls_CallsExpected() var stepToTrigger = ProcessStepTypeId.RETRIGGER_INVITATION_UPDATE_CENTRAL_IDP_URLS; var processStepTypeId = ProcessStepTypeId.INVITATION_UPDATE_CENTRAL_IDP_URLS; var processSteps = new List(); - var process = _fixture.Build().With(x => x.LockExpiryDate, (DateTimeOffset?)null).Create(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); var processStepId = Guid.NewGuid(); SetupFakesForRetrigger(processSteps); var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); @@ -258,7 +258,7 @@ public async Task RetriggerCreateCentralIdpOrgMapper_CallsExpected() var stepToTrigger = ProcessStepTypeId.RETRIGGER_INVITATION_CREATE_CENTRAL_IDP_ORG_MAPPER; var processStepTypeId = ProcessStepTypeId.INVITATION_CREATE_CENTRAL_IDP_ORG_MAPPER; var processSteps = new List(); - var process = _fixture.Build().With(x => x.LockExpiryDate, (DateTimeOffset?)null).Create(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); var processStepId = Guid.NewGuid(); SetupFakesForRetrigger(processSteps); var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); @@ -303,7 +303,7 @@ public async Task RetriggerCreateSharedRealmIdpClient_CallsExpected() var stepToTrigger = ProcessStepTypeId.RETRIGGER_INVITATION_CREATE_SHARED_REALM; var processStepTypeId = ProcessStepTypeId.INVITATION_CREATE_SHARED_REALM; var processSteps = new List(); - var process = _fixture.Build().With(x => x.LockExpiryDate, (DateTimeOffset?)null).Create(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); var processStepId = Guid.NewGuid(); SetupFakesForRetrigger(processSteps); var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); @@ -348,7 +348,7 @@ public async Task RetriggerEnableCentralIdp_CallsExpected() var stepToTrigger = ProcessStepTypeId.RETRIGGER_INVITATION_ENABLE_CENTRAL_IDP; var processStepTypeId = ProcessStepTypeId.INVITATION_ENABLE_CENTRAL_IDP; var processSteps = new List(); - var process = _fixture.Build().With(x => x.LockExpiryDate, (DateTimeOffset?)null).Create(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); var processStepId = Guid.NewGuid(); SetupFakesForRetrigger(processSteps); var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); @@ -393,7 +393,7 @@ public async Task RetriggerCreateDatabaseIdp_CallsExpected() var stepToTrigger = ProcessStepTypeId.RETRIGGER_INVITATION_CREATE_DATABASE_IDP; var processStepTypeId = ProcessStepTypeId.INVITATION_CREATE_DATABASE_IDP; var processSteps = new List(); - var process = _fixture.Build().With(x => x.LockExpiryDate, (DateTimeOffset?)null).Create(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); var processStepId = Guid.NewGuid(); SetupFakesForRetrigger(processSteps); var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); @@ -438,7 +438,7 @@ public async Task RetriggerInvitationCreateUser_CallsExpected() var stepToTrigger = ProcessStepTypeId.RETRIGGER_INVITATION_CREATE_USER; var processStepTypeId = ProcessStepTypeId.INVITATION_CREATE_USER; var processSteps = new List(); - var process = _fixture.Build().With(x => x.LockExpiryDate, (DateTimeOffset?)null).Create(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); var processStepId = Guid.NewGuid(); SetupFakesForRetrigger(processSteps); var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs index 090d0cb93a..4959f09092 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs @@ -275,7 +275,7 @@ public async Task UpdateCompanyBpnAsync_WithInvalidBpn_ThrowsControllerArgumentE var bpn = "123"; // Act - async Task Act() => await _logic.UpdateCompanyBpn(IdWithBpn, bpn); + Task Act() => _logic.UpdateCompanyBpn(IdWithBpn, bpn); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -290,7 +290,7 @@ public async Task UpdateCompanyBpnAsync_WithNotExistingApplication_ThrowsNotFoun SetupForUpdateCompanyBpn(); // Act - async Task Act() => await _logic.UpdateCompanyBpn(NotExistingApplicationId, ValidBpn); + Task Act() => _logic.UpdateCompanyBpn(NotExistingApplicationId, ValidBpn); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -304,7 +304,7 @@ public async Task UpdateCompanyBpnAsync_WithAlreadyTakenBpn_ThrowsConflictExcept SetupForUpdateCompanyBpn(); // Act - async Task Act() => await _logic.UpdateCompanyBpn(IdWithoutBpn, AlreadyTakenBpn); + Task Act() => _logic.UpdateCompanyBpn(IdWithoutBpn, AlreadyTakenBpn); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -318,7 +318,7 @@ public async Task UpdateCompanyBpnAsync_WithActiveCompanyForApplication_ThrowsCo SetupForUpdateCompanyBpn(); // Act - async Task Act() => await _logic.UpdateCompanyBpn(ActiveApplicationCompanyId, ValidBpn); + Task Act() => _logic.UpdateCompanyBpn(ActiveApplicationCompanyId, ValidBpn); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -332,7 +332,7 @@ public async Task UpdateCompanyBpnAsync_WithBpnAlreadySet_ThrowsConflictExceptio SetupForUpdateCompanyBpn(); // Act - async Task Act() => await _logic.UpdateCompanyBpn(IdWithBpn, ValidBpn); + Task Act() => _logic.UpdateCompanyBpn(IdWithBpn, ValidBpn); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -392,7 +392,7 @@ public async Task ProcessClearinghouseResponseAsync_WithMultipleApplications_Thr // Act var data = new ClearinghouseResponseData(BusinessPartnerNumber, ClearinghouseResponseStatus.CONFIRM, null); - async Task Act() => await _logic.ProcessClearinghouseResponseAsync(data, CancellationToken.None); + Task Act() => _logic.ProcessClearinghouseResponseAsync(data, CancellationToken.None); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -408,7 +408,7 @@ public async Task ProcessClearinghouseResponseAsync_WithNoApplication_ThrowsNotF // Act var data = new ClearinghouseResponseData(BusinessPartnerNumber, ClearinghouseResponseStatus.CONFIRM, null); - async Task Act() => await _logic.ProcessClearinghouseResponseAsync(data, CancellationToken.None); + Task Act() => _logic.ProcessClearinghouseResponseAsync(data, CancellationToken.None); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -519,7 +519,7 @@ public async Task DeclineRegistrationVerification_WithApplicationNotFound_Throws var applicationId = Guid.NewGuid(); A.CallTo(() => _applicationRepository.GetCompanyIdNameForSubmittedApplication(applicationId)) .Returns<(Guid, string, Guid?, IEnumerable<(Guid, string, IdentityProviderTypeId, IEnumerable)>, IEnumerable)>(default); - async Task Act() => await _logic.DeclineRegistrationVerification(applicationId, "test", CancellationToken.None); + Task Act() => _logic.DeclineRegistrationVerification(applicationId, "test", CancellationToken.None); // Act var ex = await Assert.ThrowsAsync(Act); @@ -564,27 +564,27 @@ public async Task DeclineRegistrationVerification_WithMultipleIdps_CallsExpected await _logic.DeclineRegistrationVerification(applicationId, "test", CancellationToken.None); // Assert - A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(companyId, sharedIdpId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(companyId, sharedIdpId)).MustNotHaveHappened(); A.CallTo(() => _identityProviderRepository.DeleteIamIdentityProvider("idp1")).MustHaveHappenedOnceExactly(); A.CallTo(() => _identityProviderRepository.DeleteIdentityProvider(sharedIdpId)).MustHaveHappenedOnceExactly(); A.CallTo(() => _provisioningManager.DeleteSharedIdpRealmAsync("idp1")).MustHaveHappenedOnceExactly(); A.CallTo(() => _provisioningManager.DeleteCentralIdentityProviderAsync("idp1")).MustHaveHappenedOnceExactly(); - A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(companyId, sharedIdpId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(companyId, managedIdpId)).MustHaveHappenedOnceExactly(); A.CallTo(() => _identityProviderRepository.DeleteIamIdentityProvider("idp2")).MustNotHaveHappened(); A.CallTo(() => _identityProviderRepository.DeleteIdentityProvider(managedIdpId)).MustNotHaveHappened(); A.CallTo(() => _provisioningManager.DeleteSharedIdpRealmAsync("idp2")).MustNotHaveHappened(); A.CallTo(() => _provisioningManager.DeleteCentralIdentityProviderAsync("idp2")).MustNotHaveHappened(); - A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(companyId, ownIdpId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _identityProviderRepository.DeleteCompanyIdentityProvider(companyId, ownIdpId)).MustNotHaveHappened(); A.CallTo(() => _identityProviderRepository.DeleteIamIdentityProvider("idp3")).MustHaveHappenedOnceExactly(); A.CallTo(() => _identityProviderRepository.DeleteIdentityProvider(ownIdpId)).MustHaveHappenedOnceExactly(); A.CallTo(() => _provisioningManager.DeleteSharedIdpRealmAsync("idp3")).MustNotHaveHappened(); A.CallTo(() => _provisioningManager.DeleteCentralIdentityProviderAsync("idp3")).MustHaveHappenedOnceExactly(); - A.CallTo(() => _userRepository.RemoveCompanyUserAssignedIdentityProviders(A>.That.IsSameSequenceAs(new[] { new ValueTuple(user1, sharedIdpId) }))).MustHaveHappenedOnceExactly(); + A.CallTo(() => _userRepository.RemoveCompanyUserAssignedIdentityProviders(A>.That.IsSameSequenceAs(new[] { new ValueTuple(user1, sharedIdpId) }))).MustNotHaveHappened(); A.CallTo(() => _userRepository.RemoveCompanyUserAssignedIdentityProviders(A>.That.IsSameSequenceAs(new[] { new ValueTuple(user2, managedIdpId) }))).MustHaveHappenedOnceExactly(); - A.CallTo(() => _userRepository.RemoveCompanyUserAssignedIdentityProviders(A>.That.IsSameSequenceAs(new[] { new ValueTuple(user3, ownIdpId) }))).MustHaveHappenedOnceExactly(); + A.CallTo(() => _userRepository.RemoveCompanyUserAssignedIdentityProviders(A>.That.IsSameSequenceAs(new[] { new ValueTuple(user3, ownIdpId) }))).MustNotHaveHappened(); } #endregion @@ -600,7 +600,7 @@ public async Task GetChecklistForApplicationAsync_WithNotExistingApplication_Thr .Returns<(bool, IEnumerable<(ApplicationChecklistEntryTypeId, ApplicationChecklistEntryStatusId, string?)>, IEnumerable)>(default); //Act - async Task Act() => await _logic.GetChecklistForApplicationAsync(applicationId); + Task Act() => _logic.GetChecklistForApplicationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -655,7 +655,7 @@ public async Task TriggerChecklistAsync_WithFailingChecklistServiceCall_ReturnsE .Throws(new ConflictException("Test")); //Act - async Task Act() => await _logic.TriggerChecklistAsync(applicationId, ApplicationChecklistEntryTypeId.CLEARING_HOUSE, ProcessStepTypeId.RETRIGGER_CLEARING_HOUSE); + Task Act() => _logic.TriggerChecklistAsync(applicationId, ApplicationChecklistEntryTypeId.CLEARING_HOUSE, ProcessStepTypeId.RETRIGGER_CLEARING_HOUSE); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -747,7 +747,7 @@ public async Task ProcessClearinghouseSelfDescription_WithNotExistingApplication .Returns<(bool, Guid, bool)>(default); // Act - async Task Act() => await _logic.ProcessClearinghouseSelfDescription(data, CancellationToken.None); + Task Act() => _logic.ProcessClearinghouseSelfDescription(data, CancellationToken.None); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -763,7 +763,7 @@ public async Task ProcessClearinghouseSelfDescription_WithNotSubmittedApplicatio .Returns((true, Guid.NewGuid(), false)); // Act - async Task Act() => await _logic.ProcessClearinghouseSelfDescription(data, CancellationToken.None); + Task Act() => _logic.ProcessClearinghouseSelfDescription(data, CancellationToken.None); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -802,7 +802,7 @@ public async Task TriggerChecklistAsync_WithWrongProcessStepForChecklist_ThrowsC var applicationId = _fixture.Create(); //Act - async Task Act() => await _logic.TriggerChecklistAsync(applicationId, typeId, stepId); + Task Act() => _logic.TriggerChecklistAsync(applicationId, typeId, stepId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -841,7 +841,7 @@ public async Task GetDocumentAsync_WithNotExistingDocument_ThrowsNotFoundExcepti .Returns(null); // Act - async Task Act() => await _logic.GetDocumentAsync(documentId); + Task Act() => _logic.GetDocumentAsync(documentId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -973,6 +973,194 @@ public async Task ProcessIssuerMembershipResponseAsync_WithNoApplication_ThrowsN #endregion + #region RetriggerProcessStepsForIdpDeletion + + [Fact] + public async Task RetriggerDeleteIdpSharedRealm_CallsExpected() + { + // Arrange + var stepToTrigger = ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_REALM; + var processStepTypeId = ProcessStepTypeId.DELETE_IDP_SHARED_REALM; + var processSteps = new List(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); + var processStepId = Guid.NewGuid(); + SetupFakesForRetrigger(processSteps); + var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); + A.CallTo(() => _processStepRepository.IsValidProcess(A._, A._, A>._)) + .Returns((true, verifyProcessData)); + + // Act + await _logic.RetriggerDeleteIdpSharedRealm(process.Id); + + // Assert + processSteps.Should().ContainSingle().And.Satisfy(x => x.ProcessStepTypeId == processStepTypeId); + A.CallTo(() => _processStepRepository.IsValidProcess(process.Id, ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, A>.That.Matches(x => x.Count() == 1 && x.Single() == stepToTrigger))) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A? Initialize, Action Modify)>>._)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task RetriggerDeleteIdpSharedRealm_WithNotExistingProcess_ThrowsException() + { + // Arrange + var stepToTrigger = ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_REALM; + var processId = Guid.NewGuid(); + A.CallTo(() => _processStepRepository.IsValidProcess(A._, A._, A>._)) + .Returns((false, _fixture.Create())); + + Task Act() => _logic.RetriggerDeleteIdpSharedRealm(processId); + + // Act + var ex = await Assert.ThrowsAsync(Act); + + // Assert + ex.Message.Should().Be($"process {processId} does not exist"); + A.CallTo(() => _processStepRepository.IsValidProcess(processId, ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, A>.That.Matches(x => x.Count() == 1 && x.Single() == stepToTrigger))) + .MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task RetriggerDeleteIdpSharedServiceAccount_CallsExpected() + { + // Arrange + var stepToTrigger = ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT; + var processStepTypeId = ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT; + var processSteps = new List(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); + var processStepId = Guid.NewGuid(); + SetupFakesForRetrigger(processSteps); + var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); + A.CallTo(() => _processStepRepository.IsValidProcess(A._, A._, A>._)) + .Returns((true, verifyProcessData)); + + // Act + await _logic.RetriggerDeleteIdpSharedServiceAccount(process.Id); + + // Assert + processSteps.Should().ContainSingle().And.Satisfy(x => x.ProcessStepTypeId == processStepTypeId); + A.CallTo(() => _processStepRepository.IsValidProcess(process.Id, ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, A>.That.Matches(x => x.Count() == 1 && x.Single() == stepToTrigger))) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A? Initialize, Action Modify)>>._)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task RetriggerDeleteIdpSharedServiceAccount_WithNotExistingProcess_ThrowsException() + { + // Arrange + var stepToTrigger = ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT; + var processId = Guid.NewGuid(); + A.CallTo(() => _processStepRepository.IsValidProcess(A._, A._, A>._)) + .Returns((false, _fixture.Create())); + + Task Act() => _logic.RetriggerDeleteIdpSharedServiceAccount(processId); + + // Act + var ex = await Assert.ThrowsAsync(Act); + + // Assert + ex.Message.Should().Be($"process {processId} does not exist"); + A.CallTo(() => _processStepRepository.IsValidProcess(processId, ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, A>.That.Matches(x => x.Count() == 1 && x.Single() == stepToTrigger))) + .MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task RetriggerDeleteCentralIdentityProvider_CallsExpected() + { + // Arrange + var stepToTrigger = ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER; + var processStepTypeId = ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER; + var processSteps = new List(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); + var processStepId = Guid.NewGuid(); + SetupFakesForRetrigger(processSteps); + var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); + A.CallTo(() => _processStepRepository.IsValidProcess(A._, A._, A>._)) + .Returns((true, verifyProcessData)); + + // Act + await _logic.RetriggerDeleteCentralIdentityProvider(process.Id); + + // Assert + processSteps.Should().ContainSingle().And.Satisfy(x => x.ProcessStepTypeId == processStepTypeId); + A.CallTo(() => _processStepRepository.IsValidProcess(process.Id, ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, A>.That.Matches(x => x.Count() == 1 && x.Single() == stepToTrigger))) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A? Initialize, Action Modify)>>._)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task RetriggerDeleteCentralIdentityProvider_WithNotExistingProcess_ThrowsException() + { + // Arrange + var stepToTrigger = ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER; + var processId = Guid.NewGuid(); + A.CallTo(() => _processStepRepository.IsValidProcess(A._, A._, A>._)) + .Returns((false, _fixture.Create())); + + Task Act() => _logic.RetriggerDeleteCentralIdentityProvider(processId); + + // Act + var ex = await Assert.ThrowsAsync(Act); + + // Assert + ex.Message.Should().Be($"process {processId} does not exist"); + A.CallTo(() => _processStepRepository.IsValidProcess(processId, ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, A>.That.Matches(x => x.Count() == 1 && x.Single() == stepToTrigger))) + .MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task RetriggerDeleteCentralUser_CallsExpected() + { + // Arrange + var stepToTrigger = ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_USER; + var processStepTypeId = ProcessStepTypeId.DELETE_CENTRAL_USER; + var processSteps = new List(); + var process = _fixture.Build().With(x => x.LockExpiryDate, default(DateTimeOffset?)).Create(); + var processStepId = Guid.NewGuid(); + SetupFakesForRetrigger(processSteps); + var verifyProcessData = new VerifyProcessData(process, Enumerable.Repeat(new ProcessStep(processStepId, stepToTrigger, ProcessStepStatusId.TODO, process.Id, DateTimeOffset.UtcNow), 1)); + A.CallTo(() => _processStepRepository.IsValidProcess(A._, A._, A>._)) + .Returns((true, verifyProcessData)); + + // Act + await _logic.RetriggerDeleteCentralUser(process.Id); + + // Assert + processSteps.Should().ContainSingle().And.Satisfy(x => x.ProcessStepTypeId == processStepTypeId); + A.CallTo(() => _processStepRepository.IsValidProcess(process.Id, ProcessTypeId.USER_PROVISIONING, A>.That.Matches(x => x.Count() == 1 && x.Single() == stepToTrigger))) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _processStepRepository.AttachAndModifyProcessSteps(A? Initialize, Action Modify)>>._)) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task RetriggerDeleteCentralUser_WithNotExistingProcess_ThrowsException() + { + // Arrange + var stepToTrigger = ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_USER; + var processId = Guid.NewGuid(); + A.CallTo(() => _processStepRepository.IsValidProcess(A._, A._, A>._)) + .Returns((false, _fixture.Create())); + + Task Act() => _logic.RetriggerDeleteCentralUser(processId); + + // Act + var ex = await Assert.ThrowsAsync(Act); + + // Assert + ex.Message.Should().Be($"process {processId} does not exist"); + A.CallTo(() => _processStepRepository.IsValidProcess(processId, ProcessTypeId.USER_PROVISIONING, A>.That.Matches(x => x.Count() == 1 && x.Single() == stepToTrigger))) + .MustHaveHappenedOnceExactly(); + } + + #endregion + #region Setup private void SetupForUpdateCompanyBpn(ApplicationChecklistEntry? applicationChecklistEntry = null) @@ -1078,5 +1266,14 @@ private void SetupForDeclineRegistrationVerification(ApplicationChecklistEntry a }); } + private void SetupFakesForRetrigger(List processSteps) + { + A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) + .Invokes((IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepTypeStatus) => + { + processSteps.AddRange(processStepTypeStatus.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, DateTimeOffset.UtcNow)).ToList()); + }); + } + #endregion } diff --git a/tests/administration/Administration.Service.Tests/Controllers/RegistrationControllerTest.cs b/tests/administration/Administration.Service.Tests/Controllers/RegistrationControllerTest.cs index f45866bad0..c6b6aa75e1 100644 --- a/tests/administration/Administration.Service.Tests/Controllers/RegistrationControllerTest.cs +++ b/tests/administration/Administration.Service.Tests/Controllers/RegistrationControllerTest.cs @@ -304,4 +304,60 @@ public async Task RetriggerValidateDid_ReturnsExpectedResult() A.CallTo(() => _logic.TriggerChecklistAsync(applicationId, ApplicationChecklistEntryTypeId.IDENTITY_WALLET, ProcessStepTypeId.RETRIGGER_VALIDATE_DID_DOCUMENT)).MustHaveHappenedOnceExactly(); result.Should().BeOfType(); } + + [Fact] + public async Task RetriggerDeleteIdpSharedRealm_ReturnsExpectedResult() + { + // Arrange + var processId = _fixture.Create(); + + // Act + var result = await _controller.RetriggerDeleteIdpSharedRealm(processId); + + // Assert + A.CallTo(() => _logic.RetriggerDeleteIdpSharedRealm(processId)).MustHaveHappenedOnceExactly(); + result.Should().BeOfType(); + } + + [Fact] + public async Task RetriggerDeleteIdpSharedServiceAccount_ReturnsExpectedResult() + { + // Arrange + var processId = _fixture.Create(); + + // Act + var result = await _controller.RetriggerDeleteIdpSharedServiceAccount(processId); + + // Assert + A.CallTo(() => _logic.RetriggerDeleteIdpSharedServiceAccount(processId)).MustHaveHappenedOnceExactly(); + result.Should().BeOfType(); + } + + [Fact] + public async Task RetriggerDeleteCentralIdentityProvider_ReturnsExpectedResult() + { + // Arrange + var processId = _fixture.Create(); + + // Act + var result = await _controller.RetriggerDeleteCentralIdentityProvider(processId); + + // Assert + A.CallTo(() => _logic.RetriggerDeleteCentralIdentityProvider(processId)).MustHaveHappenedOnceExactly(); + result.Should().BeOfType(); + } + + [Fact] + public async Task RetriggerDeleteCentralUser_ReturnsExpectedResult() + { + // Arrange + var processId = _fixture.Create(); + + // Act + var result = await _controller.RetriggerDeleteCentralUser(processId); + + // Assert + A.CallTo(() => _logic.RetriggerDeleteCentralUser(processId)).MustHaveHappenedOnceExactly(); + result.Should().BeOfType(); + } } diff --git a/tests/marketplace/Offers.Library.Tests/Service/OfferServiceTests.cs b/tests/marketplace/Offers.Library.Tests/Service/OfferServiceTests.cs index b33036ca1d..6a71983f01 100644 --- a/tests/marketplace/Offers.Library.Tests/Service/OfferServiceTests.cs +++ b/tests/marketplace/Offers.Library.Tests/Service/OfferServiceTests.cs @@ -2628,19 +2628,18 @@ private void SetupRepositories() A.CallTo(() => _agreementRepository.CheckAgreementsExistsForSubscriptionAsync(A>.That.Matches(x => x.All(y => y != _existingAgreementId)), A._, A._)) .Returns(false); - var offerSubscription = _fixture.Create(); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync( A.That.Matches(x => x == _existingServiceId), _companyUserId, A.That.Matches(x => x == OfferTypeId.SERVICE))) - .Returns((_companyId, offerSubscription)); + .Returns((_companyId, true)); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync( A.That.Matches(x => x == _existingServiceId), _companyUserId, A.That.Not.Matches(x => x == OfferTypeId.SERVICE))) - .Returns<(Guid, OfferSubscription?)>((_companyId, null)); + .Returns((_companyId, false)); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync(A.That.Not.Matches(x => x == _existingServiceId), _companyUserId, A._)) - .Returns<(Guid, OfferSubscription?)>((_companyId, null)); + .Returns((_companyId, false)); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync( A.That.Matches(x => x == _existingServiceId), A.That.Not.Matches(x => x == _companyUserId), A._)) - .Returns<(Guid companyId, OfferSubscription? offerSubscription)>(default); + .Returns<(Guid, bool)>(default); var agreementData = _fixture.CreateMany(1); A.CallTo(() => _agreementRepository.GetOfferAgreementDataForOfferId(A.That.Matches(x => x == _existingServiceId), A._)) diff --git a/tests/marketplace/Offers.Library.Tests/Service/OfferSubscriptionServiceTests.cs b/tests/marketplace/Offers.Library.Tests/Service/OfferSubscriptionServiceTests.cs index 4b89e76f9f..7c93d9150d 100644 --- a/tests/marketplace/Offers.Library.Tests/Service/OfferSubscriptionServiceTests.cs +++ b/tests/marketplace/Offers.Library.Tests/Service/OfferSubscriptionServiceTests.cs @@ -570,7 +570,6 @@ private void SetupRepositories() A.CallTo(() => _offerRepository.GetOfferProviderDetailsAsync(A.That.Not.Matches(x => x == _existingOfferId || x == _existingOfferWithFailingAutoSetupId || x == _existingOfferWithoutDetailsFilled || x == _existingOfferIdWithoutProviderEmail), A._)) .Returns(null); - var offerSubscription = _fixture.Create(); A.CallTo(() => _offerSubscriptionsRepository.GetSubscriptionDetailDataForOwnUserAsync( A.That.Matches(x => x == _validSubscriptionId), A.That.Matches(x => x == _companyId), @@ -583,15 +582,15 @@ private void SetupRepositories() .Returns(null); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync( A.That.Matches(x => x == _existingOfferId), A.That.Matches(x => x == _identity.IdentityId), A._)) - .Returns((_companyId, offerSubscription)); + .Returns((_companyId, true)); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync( A.That.Not.Matches(x => x == _existingOfferId), A.That.Matches(x => x == _identity.IdentityId), A._)) - .Returns((_companyId, null)); + .Returns((_companyId, false)); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync( A.That.Matches(x => x == _existingOfferId), A.That.Not.Matches(x => x == _identity.IdentityId), A._)) - .Returns<(Guid companyId, OfferSubscription? offerSubscription)>(default); + .Returns<(Guid, bool)>(default); A.CallTo(() => _agreementRepository.GetAgreementIdsForOfferAsync(A.That.Matches(id => id == _existingOfferId || id == _existingOfferWithFailingAutoSetupId || id == _existingOfferWithoutDetailsFilled || id == _existingOfferIdWithoutProviderEmail))) .Returns(_agreementStatusDatas.ToAsyncEnumerable()); diff --git a/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs b/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs index 7fb7ab0062..783e979371 100644 --- a/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs +++ b/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs @@ -670,7 +670,6 @@ private void SetupRepositories() A.CallTo(() => _agreementRepository.CheckAgreementExistsForSubscriptionAsync(A._, A._, A.That.Not.Matches(x => x == OfferTypeId.SERVICE))) .Returns(false); - var offerSubscription = _fixture.Create(); A.CallTo(() => _offerSubscriptionsRepository.GetSubscriptionDetailDataForOwnUserAsync( _validSubscriptionId, _identity.CompanyId, @@ -683,15 +682,15 @@ private void SetupRepositories() .Returns(null); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync( _existingServiceId, _identity.IdentityId, A._)) - .Returns((_identity.CompanyId, offerSubscription)); + .Returns((_identity.CompanyId, true)); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync( A.That.Not.Matches(x => x == _existingServiceId), _identity.IdentityId, A._)) - .Returns((_identity.CompanyId, default(OfferSubscription?))); + .Returns((_identity.CompanyId, false)); A.CallTo(() => _offerSubscriptionsRepository.GetCompanyIdWithAssignedOfferForCompanyUserAndSubscriptionAsync( _existingServiceId, A.That.Not.Matches(x => x == _identity.IdentityId), A._)) - .Returns<(Guid companyId, OfferSubscription? offerSubscription)>(default); + .Returns<(Guid, bool)>(default); A.CallTo(() => _consentRepository.GetConsentDetailData(_validConsentId, OfferTypeId.SERVICE)) .Returns(new ConsentDetailData(_validConsentId, "The Company", _companyUser.Id, ConsentStatusId.ACTIVE, "Agreed")); diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs index f8db8b2c39..80ddcb379c 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs @@ -599,6 +599,69 @@ public async Task GetCompanyApplicationsDeclineData_WithSubmittedApplication_Ret #endregion + #region GetDeclineApplicationForApplicationId + + [Fact] + public async Task GetDeclineApplicationForApplicationId_ReturnsExpected() + { + // Arrange + var companyApplicationStatusIds = new[] { + CompanyApplicationStatusId.CREATED, + CompanyApplicationStatusId.ADD_COMPANY_DATA, + CompanyApplicationStatusId.INVITE_USER, + CompanyApplicationStatusId.SELECT_COMPANY_ROLE, + CompanyApplicationStatusId.UPLOAD_DOCUMENTS, + CompanyApplicationStatusId.VERIFY + }; + var sut = await CreateSut().ConfigureAwait(false); + + // Act + var result = await sut.GetDeclineApplicationDataForApplicationId(new Guid("7f31e08c-4420-4eac-beab-9540fbd55595"), new Guid("729e0af2-6723-4a7f-85a1-833d84b39bdf"), companyApplicationStatusIds).ConfigureAwait(false); + + // Assert + result.Should().Match<(bool IsValidApplicationId, bool IsValidCompany, ApplicationDeclineData? ApplicationDeclineData)>(x => + x.IsValidApplicationId && + x.IsValidCompany && + x.ApplicationDeclineData != null + ); + result.ApplicationDeclineData!.CompanyName.Should().Be("Onboarded Company"); + result.ApplicationDeclineData.CompanyUserStatusDatas.Should().ContainSingle() + .Which.Should().Match(x => + x.CompanyUserId == new Guid("8b42e6de-7b59-4217-a63c-198e83d93777") && + x.FirstName == "First" && + x.LastName == "User" && + x.Email == "test@email.com" && + x.UserStatusId == UserStatusId.ACTIVE && + x.IdentityAssignedRoleIds.SequenceEqual(new Guid[] { new("7410693c-c893-409e-852f-9ee886ce94a6") })); + } + + [Fact] + public async Task GetDeclineApplicationForApplicationId_WithInvalidCompanyId_ReturnsExpected() + { + // Arrange + var companyApplicationStatusIds = new[] { + CompanyApplicationStatusId.CREATED, + CompanyApplicationStatusId.ADD_COMPANY_DATA, + CompanyApplicationStatusId.INVITE_USER, + CompanyApplicationStatusId.SELECT_COMPANY_ROLE, + CompanyApplicationStatusId.UPLOAD_DOCUMENTS, + CompanyApplicationStatusId.VERIFY + }; + var sut = await CreateSut().ConfigureAwait(false); + + // Act + var result = await sut.GetDeclineApplicationDataForApplicationId(new Guid("7f31e08c-4420-4eac-beab-9540fbd55595"), Guid.NewGuid(), companyApplicationStatusIds).ConfigureAwait(false); + + // Assert + result.Should().Match<(bool IsValidApplicationId, bool IsValidCompany, ApplicationDeclineData? ApplicationDeclineData)>(x => + x.IsValidApplicationId && + !x.IsValidCompany && + x.ApplicationDeclineData == null + ); + } + + #endregion + private async Task<(IApplicationRepository sut, PortalDbContext context)> CreateSutWithContext() { var context = await _dbTestDbFixture.GetPortalDbContext(); diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyIdpViewTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyIdpViewTests.cs index c228ea02e0..84a10a3fc8 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyIdpViewTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyIdpViewTests.cs @@ -46,7 +46,7 @@ public async Task CompanyIdpView_GetAll_ReturnsExpected() // Act var result = await sut.CompanyIdpView.ToListAsync(); - result.Should().HaveCount(6); + result.Should().HaveCount(7); } [Fact] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/IdentityProviderRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/IdentityProviderRepositoryTests.cs index 6892b21db9..dc3dd5cecd 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/IdentityProviderRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/IdentityProviderRepositoryTests.cs @@ -17,27 +17,30 @@ * 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; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; +using System.Collections.Immutable; using Xunit.Extensions.AssemblyFixture; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Tests; public class IdentityProviderRepositoryTests : IAssemblyFixture { + private readonly IFixture _fixture; private readonly TestDbFixture _dbTestDbFixture; private readonly Guid _companyId = new("ac861325-bc54-4583-bcdc-9e9f2a38ff84"); public IdentityProviderRepositoryTests(TestDbFixture testDbFixture) { - var fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); - fixture.Behaviors.OfType().ToList() - .ForEach(b => fixture.Behaviors.Remove(b)); + _fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); + _fixture.Behaviors.OfType().ToList() + .ForEach(b => _fixture.Behaviors.Remove(b)); - fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); _dbTestDbFixture = testDbFixture; } @@ -222,8 +225,8 @@ public async Task GetCompanyIdentityProviderCategoryDataUntracked_WithValid_Retu var results = await sut.GetCompanyIdentityProviderCategoryDataUntracked(_companyId).ToListAsync(); // Assert - results.Should().HaveCount(3); - results.Should().Satisfy( + results.Should().HaveCount(3) + .And.Satisfy( x => x.Alias == "Idp-123" && x.CategoryId == IdentityProviderCategoryId.KEYCLOAK_OIDC && x.TypeId == IdentityProviderTypeId.MANAGED, x => x.Alias == "Shared-Alias" && x.CategoryId == IdentityProviderCategoryId.KEYCLOAK_OIDC && x.TypeId == IdentityProviderTypeId.SHARED, x => x.Alias == "Managed-Alias" && x.CategoryId == IdentityProviderCategoryId.KEYCLOAK_OIDC && x.TypeId == IdentityProviderTypeId.MANAGED); @@ -443,6 +446,56 @@ public async Task GetOwnIdentityProviderWithConnectedCompanies_WithMultipleValid #endregion + #region GetIdentityProviderDataForProcessId + + [Fact] + public async Task GetIdentityProviderDataForProcessIdAsync_ReturnsExpected() + { + // Arrange + var sut = await CreateSut(); + + // Act + var result = await sut.GetIdentityProviderDataForProcessIdAsync(new Guid("44927361-3766-4f07-9f18-860158880d87")); + + // Assert + result.Should().NotBeNull().And.Match(x => + x.IdentityProviderId == new Guid("38f56465-ce26-4f25-9745-1791620dc203") && + x.IdentityProviderTypeId == IdentityProviderTypeId.MANAGED && + x.IamAlias == "to-decline-alias" + ); + } + + #endregion + + #region DeleteCompanyIdentityProviderRange + + [Fact] + public async Task DeleteCompanyIdentityProviderRange_ReturnsExpected() + { + // Arrange + var ids = _fixture.CreateMany<(Guid CompanyId, Guid IdentityProviderId)>(3).ToImmutableArray(); + var (sut, context) = await CreateSutWithContext(); + + // Act + sut.DeleteCompanyIdentityProviderRange(ids); + + // Assert + var changeTracker = context.ChangeTracker; + changeTracker.HasChanges().Should().BeTrue(); + var entries = changeTracker.Entries(); + entries.Should().HaveCount(3) + .And.AllSatisfy(x => x.State.Should().Be(Microsoft.EntityFrameworkCore.EntityState.Deleted)); + entries.Select(x => x.Entity) + .Should().AllBeOfType() + .Which.Should().Satisfy( + x => x.CompanyId == ids[0].CompanyId && x.IdentityProviderId == ids[0].IdentityProviderId, + x => x.CompanyId == ids[1].CompanyId && x.IdentityProviderId == ids[1].IdentityProviderId, + x => x.CompanyId == ids[2].CompanyId && x.IdentityProviderId == ids[2].IdentityProviderId + ); + } + + #endregion + #region Setup private async Task<(IdentityProviderRepository, PortalDbContext)> CreateSutWithContext() diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/iam_identity_providers.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/iam_identity_providers.test.json index 268736d87e..fbf3e036cf 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/iam_identity_providers.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/iam_identity_providers.test.json @@ -18,5 +18,9 @@ { "iam_idp_alias": "Managed-Alias", "identity_provider_id": "38f56465-ce26-4f25-9745-1791620dc202" + }, + { + "iam_idp_alias": "to-decline-alias", + "identity_provider_id": "38f56465-ce26-4f25-9745-1791620dc203" } ] \ No newline at end of file diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_assigned_roles.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_assigned_roles.test.json index 678b849b29..67e4b02a52 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_assigned_roles.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_assigned_roles.test.json @@ -58,10 +58,15 @@ "identity_id": "8b42e6de-7b59-4217-a63c-198e83d93776", "user_role_id": "aabcdfeb-6669-4c74-89f0-19cda090873e", "last_editor_id": null - } , + }, { "identity_id": "d0c8ae19-d4f3-49cc-9cb4-6c766d4680f2", "user_role_id": "aabcdfeb-6669-4c74-89f0-19cda090873e", "last_editor_id": null + }, + { + "identity_id": "8b42e6de-7b59-4217-a63c-198e83d93777", + "user_role_id": "7410693c-c893-409e-852f-9ee886ce94a6", + "last_editor_id": null } ] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_provider_assigned_processes.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_provider_assigned_processes.test.json new file mode 100644 index 0000000000..d52a31ea88 --- /dev/null +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_provider_assigned_processes.test.json @@ -0,0 +1,6 @@ +[ + { + "identity_provider_id": "38f56465-ce26-4f25-9745-1791620dc203", + "process_id": "44927361-3766-4f07-9f18-860158880d87" + } +] \ No newline at end of file diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_providers.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_providers.test.json index c203541df0..95a869340e 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_providers.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/identity_providers.test.json @@ -33,5 +33,12 @@ "identity_provider_type_id": 2, "owner_id": "ac861325-bc54-4583-bcdc-9e9f2a38ff84", "date_created": "2022-05-05 00:00:00.000000 +00:00" + }, + { + "id": "38f56465-ce26-4f25-9745-1791620dc203", + "identity_provider_category_id": 2, + "identity_provider_type_id": 2, + "owner_id": "3390c2d7-75c1-4169-aa27-6ce00e1f3cdd", + "date_created": "2022-05-05 00:00:00.000000 +00:00" } ] \ No newline at end of file diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/processes.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/processes.test.json index 471aa120d1..b58d3ddba9 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/processes.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/processes.test.json @@ -82,5 +82,11 @@ "process_type_id" : 5, "lock_expiry_date" : "2023-03-01 00:00:00.000000 +00:00", "version" : "deadbeef-dead-beef-dead-beefdeadbeef" + }, + { + "id": "44927361-3766-4f07-9f18-860158880d87", + "process_type_id" : 7, + "lock_expiry_date" : "2023-03-01 00:00:00.000000 +00:00", + "version" : "deadbeef-dead-beef-dead-beefdeadbeef" } ] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Setup/TestDbFixture.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/Setup/TestDbFixture.cs index 6ea30d7ebe..6b77e0ea6c 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Setup/TestDbFixture.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Setup/TestDbFixture.cs @@ -76,8 +76,7 @@ public async Task GetPortalDbContext(IDateTimeProvider? dateTim /// public async Task InitializeAsync() { - await _container.StartAsync() - ; + await _container.StartAsync(); var optionsBuilder = new DbContextOptionsBuilder(); @@ -107,7 +106,6 @@ await _container.StartAsync() /// public async Task DisposeAsync() { - await _container.DisposeAsync() - ; + await _container.DisposeAsync(); } } diff --git a/tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioning.Executor.Tests.csproj b/tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioning.Executor.Tests.csproj new file mode 100644 index 0000000000..d911696651 --- /dev/null +++ b/tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioning.Executor.Tests.csproj @@ -0,0 +1,47 @@ + + + + net8.0 + enable + enable + false + Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor.Tests + Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor.Tests + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + \ No newline at end of file diff --git a/tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioningExtensionsTest.cs b/tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioningExtensionsTest.cs new file mode 100644 index 0000000000..096a4fc3de --- /dev/null +++ b/tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioningExtensionsTest.cs @@ -0,0 +1,50 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; + +namespace Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor.Tests; + +public class IdentityProviderProvisioningExtensionsTest +{ + [Theory] + [InlineData(ProcessStepTypeId.DELETE_IDP_SHARED_REALM, ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_REALM)] + [InlineData(ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT, ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT)] + [InlineData(ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER)] + public void GetRetriggerStep_WithValid_ReturnsExpected(ProcessStepTypeId processStep, ProcessStepTypeId expectedStep) + { + // Act + var result = processStep.GetIdentityProviderProvisioningRetriggerStep(); + + // Assert + result.Should().ContainSingle() + .Which.Should().Be(expectedStep); + } + + [Fact] + public void GetRetriggerStep_WithInvalidStep_ReturnsNull() + { + // Act + var ex = Assert.Throws(() => ProcessStepTypeId.START_AUTOSETUP.GetIdentityProviderProvisioningRetriggerStep()); + + // Assert + ex.Message.Should().Be("ProcessStepTypeId START_AUTOSETUP is not supported for Process IdentityProviderProvisioning"); + } +} diff --git a/tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioningProcessTypeExecutorTests.cs b/tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioningProcessTypeExecutorTests.cs new file mode 100644 index 0000000000..23b4c74432 --- /dev/null +++ b/tests/processes/IdentityProviderProvisioning.Executor.Tests/IdentityProviderProvisioningProcessTypeExecutorTests.cs @@ -0,0 +1,205 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library; + +namespace Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor.Tests; + +public class IdentityProviderProvisioningProcessTypeExecutorTests +{ + private readonly Guid _sharedProcessId = Guid.NewGuid(); + private readonly Guid _ownProcessId = Guid.NewGuid(); + private readonly IdpData _sharedIdpData; + private readonly IdpData _ownIdpData; + private readonly IPortalRepositories _portalRepositories; + private readonly IProvisioningManager _provisioningManager; + private readonly IIdentityProviderRepository _identityProviderRepository; + private readonly IFixture _fixture; + private readonly IdentityProviderProvisioningProcessTypeExecutor _executor; + + public IdentityProviderProvisioningProcessTypeExecutorTests() + { + _fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); + _fixture.Behaviors.OfType().ToList() + .ForEach(b => _fixture.Behaviors.Remove(b)); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + + _portalRepositories = A.Fake(); + _provisioningManager = A.Fake(); + _identityProviderRepository = A.Fake(); + + _sharedIdpData = new IdpData(Guid.NewGuid(), "sharedIdp", IdentityProviderTypeId.SHARED); + + _ownIdpData = new IdpData(Guid.NewGuid(), "ownIdp", IdentityProviderTypeId.OWN); + + A.CallTo(() => _portalRepositories.GetInstance()) + .Returns(_identityProviderRepository); + + _executor = new IdentityProviderProvisioningProcessTypeExecutor(_portalRepositories, _provisioningManager); + SetupFakes(); + } + + #region GetProcessTypeId + + [Fact] + public void GetProcessTypeId_ReturnsExpected() + { + // Act + var result = _executor.GetProcessTypeId(); + + // Assert + result.Should().Be(ProcessTypeId.IDENTITYPROVIDER_PROVISIONING); + } + + #endregion + + #region IsLockRequested + + [Fact] + public async Task IsLockRequested_ReturnsExpected() + { + // Act + var result = await _executor.IsLockRequested(_fixture.Create()); + + // Assert + result.Should().BeFalse(); + } + + #endregion + + #region IsExecutableStepTypeId + + [Theory] + [InlineData(ProcessStepTypeId.DELETE_IDP_SHARED_REALM, true)] + [InlineData(ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT, true)] + [InlineData(ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, true)] + [InlineData(ProcessStepTypeId.DELETE_IDENTITY_PROVIDER, true)] + [InlineData(ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_REALM, false)] + [InlineData(ProcessStepTypeId.RETRIGGER_DELETE_IDP_SHARED_SERVICEACCOUNT, false)] + [InlineData(ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_IDENTITY_PROVIDER, false)] + public void IsExecutableProcessStep_ReturnsExpected(ProcessStepTypeId processStepTypeId, bool executable) + { + // Act + var result = _executor.IsExecutableStepTypeId(processStepTypeId); + + // Assert + result.Should().Be(executable); + } + + #endregion + + #region GetExecutableStepTypeIds + + [Fact] + public void GetExecutableStepTypeIds_ReturnsExpected() + { + //Act + var result = _executor.GetExecutableStepTypeIds(); + + // Assert + result.Should().HaveCount(4) + .And.Satisfy( + x => x == ProcessStepTypeId.DELETE_IDP_SHARED_REALM, + x => x == ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT, + x => x == ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, + x => x == ProcessStepTypeId.DELETE_IDENTITY_PROVIDER); + } + + #endregion + + #region InitializeProcess + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task InitializeProcess_ValidProcessId_ReturnsExpected(bool shared) + { + // Arrange + var processId = shared ? _sharedProcessId : _ownProcessId; + + // Act + var result = await _executor.InitializeProcess(processId, _fixture.CreateMany()); + + // Assert + result.Modified.Should().BeFalse(); + result.ScheduleStepTypeIds.Should().BeNull(); + } + + #endregion + + #region ExecuteProcessStep + + [Theory] + [InlineData(true, ProcessStepTypeId.DELETE_IDP_SHARED_REALM, ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT, ProcessStepStatusId.DONE, null, false)] + [InlineData(true, ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT, ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, ProcessStepStatusId.DONE, null, false)] + [InlineData(true, ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, ProcessStepTypeId.DELETE_IDENTITY_PROVIDER, ProcessStepStatusId.DONE, null, false)] + [InlineData(true, ProcessStepTypeId.DELETE_IDENTITY_PROVIDER, null, ProcessStepStatusId.DONE, null, true)] + [InlineData(false, ProcessStepTypeId.DELETE_IDP_SHARED_REALM, ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, ProcessStepStatusId.SKIPPED, "IdentityProvider ownIdp is not a shared idp", false)] + [InlineData(false, ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT, ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, ProcessStepStatusId.SKIPPED, "IdentityProvider ownIdp is not a shared idp", false)] + [InlineData(false, ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, ProcessStepTypeId.DELETE_IDENTITY_PROVIDER, ProcessStepStatusId.DONE, null, false)] + [InlineData(false, ProcessStepTypeId.DELETE_IDENTITY_PROVIDER, null, ProcessStepStatusId.DONE, null, true)] + public async Task ExecuteProcessStep_WithValidTriggerData_CallsExpected(bool shared, ProcessStepTypeId processStepTypeId, ProcessStepTypeId? nextprocessStepTypeId, ProcessStepStatusId stepStatus, string? message, bool modified) + { + // Arrange + var processId = shared ? _sharedProcessId : _ownProcessId; + + // Act InitializeProcess + var initializeResult = await _executor.InitializeProcess(processId, Enumerable.Empty()); + + // Assert InitializeProcess + initializeResult.Modified.Should().BeFalse(); + initializeResult.ScheduleStepTypeIds.Should().BeNull(); + + // Act + var result = await _executor.ExecuteProcessStep(processStepTypeId, Enumerable.Empty(), CancellationToken.None); + + // Assert + result.Modified.Should().Be(modified); + if (nextprocessStepTypeId == null) + { + result.ScheduleStepTypeIds.Should().BeNullOrEmpty(); + } + else + { + result.ScheduleStepTypeIds.Should().ContainSingle() + .Which.Should().Be(nextprocessStepTypeId); + } + result.ProcessStepStatusId.Should().Be(stepStatus); + result.ProcessMessage.Should().Be(message); + result.SkipStepTypeIds.Should().BeNull(); + } + + #endregion + + #region SetUp + private void SetupFakes() + { + A.CallTo(() => _identityProviderRepository.GetIdentityProviderDataForProcessIdAsync(_sharedProcessId)) + .Returns(_sharedIdpData); + A.CallTo(() => _identityProviderRepository.GetIdentityProviderDataForProcessIdAsync(_ownProcessId)) + .Returns(_ownIdpData); + } + + #endregion + +} diff --git a/tests/processes/IdentityProviderProvisioning.Executor.Tests/Using.cs b/tests/processes/IdentityProviderProvisioning.Executor.Tests/Using.cs new file mode 100644 index 0000000000..14669b9c8a --- /dev/null +++ b/tests/processes/IdentityProviderProvisioning.Executor.Tests/Using.cs @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +global using AutoFixture; +global using AutoFixture.AutoFakeItEasy; +global using FakeItEasy; +global using FluentAssertions; +global using Xunit; diff --git a/tests/processes/UserProvisioning.Executor.Tests/UserProvisioning.Executor.Tests.csproj b/tests/processes/UserProvisioning.Executor.Tests/UserProvisioning.Executor.Tests.csproj new file mode 100644 index 0000000000..85c552e875 --- /dev/null +++ b/tests/processes/UserProvisioning.Executor.Tests/UserProvisioning.Executor.Tests.csproj @@ -0,0 +1,47 @@ + + + + net8.0 + enable + enable + false + Org.Eclipse.TractusX.Portal.Backend.Processes.UserProvisioning.Executor.Tests + Org.Eclipse.TractusX.Portal.Backend.Processes.UserProvisioning.Executor.Tests + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + \ No newline at end of file diff --git a/tests/processes/UserProvisioning.Executor.Tests/UserProvisioningExtensionsTest.cs b/tests/processes/UserProvisioning.Executor.Tests/UserProvisioningExtensionsTest.cs new file mode 100644 index 0000000000..defa3c9256 --- /dev/null +++ b/tests/processes/UserProvisioning.Executor.Tests/UserProvisioningExtensionsTest.cs @@ -0,0 +1,48 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; + +namespace Org.Eclipse.TractusX.Portal.Backend.Processes.UserProvisioning.Executor.Tests; + +public class UserProvisioningExtensionsTest +{ + [Theory] + [InlineData(ProcessStepTypeId.DELETE_CENTRAL_USER, ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_USER)] + public void GetRetriggerStep_WithValid_ReturnsExpected(ProcessStepTypeId processStep, ProcessStepTypeId expectedStep) + { + // Act + var result = processStep.GetUserProvisioningRetriggerStep(); + + // Assert + result.Should().ContainSingle() + .Which.Should().Be(expectedStep); + } + + [Fact] + public void GetRetriggerStep_WithInvalidStep_ReturnsNull() + { + // Act + var ex = Assert.Throws(() => ProcessStepTypeId.START_AUTOSETUP.GetUserProvisioningRetriggerStep()); + + // Assert + ex.Message.Should().Be("ProcessStepTypeId START_AUTOSETUP is not supported for Process UserProvisioning"); + } +} diff --git a/tests/processes/UserProvisioning.Executor.Tests/UserProvisioningProcessTypeExecutorTests.cs b/tests/processes/UserProvisioning.Executor.Tests/UserProvisioningProcessTypeExecutorTests.cs new file mode 100644 index 0000000000..05519bfcea --- /dev/null +++ b/tests/processes/UserProvisioning.Executor.Tests/UserProvisioningProcessTypeExecutorTests.cs @@ -0,0 +1,194 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; +using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library; + +namespace Org.Eclipse.TractusX.Portal.Backend.Processes.UserProvisioning.Executor.Tests; + +public class UserProvisioningProcessTypeExecutorTests +{ + private readonly Guid _processId = Guid.NewGuid(); + private readonly Guid _userId = Guid.NewGuid(); + private readonly IPortalRepositories _portalRepositories; + private readonly IProvisioningManager _provisioningManager; + private readonly IUserRepository _userRepository; + private readonly IFixture _fixture; + private readonly UserProvisioningProcessTypeExecutor _executor; + + public UserProvisioningProcessTypeExecutorTests() + { + _fixture = new Fixture().Customize(new AutoFakeItEasyCustomization { ConfigureMembers = true }); + _fixture.Behaviors.OfType().ToList() + .ForEach(b => _fixture.Behaviors.Remove(b)); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + + _portalRepositories = A.Fake(); + _provisioningManager = A.Fake(); + _userRepository = A.Fake(); + + A.CallTo(() => _portalRepositories.GetInstance()) + .Returns(_userRepository); + + _executor = new UserProvisioningProcessTypeExecutor(_portalRepositories, _provisioningManager); + SetupFakes(); + } + + #region GetProcessTypeId + + [Fact] + public void GetProcessTypeId_ReturnsExpected() + { + // Act + var result = _executor.GetProcessTypeId(); + + // Assert + result.Should().Be(ProcessTypeId.USER_PROVISIONING); + } + + #endregion + + #region IsLockRequested + + [Fact] + public async Task IsLockRequested_ReturnsExpected() + { + // Act + var result = await _executor.IsLockRequested(_fixture.Create()); + + // Assert + result.Should().BeFalse(); + } + + #endregion + + #region IsExecutableStepTypeId + + [Theory] + [InlineData(ProcessStepTypeId.DELETE_CENTRAL_USER, true)] + [InlineData(ProcessStepTypeId.RETRIGGER_DELETE_CENTRAL_USER, false)] + [InlineData(ProcessStepTypeId.DELETE_COMPANYUSER_ASSIGNED_PROCESS, true)] + public void IsExecutableProcessStep_ReturnsExpected(ProcessStepTypeId processStepTypeId, bool executable) + { + // Act + var result = _executor.IsExecutableStepTypeId(processStepTypeId); + + // Assert + result.Should().Be(executable); + } + + #endregion + + #region GetExecutableStepTypeIds + + [Fact] + public void GetExecutableStepTypeIds_ReturnsExpected() + { + //Act + var result = _executor.GetExecutableStepTypeIds(); + + // Assert + result.Should().HaveCount(2) + .And.Satisfy( + x => x == ProcessStepTypeId.DELETE_CENTRAL_USER, + x => x == ProcessStepTypeId.DELETE_COMPANYUSER_ASSIGNED_PROCESS); + } + + #endregion + + #region InitializeProcess + + [Fact] + public async Task InitializeProcess_ValidUserId_ReturnsExpected() + { + + // Act + var result = await _executor.InitializeProcess(_processId, _fixture.CreateMany()); + + // Assert + result.Modified.Should().BeFalse(); + result.ScheduleStepTypeIds.Should().BeNull(); + } + + #endregion + + #region DeleteCentralUser + + [Fact] + public async Task DeleteCentralUser_ReturnsExpected() + { + // Arrange + var keycloakUserId = _fixture.Create(); + A.CallTo(() => _provisioningManager.GetUserByUserName(A._)) + .Returns(keycloakUserId); + + // Act InitializeProcess + await _executor.InitializeProcess(_processId, Enumerable.Empty()); + + // Act + var result = await _executor.ExecuteProcessStep(ProcessStepTypeId.DELETE_CENTRAL_USER, Enumerable.Empty(), CancellationToken.None); + + result.ProcessStepStatusId.Should().Be(ProcessStepStatusId.DONE); + result.ScheduleStepTypeIds.Should().ContainSingle() + .Which.Should().Be(ProcessStepTypeId.DELETE_COMPANYUSER_ASSIGNED_PROCESS); + result.Modified.Should().BeFalse(); + + A.CallTo(() => _provisioningManager.GetUserByUserName(_userId.ToString())) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _provisioningManager.DeleteCentralRealmUserAsync(keycloakUserId)) + .MustHaveHappenedOnceExactly(); + } + + #endregion + + #region DeleteCompanyUserAssignedProcess + + [Fact] + public async Task DeleteCompanyUserAssignedProcess_ReturnsExpected() + { + // Act InitializeProcess + await _executor.InitializeProcess(_processId, Enumerable.Empty()); + + // Act + var result = await _executor.ExecuteProcessStep(ProcessStepTypeId.DELETE_COMPANYUSER_ASSIGNED_PROCESS, Enumerable.Empty(), CancellationToken.None); + + result.ProcessStepStatusId.Should().Be(ProcessStepStatusId.DONE); + result.ScheduleStepTypeIds.Should().BeNullOrEmpty(); + result.Modified.Should().BeTrue(); + + A.CallTo(() => _userRepository.DeleteCompanyUserAssignedProcess(_userId, _processId)) + .MustHaveHappenedOnceExactly(); + } + + #endregion + + #region SetUp + private void SetupFakes() + { + A.CallTo(() => _userRepository.GetCompanyUserIdForProcessIdAsync(A.That.Not.IsEqualTo(_processId))) + .Returns(Guid.Empty); + A.CallTo(() => _userRepository.GetCompanyUserIdForProcessIdAsync(_processId)) + .Returns(_userId); + } + + #endregion + +} diff --git a/tests/processes/UserProvisioning.Executor.Tests/Using.cs b/tests/processes/UserProvisioning.Executor.Tests/Using.cs new file mode 100644 index 0000000000..14669b9c8a --- /dev/null +++ b/tests/processes/UserProvisioning.Executor.Tests/Using.cs @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +global using AutoFixture; +global using AutoFixture.AutoFakeItEasy; +global using FakeItEasy; +global using FluentAssertions; +global using Xunit; diff --git a/tests/provisioning/Provisioning.Library.Tests/ProvisioningManagerTests.cs b/tests/provisioning/Provisioning.Library.Tests/ProvisioningManagerTests.cs index ff27baf43e..02e84d3fae 100644 --- a/tests/provisioning/Provisioning.Library.Tests/ProvisioningManagerTests.cs +++ b/tests/provisioning/Provisioning.Library.Tests/ProvisioningManagerTests.cs @@ -110,7 +110,7 @@ public async Task SetupClientAsync_CallsExpected() .WithGetClientSecretAsync(newClientId, new Credentials { Value = "super-secret" }); // Act - await _sut.SetupClientAsync($"{url}/*", url, new[] { "adminRole" }); + await _sut.SetupClientAsync($"{url}/*", url, ["adminRole"]); // Assert httpTest.ShouldHaveCalled($"{CentralUrl}/admin/realms/test/clients/{newClientId}/protocol-mappers/models") @@ -129,7 +129,7 @@ public async Task UpdateSharedIdentityProviderAsync_CallsExpected() using var httpTest = new HttpTest(); httpTest.WithAuthorization() .WithGetIdentityProviderAsync(ValidClientName, new IdentityProvider.IdentityProvider { Alias = "Test", DisplayName = "test", Config = new Keycloak.Library.Models.RealmsAdmin.Config() }) - .WithGetClientsAsync("master", new[] { new Client { Id = id, ClientId = "savalid" } }) + .WithGetClientsAsync("master", [new Client { Id = id, ClientId = "savalid" }]) .WithGetClientSecretAsync(id, new Credentials { Value = "super-secret" }) .WithGetRealmAsync(ValidClientName, new Realm { DisplayName = "test", LoginTheme = "test" }); @@ -153,7 +153,7 @@ public async Task UpdateSharedRealmTheme_CallsExpected() using var httpTest = new HttpTest(); httpTest.WithAuthorization() .WithGetIdentityProviderAsync(ValidClientName, new IdentityProvider.IdentityProvider { Alias = "Test", DisplayName = "test", Config = new Keycloak.Library.Models.RealmsAdmin.Config() }) - .WithGetClientsAsync("master", new[] { new Client { Id = id, ClientId = "savalid" } }) + .WithGetClientsAsync("master", [new Client { Id = id, ClientId = "savalid" }]) .WithGetClientSecretAsync(id, new Credentials { Value = "super-secret" }) .WithGetRealmAsync(ValidClientName, new Realm { DisplayName = "test", LoginTheme = "test" }); @@ -182,4 +182,55 @@ public async Task GetIdentityProviderDisplayName_CallsExpected() displayName.Should().NotBeNullOrWhiteSpace(); displayName.Should().Be("test"); } + + #region DeleteSharedRealm + + [Fact] + public async Task DeleteSharedRealmAsync_ReturnsExpected() + { + // Arrange + const string alias = "idp123"; + const string id = "123"; + using var httpTest = new HttpTest(); + httpTest.WithAuthorization() + .WithGetIdentityProviderAsync(ValidClientName, new IdentityProvider.IdentityProvider { Alias = "Test", DisplayName = "test", Config = new Keycloak.Library.Models.RealmsAdmin.Config() }) + .WithGetClientsAsync("master", [new Client { Id = id, ClientId = "saidp123" }]) + .WithGetClientSecretAsync(id, new Credentials { Value = "super-secret" }) + .WithGetRealmAsync(ValidClientName, new Realm { DisplayName = "test", LoginTheme = "test" }); + // Act + await _sut.DeleteSharedRealmAsync(alias); + + //Assert + httpTest.ShouldHaveCalled($"{SharedUrl}/admin/realms/{alias}") + .WithVerb(HttpMethod.Delete) + .Times(1); + } + + #endregion + + #region DeleteIdpSharedServiceAccount + + [Fact] + public async Task DeleteIdpSharedServiceAccount_ReturnsExpected() + { + // Arrange + const string alias = "idp123"; + const string id = "123"; + using var httpTest = new HttpTest(); + httpTest.WithAuthorization() + .WithGetIdentityProviderAsync(ValidClientName, new IdentityProvider.IdentityProvider { Alias = "Test", DisplayName = "test", Config = new Keycloak.Library.Models.RealmsAdmin.Config() }) + .WithGetClientsAsync("master", [new Client { Id = id, ClientId = "saidp123" }]) + .WithGetClientSecretAsync(id, new Credentials { Value = "super-secret" }) + .WithGetRealmAsync(ValidClientName, new Realm { DisplayName = "test", LoginTheme = "test" }); + // Act + await _sut.DeleteIdpSharedServiceAccount(alias); + + //Assert + httpTest.ShouldHaveCalled($"{SharedUrl}/admin/realms/master/clients/{id}") + .WithVerb(HttpMethod.Delete) + .Times(1); + } + + #endregion + } diff --git a/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs b/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs index 9abfda48fc..166b663bb5 100644 --- a/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs +++ b/tests/registration/Registration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs @@ -67,6 +67,7 @@ public class RegistrationBusinessLogicTest private readonly IMailingProcessCreation _mailingProcessCreation; private readonly IConsentRepository _consentRepository; private readonly IProcessStepRepository _processStepRepository; + private readonly IIdentityProviderRepository _identityProviderRepository; private readonly IApplicationChecklistCreationService _checklistService; private readonly IIdentityData _identity; private readonly Guid _existingApplicationId; @@ -104,6 +105,7 @@ public RegistrationBusinessLogicTest() _checklistService = A.Fake(); _staticDataRepository = A.Fake(); _processStepRepository = A.Fake(); + _identityProviderRepository = A.Fake(); _dateTimeProvider = A.Fake(); _identityService = A.Fake(); @@ -146,6 +148,11 @@ public RegistrationBusinessLogicTest() public async Task GetClientRolesCompositeAsync_GetsAllRoles() { //Arrange + var roles = _fixture.CreateMany(3).ToImmutableArray(); + + A.CallTo(() => _portalRepositories.GetInstance().GetClientRolesCompositeAsync(A._)) + .Returns(roles.ToAsyncEnumerable()); + var sut = new RegistrationBusinessLogic( _options, null!, @@ -158,13 +165,12 @@ public async Task GetClientRolesCompositeAsync_GetsAllRoles() _mailingProcessCreation); // Act - var result = sut.GetClientRolesCompositeAsync(); - await foreach (var item in result) - { - // Assert - A.CallTo(() => _userRoleRepository.GetClientRolesCompositeAsync(A._)).MustHaveHappenedOnceExactly(); - Assert.NotNull(item); - } + var result = await sut.GetClientRolesCompositeAsync().ToListAsync(); + + // Assert + A.CallTo(() => _userRoleRepository.GetClientRolesCompositeAsync("CatenaX")).MustHaveHappenedOnceExactly(); + result.Should().HaveSameCount(roles) + .And.ContainInOrder(roles); } #endregion @@ -282,9 +288,7 @@ public async Task GetCompanyBpdmDetailDataByBusinessPartnerNumber_WithValidBpn_T _mailingProcessCreation); // Act - async Task Act() => - await sut.GetCompanyBpdmDetailDataByBusinessPartnerNumber("NotLongEnough", "justatoken", - CancellationToken.None); + Task Act() => sut.GetCompanyBpdmDetailDataByBusinessPartnerNumber("NotLongEnough", "justatoken", CancellationToken.None); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -322,8 +326,7 @@ public async Task GetAllApplicationsForUserWithStatus_WithValidUser_GetsAllRoles _fixture.Create(), CompanyApplicationStatusId.VERIFY, CompanyApplicationTypeId.INTERNAL, - new[] - { + [ new ApplicationChecklistData(ApplicationChecklistEntryTypeId.APPLICATION_ACTIVATION, ApplicationChecklistEntryStatusId.DONE), new ApplicationChecklistData(ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER, @@ -336,7 +339,7 @@ public async Task GetAllApplicationsForUserWithStatus_WithValidUser_GetsAllRoles ApplicationChecklistEntryStatusId.FAILED), new ApplicationChecklistData(ApplicationChecklistEntryTypeId.SELF_DESCRIPTION_LP, ApplicationChecklistEntryStatusId.TO_DO) - }) + ]) }; A.CallTo(() => _userRepository.GetApplicationsWithStatusUntrackedAsync(userCompanyId)) .Returns(resultList.ToAsyncEnumerable()); @@ -418,7 +421,7 @@ public async Task GetCompanyWithAddressAsync_WithInvalidApplication_ThrowsNotFou .Returns(null); // Act - async Task Act() => await sut.GetCompanyDetailData(applicationId); + Task Act() => sut.GetCompanyDetailData(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -447,7 +450,7 @@ public async Task GetCompanyWithAddressAsync_WithInvalidUser_ThrowsForbiddenExce .Returns(_fixture.Build().With(x => x.IsUserOfCompany, false).Create()); // Act - async Task Act() => await sut.GetCompanyDetailData(applicationId); + Task Act() => sut.GetCompanyDetailData(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -497,7 +500,7 @@ public async Task SetCompanyWithAddressAsync_WithMissingData_ThrowsArgumentExcep null, null, null, null, uniqueIdData); // Act - async Task Act() => await sut.SetCompanyDetailDataAsync(Guid.NewGuid(), companyData); + Task Act() => sut.SetCompanyDetailDataAsync(Guid.NewGuid(), companyData); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -528,7 +531,7 @@ public async Task SetCompanyWithAddressAsync_WithInvalidApplicationId_ThrowsNotF .Returns(null); // Act - async Task Act() => await sut.SetCompanyDetailDataAsync(applicationId, companyData); + Task Act() => sut.SetCompanyDetailDataAsync(applicationId, companyData); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -564,7 +567,7 @@ public async Task SetCompanyWithAddressAsync_WithoutCompanyUserId_ThrowsForbidde .Returns(_fixture.Build().With(x => x.IsUserOfCompany, false).Create()); // Act - async Task Act() => await sut.SetCompanyDetailDataAsync(applicationId, companyData); + Task Act() => sut.SetCompanyDetailDataAsync(applicationId, companyData); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -600,7 +603,7 @@ public async Task SetCompanyWithAddressAsync__WithInvalidBpn_ThrowsControllerArg _mailingProcessCreation); // Act - async Task Act() => await sut.SetCompanyDetailDataAsync(applicationId, companyData); + Task Act() => sut.SetCompanyDetailDataAsync(applicationId, companyData); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -950,16 +953,16 @@ public async Task SetCompanyWithAddressAsync_WithUniqueIdentifiers_CreateModifyD .With(x => x.BusinessPartnerNumber, default(string?)) .With(x => x.CompanyId, companyId) .With(x => x.CountryAlpha2Code, _alpha2code) - .With(x => x.UniqueIds, new[] { firstIdData, secondIdData, thirdIdData }) + .With(x => x.UniqueIds, [firstIdData, secondIdData, thirdIdData]) .Create(); var existingData = _fixture.Build() - .With(x => x.UniqueIds, new[] - { + .With(x => x.UniqueIds, + [ (firstIdData.UniqueIdentifierId, firstIdData.Value), // shall be left unmodified (secondIdData.UniqueIdentifierId, _fixture.Create()), // shall be modified - (uniqueIdentifiers.ElementAt(3), _fixture.Create()) - }) // shall be deleted + (uniqueIdentifiers.ElementAt(3), _fixture.Create()) // shall be deleted + ]) .With(x => x.IsUserOfCompany, true) .Create(); var application = _fixture.Build() @@ -1054,7 +1057,7 @@ public async Task SetCompanyWithAddressAsync_WithInvalidCountryCode_Throws() .Returns((false, null!)); // Act - var Act = () => sut.SetCompanyDetailDataAsync(Guid.NewGuid(), companyData); + Task Act() => sut.SetCompanyDetailDataAsync(Guid.NewGuid(), companyData); //Assert var result = await Assert.ThrowsAsync(Act); @@ -1096,7 +1099,7 @@ public async Task SetCompanyWithAddressAsync_WithInvalidUniqueIdentifiers_Throws .Returns((true, new[] { identifiers.First() })); // Act - var Act = () => sut.SetCompanyDetailDataAsync(Guid.NewGuid(), companyData); + Task Act() => sut.SetCompanyDetailDataAsync(Guid.NewGuid(), companyData); //Assert var result = await Assert.ThrowsAsync(Act); @@ -1130,7 +1133,7 @@ public async Task SetOwnCompanyApplicationStatusAsync_WithInvalidStatus_ThrowsCo _mailingProcessCreation); // Act - async Task Act() => await sut.SetOwnCompanyApplicationStatusAsync(applicationId, 0); + Task Act() => sut.SetOwnCompanyApplicationStatusAsync(applicationId, 0); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -1162,9 +1165,7 @@ public async Task SetOwnCompanyApplicationStatusAsync_WithInvalidApplication_Thr .Returns<(bool, CompanyApplicationStatusId)>(default); // Act - async Task Act() => - await sut.SetOwnCompanyApplicationStatusAsync(applicationId, CompanyApplicationStatusId.VERIFY) - ; + Task Act() => sut.SetOwnCompanyApplicationStatusAsync(applicationId, CompanyApplicationStatusId.VERIFY); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -1198,7 +1199,7 @@ public async Task SetOwnCompanyApplicationStatusAsync_WithInvalidStatus_ThrowsAr var status = CompanyApplicationStatusId.VERIFY; // Act - async Task Act() => await sut.SetOwnCompanyApplicationStatusAsync(applicationId, status); + Task Act() => sut.SetOwnCompanyApplicationStatusAsync(applicationId, status); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -1328,10 +1329,10 @@ public async Task GetInvitedUsersDetail_ThrowException_WhenIdIsNull() var sut = _fixture.Create(); //Act - async Task Action() => await sut.GetInvitedUsersAsync(Guid.Empty).ToListAsync(); + async Task Act() => await sut.GetInvitedUsersAsync(Guid.Empty).ToListAsync(); // Assert - await Assert.ThrowsAsync(Action); + await Assert.ThrowsAsync(Act); } #endregion @@ -1351,10 +1352,10 @@ public async Task UploadDocumentAsync_WithValidData_CreatesDocument() .Create(); var settings = new RegistrationSettings { - DocumentTypeIds = new[]{ + DocumentTypeIds = [ DocumentTypeId.CX_FRAME_CONTRACT, DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _dateTimeProvider.OffsetNow).Returns(now); A.CallTo(() => _documentRepository.CreateDocument(A._, A._, A._, A._, A._, A?>._)) @@ -1398,10 +1399,10 @@ public async Task UploadDocumentAsync_WithJsonDocument_ThrowsException() var sut = _fixture.Create(); // Act - async Task Action() => await sut.UploadDocumentAsync(_existingApplicationId, file, DocumentTypeId.ADDITIONAL_DETAILS, CancellationToken.None); + Task Act() => sut.UploadDocumentAsync(_existingApplicationId, file, DocumentTypeId.ADDITIONAL_DETAILS, CancellationToken.None); // Assert - var ex = await Assert.ThrowsAsync(Action); + var ex = await Assert.ThrowsAsync(Act); ex.Message.Should().Be("Only .pdf files are allowed."); } @@ -1413,10 +1414,10 @@ public async Task UploadDocumentAsync_WithEmptyTitle_ThrowsException() var sut = _fixture.Create(); // Act - async Task Action() => await sut.UploadDocumentAsync(_existingApplicationId, file, DocumentTypeId.ADDITIONAL_DETAILS, CancellationToken.None); + Task Act() => sut.UploadDocumentAsync(_existingApplicationId, file, DocumentTypeId.ADDITIONAL_DETAILS, CancellationToken.None); // Assert - var ex = await Assert.ThrowsAsync(Action); + var ex = await Assert.ThrowsAsync(Act); ex.Message.Should().Be("File name is must not be null"); } @@ -1427,10 +1428,10 @@ public async Task UploadDocumentAsync_WithNotExistingApplicationId_ThrowsExcepti var file = FormFileHelper.GetFormFile("this is just a test", "superFile.pdf", "application/pdf"); var settings = new RegistrationSettings { - DocumentTypeIds = new[]{ + DocumentTypeIds = [ DocumentTypeId.CX_FRAME_CONTRACT, DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; var sut = new RegistrationBusinessLogic( Options.Create(settings), @@ -1445,10 +1446,10 @@ public async Task UploadDocumentAsync_WithNotExistingApplicationId_ThrowsExcepti var notExistingId = Guid.NewGuid(); // Act - async Task Action() => await sut.UploadDocumentAsync(notExistingId, file, DocumentTypeId.CX_FRAME_CONTRACT, CancellationToken.None); + Task Act() => sut.UploadDocumentAsync(notExistingId, file, DocumentTypeId.CX_FRAME_CONTRACT, CancellationToken.None); // Assert - var ex = await Assert.ThrowsAsync(Action); + var ex = await Assert.ThrowsAsync(Act); ex.Message.Should().Be($"The users company is not assigned with application {notExistingId}"); } @@ -1459,10 +1460,10 @@ public async Task UploadDocumentAsync_WithNotExistingIamUser_ThrowsException() var file = FormFileHelper.GetFormFile("this is just a test", "superFile.pdf", "application/pdf"); var settings = new RegistrationSettings { - DocumentTypeIds = new[]{ + DocumentTypeIds = [ DocumentTypeId.CX_FRAME_CONTRACT, DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _portalRepositories.GetInstance().IsValidApplicationForCompany(A._, A._)) .Returns(false); @@ -1479,10 +1480,10 @@ public async Task UploadDocumentAsync_WithNotExistingIamUser_ThrowsException() _mailingProcessCreation); // Act - async Task Action() => await sut.UploadDocumentAsync(_existingApplicationId, file, DocumentTypeId.CX_FRAME_CONTRACT, CancellationToken.None); + Task Act() => sut.UploadDocumentAsync(_existingApplicationId, file, DocumentTypeId.CX_FRAME_CONTRACT, CancellationToken.None); // Assert - var ex = await Assert.ThrowsAsync(Action); + var ex = await Assert.ThrowsAsync(Act); ex.Message.Should().Be($"The users company is not assigned with application {_existingApplicationId}"); A.CallTo(() => _portalRepositories.GetInstance().IsValidApplicationForCompany(_existingApplicationId, _identity.CompanyId)) .MustHaveHappenedOnceExactly(); @@ -1495,10 +1496,10 @@ public async Task UploadDocumentAsync_WithInvalidDocumentTypeId_ThrowsException( var file = FormFileHelper.GetFormFile("this is just a test", "superFile.pdf", "application/pdf"); var settings = new RegistrationSettings { - DocumentTypeIds = new[]{ + DocumentTypeIds = [ DocumentTypeId.CX_FRAME_CONTRACT, DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; var sut = new RegistrationBusinessLogic( Options.Create(settings), @@ -1510,11 +1511,12 @@ public async Task UploadDocumentAsync_WithInvalidDocumentTypeId_ThrowsException( _identityService, _dateTimeProvider, _mailingProcessCreation); + // Act - async Task Action() => await sut.UploadDocumentAsync(_existingApplicationId, file, DocumentTypeId.ADDITIONAL_DETAILS, CancellationToken.None); + Task Act() => sut.UploadDocumentAsync(_existingApplicationId, file, DocumentTypeId.ADDITIONAL_DETAILS, CancellationToken.None); // Assert - var ex = await Assert.ThrowsAsync(Action); + var ex = await Assert.ThrowsAsync(Act); ex.Message.Should().Be($"documentType must be either: {string.Join(",", settings.DocumentTypeIds)}"); } @@ -1771,8 +1773,7 @@ public async Task SubmitRoleConsentsAsync_WithNotExistingApplication_ThrowsNotFo var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRoleConsentAsync(notExistingId, _fixture.Create()) - ; + Task Act() => sut.SubmitRoleConsentAsync(notExistingId, _fixture.Create()); // Arrange var ex = await Assert.ThrowsAsync(Act); @@ -1791,8 +1792,7 @@ public async Task SubmitRoleConsentsAsync_WithWrongCompanyUser_ThrowsForbiddenEx var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRoleConsentAsync(applicationId, _fixture.Create()) - ; + Task Act() => sut.SubmitRoleConsentAsync(applicationId, _fixture.Create()); // Arrange var ex = await Assert.ThrowsAsync(Act); @@ -1806,11 +1806,11 @@ public async Task SubmitRoleConsentsAsync_WithInvalidRoles_ThrowsControllerArgum var applicationId = _fixture.Create(); var applicationStatusId = _fixture.Create(); var data = new CompanyRoleAgreementConsentData(_identity.CompanyId, applicationStatusId, _fixture.CreateMany(2), _fixture.CreateMany(5)); - var roleIds = new List + var roleIds = new CompanyRoleId[] { CompanyRoleId.APP_PROVIDER, }; - var companyRoleAssignedAgreements = new List<(CompanyRoleId CompanyRoleId, IEnumerable AgreementIds)> + var companyRoleAssignedAgreements = new[] { (CompanyRoleId.APP_PROVIDER, _fixture.CreateMany(5)), }; @@ -1821,8 +1821,7 @@ public async Task SubmitRoleConsentsAsync_WithInvalidRoles_ThrowsControllerArgum var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRoleConsentAsync(applicationId, _fixture.Create()) - ; + Task Act() => sut.SubmitRoleConsentAsync(applicationId, _fixture.Create()); // Arrange var ex = await Assert.ThrowsAsync(Act); @@ -1835,18 +1834,17 @@ public async Task SubmitRoleConsentsAsync_WithoutAllRolesConsentGiven_ThrowsCont // Arrange var agreementIds1 = new Guid("0a283850-5a73-4940-9215-e713d0e1c419"); var agreementIds2 = new Guid("e38da3a1-36f9-4002-9447-c55a38ac2a53"); - var consents = new CompanyRoleAgreementConsents(new[] - { + var consents = new CompanyRoleAgreementConsents( + [ CompanyRoleId.APP_PROVIDER, - }, - new AgreementConsentStatus[] - { + ], + [ new(agreementIds1, ConsentStatusId.ACTIVE), new(agreementIds2, ConsentStatusId.INACTIVE) - }); + ]); var applicationId = _fixture.Create(); var applicationStatusId = _fixture.Create(); - var data = new CompanyRoleAgreementConsentData(_identity.CompanyId, applicationStatusId, new[] { CompanyRoleId.APP_PROVIDER }, new List()); + var data = new CompanyRoleAgreementConsentData(_identity.CompanyId, applicationStatusId, [CompanyRoleId.APP_PROVIDER], []); var companyRoleAssignedAgreements = new (CompanyRoleId CompanyRoleId, IEnumerable AgreementIds)[] { (CompanyRoleId.APP_PROVIDER, new AgreementStatusData[]{ new(agreementIds1, AgreementStatusId.ACTIVE), new(agreementIds2, AgreementStatusId.ACTIVE) }) @@ -1859,8 +1857,7 @@ public async Task SubmitRoleConsentsAsync_WithoutAllRolesConsentGiven_ThrowsCont var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRoleConsentAsync(applicationId, consents) - ; + Task Act() => sut.SubmitRoleConsentAsync(applicationId, consents); // Arrange var ex = await Assert.ThrowsAsync(Act); @@ -1880,16 +1877,15 @@ public async Task SubmitRoleConsentsAsync_WithValidData_CallsExpected() IEnumerable? removedCompanyRoleIds = null; // Arrange - var consents = new CompanyRoleAgreementConsents(new[] - { + var consents = new CompanyRoleAgreementConsents( + [ CompanyRoleId.APP_PROVIDER, CompanyRoleId.ACTIVE_PARTICIPANT - }, - new[] - { + ], + [ new AgreementConsentStatus(agreementId_1, ConsentStatusId.ACTIVE), new AgreementConsentStatus(agreementId_2, ConsentStatusId.ACTIVE) - }); + ]); var applicationId = _fixture.Create(); var applicationStatusId = CompanyApplicationStatusId.INVITE_USER; var application = _fixture.Build() @@ -1899,14 +1895,13 @@ public async Task SubmitRoleConsentsAsync_WithValidData_CallsExpected() var data = new CompanyRoleAgreementConsentData( _identity.CompanyId, applicationStatusId, - new[] - { + [ CompanyRoleId.APP_PROVIDER, CompanyRoleId.SERVICE_PROVIDER, - }, - new[] { + ], + [ new ConsentData(consentId, ConsentStatusId.INACTIVE, agreementId_1) - }); + ]); var companyRoleAssignedAgreements = new (CompanyRoleId CompanyRoleId, IEnumerable AgreementIds)[] { (CompanyRoleId.APP_PROVIDER, @@ -1969,20 +1964,19 @@ public async Task SubmitRoleConsentsAsync_WithextraAgreement_ThrowsControllerArg var agreementIds1 = new Guid("e38da3a1-36f9-4002-9447-c55a38ac2a53"); var agreementIds2 = new Guid("0a283850-5a73-4940-9215-e713d0e1c419"); var agreementIds3 = new Guid("e38da3a1-36f9-4002-9447-c55a38ac2a54"); - var consents = new CompanyRoleAgreementConsents(new[] - { + var consents = new CompanyRoleAgreementConsents( + [ CompanyRoleId.APP_PROVIDER, - }, - new[] - { + ], + [ new AgreementConsentStatus(agreementIds1, ConsentStatusId.ACTIVE), new AgreementConsentStatus(agreementIds2, ConsentStatusId.ACTIVE), new AgreementConsentStatus(agreementIds3, ConsentStatusId.ACTIVE) - }); + ]); var applicationId = _fixture.Create(); var applicationStatusId = _fixture.Create(); - var data = new CompanyRoleAgreementConsentData(_identity.CompanyId, applicationStatusId, new[] { CompanyRoleId.APP_PROVIDER }, new List()); + var data = new CompanyRoleAgreementConsentData(_identity.CompanyId, applicationStatusId, [CompanyRoleId.APP_PROVIDER], []); var companyRoleAssignedAgreements = new (CompanyRoleId CompanyRoleId, IEnumerable AgreementIds)[] { (CompanyRoleId.APP_PROVIDER, @@ -1998,8 +1992,7 @@ public async Task SubmitRoleConsentsAsync_WithextraAgreement_ThrowsControllerArg var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRoleConsentAsync(applicationId, consents) - ; + Task Act() => sut.SubmitRoleConsentAsync(applicationId, consents); // Arrange var ex = await Assert.ThrowsAsync(Act); @@ -2017,17 +2010,16 @@ public async Task SubmitRegistrationAsync_WithNotExistingApplication_ThrowsNotFo var notExistingId = _fixture.Create(); var settings = new RegistrationSettings { - SubmitDocumentTypeIds = new[]{ + SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) .Returns(null); var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(notExistingId) - ; + Task Act() => sut.SubmitRegistrationAsync(notExistingId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2050,7 +2042,7 @@ public async Task SubmitRegistrationAsync_WithDocumentId_Success() var stepTypeIds = _fixture.CreateMany(3).ToImmutableArray(); var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; @@ -2110,9 +2102,9 @@ public async Task SubmitRegistrationAsync_WithDocumentId_Success() }); var settings = new RegistrationSettings { - SubmitDocumentTypeIds = new[]{ + SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, _checklistService, _identityService, _dateTimeProvider, _mailingProcessCreation); @@ -2192,15 +2184,15 @@ public async Task SubmitRegistrationAsync_InvalidStatus_ThrowsForbiddenException new(Guid.NewGuid(),DocumentStatusId.PENDING), new(Guid.NewGuid(),DocumentStatusId.INACTIVE) }; - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; var settings = new RegistrationSettings { - SubmitDocumentTypeIds = new[]{ + SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) @@ -2208,8 +2200,7 @@ public async Task SubmitRegistrationAsync_InvalidStatus_ThrowsForbiddenException var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2238,24 +2229,23 @@ public async Task SubmitRegistrationAsync_AlreadyClosed_ThrowsForbiddenException new(Guid.NewGuid(),DocumentStatusId.PENDING), new(Guid.NewGuid(),DocumentStatusId.INACTIVE) }; - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); var settings = new RegistrationSettings { - SubmitDocumentTypeIds = new[]{ + SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) .Returns(new CompanyApplicationUserEmailData(statusId, true, _fixture.Create(), documents, companyData, agreementConsents)); var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2277,24 +2267,23 @@ public async Task SubmitRegistrationAsync_WithNotExistingCompanyUser_ThrowsForbi var applicationId = _fixture.Create(); var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); var settings = new RegistrationSettings { - SubmitDocumentTypeIds = new[]{ + SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(A._, A._, A>._)) .Returns(new CompanyApplicationUserEmailData(CompanyApplicationStatusId.VERIFY, false, null, null!, companyData, agreementConsents)); var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2316,24 +2305,23 @@ public async Task SubmitRegistrationAsync_WithNotExistingStreetName_ThrowsConfli var applicationId = _fixture.Create(); var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; var companyData = new CompanyData("Test Company", Guid.NewGuid(), string.Empty, "Munich", "Germany", uniqueIds, companyRoleIds); var settings = new RegistrationSettings { - SubmitDocumentTypeIds = new[]{ + SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _applicationRepository.GetOwnCompanyApplicationUserEmailDataAsync(applicationId, userId, A>._)) .Returns(new CompanyApplicationUserEmailData(CompanyApplicationStatusId.VERIFY, true, _fixture.Create(), Enumerable.Empty(), companyData, agreementConsents)); var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2353,7 +2341,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingAddressId_ThrowsConflic var applicationId = _fixture.Create(); var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; @@ -2363,8 +2351,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingAddressId_ThrowsConflic var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2384,7 +2371,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingCompanyName_ThrowsConfl var applicationId = _fixture.Create(); var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; @@ -2394,8 +2381,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingCompanyName_ThrowsConfl var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2414,7 +2400,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingUniqueId_ThrowsConflict A.CallTo(() => _identityService.IdentityData).Returns(identityData); var applicationId = _fixture.Create(); var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; @@ -2425,8 +2411,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingUniqueId_ThrowsConflict var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2445,7 +2430,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingCompanyRoleId_ThrowsCon A.CallTo(() => _identityService.IdentityData).Returns(identityData); var applicationId = _fixture.Create(); var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; @@ -2456,8 +2441,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingCompanyRoleId_ThrowsCon var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2484,8 +2468,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingAgreementandConsent_Thr var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2505,7 +2488,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingCity_ThrowsConflictExce var applicationId = _fixture.Create(); var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; @@ -2515,8 +2498,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingCity_ThrowsConflictExce var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2536,7 +2518,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingCountry_ThrowsConflictE var applicationId = _fixture.Create(); var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; @@ -2547,8 +2529,7 @@ public async Task SubmitRegistrationAsync_WithNotExistingCountry_ThrowsConflictE var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.SubmitRegistrationAsync(applicationId) - ; + Task Act() => sut.SubmitRegistrationAsync(applicationId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2563,20 +2544,20 @@ public async Task SubmitRegistrationAsync_WithUserEmail_SendsMail() var now = DateTimeOffset.Now; var uniqueIds = _fixture.CreateMany(3).ToImmutableArray(); var companyRoleIds = _fixture.CreateMany(3).ToImmutableArray(); - var agreementConsents = new (Guid AgreementId, ConsentStatusId ConsentStatusId)[] + var agreementConsents = new[] { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; - IEnumerable documents = new DocumentStatusData[]{ + IEnumerable documents = [ new( - Guid.NewGuid(),DocumentStatusId.INACTIVE - )}; + Guid.NewGuid(), DocumentStatusId.INACTIVE + )]; var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); var settings = new RegistrationSettings { - SubmitDocumentTypeIds = new[]{ + SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; var application = _fixture.Build() .With(x => x.Id, applicationId) @@ -2617,16 +2598,16 @@ public async Task SubmitRegistrationAsync_WithoutUserEmail_DoesntSendMail() { (Guid.NewGuid(), ConsentStatusId.ACTIVE), }; - IEnumerable documents = new DocumentStatusData[]{ + IEnumerable documents = [ new( - Guid.NewGuid(),DocumentStatusId.PENDING - )}; + Guid.NewGuid(), DocumentStatusId.PENDING + )]; var companyData = new CompanyData("Test Company", Guid.NewGuid(), "Strabe Street", "Munich", "Germany", uniqueIds, companyRoleIds); var settings = new RegistrationSettings { - SubmitDocumentTypeIds = new[]{ + SubmitDocumentTypeIds = [ DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; var application = _fixture.Build() .With(x => x.Id, applicationId) @@ -2713,7 +2694,7 @@ public async Task GetCompanyIdentifiers_InvalidCountry_Throws() var countryCode = _fixture.Create(); // Act - var Act = () => sut.GetCompanyIdentifiers(countryCode); + Task Act() => sut.GetCompanyIdentifiers(countryCode); // Assert var result = await Assert.ThrowsAsync(Act); @@ -2780,7 +2761,7 @@ public async Task GetRegistrationDataAsync_WithInvalidApplicationId_Throws() var sut = new RegistrationBusinessLogic(_options, null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - var Act = () => sut.GetRegistrationDataAsync(applicationId); + Task Act() => sut.GetRegistrationDataAsync(applicationId); // Assert var result = await Assert.ThrowsAsync(Act); @@ -2799,7 +2780,7 @@ public async Task GetRegistrationDataAsync_WithInvalidUser_Throws() var sut = new RegistrationBusinessLogic(_options, null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - var Act = () => sut.GetRegistrationDataAsync(applicationId); + Task Act() => sut.GetRegistrationDataAsync(applicationId); // Assert var result = await Assert.ThrowsAsync(Act); @@ -2818,7 +2799,7 @@ public async Task GetRegistrationDataAsync_WithNullData_Throws() var sut = new RegistrationBusinessLogic(_options, null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - var Act = () => sut.GetRegistrationDataAsync(applicationId); + Task Act() => sut.GetRegistrationDataAsync(applicationId); // Assert var result = await Assert.ThrowsAsync(Act); @@ -2857,7 +2838,7 @@ public async Task GetRegistrationDocumentAsync_WithInvalidDocumentTypeId_ThrowsN var sut = new RegistrationBusinessLogic(_options, null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); //Act - var Act = () => sut.GetRegistrationDocumentAsync(documentId); + Task Act() => sut.GetRegistrationDocumentAsync(documentId); // Assert var result = await Assert.ThrowsAsync(Act); @@ -2874,7 +2855,7 @@ public async Task GetRegistrationDocumentAsync_WithInvalidDocumentId_ThrowsNotFo var sut = new RegistrationBusinessLogic(_options, null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); //Act - var Act = () => sut.GetRegistrationDocumentAsync(documentId); + Task Act() => sut.GetRegistrationDocumentAsync(documentId); // Assert var result = await Assert.ThrowsAsync(Act); @@ -2914,7 +2895,7 @@ public async Task GetDocumentAsync_WithoutDocument_ThrowsNotFoundException() var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.GetDocumentContentAsync(documentId); + Task Act() => sut.GetDocumentContentAsync(documentId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2931,7 +2912,7 @@ public async Task GetDocumentAsync_WithWrongUser_ThrowsForbiddenException() var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - async Task Act() => await sut.GetDocumentContentAsync(documentId); + Task Act() => sut.GetDocumentContentAsync(documentId); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -2987,7 +2968,7 @@ public async Task SetInvitationStatusAsync_Throws_ForbiddenException() var sut = new RegistrationBusinessLogic(_options, null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); //Act - var Act = sut.SetInvitationStatusAsync; + Task Act() => sut.SetInvitationStatusAsync(); // Assert var result = await Assert.ThrowsAsync(Act); @@ -3011,15 +2992,15 @@ public async Task DeleteRegistrationDocumentAsync_ReturnsExpected() var modifiedApplication = new List<(CompanyApplication Initial, CompanyApplication Modified)>(); var settings = new RegistrationSettings { - ApplicationStatusIds = new[]{ + ApplicationStatusIds = [ CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.DECLINED - }, - DocumentTypeIds = new[]{ + ], + DocumentTypeIds = [ DocumentTypeId.CX_FRAME_CONTRACT, DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _dateTimeProvider.OffsetNow).Returns(now); @@ -3063,15 +3044,15 @@ public async Task DeleteRegistrationDocumentAsync_DocumentTypeId_ConflictExcepti var applicationId = _fixture.CreateMany(); var settings = new RegistrationSettings { - ApplicationStatusIds = new[]{ + ApplicationStatusIds = [ CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.DECLINED - }, - DocumentTypeIds = new[]{ + ], + DocumentTypeIds = [ DocumentTypeId.CX_FRAME_CONTRACT, DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _documentRepository.GetDocumentDetailsForApplicationUntrackedAsync(documentId, _identity.CompanyId, settings.ApplicationStatusIds)) .Returns((documentId, DocumentStatusId.PENDING, true, DocumentTypeId.CONFORMITY_APPROVAL_BUSINESS_APPS, false, applicationId)); @@ -3079,7 +3060,7 @@ public async Task DeleteRegistrationDocumentAsync_DocumentTypeId_ConflictExcepti var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - var Act = async () => await sut.DeleteRegistrationDocumentAsync(documentId); + Task Act() => sut.DeleteRegistrationDocumentAsync(documentId); // Assert var result = await Assert.ThrowsAsync(Act); @@ -3096,7 +3077,7 @@ public async Task DeleteRegistrationDocumentAsync_Throws_NotFoundException() var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - var Act = async () => await sut.DeleteRegistrationDocumentAsync(_fixture.Create()); + Task Act() => sut.DeleteRegistrationDocumentAsync(_fixture.Create()); // Assert var result = await Assert.ThrowsAsync(Act); @@ -3111,15 +3092,15 @@ public async Task DeleteRegistrationDocumentAsync_Throws_ConflictException() var applicationId = _fixture.CreateMany(); var settings = new RegistrationSettings { - ApplicationStatusIds = new[]{ + ApplicationStatusIds = [ CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.DECLINED - }, - DocumentTypeIds = new[]{ + ], + DocumentTypeIds = [ DocumentTypeId.CX_FRAME_CONTRACT, DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _documentRepository.GetDocumentDetailsForApplicationUntrackedAsync(A._, _identity.CompanyId, A>._)) .Returns((documentId, DocumentStatusId.PENDING, true, DocumentTypeId.CX_FRAME_CONTRACT, true, applicationId)); @@ -3127,7 +3108,7 @@ public async Task DeleteRegistrationDocumentAsync_Throws_ConflictException() var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - var Act = async () => await sut.DeleteRegistrationDocumentAsync(documentId); + Task Act() => sut.DeleteRegistrationDocumentAsync(documentId); // Assert var result = await Assert.ThrowsAsync(Act); @@ -3142,15 +3123,15 @@ public async Task DeleteRegistrationDocumentAsync_Throws_ForbiddenException() var applicationId = _fixture.CreateMany(); var settings = new RegistrationSettings { - ApplicationStatusIds = new[]{ + ApplicationStatusIds = [ CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.DECLINED - }, - DocumentTypeIds = new[]{ + ], + DocumentTypeIds = [ DocumentTypeId.CX_FRAME_CONTRACT, DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _documentRepository.GetDocumentDetailsForApplicationUntrackedAsync(A._, _identity.CompanyId, A>._)) .Returns((documentId, DocumentStatusId.PENDING, false, DocumentTypeId.CX_FRAME_CONTRACT, false, applicationId)); @@ -3158,7 +3139,7 @@ public async Task DeleteRegistrationDocumentAsync_Throws_ForbiddenException() var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - var Act = async () => await sut.DeleteRegistrationDocumentAsync(documentId); + Task Act() => sut.DeleteRegistrationDocumentAsync(documentId); // Assert var result = await Assert.ThrowsAsync(Act); @@ -3173,15 +3154,15 @@ public async Task DeleteRegistrationDocumentAsync_DocumentStatusId_Throws_Confli var applicationId = _fixture.CreateMany(); var settings = new RegistrationSettings { - ApplicationStatusIds = new[]{ + ApplicationStatusIds = [ CompanyApplicationStatusId.CONFIRMED, CompanyApplicationStatusId.SUBMITTED, CompanyApplicationStatusId.DECLINED - }, - DocumentTypeIds = new[]{ + ], + DocumentTypeIds = [ DocumentTypeId.CX_FRAME_CONTRACT, DocumentTypeId.COMMERCIAL_REGISTER_EXTRACT - } + ] }; A.CallTo(() => _documentRepository.GetDocumentDetailsForApplicationUntrackedAsync(A._, _identity.CompanyId, A>._)) .Returns((documentId, DocumentStatusId.LOCKED, true, DocumentTypeId.CX_FRAME_CONTRACT, false, applicationId)); @@ -3189,7 +3170,7 @@ public async Task DeleteRegistrationDocumentAsync_DocumentStatusId_Throws_Confli var sut = new RegistrationBusinessLogic(Options.Create(settings), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - var Act = async () => await sut.DeleteRegistrationDocumentAsync(documentId); + Task Act() => sut.DeleteRegistrationDocumentAsync(documentId); // Assert var result = await Assert.ThrowsAsync(Act); @@ -3203,7 +3184,7 @@ public async Task DeleteRegistrationDocumentAsync_Throws_ControllerArgumentExcep var sut = new RegistrationBusinessLogic(Options.Create(new RegistrationSettings()), null!, null!, null!, _portalRepositories, null!, _identityService, _dateTimeProvider, _mailingProcessCreation); // Act - var Act = async () => await sut.DeleteRegistrationDocumentAsync(default); + Task Act() => sut.DeleteRegistrationDocumentAsync(default); // Assert var result = await Assert.ThrowsAsync(Act); @@ -3269,6 +3250,10 @@ private void SetupRepositories() .Returns(_staticDataRepository); A.CallTo(() => _portalRepositories.GetInstance()) .Returns(_processStepRepository); + A.CallTo(() => _portalRepositories.GetInstance()) + .Returns(_identityProviderRepository); + A.CallTo(() => _portalRepositories.GetInstance()) + .Returns(_userRoleRepository); } private void SetupFakesForInvitation() @@ -3300,7 +3285,7 @@ private void SetupFakesForInvitation() #region GetApplicationsDeclineData [Fact] - public async Task Foo() + public async Task GetApplicationsDeclineData_CallsExpected() { // Arrange var applicationId = Guid.NewGuid(); @@ -3316,7 +3301,7 @@ public async Task Foo() var options = Options.Create(new RegistrationSettings { - ApplicationDeclineStatusIds = new[] { CompanyApplicationStatusId.CREATED } + ApplicationDeclineStatusIds = [CompanyApplicationStatusId.CREATED] }); var sut = new RegistrationBusinessLogic(options, null!, null!, null!, _portalRepositories, null!, _identityService, null!, _mailingProcessCreation); @@ -3332,9 +3317,326 @@ public async Task Foo() x.ApplicationId == applicationId && x.ApplicationStatus == CompanyApplicationStatusId.CREATED && x.CompanyName == "Acme Corp" && - x.User == "Tony, Stark (t.stark@acme.corp)"); + x.User == "Tony, Stark (t.stark@acme.corp)" && + x.Users.SequenceEqual(new[] { "Test, User (t.user@acme.corp)", "foo@bar.org" })); + } + + #endregion + + #region DeclineApplicationRegistration + + [Fact] + public async Task DeclineApplicationRegistrationAsync_CallsExpected() + { + // Arrange + var applicationId = Guid.NewGuid(); + var idpStatusData = new IdentityProviderStatusData[] { + new(Guid.NewGuid(), IdentityProviderTypeId.SHARED), + new(Guid.NewGuid(), IdentityProviderTypeId.OWN), + new(Guid.NewGuid(), IdentityProviderTypeId.MANAGED), + }; + var invitationStatusData = new InvitationsStatusData[] { + new(Guid.NewGuid(), InvitationStatusId.ACCEPTED), + new(Guid.NewGuid(), InvitationStatusId.CREATED), + new(Guid.NewGuid(), InvitationStatusId.PENDING), + }; + var identityStatusData = new CompanyUserStatusData[] { + new(Guid.NewGuid(), null, null, "email1", UserStatusId.ACTIVE, _fixture.CreateMany(3).ToImmutableArray()), + new(Guid.NewGuid(), "First", "Last", "email2", UserStatusId.INACTIVE, _fixture.CreateMany(3).ToImmutableArray()), + new(Guid.NewGuid(), "Other", null, "email3", UserStatusId.PENDING, _fixture.CreateMany(3).ToImmutableArray()) + }; + var documentStatusData = new DocumentStatusData[] { + new(Guid.NewGuid(), DocumentStatusId.PENDING), + new(Guid.NewGuid(), DocumentStatusId.LOCKED) + }; + var applicationDeclineData = new ApplicationDeclineData( + idpStatusData, + "TestCompany", + CompanyApplicationStatusId.CREATED, + invitationStatusData, + identityStatusData, + documentStatusData + ); + var options = Options.Create(new RegistrationSettings + { + ApplicationDeclineStatusIds = [CompanyApplicationStatusId.CREATED] + }); + + A.CallTo(() => _applicationRepository.GetDeclineApplicationDataForApplicationId(A._, A._, A>._)) + .Returns((true, true, applicationDeclineData)); + + CompanyApplication? application = null; + A.CallTo(() => _applicationRepository.AttachAndModifyCompanyApplication(applicationId, A>._)) + .Invokes((Guid _, Action setOptionalFields) => + { + application = new(applicationId, Guid.Empty, default, default, default); + setOptionalFields.Invoke(application); + }); + + Company? company = null; + A.CallTo(() => _companyRepository.AttachAndModifyCompany(A._, A>._, A>._)) + .Invokes((Guid companyId, Action? initialize, Action modify) => + { + company = new Company(companyId, null!, default, default); + initialize?.Invoke(company); + modify(company); + }); + + var modifiedInvitationsBuilder = ImmutableArray.CreateBuilder<(Invitation Initial, Invitation Modified)>(); + A.CallTo(() => _invitationRepository.AttachAndModifyInvitations(A?, Action)>>._)) + .Invokes((IEnumerable<(Guid InvitationId, Action? Initialize, Action Modify)> invitationKeyActions) => + { + foreach (var x in invitationKeyActions) + { + var initial = new Invitation(x.InvitationId, Guid.Empty, Guid.Empty, default, default); + x.Initialize?.Invoke(initial); + var modified = new Invitation(x.InvitationId, Guid.Empty, Guid.Empty, default, default); + x.Modify(modified); + modifiedInvitationsBuilder.Add((initial, modified)); + } + }); + + var modifiedDocumentsBuilder = ImmutableArray.CreateBuilder<(Document Initial, Document Modified)>(); + A.CallTo(() => _documentRepository.AttachAndModifyDocuments(A?, Action)>>._)) + .Invokes((IEnumerable<(Guid DocumentId, Action? Initialize, Action Modify)> documentKeyActions) => + { + foreach (var x in documentKeyActions) + { + var initial = new Document(x.DocumentId, null!, null!, null!, default, default, default, default); + x.Initialize?.Invoke(initial); + var modified = new Document(x.DocumentId, null!, null!, null!, default, default, default, default); + x.Modify(modified); + modifiedDocumentsBuilder.Add((initial, modified)); + } + }); + + var createdProcessesBuilder = ImmutableArray.CreateBuilder(); + A.CallTo(() => _processStepRepository.CreateProcessRange(A>._)) + .ReturnsLazily((IEnumerable processTypeIds) => + { + var processes = processTypeIds.Select(x => new Process(Guid.NewGuid(), x, Guid.NewGuid())).ToImmutableArray(); + createdProcessesBuilder.AddRange(processes); + return processes; + }); + + A.CallTo(() => _processStepRepository.CreateProcessStepRange(A>._)) + .ReturnsLazily((IEnumerable<(ProcessStepTypeId ProcessStepTypeId, ProcessStepStatusId ProcessStepStatusId, Guid ProcessId)> processStepStatusTypeIds) => + processStepStatusTypeIds.Select(x => new ProcessStep(Guid.NewGuid(), x.ProcessStepTypeId, x.ProcessStepStatusId, x.ProcessId, DateTimeOffset.UtcNow)).ToImmutableArray()); - result.First().Users.Should().ContainInOrder(new[] { "Test, User (t.user@acme.corp)", "foo@bar.org" }); + var modifiedIdentitiesBuilder = ImmutableArray.CreateBuilder<(Identity Initial, Identity Modified)>(); + A.CallTo(() => _userRepository.AttachAndModifyIdentities(A?, Action)>>._)) + .Invokes((IEnumerable<(Guid IdentityId, Action? Initialize, Action Modify)> identityKeyActions) => + { + foreach (var x in identityKeyActions) + { + var initial = new Identity(x.IdentityId, default, Guid.Empty, default, default); + x.Initialize?.Invoke(initial); + var modified = new Identity(x.IdentityId, default, Guid.Empty, default, default); + x.Modify(modified); + modifiedIdentitiesBuilder.Add((initial, modified)); + } + }); + + var sut = new RegistrationBusinessLogic(options, null!, null!, null!, _portalRepositories, null!, _identityService, null!, _mailingProcessCreation); + + // Act + await sut.DeclineApplicationRegistrationAsync(applicationId); + + var modifiedInvitations = modifiedInvitationsBuilder.ToImmutable(); + var modifiedDocuments = modifiedDocumentsBuilder.ToImmutable(); + var createdProcesses = createdProcessesBuilder.ToImmutable(); + var modifiedIdentities = modifiedIdentitiesBuilder.ToImmutable(); + + // Assert + + A.CallTo(() => _applicationRepository + .GetDeclineApplicationDataForApplicationId(applicationId, _identity.CompanyId, A>.That.IsSameSequenceAs(new[] + { + CompanyApplicationStatusId.CREATED + }))) + .MustHaveHappenedOnceExactly(); + + // DeclineApplication + + A.CallTo(() => _applicationRepository.AttachAndModifyCompanyApplication(applicationId, A>._)) + .MustHaveHappenedOnceExactly(); + application.Should().NotBeNull(); + application!.ApplicationStatusId.Should().Be(CompanyApplicationStatusId.DECLINED); + + // DeleteCompany + + A.CallTo(() => _companyRepository.AttachAndModifyCompany(_identity.CompanyId, A>._, A>._)) + .MustHaveHappenedOnceExactly(); + company.Should().NotBeNull().And.Match(x => + x.Id == _identity.CompanyId && + x.CompanyStatusId == CompanyStatusId.DELETED + ); + + // DeclineInvitations + + A.CallTo(() => _invitationRepository + .AttachAndModifyInvitations(A?, Action)>>.That.Matches(x => x.Select(y => y.InvitationId).SequenceEqual(new Guid[] + { + invitationStatusData[0].InvitationId, + invitationStatusData[1].InvitationId, + invitationStatusData[2].InvitationId + })))) + .MustHaveHappenedOnceExactly(); + + modifiedInvitations.Should().HaveCount(3) + .And.AllSatisfy(x => x.Modified.InvitationStatusId.Should().Be(InvitationStatusId.DECLINED)) + .And.Satisfy( + x => x.Initial.Id == invitationStatusData[0].InvitationId && x.Initial.InvitationStatusId == invitationStatusData[0].InvitationStatusId, + x => x.Initial.Id == invitationStatusData[1].InvitationId && x.Initial.InvitationStatusId == invitationStatusData[1].InvitationStatusId, + x => x.Initial.Id == invitationStatusData[2].InvitationId && x.Initial.InvitationStatusId == invitationStatusData[2].InvitationStatusId + ); + + // DeactivateDocuments + + _ = A.CallTo(() => _documentRepository + .AttachAndModifyDocuments(A?, Action)>>.That.Matches(x => x.Select(y => y.DocumentId).SequenceEqual(new Guid[] + { + documentStatusData[0].DocumentId, + documentStatusData[1].DocumentId, + })))) + .MustHaveHappenedOnceExactly(); + + modifiedDocuments.Should().HaveCount(2) + .And.AllSatisfy(x => x.Modified.DocumentStatusId.Should().Be(DocumentStatusId.INACTIVE)) + .And.Satisfy( + x => x.Initial.Id == documentStatusData[0].DocumentId && x.Initial.DocumentStatusId == documentStatusData[0].StatusId, + x => x.Initial.Id == documentStatusData[1].DocumentId && x.Initial.DocumentStatusId == documentStatusData[1].StatusId + ); + + // ScheduleDeleteIdentityProviders + + A.CallTo(() => _identityProviderRepository + .DeleteCompanyIdentityProviderRange(A>.That.IsSameSequenceAs(new (Guid, Guid)[] + { + new(_identity.CompanyId, idpStatusData[2].IdentityProviderId) + }))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _processStepRepository + .CreateProcessRange(A>.That.IsSameSequenceAs(Enumerable.Repeat(ProcessTypeId.IDENTITYPROVIDER_PROVISIONING, 2)))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _processStepRepository + .CreateProcessStepRange(A>.That.IsSameSequenceAs(new (ProcessStepTypeId, ProcessStepStatusId, Guid)[] + { + new(ProcessStepTypeId.DELETE_IDP_SHARED_REALM, ProcessStepStatusId.TODO, createdProcesses[0].Id), + new(ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER, ProcessStepStatusId.TODO, createdProcesses[1].Id) + }))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _identityProviderRepository + .CreateIdentityProviderAssignedProcessRange(A>.That.IsSameSequenceAs(new (Guid, Guid)[] + { + new(idpStatusData[0].IdentityProviderId, createdProcesses[0].Id), + new(idpStatusData[1].IdentityProviderId, createdProcesses[1].Id) + }))) + .MustHaveHappenedOnceExactly(); + + // ScheduleDeleteCompanyUsers + + A.CallTo(() => _userRepository.AttachAndModifyIdentities(A?, Action)>>.That.Matches(x => x.Select(y => y.IdentityId).SequenceEqual(new Guid[] + { + identityStatusData[0].CompanyUserId, + identityStatusData[1].CompanyUserId, + identityStatusData[2].CompanyUserId, + })))) + .MustHaveHappenedOnceExactly(); + + modifiedIdentities.Should().HaveCount(3) + .And.AllSatisfy(x => x.Modified.UserStatusId.Should().Be(UserStatusId.DELETED)) + .And.Satisfy( + x => x.Initial.Id == identityStatusData[0].CompanyUserId, + x => x.Initial.Id == identityStatusData[1].CompanyUserId, + x => x.Initial.Id == identityStatusData[2].CompanyUserId + ); + + A.CallTo(() => _userRoleRepository.DeleteCompanyUserAssignedRoles(A>.That.IsSameSequenceAs(new (Guid, Guid)[] + { + new (identityStatusData[0].CompanyUserId, identityStatusData[0].IdentityAssignedRoleIds.ElementAt(0)), + new (identityStatusData[0].CompanyUserId, identityStatusData[0].IdentityAssignedRoleIds.ElementAt(1)), + new (identityStatusData[0].CompanyUserId, identityStatusData[0].IdentityAssignedRoleIds.ElementAt(2)), + new (identityStatusData[1].CompanyUserId, identityStatusData[1].IdentityAssignedRoleIds.ElementAt(0)), + new (identityStatusData[1].CompanyUserId, identityStatusData[1].IdentityAssignedRoleIds.ElementAt(1)), + new (identityStatusData[1].CompanyUserId, identityStatusData[1].IdentityAssignedRoleIds.ElementAt(2)), + new (identityStatusData[2].CompanyUserId, identityStatusData[2].IdentityAssignedRoleIds.ElementAt(0)), + new (identityStatusData[2].CompanyUserId, identityStatusData[2].IdentityAssignedRoleIds.ElementAt(1)), + new (identityStatusData[2].CompanyUserId, identityStatusData[2].IdentityAssignedRoleIds.ElementAt(2)), + }))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _processStepRepository + .CreateProcessRange(A>.That.IsSameSequenceAs(Enumerable.Repeat(ProcessTypeId.USER_PROVISIONING, 3)))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _processStepRepository + .CreateProcessStepRange(A>.That.IsSameSequenceAs(new (ProcessStepTypeId, ProcessStepStatusId, Guid)[] + { + new(ProcessStepTypeId.DELETE_CENTRAL_USER, ProcessStepStatusId.TODO, createdProcesses[2].Id), + new(ProcessStepTypeId.DELETE_CENTRAL_USER, ProcessStepStatusId.TODO, createdProcesses[3].Id), + new(ProcessStepTypeId.DELETE_CENTRAL_USER, ProcessStepStatusId.TODO, createdProcesses[4].Id) + }))) + .MustHaveHappenedOnceExactly(); + + A.CallTo(() => _userRepository.CreateCompanyUserAssignedProcessRange(A>.That.IsSameSequenceAs(new (Guid, Guid)[] + { + new(identityStatusData[0].CompanyUserId, createdProcesses[2].Id), + new(identityStatusData[1].CompanyUserId, createdProcesses[3].Id), + new(identityStatusData[2].CompanyUserId, createdProcesses[4].Id), + }))) + .MustHaveHappenedOnceExactly(); + + // CreateDeclineApplicationEmailProcesses + + A.CallTo(() => _mailingProcessCreation.CreateMailProcess("email1", "EmailRegistrationDeclineTemplate", A>.That.Matches(x => x.OrderBy(y => y.Key).SequenceEqual(new KeyValuePair[] + { + KeyValuePair.Create("companyName", "TestCompany"), + KeyValuePair.Create("userName", "email1") + })))) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess("email2", "EmailRegistrationDeclineTemplate", A>.That.Matches(x => x.OrderBy(y => y.Key).SequenceEqual(new KeyValuePair[] + { + KeyValuePair.Create("companyName", "TestCompany"), + KeyValuePair.Create("userName", "First Last") + })))) + .MustHaveHappenedOnceExactly(); + A.CallTo(() => _mailingProcessCreation.CreateMailProcess("email3", "EmailRegistrationDeclineTemplate", A>.That.Matches(x => x.OrderBy(y => y.Key).SequenceEqual(new KeyValuePair[] + { + KeyValuePair.Create("companyName", "TestCompany"), + KeyValuePair.Create("userName", "Other") + })))) + .MustHaveHappenedOnceExactly(); + + // final save + + A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task DeclineApplicationRegistrationAsync_ThrowsNotFoundException_ReturnsExpected() + { + // Arrange + var applicationId = _fixture.Create(); + var options = Options.Create(new RegistrationSettings + { + ApplicationDeclineStatusIds = [CompanyApplicationStatusId.CREATED] + }); + + A.CallTo(() => _applicationRepository.GetDeclineApplicationDataForApplicationId(A._, A._, A>._)) + .Returns<(bool, bool, ApplicationDeclineData?)>(default); + + var sut = new RegistrationBusinessLogic(options, null!, null!, null!, _portalRepositories, null!, _identityService, null!, _mailingProcessCreation); + + // Act + Task Act() => sut.DeclineApplicationRegistrationAsync(applicationId); + + // Assert + var result = await Assert.ThrowsAsync(Act); + result.Message.Should().Be($"Application {applicationId} does not exits"); } #endregion diff --git a/tests/registration/Registration.Service.Tests/Controller/RegistrationControllerTest.cs b/tests/registration/Registration.Service.Tests/Controller/RegistrationControllerTest.cs index d29c7d33c6..4a43133816 100644 --- a/tests/registration/Registration.Service.Tests/Controller/RegistrationControllerTest.cs +++ b/tests/registration/Registration.Service.Tests/Controller/RegistrationControllerTest.cs @@ -192,4 +192,18 @@ public async Task GetApplicationsWithStatusAsync_WithValidData_ReturnsExpected() A.CallTo(() => _registrationBusinessLogicFake.GetAllApplicationsForUserWithStatus()).MustHaveHappenedOnceExactly(); result.Should().HaveCount(2); } + + [Fact] + public async Task DeclineApplicationRegistrationAsync_ReturnsExpectedCalls() + { + // Arrange + var applicationId = _fixture.Create(); + + // Act + var result = await _controller.DeclineApplicationRegistrationAsync(applicationId); + + // Assert + A.CallTo(() => _registrationBusinessLogicFake.DeclineApplicationRegistrationAsync(applicationId)).MustHaveHappenedOnceExactly(); + result.Should().BeOfType(); + } } From bbe8dabac40a11078d1b231f0249f65b8980d1f8 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Thu, 23 May 2024 18:11:51 +0200 Subject: [PATCH 17/24] fix(serviceaccount): fix conflict errors for inactive and pending serviceaccoutns (#769) --- .../ServiceAccountBusinessLogic.cs | 26 ++--- .../ServiceAccountConnectorOfferData.cs | 4 +- .../Repositories/ServiceAccountRepository.cs | 96 ++++++++++--------- .../ServiceAccountBusinessLogicTests.cs | 7 +- 4 files changed, 73 insertions(+), 60 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs index 174ad1080d..16ce75b829 100644 --- a/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs @@ -147,19 +147,24 @@ public async Task GetOwnCompanyServiceAccountD { var companyId = _identityData.CompanyId; var result = await portalRepositories.GetInstance().GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(serviceAccountId, companyId); + if (result == null) { - throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_CONFLICT, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]); + throw NotFoundException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_CONFLICT, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]); } - if (result.ClientClientId == null) + IamClientAuthMethod? iamClientAuthMethod; + string? secret; + + if (result.DimServiceAccountData != null) { - throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_UNDEFINED_CLIENTID_CONFLICT, [new("serviceAccountId", serviceAccountId.ToString())]); + iamClientAuthMethod = IamClientAuthMethod.SECRET; + secret = Decrypt( + result.DimServiceAccountData.ClientSecret, + result.DimServiceAccountData.InitializationVector, + result.DimServiceAccountData.EncryptionMode); } - - IamClientAuthMethod iamClientAuthMethod; - string? secret; - if (result.DimServiceAccountData == null) + else if (result.ClientClientId != null) { var internalClientId = await provisioningManager.GetIdOfCentralClientAsync(result.ClientClientId).ConfigureAwait(ConfigureAwaitOptions.None); var authData = await provisioningManager.GetCentralClientAuthDataAsync(internalClientId).ConfigureAwait(ConfigureAwaitOptions.None); @@ -168,11 +173,8 @@ public async Task GetOwnCompanyServiceAccountD } else { - iamClientAuthMethod = IamClientAuthMethod.SECRET; - secret = Decrypt( - result.DimServiceAccountData.ClientSecret, - result.DimServiceAccountData.InitializationVector, - result.DimServiceAccountData.EncryptionMode); + iamClientAuthMethod = null; + secret = null; } return new ServiceAccountConnectorOfferData( diff --git a/src/administration/Administration.Service/Models/ServiceAccountConnectorOfferData.cs b/src/administration/Administration.Service/Models/ServiceAccountConnectorOfferData.cs index ed8e4224da..ac2e4a0ca4 100644 --- a/src/administration/Administration.Service/Models/ServiceAccountConnectorOfferData.cs +++ b/src/administration/Administration.Service/Models/ServiceAccountConnectorOfferData.cs @@ -27,10 +27,10 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; public record ServiceAccountConnectorOfferData( [property: JsonPropertyName("serviceAccountId")] Guid ServiceAccountId, - [property: JsonPropertyName("clientId")] string ClientId, + [property: JsonPropertyName("clientId")] string? ClientId, [property: JsonPropertyName("name")] string Name, [property: JsonPropertyName("description")] string Description, - [property: JsonPropertyName("authenticationType")] IamClientAuthMethod IamClientAuthMethod, + [property: JsonPropertyName("authenticationType")] IamClientAuthMethod? IamClientAuthMethod, [property: JsonPropertyName("roles")] IEnumerable UserRoleDatas, [property: JsonPropertyName("companyServiceAccountTypeId")] CompanyServiceAccountTypeId CompanyServiceAccountTypeId, [property: JsonPropertyName("status")] UserStatusId UserStatusId, diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs index 2f10d7d662..d5fd0ecffb 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ServiceAccountRepository.cs @@ -114,49 +114,59 @@ public void AttachAndModifyCompanyServiceAccount( public Task GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(Guid serviceAccountId, Guid companyId) => _dbContext.CompanyServiceAccounts .AsNoTracking() - .Where(serviceAccount => - serviceAccount.Id == serviceAccountId && - serviceAccount.Identity!.UserStatusId != UserStatusId.DELETED && - (serviceAccount.CompaniesLinkedServiceAccount!.Owners == companyId || serviceAccount.CompaniesLinkedServiceAccount!.Provider == companyId)) - .Select(serviceAccount => new CompanyServiceAccountDetailedData( - serviceAccount.Id, - serviceAccount.ClientClientId, - serviceAccount.Name, - serviceAccount.Description, - serviceAccount.Identity!.UserStatusId, - serviceAccount.Identity.IdentityAssignedRoles - .Select(assignedRole => assignedRole.UserRole) - .Select(userRole => new UserRoleData( - userRole!.Id, - userRole.Offer!.AppInstances.First().IamClient!.ClientClientId, - userRole.UserRoleText)), - serviceAccount.CompanyServiceAccountTypeId, - serviceAccount.OfferSubscriptionId, - serviceAccount.Connector == null - ? null - : new ConnectorResponseData( - serviceAccount.Connector.Id, - serviceAccount.Connector.Name), - serviceAccount!.OfferSubscription == null - ? null - : new OfferResponseData( - serviceAccount.OfferSubscription.OfferId, - serviceAccount.OfferSubscription.Offer!.OfferTypeId, - serviceAccount.OfferSubscription.Offer.Name, - serviceAccount.OfferSubscription.Id), - serviceAccount.Identity.LastEditorId == null - ? null - : new CompanyLastEditorData( - serviceAccount.Identity.LastEditor!.IdentityTypeId == IdentityTypeId.COMPANY_USER - ? serviceAccount.Identity.LastEditor.CompanyUser!.Lastname - : serviceAccount.Identity.LastEditor.CompanyServiceAccount!.Name, - serviceAccount.Identity.LastEditor.Company!.Name), - serviceAccount.DimCompanyServiceAccount == null - ? null - : new DimServiceAccountData( - serviceAccount.DimCompanyServiceAccount.ClientSecret, - serviceAccount.DimCompanyServiceAccount.InitializationVector, - serviceAccount.DimCompanyServiceAccount.EncryptionMode))) + .Select(serviceAccount => new + { + ServiceAccount = serviceAccount, + serviceAccount.Identity, + serviceAccount.Connector, + serviceAccount.OfferSubscription, + serviceAccount.Identity!.LastEditor, + serviceAccount.DimCompanyServiceAccount, + serviceAccount.CompaniesLinkedServiceAccount + }) + .Where(x => + x.ServiceAccount.Id == serviceAccountId && + x.Identity!.UserStatusId != UserStatusId.DELETED && + (x.CompaniesLinkedServiceAccount!.Owners == companyId || x.CompaniesLinkedServiceAccount!.Provider == companyId)) + .Select(x => new CompanyServiceAccountDetailedData( + x.ServiceAccount.Id, + x.ServiceAccount.ClientClientId, + x.ServiceAccount.Name, + x.ServiceAccount.Description, + x.Identity!.UserStatusId, + x.Identity.IdentityAssignedRoles + .Select(assignedRole => assignedRole.UserRole) + .Select(userRole => new UserRoleData( + userRole!.Id, + userRole.Offer!.AppInstances.First().IamClient!.ClientClientId, + userRole.UserRoleText)), + x.ServiceAccount.CompanyServiceAccountTypeId, + x.ServiceAccount.OfferSubscriptionId, + x.Connector == null + ? null + : new ConnectorResponseData( + x.Connector.Id, + x.Connector.Name), + x.OfferSubscription == null + ? null + : new OfferResponseData( + x.OfferSubscription.OfferId, + x.OfferSubscription.Offer!.OfferTypeId, + x.OfferSubscription.Offer.Name, + x.OfferSubscription.Id), + x.Identity.LastEditorId == null + ? null + : new CompanyLastEditorData( + x.LastEditor!.IdentityTypeId == IdentityTypeId.COMPANY_USER + ? x.LastEditor.CompanyUser!.Lastname + : x.LastEditor.CompanyServiceAccount!.Name, + x.LastEditor.Company!.Name), + x.ServiceAccount.DimCompanyServiceAccount == null + ? null + : new DimServiceAccountData( + x.DimCompanyServiceAccount!.ClientSecret, + x.DimCompanyServiceAccount.InitializationVector, + x.DimCompanyServiceAccount.EncryptionMode))) .SingleOrDefaultAsync(); public Func?>> GetOwnCompanyServiceAccountsUntracked(Guid userCompanyId, string? clientId, bool? isOwner, IEnumerable userStatusIds) => diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs index 2b99abbd23..de5e63a53e 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs @@ -237,7 +237,7 @@ public async Task GetOwnCompanyServiceAccountDetailsAsync_WithValidInputAndDimCo } [Fact] - public async Task GetOwnCompanyServiceAccountDetailsAsync_WithInvalidUser_NotFoundException() + public async Task GetOwnCompanyServiceAccountDetailsAsync_WithInvalidCompany_NotFoundException() { // Arrange SetupGetOwnCompanyServiceAccountDetails(); @@ -249,7 +249,7 @@ public async Task GetOwnCompanyServiceAccountDetailsAsync_WithInvalidUser_NotFou async Task Act() => await sut.GetOwnCompanyServiceAccountDetailsAsync(ValidServiceAccountId); // Assert - var exception = await Assert.ThrowsAsync(Act); + var exception = await Assert.ThrowsAsync(Act); exception.Message.Should().Be(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_CONFLICT.ToString()); } @@ -265,7 +265,7 @@ public async Task GetOwnCompanyServiceAccountDetailsAsync_WithInvalidServiceAcco async Task Act() => await sut.GetOwnCompanyServiceAccountDetailsAsync(invalidServiceAccountId); // Assert - var exception = await Assert.ThrowsAsync(Act); + var exception = await Assert.ThrowsAsync(Act); exception.Message.Should().Be(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_CONFLICT.ToString()); } @@ -733,6 +733,7 @@ private void SetupUpdateOwnCompanyServiceAccountDetails() private void SetupGetOwnCompanyServiceAccount() { var data = _fixture.Build() + .With(x => x.Status, UserStatusId.ACTIVE) .With(x => x.DimServiceAccountData, default(DimServiceAccountData?)) .Create(); From 6f08c57d7ac0323871eb6248ac374224fd39cb41 Mon Sep 17 00:00:00 2001 From: Norbert Truchsess Date: Fri, 24 May 2024 09:43:34 +0200 Subject: [PATCH 18/24] chore(migrations): rename migration for rc10 (#770) --- ...tion.Designer.cs => 20240517135403_2.0.0-rc10.Designer.cs} | 4 ++-- ...48-declineRegistration.cs => 20240517135403_2.0.0-rc10.cs} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/portalbackend/PortalBackend.Migrations/Migrations/{20240517135403_CPLP-3548-declineRegistration.Designer.cs => 20240517135403_2.0.0-rc10.Designer.cs} (99%) rename src/portalbackend/PortalBackend.Migrations/Migrations/{20240517135403_CPLP-3548-declineRegistration.cs => 20240517135403_2.0.0-rc10.cs} (99%) diff --git a/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.Designer.cs b/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_2.0.0-rc10.Designer.cs similarity index 99% rename from src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.Designer.cs rename to src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_2.0.0-rc10.Designer.cs index 37bc98806c..d9e0aeac8c 100644 --- a/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.Designer.cs +++ b/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_2.0.0-rc10.Designer.cs @@ -29,8 +29,8 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.Migrations.Migrations { [DbContext(typeof(PortalDbContext))] - [Migration("20240517135403_CPLP-3548-declineRegistration")] - partial class CPLP3548declineRegistration + [Migration("20240517135403_2.0.0-rc10")] + partial class _200rc10 { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) diff --git a/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.cs b/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_2.0.0-rc10.cs similarity index 99% rename from src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.cs rename to src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_2.0.0-rc10.cs index b83bac1eb9..01dd7ef01c 100644 --- a/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_CPLP-3548-declineRegistration.cs +++ b/src/portalbackend/PortalBackend.Migrations/Migrations/20240517135403_2.0.0-rc10.cs @@ -26,7 +26,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.Migrations.Migrations { /// - public partial class CPLP3548declineRegistration : Migration + public partial class _200rc10 : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) From 2aab4de2a01bf0fea5c72465c257d455bda2f964 Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Fri, 24 May 2024 14:07:26 +0200 Subject: [PATCH 19/24] fix(sa): fix old autosetup process for dim technical user creation (#771) * fix(sa): fix old autosetup process for dim technical user creation Refs: #762 * fix review findings --------- Co-authored-by: Norbert Truchsess --- .../ServiceAccountBusinessLogic.cs | 2 +- .../Service/IOfferSetupService.cs | 1 - .../Service/OfferSetupService.cs | 49 ++++++++++++------- .../Service/IServiceAccountCreation.cs | 2 +- .../Service/ServiceAccountCreation.cs | 8 +-- .../ServiceAccountBusinessLogicTests.cs | 2 +- .../Service/OfferSetupServiceTests.cs | 18 ++++--- 7 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs index 16ce75b829..3c66d98834 100644 --- a/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/ServiceAccountBusinessLogic.cs @@ -79,7 +79,7 @@ public async Task> CreateOwnCompanyServiceAcc .IfAny(unassignable => throw ControllerArgumentException.Create(AdministrationServiceAccountErrors.SERVICE_ROLES_NOT_ASSIGN_ARGUMENT, parameters: [new("unassignable", string.Join(",", unassignable)), new("userRoleIds", string.Join(",", result.TechnicalUserRoleIds))])); const CompanyServiceAccountTypeId CompanyServiceAccountTypeId = CompanyServiceAccountTypeId.OWN; - var (_, serviceAccounts) = await serviceAccountCreation.CreateServiceAccountAsync(serviceAccountCreationInfos, companyId, [result.Bpn], CompanyServiceAccountTypeId, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null)).ConfigureAwait(ConfigureAwaitOptions.None); + var (_, _, serviceAccounts) = await serviceAccountCreation.CreateServiceAccountAsync(serviceAccountCreationInfos, companyId, [result.Bpn], CompanyServiceAccountTypeId, false, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null)).ConfigureAwait(ConfigureAwaitOptions.None); await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); return serviceAccounts.Select(sa => new ServiceAccountDetails( diff --git a/src/marketplace/Offers.Library/Service/IOfferSetupService.cs b/src/marketplace/Offers.Library/Service/IOfferSetupService.cs index dde1abf28f..b1c385a6cf 100644 --- a/src/marketplace/Offers.Library/Service/IOfferSetupService.cs +++ b/src/marketplace/Offers.Library/Service/IOfferSetupService.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/marketplace/Offers.Library/Service/OfferSetupService.cs b/src/marketplace/Offers.Library/Service/OfferSetupService.cs index ac08c2b2c3..b87ae2b0b8 100644 --- a/src/marketplace/Offers.Library/Service/OfferSetupService.cs +++ b/src/marketplace/Offers.Library/Service/OfferSetupService.cs @@ -102,25 +102,32 @@ public async Task AutoSetupOfferAsync(OfferAutoSetup var offerSubscriptionsRepository = _portalRepositories.GetInstance(); var offerDetails = await GetAndValidateOfferDetails(data.RequestId, _identityData.CompanyId, offerTypeId, offerSubscriptionsRepository).ConfigureAwait(ConfigureAwaitOptions.None); + return await (offerDetails.InstanceData.IsSingleInstance + ? AutoSetupOfferSingleInstance(data, offerDetails, itAdminRoles, offerTypeId, serviceManagerRoles, offerSubscriptionsRepository) + : AutoSetupOfferMultiInstance(data, offerDetails, itAdminRoles, offerTypeId, basePortalAddress, serviceManagerRoles, offerSubscriptionsRepository)).ConfigureAwait(ConfigureAwaitOptions.None); + } + + private async Task AutoSetupOfferSingleInstance(OfferAutoSetupData data, OfferSubscriptionTransferData offerDetails, IEnumerable itAdminRoles, OfferTypeId offerTypeId, IEnumerable serviceManagerRoles, IOfferSubscriptionsRepository offerSubscriptionsRepository) + { offerSubscriptionsRepository.AttachAndModifyOfferSubscription(data.RequestId, subscription => { subscription.OfferSubscriptionStatusId = OfferSubscriptionStatusId.ACTIVE; }); - if (offerDetails.InstanceData.IsSingleInstance) - { - _portalRepositories.GetInstance() - .CreateAppSubscriptionDetail(data.RequestId, appSubscriptionDetail => - { - appSubscriptionDetail.AppInstanceId = offerDetails.AppInstanceIds.Single(); - appSubscriptionDetail.AppSubscriptionUrl = offerDetails.InstanceData.InstanceUrl; - }); - await CreateNotifications(itAdminRoles, offerTypeId, offerDetails, _identityData.IdentityId).ConfigureAwait(ConfigureAwaitOptions.None); - await SetNotificationsToDone(serviceManagerRoles, offerTypeId, offerDetails.OfferId, offerDetails.SalesManagerId).ConfigureAwait(ConfigureAwaitOptions.None); - await _portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); - return new OfferAutoSetupResponseData(Enumerable.Empty(), null); - } + _portalRepositories.GetInstance() + .CreateAppSubscriptionDetail(data.RequestId, appSubscriptionDetail => + { + appSubscriptionDetail.AppInstanceId = offerDetails.AppInstanceIds.Single(); + appSubscriptionDetail.AppSubscriptionUrl = offerDetails.InstanceData.InstanceUrl; + }); + await CreateNotifications(itAdminRoles, offerTypeId, offerDetails, _identityData.IdentityId).ConfigureAwait(ConfigureAwaitOptions.None); + await SetNotificationsToDone(serviceManagerRoles, offerTypeId, offerDetails.OfferId, offerDetails.SalesManagerId).ConfigureAwait(ConfigureAwaitOptions.None); + await _portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); + return new OfferAutoSetupResponseData(Enumerable.Empty(), null); + } + private async Task AutoSetupOfferMultiInstance(OfferAutoSetupData data, OfferSubscriptionTransferData offerDetails, IEnumerable itAdminRoles, OfferTypeId offerTypeId, string basePortalAddress, IEnumerable serviceManagerRoles, IOfferSubscriptionsRepository offerSubscriptionsRepository) + { var userRolesRepository = _portalRepositories.GetInstance(); ClientInfoData? clientInfoData = null; if (offerTypeId == OfferTypeId.APP) @@ -132,7 +139,13 @@ public async Task AutoSetupOfferAsync(OfferAutoSetup var technicalUserClientId = clientInfoData?.ClientId ?? $"{offerDetails.OfferName}-{offerDetails.CompanyName}"; var createTechnicalUserData = new CreateTechnicalUserData(offerDetails.CompanyId, offerDetails.OfferName, offerDetails.Bpn, technicalUserClientId, offerTypeId == OfferTypeId.APP, true); - var (_, technicalUsers) = await CreateTechnicalUserForSubscription(data.RequestId, createTechnicalUserData, null).ConfigureAwait(ConfigureAwaitOptions.None); + var (_, processId, technicalUsers) = await CreateTechnicalUserForSubscription(data.RequestId, createTechnicalUserData, null).ConfigureAwait(ConfigureAwaitOptions.None); + + offerSubscriptionsRepository.AttachAndModifyOfferSubscription(data.RequestId, subscription => + { + subscription.OfferSubscriptionStatusId = OfferSubscriptionStatusId.ACTIVE; + subscription.ProcessId = processId; + }); await CreateNotifications(itAdminRoles, offerTypeId, offerDetails, _identityData.IdentityId).ConfigureAwait(ConfigureAwaitOptions.None); await SetNotificationsToDone(serviceManagerRoles, offerTypeId, offerDetails.OfferId, offerDetails.SalesManagerId).ConfigureAwait(ConfigureAwaitOptions.None); @@ -148,7 +161,7 @@ public async Task AutoSetupOfferAsync(OfferAutoSetup clientInfoData); } - private async Task<(bool HasExternalServiceAccount, IEnumerable ServiceAccounts)> CreateTechnicalUserForSubscription(Guid subscriptionId, CreateTechnicalUserData data, Guid? processId) + private async Task<(bool HasExternalServiceAccount, Guid? ProcessId, IEnumerable ServiceAccounts)> CreateTechnicalUserForSubscription(Guid subscriptionId, CreateTechnicalUserData data, Guid? processId) { var technicalUserInfoCreations = await _technicalUserProfileService.GetTechnicalUserProfilesForOfferSubscription(subscriptionId).ConfigureAwait(ConfigureAwaitOptions.None); @@ -164,7 +177,7 @@ public async Task AutoSetupOfferAsync(OfferAutoSetup if (serviceAccountCreationInfo == null) { - return (false, []); + return (false, null, []); } return await _serviceAccountCreation @@ -262,7 +275,7 @@ private async IAsyncEnumerable> CreateTechnic var creationData = await _technicalUserProfileService.GetTechnicalUserProfilesForOffer(offerId, offerTypeId).ConfigureAwait(ConfigureAwaitOptions.None); foreach (var creationInfo in creationData) { - var (_, result) = await _serviceAccountCreation + var (_, _, result) = await _serviceAccountCreation .CreateServiceAccountAsync( creationInfo, data.CompanyId, @@ -530,7 +543,7 @@ public async Task CreateSingleInstanceSubscriptionDetail(Guid offerSubscriptionI var technicalUserClientId = data.ClientId ?? $"{data.OfferName}-{data.CompanyName}"; var createTechnicalUserData = new CreateTechnicalUserData(data.CompanyId, data.OfferName, data.Bpn, technicalUserClientId, true, false); - var (hasExternalServiceAccount, serviceAccounts) = await CreateTechnicalUserForSubscription(offerSubscriptionId, createTechnicalUserData, processId).ConfigureAwait(ConfigureAwaitOptions.None); + var (hasExternalServiceAccount, _, serviceAccounts) = await CreateTechnicalUserForSubscription(offerSubscriptionId, createTechnicalUserData, processId).ConfigureAwait(ConfigureAwaitOptions.None); var technicalClientIds = serviceAccounts.Select(x => x.ClientId); var content = JsonSerializer.Serialize(new diff --git a/src/provisioning/Provisioning.Library/Service/IServiceAccountCreation.cs b/src/provisioning/Provisioning.Library/Service/IServiceAccountCreation.cs index 52ae0e3853..815f2829e1 100644 --- a/src/provisioning/Provisioning.Library/Service/IServiceAccountCreation.cs +++ b/src/provisioning/Provisioning.Library/Service/IServiceAccountCreation.cs @@ -37,7 +37,7 @@ public interface IServiceAccountCreation /// The process that should be created if a role for a provider type was selected /// /// Returns information about the created technical user - Task<(bool HasExternalServiceAccount, IEnumerable ServiceAccounts)> CreateServiceAccountAsync( + Task<(bool HasExternalServiceAccount, Guid? processId, IEnumerable ServiceAccounts)> CreateServiceAccountAsync( ServiceAccountCreationInfo creationData, Guid companyId, IEnumerable bpns, diff --git a/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs b/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs index 53f117c01e..10a81ef4a9 100644 --- a/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs +++ b/src/provisioning/Provisioning.Library/Service/ServiceAccountCreation.cs @@ -45,7 +45,7 @@ public class ServiceAccountCreation( private readonly ServiceAccountCreationSettings _settings = options.Value; /// - async Task<(bool HasExternalServiceAccount, IEnumerable ServiceAccounts)> IServiceAccountCreation.CreateServiceAccountAsync(ServiceAccountCreationInfo creationData, + async Task<(bool HasExternalServiceAccount, Guid? processId, IEnumerable ServiceAccounts)> IServiceAccountCreation.CreateServiceAccountAsync(ServiceAccountCreationInfo creationData, Guid companyId, IEnumerable bpns, CompanyServiceAccountTypeId companyServiceAccountTypeId, @@ -83,6 +83,7 @@ public class ServiceAccountCreation( await keycloakRolesTask!.ConfigureAwait(ConfigureAwaitOptions.None); } + Guid? processId = null; var hasExternalServiceAccount = userRoleData.IntersectBy(dimConfigRoles, roleData => (roleData.ClientClientId, roleData.UserRoleText)).IfAny( roleData => { @@ -92,7 +93,6 @@ public class ServiceAccountCreation( var processStepRepository = portalRepositories.GetInstance(); if (processData?.ProcessTypeId is not null) { - Guid processId; if (processData.ProcessId is null) { var process = processStepRepository.CreateProcess(processData.ProcessTypeId.Value); @@ -104,7 +104,7 @@ public class ServiceAccountCreation( processId = processData.ProcessId.Value; } - portalRepositories.GetInstance().CreateDimUserCreationData(dimServiceAccountId, processId); + portalRepositories.GetInstance().CreateDimUserCreationData(dimServiceAccountId, processId.Value); } serviceAccounts.Add(new CreatedServiceAccountData( @@ -117,7 +117,7 @@ public class ServiceAccountCreation( dimRoleData)); }); - return (hasExternalServiceAccount, serviceAccounts.ToImmutable()); + return (hasExternalServiceAccount, processId, serviceAccounts.ToImmutable()); } private static async Task> GetAndValidateUserRoleData(IUserRolesRepository userRolesRepository, IEnumerable userRoleIds) diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs index de5e63a53e..66e5a8948b 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/ServiceAccountBusinessLogicTests.cs @@ -680,7 +680,7 @@ private void SetupCreateOwnCompanyServiceAccount() .Returns<(string?, IEnumerable)>(default); A.CallTo(() => _serviceAccountCreation.CreateServiceAccountAsync(A._, A.That.Matches(x => x == ValidCompanyId), A>._, CompanyServiceAccountTypeId.OWN, A._, true, new ServiceAccountCreationProcessData(ProcessTypeId.DIM_TECHNICAL_USER, null), null)) - .Returns((false, [new CreatedServiceAccountData(Guid.NewGuid(), "test", "description", UserStatusId.ACTIVE, ClientId, new(ClientId, Guid.NewGuid().ToString(), new ClientAuthData(IamClientAuthMethod.SECRET)), Enumerable.Empty())])); + .Returns((false, null, [new CreatedServiceAccountData(Guid.NewGuid(), "test", "description", UserStatusId.ACTIVE, ClientId, new(ClientId, Guid.NewGuid().ToString(), new ClientAuthData(IamClientAuthMethod.SECRET)), Enumerable.Empty())])); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_companyRepository); } diff --git a/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs b/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs index c0fc1590ef..d55165e87e 100644 --- a/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs +++ b/tests/marketplace/Offers.Library.Tests/Service/OfferSetupServiceTests.cs @@ -256,9 +256,7 @@ public async Task AutoSetup_WithValidData_ReturnsExpectedNotificationAndSecret(O public async Task AutoSetup_WithMultipleTechnicalUsers_ThrowsException() { // 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); - SetupAutoSetup(OfferTypeId.APP, offerSubscription, false, companyServiceAccount); + SetupAutoSetup(OfferTypeId.APP); var clientId = Guid.NewGuid(); var appInstanceId = Guid.NewGuid(); A.CallTo(() => _clientRepository.CreateClient(A._)) @@ -1118,16 +1116,20 @@ public async Task CreateTechnicalUser_WithTechnicalUserNeeded_ReturnsExpected(st setOptionalParameter?.Invoke(companyServiceAccount); } }) - .Returns((withMatchingDimRoles, [ - new CreatedServiceAccountData( + .Returns(( + withMatchingDimRoles, + withMatchingDimRoles + ? Guid.NewGuid() + : null, + [new CreatedServiceAccountData( serviceAccountId, "test", "test description", withMatchingDimRoles ? UserStatusId.PENDING : UserStatusId.ACTIVE, clientId ?? $"{data.OfferName}-{data.CompanyName}", serviceAccountData, - userRoleData) - ])); + userRoleData)] + )); var itAdminRoles = Enumerable.Repeat(new UserRoleConfig("Test", ["AdminRoles"]), 1); // Act @@ -1457,7 +1459,7 @@ private IAsyncEnumerator SetupServices(CompanyServiceAccount? companyServi setOptionalParameter?.Invoke(companyServiceAccount); } }) - .Returns(new ValueTuple>(false, [ + .Returns(new ValueTuple>(false, null, [ new CreatedServiceAccountData( _technicalUserId, "sa2", From 0a979697d921c32e71b6aec0d8d260f832de5572 Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Mon, 27 May 2024 10:37:41 +0200 Subject: [PATCH 20/24] fix(ownCompany): allow deletion of configured url for own company (#773) Refs: #764 Reviewed-By: Evelyn Gurschler --- .../SubscriptionConfigurationBusinessLogic.cs | 59 +++++++++++-------- .../Models/ProviderDetailData.cs | 2 +- .../Repositories/CompanyRepository.cs | 4 ++ .../Repositories/ICompanyRepository.cs | 1 + ...criptionConfigurationBusinessLogicTests.cs | 26 +++++++- .../CompanyRepositoryTests.cs | 23 ++++++++ 6 files changed, 88 insertions(+), 27 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/SubscriptionConfigurationBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/SubscriptionConfigurationBusinessLogic.cs index b80013a5cd..7c044fa24f 100644 --- a/src/administration/Administration.Service/BusinessLogic/SubscriptionConfigurationBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/SubscriptionConfigurationBusinessLogic.cs @@ -64,10 +64,10 @@ public async Task GetProviderCompanyDetailsAsync() /// public Task SetProviderCompanyDetailsAsync(ProviderDetailData data) { - data.Url.EnsureValidHttpsUrl(() => nameof(data.Url)); + data.Url?.EnsureValidHttpsUrl(() => nameof(data.Url)); data.CallbackUrl?.EnsureValidHttpsUrl(() => nameof(data.CallbackUrl)); - if (data.Url.Length > 100) + if (data.Url is { Length: > 100 }) { throw new ControllerArgumentException( "the maximum allowed length is 100 characters", nameof(data.Url)); @@ -82,29 +82,11 @@ private async Task SetOfferProviderCompanyDetailsInternalAsync(ProviderDetailDat var providerDetailData = await companyRepository .GetProviderCompanyDetailsExistsForUser(companyId) .ConfigureAwait(ConfigureAwaitOptions.None); - if (providerDetailData == default) + if (providerDetailData == default && data.Url != null) { - var result = await companyRepository - .IsValidCompanyRoleOwner(companyId, new[] { CompanyRoleId.APP_PROVIDER, CompanyRoleId.SERVICE_PROVIDER }) - .ConfigureAwait(ConfigureAwaitOptions.None); - if (!result.IsValidCompanyId) - { - throw new ConflictException($"Company {companyId} not found"); - } - if (!result.IsCompanyRoleOwner) - { - throw new ForbiddenException($"Company {companyId} is not an app- or service-provider"); - } - companyRepository.CreateProviderCompanyDetail(companyId, data.Url, providerDetails => - { - if (data.CallbackUrl != null) - { - providerDetails.AutoSetupCallbackUrl = data.CallbackUrl; - } - providerDetails.DateLastChanged = DateTimeOffset.UtcNow; - }); + await HandleCreateProviderCompanyDetails(data, companyId, companyRepository); } - else + else if (data.Url != null) { companyRepository.AttachAndModifyProviderCompanyDetails( providerDetailData.ProviderCompanyDetailId, @@ -115,9 +97,40 @@ private async Task SetOfferProviderCompanyDetailsInternalAsync(ProviderDetailDat details.DateLastChanged = DateTimeOffset.UtcNow; }); } + else + { + companyRepository.RemoveProviderCompanyDetails(providerDetailData.ProviderCompanyDetailId); + } + await _portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); } + private static async Task HandleCreateProviderCompanyDetails(ProviderDetailData data, Guid companyId, ICompanyRepository companyRepository) + { + var result = await companyRepository + .IsValidCompanyRoleOwner(companyId, new[] { CompanyRoleId.APP_PROVIDER, CompanyRoleId.SERVICE_PROVIDER }) + .ConfigureAwait(ConfigureAwaitOptions.None); + if (!result.IsValidCompanyId) + { + throw new ConflictException($"Company {companyId} not found"); + } + + if (!result.IsCompanyRoleOwner) + { + throw new ForbiddenException($"Company {companyId} is not an app- or service-provider"); + } + + companyRepository.CreateProviderCompanyDetail(companyId, data.Url!, providerDetails => + { + if (data.CallbackUrl != null) + { + providerDetails.AutoSetupCallbackUrl = data.CallbackUrl; + } + + providerDetails.DateLastChanged = DateTimeOffset.UtcNow; + }); + } + /// public Task RetriggerProvider(Guid offerSubscriptionId) => TriggerProcessStep(offerSubscriptionId, ProcessStepTypeId.RETRIGGER_PROVIDER, true); diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/ProviderDetailData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/ProviderDetailData.cs index 8770773d97..7b53cbfb9c 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/ProviderDetailData.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/ProviderDetailData.cs @@ -20,6 +20,6 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; -public record ProviderDetailData(string Url, string? CallbackUrl); +public record ProviderDetailData(string? Url, string? CallbackUrl); public record ProviderDetailReturnData(Guid? Id, Guid CompanyId, string? Url); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyRepository.cs index 6e9eac8dbd..80b2e19b8c 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyRepository.cs @@ -408,4 +408,8 @@ public void CreateWalletData(Guid companyId, string did, JsonDocument didDocumen c.Wallet.AuthenticationServiceUrl ))) .SingleOrDefaultAsync(); + + public void RemoveProviderCompanyDetails(Guid providerCompanyDetailId) => + context.ProviderCompanyDetails + .Remove(new ProviderCompanyDetail(providerCompanyDetailId, Guid.Empty, null!, default)); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyRepository.cs index d8ca26f2b5..d77170ded7 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyRepository.cs @@ -178,4 +178,5 @@ public interface ICompanyRepository Task<(bool Exists, Guid CompanyId, IEnumerable SubmittedCompanyApplicationId)> GetCompanyIdByBpn(string bpn); Task<(string? Bpn, string? Did, string? WalletUrl)> GetDimServiceUrls(Guid companyId); Task<(string? Holder, string? BusinessPartnerNumber, WalletInformation? WalletInformation)> GetWalletData(Guid identityId); + void RemoveProviderCompanyDetails(Guid providerCompanyDetailId); } diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/SubscriptionConfigurationBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/SubscriptionConfigurationBusinessLogicTests.cs index 5451c8bc46..c9b0b58de5 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/SubscriptionConfigurationBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/SubscriptionConfigurationBusinessLogicTests.cs @@ -203,6 +203,27 @@ public async Task SetProviderCompanyDetailsAsync_EmptyProviderDetailsId_ReturnsE _serviceProviderDetails.Should().ContainSingle(); } + [Fact] + public async Task SetProviderCompanyDetailsAsync_WithProviderDetailsAndNoUrl_RemovesProviderDetails() + { + // Arrange + SetupProviderCompanyDetails(); + var providerCompanyId = Guid.NewGuid(); + var providerDetailData = new ProviderDetailData(null, null); + A.CallTo(() => _companyRepository.GetProviderCompanyDetailsExistsForUser(ExistingCompanyId)) + .Returns((providerCompanyId, null!)); + + // Act + await _sut.SetProviderCompanyDetailsAsync(providerDetailData); + + // Assert + A.CallTo(() => _companyRepository.RemoveProviderCompanyDetails(providerCompanyId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _companyRepository.CreateProviderCompanyDetail(A._, A._, A>._)).MustNotHaveHappened(); + A.CallTo(() => _companyRepository.AttachAndModifyProviderCompanyDetails(A._, A>._, A>._)).MustNotHaveHappened(); + A.CallTo(() => _portalRepositories.SaveAsync()).MustHaveHappenedOnceExactly(); + _serviceProviderDetails.Should().BeEmpty(); + } + [Fact] public async Task SetProviderCompanyDetailsAsync_WithServiceProviderDetailsId_ReturnsExpectedResult() { @@ -280,14 +301,13 @@ public async Task SetServiceProviderCompanyDetailsAsync_WithNotServiceProvider_T [Theory] [InlineData("foo")] [InlineData("")] - [InlineData(null)] [InlineData("http://www.service-url.com")] [InlineData("https://www.super-duper-long-url-which-is-actually-to-long-to-be-valid-but-it-is-not-long-enough-yet-so-add-a-few-words.com")] - public async Task SetServiceProviderCompanyDetailsAsync_WithInvalidUrl_ThrowsException(string? url) + public async Task SetServiceProviderCompanyDetailsAsync_WithInvalidUrl_ThrowsException(string url) { //Arrange SetupProviderCompanyDetails(); - var providerDetailData = new ProviderDetailData(url!, null); + var providerDetailData = new ProviderDetailData(url, null); //Act async Task Action() => await _sut.SetProviderCompanyDetailsAsync(providerDetailData); diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRepositoryTests.cs index b32ffc7f80..629321e172 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRepositoryTests.cs @@ -1002,6 +1002,29 @@ public async Task GetWalletServiceUrl_ReturnsExpected() #endregion + #region RemoveProviderCompanyDetails + + [Fact] + public async Task RemoveProviderCompanyDetails_ExecutesExpected() + { + // Arrange + var (sut, context) = await CreateSut(); + + // Act + sut.RemoveProviderCompanyDetails(new Guid("7e86a0b8-6903-496b-96d1-0ef508206833")); + + // Assert + var changeTracker = context.ChangeTracker; + var changedEntries = changeTracker.Entries().ToList(); + changeTracker.HasChanges().Should().BeTrue(); + changedEntries.Should().NotBeEmpty(); + changedEntries.Should().HaveCount(1); + var removedEntity = changedEntries.Single(); + removedEntity.State.Should().Be(EntityState.Deleted); + } + + #endregion + #region Setup private async Task<(ICompanyRepository, PortalDbContext)> CreateSut() From 42e73066a27fb5a7343d4b08459f832eb9334c85 Mon Sep 17 00:00:00 2001 From: Evelyn Gurschler Date: Mon, 27 May 2024 12:50:38 +0200 Subject: [PATCH 21/24] chore(roles-seeding): add bpdm roles (#772) https://github.com/eclipse-tractusx/portal-iam/issues/102 --- .../Data/user_role_assigned_collections.json | 24 +++++++++++ .../Seeder/Data/user_role_descriptions.json | 42 ++++++++++++++----- .../Seeder/Data/user_roles.json | 12 ++++++ .../CompanyRepositoryTests.cs | 2 +- .../CompanyRoleCollectionRolesViewTests.cs | 2 +- .../UserRolesRepositoryTests.cs | 4 +- 6 files changed, 71 insertions(+), 15 deletions(-) diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json index 228e7a5064..7a398fa23e 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_assigned_collections.json @@ -183,6 +183,30 @@ "user_role_collection_id": "1a24eca5-901f-4191-84a7-4ef09a894575", "user_role_id": "ec3a3005-b59c-4319-a8eb-3228984cd6e5" }, + { + "user_role_collection_id": "1a24eca5-901f-4191-84a7-4ef09a894575", + "user_role_id": "ec3a3005-b59c-4319-a8eb-3228884cd7e5" + }, + { + "user_role_collection_id": "ec428950-8b64-4646-b336-28af869b5d73", + "user_role_id": "ec3a3005-b59c-4319-a8eb-3228884cd7e5" + }, + { + "user_role_collection_id": "a5b8b1de-7759-4620-9c87-6b6d74fb4fbc", + "user_role_id": "ec3a3005-b59c-4319-a8eb-3228884cd7e5" + }, + { + "user_role_collection_id": "8cb12ea2-aed4-4d75-b041-ba297df3d2f2", + "user_role_id": "ec3a3005-b59c-4319-a8eb-3228884cd7e5" + }, + { + "user_role_collection_id": "916b09e7-7841-4e57-bdca-e0d3bd329c27", + "user_role_id": "ec3a3005-b59c-4319-a8eb-3228884cd7e5" + }, + { + "user_role_collection_id": "1a24eca5-901f-4191-84a7-4ef09a894575", + "user_role_id": "c01818be-4978-41f4-bf63-fa6d2de53267" + }, { "user_role_collection_id": "ec428950-8b64-4646-b336-28af869b5d73", "user_role_id": "a6b6a5b6-d7fe-42af-94ce-35c16b3ae128" diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_descriptions.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_descriptions.json index 98ce321a55..b0e3fb9171 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_descriptions.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_role_descriptions.json @@ -162,22 +162,22 @@ { "user_role_id": "a6b6a5b6-d7fe-42af-94ce-35c16b3ae128", "language_short_name": "de", - "description": "BPDM Sharing Input Consumer - Beschreibung tbd" + "description": "BPDM Sharing Input Consumer" }, { "user_role_id": "a6b6a5b6-d7fe-42af-94ce-35c16b3ae128", "language_short_name": "en", - "description": "BPDM Sharing Input Consumer - description tbd" + "description": "BPDM Sharing Input Consumer" }, { "user_role_id": "607818be-4978-41f4-bf63-fa8d2de52262", "language_short_name": "de", - "description": "BPDM Pool Admin - Beschreibung tbd" + "description": "BPDM Pool Admin" }, { "user_role_id": "607818be-4978-41f4-bf63-fa8d2de52262", "language_short_name": "en", - "description": "BPDM Pool Admin - description tbd" + "description": "BPDM Pool Admin" }, { "user_role_id": "3940f9b0-4393-4463-b659-15463098557b", @@ -202,17 +202,17 @@ { "user_role_id": "9956fa8d-e454-49ca-a3b1-45e2c106fe59", "language_short_name": "de", - "description": "BPDM Sharing Output Consumer - Beschreibung tbd" + "description": "BPDM Sharing Output Consumer" }, { "user_role_id": "9956fa8d-e454-49ca-a3b1-45e2c106fe59", "language_short_name": "en", - "description": "BPDM Sharing Output Consumer - description tbd" + "description": "BPDM Sharing Output Consumer" }, { "user_role_id": "ec3a3115-b59c-4319-a8eb-3228014cd6e6", "language_short_name": "de", - "description": "BPDM Sharing Admin - Beschreibung tbd" + "description": "BPDM Sharing Admin" }, { "user_role_id": "ec3a3115-b59c-4319-a8eb-3228014cd6e6", @@ -222,21 +222,41 @@ { "user_role_id": "ec3a3005-b59c-4319-a8eb-3228984cd6e5", "language_short_name": "de", - "description": "BPDM Sharing Input Manager - Beschreibung tbd" + "description": "BPDM Sharing Input Manager" }, { "user_role_id": "ec3a3005-b59c-4319-a8eb-3228984cd6e5", "language_short_name": "en", - "description": "BPDM Sharing Input Manager - description tbd" + "description": "BPDM Sharing Input Manager" }, { "user_role_id": "607818be-4978-41f4-bf63-fa6d2de51262", "language_short_name": "de", - "description": "BPDM Pool Consumer - Beschreibung tbd" + "description": "BPDM Pool Consumer" }, { "user_role_id": "607818be-4978-41f4-bf63-fa6d2de51262", "language_short_name": "en", - "description": "BPDM Pool Consumer - description tbd" + "description": "BPDM Pool Consumer" + }, + { + "user_role_id": "ec3a3005-b59c-4319-a8eb-3228884cd7e5", + "language_short_name": "de", + "description": "Business Partner Data Manager" + }, + { + "user_role_id": "ec3a3005-b59c-4319-a8eb-3228884cd7e5", + "language_short_name": "en", + "description": "Business Partner Data Manager" + }, + { + "user_role_id": "c01818be-4978-41f4-bf63-fa6d2de53267", + "language_short_name": "de", + "description": "BPDM Pool Sharing Consumer" + }, + { + "user_role_id": "c01818be-4978-41f4-bf63-fa6d2de53267", + "language_short_name": "en", + "description": "BPDM Pool Sharing Consumer" } ] diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_roles.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_roles.json index 60a667a232..3ee20a0609 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_roles.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/user_roles.json @@ -148,5 +148,17 @@ "user_role": "BPDM Pool Consumer", "offer_id": "0ffcb416-1101-4ba6-8d4a-a9dfa31745a4", "last_editor_id": null + }, + { + "id": "ec3a3005-b59c-4319-a8eb-3228884cd7e5", + "user_role": "Business Partner Data Manager", + "offer_id": "9b957704-3505-4445-822c-d7ef80f27fcd", + "last_editor_id": null + }, + { + "id": "c01818be-4978-41f4-bf63-fa6d2de53267", + "user_role": "BPDM Pool Sharing Consumer", + "offer_id": "0ffcb416-1101-4ba6-8d4a-a9dfa31745a4", + "last_editor_id": null } ] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRepositoryTests.cs index 629321e172..113c456f82 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRepositoryTests.cs @@ -688,7 +688,7 @@ public async Task GetCompanyIdAndBpnForIamUserUntrackedAsync_WithValidData_Retur // Assert result.Should().NotBe(default); result.Bpn.Should().Be("BPNL00000003CRHK"); - result.TechnicalUserRoleIds.Should().HaveCount(12).And.OnlyHaveUniqueItems(); + result.TechnicalUserRoleIds.Should().HaveCount(13).And.OnlyHaveUniqueItems(); } #endregion diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs index 5017cb887e..d8a86d112d 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyRoleCollectionRolesViewTests.cs @@ -45,7 +45,7 @@ public async Task CompanyRoleCollectionRolesView_GetAll_ReturnsExpected() // Act var result = await sut.CompanyRoleCollectionRolesView.ToListAsync(); - result.Should().HaveCount(50); + result.Should().HaveCount(56); } [Fact] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs index 524cec69bf..ef531c33b5 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/UserRolesRepositoryTests.cs @@ -56,7 +56,7 @@ public async Task GetCoreOfferRolesAsync_WithValidData_ReturnsExpected() var data = await sut.GetCoreOfferRolesAsync(_validCompanyId, "en", ClientId).ToListAsync(); // Assert - data.Should().HaveCount(12); + data.Should().HaveCount(13); } #endregion @@ -134,7 +134,7 @@ public async Task GetServiceAccountRolesAsync_WithValidData_ReturnsExpected() var data = await sut.GetServiceAccountRolesAsync(_validCompanyId, ClientId, Constants.DefaultLanguage).ToListAsync(); // Assert - data.Should().HaveCount(12); + data.Should().HaveCount(13); data.Should().OnlyHaveUniqueItems(); } From eb5966fab2080754fa0760b5de0edfc6aff416aa Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Mon, 27 May 2024 14:06:55 +0200 Subject: [PATCH 22/24] fix(permission): adjust permission for /declineregistration (#774) Reviewed-By: Evelyn Gurschler --- .../Registration.Service/Controllers/RegistrationController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registration/Registration.Service/Controllers/RegistrationController.cs b/src/registration/Registration.Service/Controllers/RegistrationController.cs index a863ee9b11..5675fe7ef2 100644 --- a/src/registration/Registration.Service/Controllers/RegistrationController.cs +++ b/src/registration/Registration.Service/Controllers/RegistrationController.cs @@ -502,7 +502,7 @@ public async Task GetRegistrationDocumentAsync([FromRoute] Guid do /// Successfully declined the application /// Application ID not found. [HttpPost] - [Authorize(Roles = "decline_new_partner")] + [Authorize(Roles = "view_registration")] [Authorize(Policy = PolicyTypes.CompanyUser)] [Route("applications/{applicationId}/declineregistration")] [ProducesResponseType(StatusCodes.Status204NoContent)] From a53ddaaff4703059bb4d832a9ed2ddc07921fd37 Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Mon, 27 May 2024 15:14:01 +0200 Subject: [PATCH 23/24] fix(policy): add valid company policy (#775) Reviewed-By: Evelyn Gurschler --- .../Registration.Service/Controllers/RegistrationController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/registration/Registration.Service/Controllers/RegistrationController.cs b/src/registration/Registration.Service/Controllers/RegistrationController.cs index 5675fe7ef2..4b2211779a 100644 --- a/src/registration/Registration.Service/Controllers/RegistrationController.cs +++ b/src/registration/Registration.Service/Controllers/RegistrationController.cs @@ -504,6 +504,7 @@ public async Task GetRegistrationDocumentAsync([FromRoute] Guid do [HttpPost] [Authorize(Roles = "view_registration")] [Authorize(Policy = PolicyTypes.CompanyUser)] + [Authorize(Policy = PolicyTypes.ValidCompany)] [Route("applications/{applicationId}/declineregistration")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] From c04509d176976f2d9af74c633b5943cdff20694c Mon Sep 17 00:00:00 2001 From: Evelyn Gurschler Date: Mon, 27 May 2024 18:45:36 +0200 Subject: [PATCH 24/24] build(2.0.0-rc10): bump version and update docs --- CHANGELOG.md | 23 +++++++++++++++++++++++ src/Directory.Build.props | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35862989d3..c3c3b50f1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ New features, fixed bugs, known defects and other noteworthy changes to each release of the Catena-X Portal Backend. +## 2.0.0-RC10 + +### Feature +* **Processes Worker** +* added process to decline own companies registration +* **Administration Service** +* enabled the retrieval of service accounts with userstatusid != DELETED +* include pending serviceaccounts and add userstatus to result + +### Changes +* **Seeding** +* add bpdm roles + +### Bugfix +* **Registration Service** +* adjusted permission for /declineregistration +* add valid company policy +* **Administration Service** +* allowed deletion of configured url for own company +* fixed old autosetup process for dim technical user creation +* fixed conflict errors for inactive and pending service accounts +* fixed error "Sequence contains more than one element" for GET /serviceAccounts/{serviceAccountID} endpoint + ## 2.0.0-RC9 ### Changes diff --git a/src/Directory.Build.props b/src/Directory.Build.props index aab938b2ba..d5135fbe1d 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -20,6 +20,6 @@ 2.0.0 - RC9 + RC10