diff --git a/.github/workflows/nuget-package-push.yml b/.github/workflows/nuget-package-push.yml index 29b78c3270..7d14c3c815 100644 --- a/.github/workflows/nuget-package-push.yml +++ b/.github/workflows/nuget-package-push.yml @@ -71,4 +71,4 @@ jobs: - name: Create git tag uses: rickstaa/action-create-tag@v1 with: - tag: v${{ steps.nugetPackageVersion.outputs.version }} + tag: ${{ steps.nugetPackageVersion.outputs.version }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b858c4b21..9053d5efa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,22 @@ New features, fixed bugs, known defects and other noteworthy changes to each release of the Catena-X Portal Backend. -## 1.8.0-RC5 +## 1.8.0-RC7 + +### Feature +* Certificate Management (Administration Service) + * released new endpoint to fetch own company certificate data incl sorting and filters - GET /api/administration/companydata/companyCertificates + * released new endpoint to fetch other company certificate data using businesspartner number via the new endpoint GET /api/administration/companydata/{businessPartnerNumber}/companyCertificates + +### Bugfix +* fixed endpoint GET /api/administration/user/owncompany/users/{userid} missing assignments of firstname, lastname and email were added to busineslogic and setters were removed from company-user related record-definitions +* fixed endpoint api/administration/registration/application/{applicationId}/decline +* fixed bpdm interface connection + * switch from Put to Post for the sharing-state/ready call + * add BpdmSharingStateBusinessPartnerType 'GENERIC' + * add BpdmSharingStateType 'Ready' + +## 1.8.0-RC6 ### Feature * Certificate Management (Administration Service) @@ -20,7 +35,7 @@ New features, fixed bugs, known defects and other noteworthy changes to each rel * Added ValidCompany Attribute to endpoint POST api/registration/network/{externalId}/decline to initialize the companyId of the current user correctly * External Registration submission endpoint POST /api/registration/Network/partnerRegistration/submit fixed -## 1.8.0-RC4 +## 1.8.0-RC5 ### Change * Registration Service diff --git a/scripts/get_current_version.sh b/scripts/get_current_version.sh index 7719114b99..c185a0b414 100755 --- a/scripts/get_current_version.sh +++ b/scripts/get_current_version.sh @@ -33,4 +33,4 @@ else version="$version_prefix-framework" fi -echo "Version: $version" +echo "v$version" diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d56ca7f8f1..4c11966055 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -20,6 +20,6 @@ 1.8.0 - RC6 + RC7 diff --git a/src/administration/Administration.Service/BusinessLogic/CompanyDataBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/CompanyDataBusinessLogic.cs index 07370c0bcd..a30af520ee 100644 --- a/src/administration/Administration.Service/BusinessLogic/CompanyDataBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/CompanyDataBusinessLogic.cs @@ -577,4 +577,33 @@ await _mailingService.SendMails(requesterEmail, mailParameters, Enumerable.Repea /// public IAsyncEnumerable GetCertificateTypes() => _portalRepositories.GetInstance().GetCertificateTypes(_identityData.CompanyId); + + /// + public async IAsyncEnumerable GetCompanyCertificatesByBpn(string businessPartnerNumber) + { + if (string.IsNullOrWhiteSpace(businessPartnerNumber)) + { + throw new ControllerArgumentException("businessPartnerNumber must not be empty"); + } + + var companyCertificateRepository = _portalRepositories.GetInstance(); + + var companyId = await companyCertificateRepository.GetCompanyIdByBpn(businessPartnerNumber).ConfigureAwait(false); + if (companyId == Guid.Empty) + { + throw new ControllerArgumentException($"company does not exist for {businessPartnerNumber}"); + } + + await foreach (var data in companyCertificateRepository.GetCompanyCertificateData(companyId)) + { + yield return data; + } + } + + public Task> GetAllCompanyCertificatesAsync(int page, int size, CertificateSorting? sorting, CompanyCertificateStatusId? certificateStatus, CompanyCertificateTypeId? certificateType) => + Pagination.CreateResponseAsync( + page, + size, + _settings.MaxPageSize, + _portalRepositories.GetInstance().GetActiveCompanyCertificatePaginationSource(sorting, certificateStatus, certificateType, _identityData.CompanyId)); } diff --git a/src/administration/Administration.Service/BusinessLogic/ICompanyDataBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/ICompanyDataBusinessLogic.cs index 88bc9cceac..f99c8629ad 100644 --- a/src/administration/Administration.Service/BusinessLogic/ICompanyDataBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/ICompanyDataBusinessLogic.cs @@ -53,6 +53,8 @@ public interface ICompanyDataBusinessLogic Task RejectCredential(Guid credentialId); IAsyncEnumerable GetCertificateTypes(); - + IAsyncEnumerable GetCompanyCertificatesByBpn(string businessPartnerNumber); Task CreateCompanyCertificate(CompanyCertificateCreationData data, CancellationToken cancellationToken); + + Task> GetAllCompanyCertificatesAsync(int page, int size, CertificateSorting? sorting, CompanyCertificateStatusId? certificateStatus, CompanyCertificateTypeId? certificateType); } diff --git a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs index f8ba83d385..59b98bfa34 100644 --- a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs @@ -497,6 +497,8 @@ public async Task DeclineRegistrationVerification(Guid applicationId, string com await _provisioningManager.DeleteCentralRealmUserAsync(iamUserId).ConfigureAwait(false); } } + + var emailData = await _portalRepositories.GetInstance().GetEmailDataUntrackedAsync(applicationId).ToListAsync(cancellationToken).ConfigureAwait(false); userRepository.AttachAndModifyIdentities(companyUserIds.Select(userId => new ValueTuple?, Action>(userId, null, identity => { identity.UserStatusId = UserStatusId.DELETED; }))); _checklistService.FinalizeChecklistEntryAndProcessSteps( @@ -512,17 +514,17 @@ public async Task DeclineRegistrationVerification(Guid applicationId, string com : new[] { ProcessStepTypeId.TRIGGER_CALLBACK_OSP_DECLINED }); await _portalRepositories.SaveAsync().ConfigureAwait(false); - await PostRegistrationCancelEmailAsync(applicationId, companyName, comment).ConfigureAwait(false); + await PostRegistrationCancelEmailAsync(emailData, companyName, comment).ConfigureAwait(false); } - private async Task PostRegistrationCancelEmailAsync(Guid applicationId, string companyName, string comment) + private async Task PostRegistrationCancelEmailAsync(ICollection emailData, string companyName, string comment) { if (string.IsNullOrWhiteSpace(comment)) { throw new ConflictException("No comment set."); } - await foreach (var user in _portalRepositories.GetInstance().GetEmailDataUntrackedAsync(applicationId).ConfigureAwait(false)) + foreach (var user in emailData) { var userName = string.Join(" ", new[] { user.FirstName, user.LastName }.Where(item => !string.IsNullOrWhiteSpace(item))); diff --git a/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs index fd1a04f1d8..f35bdf0b02 100644 --- a/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/UserBusinessLogic.cs @@ -312,7 +312,10 @@ await Task.WhenAll(details.IdpUserIds.Select(async x => new IdpUserId( await GetDisplayName(x.Alias ?? throw new ConflictException("Alias must not be null")).ConfigureAwait(false), x.Alias, - x.UserId))).ConfigureAwait(false)); + x.UserId))).ConfigureAwait(false), + details.FirstName, + details.LastName, + details.Email); } public async Task AddOwnCompanyUsersBusinessPartnerNumbersAsync(Guid userId, IEnumerable businessPartnerNumbers) @@ -366,7 +369,10 @@ await Task.WhenAll(details.IdpUserIds.Select(async x => new IdpUserId( await GetDisplayName(x.Alias ?? throw new ConflictException("Alias must not be null")).ConfigureAwait(false), x.Alias, - x.UserId))).ConfigureAwait(false)); + x.UserId))).ConfigureAwait(false), + details.FirstName, + details.LastName, + details.Email); } public async Task UpdateOwnUserDetails(Guid companyUserId, OwnCompanyUserEditableDetails ownCompanyUserEditableDetails) @@ -419,12 +425,10 @@ await _provisioningManager.UpdateSharedRealmUserAsync( userData.BusinessPartnerNumbers, companyUser.CompanyName, companyUser.UserStatusId, - userData.AssignedRoles) - { - FirstName = companyUser.Firstname, - LastName = companyUser.Lastname, - Email = companyUser.Email - }; + userData.AssignedRoles, + companyUser.Firstname, + companyUser.Lastname, + companyUser.Email); } public async Task DeleteOwnUserAsync(Guid companyUserId) diff --git a/src/administration/Administration.Service/Controllers/CompanyDataController.cs b/src/administration/Administration.Service/Controllers/CompanyDataController.cs index d4c1ab1f86..a29ae89001 100644 --- a/src/administration/Administration.Service/Controllers/CompanyDataController.cs +++ b/src/administration/Administration.Service/Controllers/CompanyDataController.cs @@ -293,6 +293,44 @@ public async Task CreateCompanyCertificate([FromForm] CompanyCe return NoContent(); } + /// + /// Gets the companyCertificates Details + /// + /// the companyCertificates details + /// Example: GET: api/administration/companydata/businessPartnerNumber}/companyCertificates + /// Returns the companyCertificates details. + [HttpGet] + [Authorize(Roles = "view_certificates")] + [Authorize(Policy = PolicyTypes.ValidCompany)] + [Route("company/{businessPartnerNumber}/companyCertificates")] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] + [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status409Conflict)] + public IAsyncEnumerable GetCompanyCertificatesByBpn(string businessPartnerNumber) => + _logic.GetCompanyCertificatesByBpn(businessPartnerNumber); + + /// + /// Retrieves all company certificates with respect userId. + /// + /// Optional the page of company certificate. + /// Amount of company certificate, default is 15. + /// Optional Sorting of the pagination + /// Optional filter for company certificate status + /// Optional filter for company certificate type + /// Collection of all active company certificates. + /// Example: GET /api/administration/companydata/companyCertificates + /// Returns the list of all active company certificates. + [HttpGet] + [Route("companyCertificates")] + [Authorize(Roles = "view_certificates")] + [Authorize(Policy = PolicyTypes.ValidIdentity)] + [Authorize(Policy = PolicyTypes.ValidCompany)] + [ProducesResponseType(typeof(Pagination.Response), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public Task> GetAllCompanyCertificatesAsync([FromQuery] int page = 0, [FromQuery] int size = 15, [FromQuery] CertificateSorting? sorting = null, [FromQuery] CompanyCertificateStatusId? certificateStatus = null, [FromQuery] CompanyCertificateTypeId? certificateType = null) => + _logic.GetAllCompanyCertificatesAsync(page, size, sorting, certificateStatus, certificateType); + /// /// Gets all outstanding, existing and inactive credentials /// diff --git a/src/administration/Administration.Service/Models/CompanyUserData.cs b/src/administration/Administration.Service/Models/CompanyUserData.cs new file mode 100644 index 0000000000..235c92df2d --- /dev/null +++ b/src/administration/Administration.Service/Models/CompanyUserData.cs @@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 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.Models; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; +using System.Text.Json.Serialization; + +namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; + +public record CompanyUserData( + [property: JsonPropertyName("companyUserId")] + Guid CompanyUserId, + [property: JsonPropertyName("status")] + UserStatusId UserStatusId, + [property: JsonPropertyName("firstName")] + string? FirstName, + [property: JsonPropertyName("lastName")] + string? LastName, + [property: JsonPropertyName("email")] + string? Email, + [property: JsonPropertyName("roles")] + IEnumerable Roles, + [property: JsonPropertyName("idpUserIds")] + IEnumerable IdpUserIds +); diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserDetails.cs b/src/administration/Administration.Service/Models/CompanyUserDetails.cs similarity index 50% rename from src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserDetails.cs rename to src/administration/Administration.Service/Models/CompanyUserDetails.cs index 8266746cea..f34affa52b 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserDetails.cs +++ b/src/administration/Administration.Service/Models/CompanyUserDetails.cs @@ -17,10 +17,11 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using System.Text.Json.Serialization; -namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; +namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; public record CompanyUserDetails( [property: JsonPropertyName("companyUserId")] Guid CompanyUserId, @@ -28,17 +29,10 @@ public record CompanyUserDetails( [property: JsonPropertyName("bpn")] IEnumerable BusinessPartnerNumbers, [property: JsonPropertyName("company")] string CompanyName, [property: JsonPropertyName("status")] UserStatusId UserStatusId, - [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles) -{ - [JsonPropertyName("firstName")] - public string? FirstName { get; set; } - - [JsonPropertyName("lastName")] - public string? LastName { get; set; } - - [JsonPropertyName("email")] - public string? Email { get; set; } -} + [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles, + [property: JsonPropertyName("firstName")] string? FirstName, + [property: JsonPropertyName("lastName")] string? LastName, + [property: JsonPropertyName("email")] string? Email); public record CompanyUserDetailData( [property: JsonPropertyName("companyUserId")] Guid CompanyUserId, @@ -47,17 +41,10 @@ public record CompanyUserDetailData( [property: JsonPropertyName("company")] string CompanyName, [property: JsonPropertyName("status")] UserStatusId UserStatusId, [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles, - [property: JsonPropertyName("idpUserIds")] IEnumerable IdpUserIds) -{ - [JsonPropertyName("firstName")] - public string? FirstName { get; set; } - - [JsonPropertyName("lastName")] - public string? LastName { get; set; } - - [JsonPropertyName("email")] - public string? Email { get; set; } -} + [property: JsonPropertyName("idpUserIds")] IEnumerable IdpUserIds, + [property: JsonPropertyName("firstName")] string? FirstName, + [property: JsonPropertyName("lastName")] string? LastName, + [property: JsonPropertyName("email")] string? Email); public record CompanyOwnUserDetails( [property: JsonPropertyName("companyUserId")] Guid CompanyUserId, @@ -67,70 +54,12 @@ public record CompanyOwnUserDetails( [property: JsonPropertyName("status")] UserStatusId UserStatusId, [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles, [property: JsonPropertyName("admin")] IEnumerable AdminDetails, - [property: JsonPropertyName("idpUserIds")] IEnumerable IdpUserIds) -{ - [JsonPropertyName("firstName")] - public string? FirstName { get; set; } - - [JsonPropertyName("lastName")] - public string? LastName { get; set; } - - [JsonPropertyName("email")] - public string? Email { get; set; } -} - -public record CompanyUserAdminDetails( - [property: JsonPropertyName("id")] Guid CompanyUserId, + [property: JsonPropertyName("idpUserIds")] IEnumerable IdpUserIds, + [property: JsonPropertyName("firstName")] string? FirstName, + [property: JsonPropertyName("lastName")] string? LastName, [property: JsonPropertyName("email")] string? Email); -public record CompanyUserAssignedRoleDetails( - [property: JsonPropertyName("appId")] Guid OfferId, - [property: JsonPropertyName("roles")] IEnumerable UserRoles); - public record IdpUserId( [property: JsonPropertyName("idpDisplayName")] string IdpDisplayName, [property: JsonPropertyName("idpAlias")] string IdpAlias, [property: JsonPropertyName("userId")] string UserId); - -public record CompanyOwnUserTransferDetails( - [property: JsonPropertyName("companyUserId")] Guid CompanyUserId, - [property: JsonPropertyName("created")] DateTimeOffset CreatedAt, - [property: JsonPropertyName("bpn")] IEnumerable BusinessPartnerNumbers, - [property: JsonPropertyName("company")] string CompanyName, - [property: JsonPropertyName("status")] UserStatusId UserStatusId, - [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles, - [property: JsonPropertyName("admin")] IEnumerable AdminDetails, - [property: JsonPropertyName("idpUserIds")] IEnumerable IdpUserIds) -{ - [JsonPropertyName("firstName")] - public string? FirstName { get; set; } - - [JsonPropertyName("lastName")] - public string? LastName { get; set; } - - [JsonPropertyName("email")] - public string? Email { get; set; } -} - -public record CompanyUserDetailTransferData( - [property: JsonPropertyName("companyUserId")] Guid CompanyUserId, - [property: JsonPropertyName("created")] DateTimeOffset CreatedAt, - [property: JsonPropertyName("bpn")] IEnumerable BusinessPartnerNumbers, - [property: JsonPropertyName("company")] string CompanyName, - [property: JsonPropertyName("status")] UserStatusId UserStatusId, - [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles, - [property: JsonPropertyName("idpUserIds")] IEnumerable IdpUserIds) -{ - [JsonPropertyName("firstName")] - public string? FirstName { get; set; } - - [JsonPropertyName("lastName")] - public string? LastName { get; set; } - - [JsonPropertyName("email")] - public string? Email { get; set; } -} - -public record IdpUserTransferId( - [property: JsonPropertyName("alias")] string? Alias, - [property: JsonPropertyName("userId")] string UserId); diff --git a/src/administration/Administration.Service/appsettings.json b/src/administration/Administration.Service/appsettings.json index d6a35b8d4b..9c23bd3e37 100644 --- a/src/administration/Administration.Service/appsettings.json +++ b/src/administration/Administration.Service/appsettings.json @@ -40,13 +40,6 @@ "ClientSecret": "", "AuthRealm": "", "UseAuthTrail": false - }, - "shareddelete": { - "ConnectionString": "", - "ClientId": "", - "ClientSecret": "", - "AuthRealm": "", - "UseAuthTrail": false } }, "ConnectionStrings": { diff --git a/src/externalsystems/Bpdm.Library/BpdmService.cs b/src/externalsystems/Bpdm.Library/BpdmService.cs index 3d89ae91d8..960e8ac9c8 100644 --- a/src/externalsystems/Bpdm.Library/BpdmService.cs +++ b/src/externalsystems/Bpdm.Library/BpdmService.cs @@ -122,7 +122,7 @@ public async Task SetSharingStateToReady(string externalId, CancellationTo var httpClient = await _tokenService.GetAuthorizedClient(_settings, cancellationToken).ConfigureAwait(false); var content = new { externalIds = Enumerable.Repeat(externalId, 1) }; - await httpClient.PutAsJsonAsync("/companies/test-company/api/catena/sharing-state/ready", content, Options, cancellationToken) + await httpClient.PostAsJsonAsync("/companies/test-company/api/catena/sharing-state/ready", content, Options, cancellationToken) .CatchingIntoServiceExceptionFor("bpdm-put-sharing-state-ready", HttpAsyncResponseMessageExtension.RecoverOptions.INFRASTRUCTURE).ConfigureAwait(false); return true; } diff --git a/src/externalsystems/Bpdm.Library/Models/BpdmLegalEntityOutputData.cs b/src/externalsystems/Bpdm.Library/Models/BpdmLegalEntityOutputData.cs index 4084ca9aa2..4fe5d9afd2 100644 --- a/src/externalsystems/Bpdm.Library/Models/BpdmLegalEntityOutputData.cs +++ b/src/externalsystems/Bpdm.Library/Models/BpdmLegalEntityOutputData.cs @@ -89,13 +89,13 @@ BpdmIdentifierId Type public record BpdmAddressPhysicalPostalAddress( BpdmGeographicCoordinatesDto? GeographicCoordinates, string? Country, - string? PostalCode, - string? City, - BpdmLegalEntityStreet? Street, string? AdministrativeAreaLevel1, string? AdministrativeAreaLevel2, string? AdministrativeAreaLevel3, + string? PostalCode, + string? City, string? District, + BpdmLegalEntityStreet? Street, string? CompanyPostalCode, string? IndustrialZone, string? Building, diff --git a/src/externalsystems/Bpdm.Library/Models/BpdmSharingState.cs b/src/externalsystems/Bpdm.Library/Models/BpdmSharingState.cs index 0f2ecba27e..c7291eed40 100644 --- a/src/externalsystems/Bpdm.Library/Models/BpdmSharingState.cs +++ b/src/externalsystems/Bpdm.Library/Models/BpdmSharingState.cs @@ -30,7 +30,8 @@ public record BpdmSharingState( string? SharingErrorCode, string? SharingErrorMessage, string? Bpn, - DateTimeOffset? SharingProcessStarted + DateTimeOffset? SharingProcessStarted, + Guid? TaskId ); public enum BpdmSharingStateType @@ -38,12 +39,14 @@ public enum BpdmSharingStateType Pending = 1, Success = 2, Error = 3, - Initial = 4 + Initial = 4, + Ready = 5, } public enum BpdmSharingStateBusinessPartnerType { LEGAL_ENTITY = 1, SITE = 2, - ADDRESS = 3 + ADDRESS = 3, + GENERIC = 4 } diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CertificateSorting.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CertificateSorting.cs new file mode 100644 index 0000000000..c0c52cabab --- /dev/null +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CertificateSorting.cs @@ -0,0 +1,43 @@ +/******************************************************************************** + * 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.DBAccess.Models; + +public enum CertificateSorting +{ + /// + /// Ascending by certificateType + /// + CertificateTypeAsc = 1, + + /// + /// Descending by certificateType + /// + CertificateTypeDesc = 2, + + /// + /// Ascending by expiryDate + /// + ExpiryDateAsc = 3, + + /// + /// Descending by expiryDate + /// + ExpiryDateDesc = 4, +} diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyCertificateBpnData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyCertificateBpnData.cs new file mode 100644 index 0000000000..ba98c67a83 --- /dev/null +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyCertificateBpnData.cs @@ -0,0 +1,31 @@ +/******************************************************************************** + * Copyright (c) 2021, 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; +using System.Reflection.Metadata; + +namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; + +public record CompanyCertificateBpnData( + CompanyCertificateTypeId CompanyCertificateType, + CompanyCertificateStatusId CompanyCertificateStatus, + Guid DocumentId, + DateTimeOffset ValidFrom, + DateTimeOffset? ValidTill +); diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyCertificateData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyCertificateData.cs new file mode 100644 index 0000000000..a927d98a19 --- /dev/null +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyCertificateData.cs @@ -0,0 +1,30 @@ +/******************************************************************************** + * Copyright (c) 2021, 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; + +namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; + +public record CompanyCertificateData( + CompanyCertificateTypeId companyCertificateType, + CompanyCertificateStatusId companyCertificateStatus, + Guid documentId, + DateTimeOffset validFrom, + DateTimeOffset? validTill +); diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserTransferData.cs similarity index 76% rename from src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserData.cs rename to src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserTransferData.cs index 683d65c9d3..ba6f04dfac 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserData.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserTransferData.cs @@ -22,23 +22,6 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; -public record CompanyUserData( - [property: JsonPropertyName("companyUserId")] - Guid CompanyUserId, - [property: JsonPropertyName("status")] - UserStatusId UserStatusId, - [property: JsonPropertyName("firstName")] - string? FirstName, - [property: JsonPropertyName("lastName")] - string? LastName, - [property: JsonPropertyName("email")] - string? Email, - [property: JsonPropertyName("roles")] - IEnumerable Roles, - [property: JsonPropertyName("idpUserIds")] - IEnumerable IdpUserIds -); - public record CompanyUserTransferData( [property: JsonPropertyName("companyUserId")] Guid CompanyUserId, diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserTransferDetails.cs b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserTransferDetails.cs new file mode 100644 index 0000000000..7425038740 --- /dev/null +++ b/src/portalbackend/PortalBackend.DBAccess/Models/CompanyUserTransferDetails.cs @@ -0,0 +1,60 @@ +/******************************************************************************** + * Copyright (c) 2021, 2023 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.PortalEntities.Enums; +using System.Text.Json.Serialization; + +namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; + +public record CompanyUserAdminDetails( + [property: JsonPropertyName("id")] Guid CompanyUserId, + [property: JsonPropertyName("email")] string? Email); + +public record CompanyUserAssignedRoleDetails( + [property: JsonPropertyName("appId")] Guid OfferId, + [property: JsonPropertyName("roles")] IEnumerable UserRoles); + +public record CompanyOwnUserTransferDetails( + [property: JsonPropertyName("companyUserId")] Guid CompanyUserId, + [property: JsonPropertyName("created")] DateTimeOffset CreatedAt, + [property: JsonPropertyName("bpn")] IEnumerable BusinessPartnerNumbers, + [property: JsonPropertyName("company")] string CompanyName, + [property: JsonPropertyName("status")] UserStatusId UserStatusId, + [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles, + [property: JsonPropertyName("admin")] IEnumerable AdminDetails, + [property: JsonPropertyName("idpUserIds")] IEnumerable IdpUserIds, + [property: JsonPropertyName("firstName")] string? FirstName, + [property: JsonPropertyName("lastName")] string? LastName, + [property: JsonPropertyName("email")] string? Email); + +public record CompanyUserDetailTransferData( + [property: JsonPropertyName("companyUserId")] Guid CompanyUserId, + [property: JsonPropertyName("created")] DateTimeOffset CreatedAt, + [property: JsonPropertyName("bpn")] IEnumerable BusinessPartnerNumbers, + [property: JsonPropertyName("company")] string CompanyName, + [property: JsonPropertyName("status")] UserStatusId UserStatusId, + [property: JsonPropertyName("assignedRoles")] IEnumerable AssignedRoles, + [property: JsonPropertyName("idpUserIds")] IEnumerable IdpUserIds, + [property: JsonPropertyName("firstName")] string? FirstName, + [property: JsonPropertyName("lastName")] string? LastName, + [property: JsonPropertyName("email")] string? Email); + +public record IdpUserTransferId( + [property: JsonPropertyName("alias")] string? Alias, + [property: JsonPropertyName("userId")] string UserId); diff --git a/src/portalbackend/PortalBackend.DBAccess/PortalBackend.DBAccess.csproj b/src/portalbackend/PortalBackend.DBAccess/PortalBackend.DBAccess.csproj index 598e4dea3d..9a86f3e25a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/PortalBackend.DBAccess.csproj +++ b/src/portalbackend/PortalBackend.DBAccess/PortalBackend.DBAccess.csproj @@ -1,45 +1,45 @@ - - - - - Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess - Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess - net7.0 - enable - enable - - - - - - - - - - - - - - - - - - + + + + + Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess + Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess + net7.0 + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyCertificateRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyCertificateRepository.cs index cd51eed405..a91fc8f23e 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyCertificateRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyCertificateRepository.cs @@ -18,7 +18,7 @@ ********************************************************************************/ using Microsoft.EntityFrameworkCore; -using Org.Eclipse.TractusX.Portal.Backend.Framework.DBAccess; +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; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; @@ -52,4 +52,51 @@ public CompanyCertificate CreateCompanyCertificate(Guid companyId, CompanyCertif setOptionalFields?.Invoke(companyCertificate); return _context.CompanyCertificates.Add(companyCertificate).Entity; } + + /// + public Task GetCompanyIdByBpn(string businessPartnerNumber) => + _context.Companies + .Where(x => x.BusinessPartnerNumber == businessPartnerNumber) + .Select(x => x.Id) + .SingleOrDefaultAsync(); + + /// + public IAsyncEnumerable GetCompanyCertificateData(Guid companyId) => + _context.CompanyCertificates + .Where(x => x.CompanyId == companyId && x.CompanyCertificateStatusId == CompanyCertificateStatusId.ACTIVE) + .Select(ccb => new CompanyCertificateBpnData( + ccb.CompanyCertificateTypeId, + ccb.CompanyCertificateStatusId, + ccb.DocumentId, + ccb.ValidFrom, + ccb.ValidTill)) + .ToAsyncEnumerable(); + + public Func?>> GetActiveCompanyCertificatePaginationSource(CertificateSorting? sorting, CompanyCertificateStatusId? certificateStatus, CompanyCertificateTypeId? certificateType, Guid companyId) => + (skip, take) => Pagination.CreateSourceQueryAsync( + skip, + take, + _context.CompanyCertificates + .AsNoTracking() + .Where(x => + x.CompanyId == companyId && + (certificateStatus == null || x.CompanyCertificateStatusId == certificateStatus) && + (certificateType == null || x.CompanyCertificateTypeId == certificateType)) + .GroupBy(x => x.CompanyId), + sorting switch + { + CertificateSorting.CertificateTypeAsc => (IEnumerable cc) => cc.OrderBy(x => x.CompanyCertificateTypeId), + CertificateSorting.CertificateTypeDesc => (IEnumerable cc) => cc.OrderByDescending(x => x.CompanyCertificateTypeId), + CertificateSorting.ExpiryDateAsc => (IEnumerable cc) => cc.OrderBy(x => x.ValidTill), + CertificateSorting.ExpiryDateDesc => (IEnumerable cc) => cc.OrderByDescending(x => x.ValidTill), + _ => null + }, + companyCertificate => new CompanyCertificateData( + companyCertificate.CompanyCertificateTypeId, + companyCertificate.CompanyCertificateStatusId, + companyCertificate.DocumentId, + companyCertificate.ValidFrom, + companyCertificate.ValidTill + )) + .SingleOrDefaultAsync(); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyCertificateRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyCertificateRepository.cs index 76d919a679..400cd1b1f6 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyCertificateRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyCertificateRepository.cs @@ -17,7 +17,11 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; 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; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories; @@ -40,4 +44,24 @@ public interface ICompanyCertificateRepository /// Action to set optional fields /// The created entity CompanyCertificate CreateCompanyCertificate(Guid companyId, CompanyCertificateTypeId companyCertificateTypeId, Guid docId, Action? setOptionalFields = null); + + /// + /// Get companyId against businessPartnerNumber + /// + /// bpn Id + /// company entity + Task GetCompanyIdByBpn(string businessPartnerNumber); + + /// + /// Gets company certificate details + /// + /// Id of the company + /// Returns the CompanyCertificateBpnData Details + IAsyncEnumerable GetCompanyCertificateData(Guid companyId); + + /// + /// Gets all company certificate data from the persistence storage as pagination + /// + /// Returns an Pagination + Func?>> GetActiveCompanyCertificatePaginationSource(CertificateSorting? sorting, CompanyCertificateStatusId? certificateStatus, CompanyCertificateTypeId? certificateType, Guid companyId); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs index 904b33ef17..ae6753e590 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/UserRepository.cs @@ -169,6 +169,7 @@ public Task IsOwnCompanyUserWithEmailExisting(string email, Guid companyId public Task GetOwnCompanyUserDetailsUntrackedAsync(Guid companyUserId, Guid companyId) => _dbContext.CompanyUsers .AsNoTracking() + .AsSplitQuery() .Where(companyUser => companyUser.Id == companyUserId && companyUser.Identity!.UserStatusId == UserStatusId.ACTIVE && @@ -186,12 +187,10 @@ public Task IsOwnCompanyUserWithEmailExisting(string email, Guid companyId offer.Id, offer.UserRoles.Where(role => companyUser.Identity!.IdentityAssignedRoles.Select(x => x.UserRole).Contains(role)).Select(x => x.UserRoleText) )), - companyUser.CompanyUserAssignedIdentityProviders.Select(cuidp => new IdpUserTransferId(cuidp.IdentityProvider!.IamIdentityProvider!.IamIdpAlias, cuidp.ProviderId))) - { - FirstName = companyUser.Firstname, - LastName = companyUser.Lastname, - Email = companyUser.Email - }) + companyUser.CompanyUserAssignedIdentityProviders.Select(cuidp => new IdpUserTransferId(cuidp.IdentityProvider!.IamIdentityProvider!.IamIdpAlias, cuidp.ProviderId)), + companyUser.Firstname, + companyUser.Lastname, + companyUser.Email)) .SingleOrDefaultAsync(); public Task<(IEnumerable AssignedBusinessPartnerNumbers, bool IsValidUser)> GetOwnCompanyUserWithAssignedBusinessPartnerNumbersUntrackedAsync(Guid companyUserId, Guid companyId) => @@ -229,12 +228,10 @@ public Task IsOwnCompanyUserWithEmailExisting(string email, Guid companyId .Select(admin => new CompanyUserAdminDetails( admin.Id, admin.Email)), - companyUser.CompanyUserAssignedIdentityProviders.Select(cuidp => new IdpUserTransferId(cuidp.IdentityProvider!.IamIdentityProvider!.IamIdpAlias, cuidp.ProviderId))) - { - FirstName = companyUser.Firstname, - LastName = companyUser.Lastname, - Email = companyUser.Email - }) + companyUser.CompanyUserAssignedIdentityProviders.Select(cuidp => new IdpUserTransferId(cuidp.IdentityProvider!.IamIdentityProvider!.IamIdpAlias, cuidp.ProviderId)), + companyUser.Firstname, + companyUser.Lastname, + companyUser.Email)) .SingleOrDefaultAsync(); public Task GetUserWithCompanyIdpAsync(Guid companyUserId) => diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/BatchInsertSeeder.cs b/src/portalbackend/PortalBackend.Migrations/Seeder/BatchInsertSeeder.cs index 3e8471970f..68f92ec9c8 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/BatchInsertSeeder.cs +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/BatchInsertSeeder.cs @@ -147,6 +147,7 @@ private async Task SeedBaseEntity(CancellationToken cancellationToken) await SeedTableForBaseEntity("technical_user_profiles", cancellationToken).ConfigureAwait(false); await SeedTableForBaseEntity("company_ssi_details", cancellationToken).ConfigureAwait(false); await SeedTableForBaseEntity("verified_credential_external_type_use_case_detail_versions", cancellationToken).ConfigureAwait(false); + await SeedTableForBaseEntity("company_certificates", cancellationToken).ConfigureAwait(false); } private async Task SeedTableForBaseEntity(string fileName, CancellationToken cancellationToken) where T : class, IBaseEntity diff --git a/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyCertificate.cs b/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyCertificate.cs index 622c19ad02..4da6f574e2 100644 --- a/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyCertificate.cs +++ b/src/portalbackend/PortalBackend.PortalEntities/Entities/CompanyCertificate.cs @@ -17,13 +17,14 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Base; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Document = Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities.Document; namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities; -public class CompanyCertificate +public class CompanyCertificate : IBaseEntity { private CompanyCertificate() { } diff --git a/src/provisioning/Provisioning.Library/ProvisioningManager.cs b/src/provisioning/Provisioning.Library/ProvisioningManager.cs index 1fbe0178c2..33a77f3f71 100644 --- a/src/provisioning/Provisioning.Library/ProvisioningManager.cs +++ b/src/provisioning/Provisioning.Library/ProvisioningManager.cs @@ -72,8 +72,9 @@ await GetCentralRealmJwksUrlAsync().ConfigureAwait(false) public async ValueTask DeleteSharedIdpRealmAsync(string alias) { - var sharedKeycloak = _Factory.CreateKeycloakClient("shareddelete"); - await sharedKeycloak.DeleteRealmAsync(alias).ConfigureAwait(false); + var deleteSharedKeycloak = await GetSharedKeycloakClient(alias).ConfigureAwait(false); + await deleteSharedKeycloak.DeleteRealmAsync(alias).ConfigureAwait(false); + var sharedKeycloak = _Factory.CreateKeycloakClient("shared"); await DeleteSharedIdpServiceAccountAsync(sharedKeycloak, alias); } diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/CompanyDataBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/CompanyDataBusinessLogicTests.cs index 09bebe92d6..53de568ba0 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/CompanyDataBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/CompanyDataBusinessLogicTests.cs @@ -23,6 +23,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Custodian.Library; using Org.Eclipse.TractusX.Portal.Backend.Framework.DateTimeProvider; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; +using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Extensions; @@ -1070,6 +1071,78 @@ public async Task CheckCompanyCertificateType_WithInvalidCall_ThrowsControllerAr } #endregion + #region GetCompanyCertificateWithBpnNumber + + [Fact] + public async Task GetCompanyCertificateWithNullOrEmptyBpn_ReturnsExpected() + { + // Act + async Task Act() => await _sut.GetCompanyCertificatesByBpn(string.Empty).ToListAsync().ConfigureAwait(false); + + // Assert + var error = await Assert.ThrowsAsync(Act).ConfigureAwait(false); + error.Message.Should().StartWith("businessPartnerNumber must not be empty"); + } + + [Fact] + public async Task GetCompanyCertificateWithNoCompanyId_ReturnsExpected() + { + // Arrange + var companyId = Guid.Empty; + var businessPartnerNumber = "BPNL07800HZ01644"; + + A.CallTo(() => _companyCertificateRepository.GetCompanyIdByBpn(businessPartnerNumber)) + .Returns(companyId); + + // Act + async Task Act() => await _sut.GetCompanyCertificatesByBpn(businessPartnerNumber).ToListAsync().ConfigureAwait(false); + + // Assert + var error = await Assert.ThrowsAsync(Act).ConfigureAwait(false); + error.Message.Should().StartWith($"company does not exist for {businessPartnerNumber}"); + } + + [Fact] + public async Task GetCompanyCertificateWithBpnNumber_WithValidRequest_ReturnsExpected() + { + // Arrange + var companyId = Guid.NewGuid(); + var data = _fixture.Build() + .With(x => x.CompanyCertificateStatus, CompanyCertificateStatusId.ACTIVE) + .With(x => x.CompanyCertificateType, CompanyCertificateTypeId.ISO_9001) + .With(x => x.DocumentId, Guid.NewGuid()) + .With(x => x.ValidFrom, DateTime.UtcNow) + .With(x => x.ValidTill, DateTime.UtcNow) + .CreateMany(5).ToAsyncEnumerable(); + A.CallTo(() => _companyCertificateRepository.GetCompanyIdByBpn("BPNL07800HZ01643")) + .Returns(companyId); + A.CallTo(() => _companyCertificateRepository.GetCompanyCertificateData(companyId)) + .Returns(data); + + // Act + var result = await _sut.GetCompanyCertificatesByBpn("BPNL07800HZ01643").ToListAsync().ConfigureAwait(false); + + // Assert + result.Should().HaveCount(5); + } + + [Fact] + public async Task GetCompanyCertificateWithBpnNumber_WithEmptyResult_ReturnsExpected() + { + // Arrange + var companyId = Guid.NewGuid(); + A.CallTo(() => _companyCertificateRepository.GetCompanyIdByBpn("BPNL07800HZ01643")) + .Returns(companyId); + + // Act + var result = await _sut.GetCompanyCertificatesByBpn("BPNL07800HZ01643").ToListAsync().ConfigureAwait(false); + + // Assert + result.Should().BeEmpty(); + } + + #endregion + #region GetCredentials [Fact] @@ -1564,6 +1637,39 @@ public async Task GetCertificateTypes_WithFilter_ReturnsList() #endregion + #region GetAllCompanyCertificates + + [Fact] + public async Task GetAllCompanyCertificatesAsync_WithDefaultRequest_GetsExpectedEntries() + { + // Arrange + SetupPagination(); + var sut = _fixture.Create(); + + // Act + var result = await sut.GetAllCompanyCertificatesAsync(0, 5, null, null, null); + + // Assert + result.Content.Should().HaveCount(3); + } + + [Fact] + public async Task GetAllCompanyCertificatesAsync_WithSmallSize_GetsExpectedEntries() + { + // Arrange + const int expectedCount = 3; + SetupPagination(expectedCount); + var sut = _fixture.Create(); + + // Act + var result = await sut.GetAllCompanyCertificatesAsync(0, expectedCount, null, null, null); + + // Assert + result.Content.Should().HaveCount(expectedCount); + } + + #endregion + #region Setup private void SetupCreateUseCaseParticipation() @@ -1590,5 +1696,16 @@ private void SetupCreateCompanyCertificate() .Returns(false); } + private void SetupPagination(int count = 5) + { + var companyCertificateDetailData = _fixture.CreateMany(count); + var paginationResult = (int skip, int take) => Task.FromResult(new Pagination.Source(companyCertificateDetailData.Count(), companyCertificateDetailData.Skip(skip).Take(take))); + + A.CallTo(() => _companyCertificateRepository.GetActiveCompanyCertificatePaginationSource(A._, A._, A._, A._)) + .Returns(paginationResult); + + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_companyCertificateRepository); + } + #endregion } diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs index d6f76690e1..ac510e8b7a 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/UserBusinessLogicTests.cs @@ -1512,6 +1512,9 @@ public async Task GetOwnUserDetails_ReturnsExpected() result.CreatedAt.Should().Be(companyOwnUserDetails.CreatedAt); result.CompanyUserId.Should().Be(companyOwnUserDetails.CompanyUserId); result.BusinessPartnerNumbers.Should().BeSameAs(companyOwnUserDetails.BusinessPartnerNumbers); + result.FirstName.Should().Be(companyOwnUserDetails.FirstName); + result.LastName.Should().Be(companyOwnUserDetails.LastName); + result.Email.Should().Be(companyOwnUserDetails.Email); } [Fact] @@ -1536,6 +1539,57 @@ public async Task GetOwnUserDetails_ThrowsNotFoundException() #endregion + #region GetOwnCompanyUserDetailsAsync + + [Fact] + public async Task GetOwnCompanyUserDetailsAsync_ReturnsExpected() + { + // Arrange + var companyOwnUserDetails = _fixture.Create(); + var userId = Guid.NewGuid(); + var companyId = Guid.NewGuid(); + A.CallTo(() => _identity.CompanyId).Returns(companyId); + + A.CallTo(() => _userRepository.GetOwnCompanyUserDetailsUntrackedAsync(A._, A._)) + .Returns(companyOwnUserDetails); + var sut = new UserBusinessLogic(_provisioningManager, null!, null!, _portalRepositories, _identityService, null!, _logger, _options); + + // Act + var result = await sut.GetOwnCompanyUserDetailsAsync(userId).ConfigureAwait(false); + + // Assert + A.CallTo(() => _userRepository.GetOwnCompanyUserDetailsUntrackedAsync(userId, companyId)).MustHaveHappenedOnceExactly(); + result.CompanyName.Should().Be(companyOwnUserDetails.CompanyName); + result.CreatedAt.Should().Be(companyOwnUserDetails.CreatedAt); + result.CompanyUserId.Should().Be(companyOwnUserDetails.CompanyUserId); + result.BusinessPartnerNumbers.Should().BeSameAs(companyOwnUserDetails.BusinessPartnerNumbers); + result.FirstName.Should().Be(companyOwnUserDetails.FirstName); + result.LastName.Should().Be(companyOwnUserDetails.LastName); + result.Email.Should().Be(companyOwnUserDetails.Email); + } + + [Fact] + public async Task GetOwnCompanyUserDetailsAsync_ThrowsNotFoundException() + { + // Arrange + var userId = Guid.NewGuid(); + var companyId = Guid.NewGuid(); + A.CallTo(() => _identity.CompanyId).Returns(companyId); + A.CallTo(() => _userRepository.GetOwnCompanyUserDetailsUntrackedAsync(A._, A._)) + .Returns((CompanyUserDetailTransferData)default!); + var sut = new UserBusinessLogic(_provisioningManager, null!, null!, _portalRepositories, _identityService, null!, _logger, _options); + + // Act + async Task Act() => await sut.GetOwnCompanyUserDetailsAsync(userId).ConfigureAwait(false); + + // Assert + var error = await Assert.ThrowsAsync(Act).ConfigureAwait(false); + error.Message.Should().Be($"no company-user data found for user {userId} in company {companyId}"); + A.CallTo(() => _userRepository.GetOwnCompanyUserDetailsUntrackedAsync(userId, companyId)).MustHaveHappenedOnceExactly(); + } + + #endregion + #region Setup private void SetupFakesForUserCreation(bool isBulkUserCreation) diff --git a/tests/endtoend/NotificationInitScenario/ModifyCoreUserRoleScenario.cs b/tests/endtoend/NotificationInitScenario/ModifyCoreUserRoleScenario.cs index b22b1c7dc6..cfd1202c9c 100644 --- a/tests/endtoend/NotificationInitScenario/ModifyCoreUserRoleScenario.cs +++ b/tests/endtoend/NotificationInitScenario/ModifyCoreUserRoleScenario.cs @@ -18,6 +18,7 @@ ********************************************************************************/ using FluentAssertions; +using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using RestAssured.Response.Logging; @@ -190,6 +191,14 @@ private string GetCompanyUserId() { throw new Exception($"Could not get company user details from {endpoint} should not be null."); } + if (companyUserDetails.FirstName is null) + { + throw new Exception($"Company user details from {endpoint} should not return firstName null"); + } + if (companyUserDetails.LastName is null) + { + throw new Exception($"Company user details from {endpoint} should not return lastName null"); + } _username = companyUserDetails.FirstName + " " + companyUserDetails.LastName; return companyUserDetails.CompanyUserId.ToString(); } diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyCertificateRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyCertificateRepositoryTests.cs index 27ef55f21e..846d866b8c 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyCertificateRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyCertificateRepositoryTests.cs @@ -17,7 +17,7 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -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; @@ -81,9 +81,110 @@ public async Task CreateCompanyCertificateData_WithValidData_ReturnsExpected() .Which.Entity.Should().BeOfType() .Which.CompanyCertificateStatusId.Should().Be(CompanyCertificateStatusId.ACTIVE); } + + #endregion + + #region GetAllCertificateData + + [Theory] + [InlineData(CertificateSorting.CertificateTypeAsc)] + [InlineData(CertificateSorting.CertificateTypeDesc)] + public async Task GetAllCertificates_ReturnsExpectedResult(CertificateSorting sorting) + { + // Arrange + var sut = await CreateSut().ConfigureAwait(false); + + // Act + var companyCertificateDetail = await sut.GetActiveCompanyCertificatePaginationSource(sorting, null, null, new Guid("2dc4249f-b5ca-4d42-bef1-7a7a950a4f87"))(0, 15).ConfigureAwait(false); + + // Assert + companyCertificateDetail.Should().NotBeNull(); + companyCertificateDetail!.Count.Should().Be(8); + companyCertificateDetail.Data.Should().HaveCount(8); + if (sorting == CertificateSorting.CertificateTypeAsc) + { + companyCertificateDetail.Data.Select(data => data.companyCertificateType).Should().BeInAscendingOrder(); + } + + if (sorting == CertificateSorting.CertificateTypeDesc) + { + companyCertificateDetail.Data.Select(data => data.companyCertificateType).Should().BeInDescendingOrder(); + } + } + + [Theory] + [InlineData(CompanyCertificateStatusId.ACTIVE, CompanyCertificateTypeId.AEO_CTPAT_Security_Declaration, 0, 2, 1, 1)] + [InlineData(CompanyCertificateStatusId.ACTIVE, CompanyCertificateTypeId.ISO_9001, 0, 2, 1, 1)] + [InlineData(CompanyCertificateStatusId.INACTVIE, CompanyCertificateTypeId.IATF, 0, 2, 0, 0)] + public async Task GetAllCertificates_WithExistingCompanyCertificateAndCertificateType_ReturnsExpectedResult(CompanyCertificateStatusId companyCertificateStatusId, CompanyCertificateTypeId companyCertificateTypeId, int page, int size, int count, int numData) + { + // Arrange + var sut = await CreateSut().ConfigureAwait(false); + + // Act + var companyCertificateDetail = await sut.GetActiveCompanyCertificatePaginationSource(null, companyCertificateStatusId, companyCertificateTypeId, new Guid("2dc4249f-b5ca-4d42-bef1-7a7a950a4f87"))(page, size).ConfigureAwait(false); + + // Assert + if (count == 0) + { + companyCertificateDetail.Should().BeNull(); + } + else + { + companyCertificateDetail.Should().NotBeNull(); + companyCertificateDetail!.Count.Should().Be(count); + companyCertificateDetail.Data.Should().HaveCount(numData); + } + } + + #endregion + + #region GetCompanyCertificatesBpn + + [Fact] + public async Task GetCompanyId_WithExistingData() + { + // Arrange + var sut = await CreateSut(); + + // Act + var result = await sut.GetCompanyIdByBpn("BPNL07800HZ01643").ConfigureAwait(false); + + // Assert + result.Should().NotBe(Guid.Empty); + result.Should().Be(new Guid("3390c2d7-75c1-4169-aa27-6ce00e1f3cdd")); + } + + [Fact] + public async Task GetCompanyId_WithNoExistingData() + { + // Arrange + var sut = await CreateSut(); + + // Act + var result = await sut.GetCompanyIdByBpn("BPNL07800HZ01644").ConfigureAwait(false); + + // Assert + result.Should().Be(Guid.Empty); + } + + [Fact] + public async Task GetCompanyCertificateData_NoResults_ReturnsExpected() + { + // Arrange + var sut = await CreateSut(); + + // Act + var result = await sut.GetCompanyCertificateData(Guid.NewGuid()).ToListAsync().ConfigureAwait(false); + + // Assert + result.Should().BeEmpty(); + } + #endregion #region Setup + private async Task CreateSut() { var context = await _dbTestDbFixture.GetPortalDbContext().ConfigureAwait(false); diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_certificates.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_certificates.test.json new file mode 100644 index 0000000000..cdb3fe2b4d --- /dev/null +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_certificates.test.json @@ -0,0 +1,74 @@ +[ + { + "id": "9f5b9934-4014-4099-91e9-7b1aee696c05", + "valid_from": "2023-06-01 00:00:00.000000 +00:00", + "valid_till": "2024-03-23 00:00:00.000000 +00:00", + "company_certificate_type_id": 1, + "company_certificate_status_id": 1, + "company_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87", + "document_id": "5adbdf90-c6ef-47a5-b596-2f00a731c39b" + }, + { + "id": "9f5b9934-4014-4099-91e9-7b1aee696c06", + "valid_from": "2023-06-05 00:00:00.000000 +00:00", + "valid_till": "2024-03-15 00:00:00.000000 +00:00", + "company_certificate_type_id": 2, + "company_certificate_status_id": 1, + "company_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87", + "document_id": "e020787d-1e04-4c0b-9c06-bd1cd44724b1" + }, + { + "id": "9f5b9934-4014-4099-91e9-7b1aee696c07", + "valid_from": "2023-06-08 00:00:00.000000 +00:00", + "valid_till": "2024-03-25 00:00:00.000000 +00:00", + "company_certificate_type_id": 3, + "company_certificate_status_id": 1, + "company_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87", + "document_id": "5adbdf90-c6ef-47a5-b596-2f00a731c39a" + }, + { + "id": "9f5b9934-4014-4099-91e9-7b1aee696c08", + "valid_from": "2023-06-14 00:00:00.000000 +00:00", + "valid_till": "2024-04-09 00:00:00.000000 +00:00", + "company_certificate_type_id": 4, + "company_certificate_status_id": 1, + "company_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87", + "document_id": "3291cae8-3c7b-4862-8cec-93ea0dc8c61e" + }, + { + "id": "9f5b9934-4014-4099-91e9-7b1aee696c09", + "valid_from": "2023-06-13 00:00:00.000000 +00:00", + "valid_till": "2024-04-22 00:00:00.000000 +00:00", + "company_certificate_type_id": 5, + "company_certificate_status_id": 1, + "company_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87", + "document_id": "e020787d-1e04-4c0b-9c06-bd1cd44724b2" + }, + { + "id": "9f5b9934-4014-4099-91e9-7b1aee696c10", + "valid_from": "2023-06-11 00:00:00.000000 +00:00", + "valid_till": "2024-04-23 00:00:00.000000 +00:00", + "company_certificate_type_id": 6, + "company_certificate_status_id": 1, + "company_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87", + "document_id": "9685f744-9d90-4102-a949-fcd0bb86f954" + }, + { + "id": "9f5b9934-4014-4099-91e9-7b1aee696c11", + "valid_from": "2023-06-11 00:00:00.000000 +00:00", + "valid_till": "2024-04-25 00:00:00.000000 +00:00", + "company_certificate_type_id": 1, + "company_certificate_status_id": 2, + "company_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87", + "document_id": "88793f9f-c5a4-4621-847b-3d47cd839283" + }, + { + "id": "9f5b9934-4014-4099-91e9-7b1aee696c12", + "valid_from": "2023-06-07 00:00:00.000000 +00:00", + "valid_till": "2024-04-26 00:00:00.000000 +00:00", + "company_certificate_type_id": 2, + "company_certificate_status_id": 2, + "company_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87", + "document_id": "88793f9f-c5a4-4621-847b-3d47cd839283" + } +]