diff --git a/src/marketplace/Apps.Service/BusinessLogic/AppChangeBusinessLogic.cs b/src/marketplace/Apps.Service/BusinessLogic/AppChangeBusinessLogic.cs
index 3c492d56d9..5672ff9ef1 100644
--- a/src/marketplace/Apps.Service/BusinessLogic/AppChangeBusinessLogic.cs
+++ b/src/marketplace/Apps.Service/BusinessLogic/AppChangeBusinessLogic.cs
@@ -283,4 +283,17 @@ private async Task UpdateTenantUrlAsyncInternal(Guid offerId, Guid subscriptionI
await _portalRepositories.SaveAsync().ConfigureAwait(false);
}
+
+ ///
+ public async Task GetActiveAppDocumentTypeDataAsync(Guid appId, Guid companyId)
+ {
+ var documentData = new Dictionary>();
+ var results = await _portalRepositories.GetInstance().GetActiveOfferDocumentTypeDataAsync(appId, companyId, OfferTypeId.APP, _settings.ActiveAppDocumentTypeIds).ConfigureAwait(false);
+ var appDocTypeData = results!.GroupBy(d => d.DocumentTypeId).ToDictionary(g => g.Key, g => g.Select(d => new DocumentData(d.DocumentId, d.DocumentName)));
+ foreach (var doctype in _settings.ActiveAppDocumentTypeIds)
+ {
+ documentData.Add(doctype, appDocTypeData.Where(x => x.Key == doctype).SelectMany(x => x.Value));
+ }
+ return new ActiveAppDocumentData(documentData);
+ }
}
diff --git a/src/marketplace/Apps.Service/BusinessLogic/AppsSettings.cs b/src/marketplace/Apps.Service/BusinessLogic/AppsSettings.cs
index 2ecde22d7b..69650d8897 100644
--- a/src/marketplace/Apps.Service/BusinessLogic/AppsSettings.cs
+++ b/src/marketplace/Apps.Service/BusinessLogic/AppsSettings.cs
@@ -183,6 +183,14 @@ public class AppsSettings
[Required]
[DistinctValues("x => x.ClientId")]
public IEnumerable SubscriptionManagerRoles { get; set; } = null!;
+
+ ///
+ /// Active Document Types
+ ///
+ [Required]
+ [EnumEnumeration]
+ [DistinctValues]
+ public IEnumerable ActiveAppDocumentTypeIds { get; set; } = null!;
}
///
diff --git a/src/marketplace/Apps.Service/BusinessLogic/IAppChangeBusinessLogic.cs b/src/marketplace/Apps.Service/BusinessLogic/IAppChangeBusinessLogic.cs
index 9a3cf710db..72e375a80f 100644
--- a/src/marketplace/Apps.Service/BusinessLogic/IAppChangeBusinessLogic.cs
+++ b/src/marketplace/Apps.Service/BusinessLogic/IAppChangeBusinessLogic.cs
@@ -76,4 +76,11 @@ public interface IAppChangeBusinessLogic
/// the data to update the url
///
Task UpdateTenantUrlAsync(Guid offerId, Guid subscriptionId, UpdateTenantData data, Guid companyId);
+
+ ///
+ /// Gets the Active App Documents
+ ///
+ /// Id of the offer
+ ///
+ Task GetActiveAppDocumentTypeDataAsync(Guid appId, Guid companyId);
}
diff --git a/src/marketplace/Apps.Service/Controllers/AppChangeController.cs b/src/marketplace/Apps.Service/Controllers/AppChangeController.cs
index cc72f0d7b6..fb04d8283d 100644
--- a/src/marketplace/Apps.Service/Controllers/AppChangeController.cs
+++ b/src/marketplace/Apps.Service/Controllers/AppChangeController.cs
@@ -186,4 +186,19 @@ public async Task UpdateTenantUrl([FromRoute] Guid appId, [From
await this.WithCompanyId(companyId => _businessLogic.UpdateTenantUrlAsync(appId, subscriptionId, data, companyId)).ConfigureAwait(false);
return NoContent();
}
+
+ ///
+ /// Returns the Active App Documents
+ ///
+ /// Id of the app.
+ /// Example: GET /apps/appchange/{appId}/documents
+ /// Gets the Active Apps documents
+ /// If App does not exists
+ [HttpGet]
+ [Route("{appId}/documents")]
+ [Authorize(Roles = "edit_apps")]
+ [ProducesResponseType(typeof(ActiveAppDocumentData), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)]
+ public async Task GetActiveAppDocuments([FromRoute] Guid appId) =>
+ await this.WithCompanyId(companyId => _businessLogic.GetActiveAppDocumentTypeDataAsync(appId, companyId)).ConfigureAwait(false);
}
diff --git a/src/marketplace/Apps.Service/ViewModels/AppData.cs b/src/marketplace/Apps.Service/ViewModels/AppData.cs
index 7f03d03e9f..c923c85e1c 100644
--- a/src/marketplace/Apps.Service/ViewModels/AppData.cs
+++ b/src/marketplace/Apps.Service/ViewModels/AppData.cs
@@ -18,6 +18,7 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
+using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;
namespace Org.Eclipse.TractusX.Portal.Backend.Apps.Service.ViewModels;
@@ -43,3 +44,9 @@ public record AppData(
string Price,
Guid LeadPictureId,
IEnumerable UseCases);
+
+///
+/// View model of an application's base data.
+///
+/// Id of the App.
+public record ActiveAppDocumentData(IDictionary> Documents);
diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferRepository.cs
index 0ebf3efd4f..85d36a2a5c 100644
--- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferRepository.cs
+++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferRepository.cs
@@ -487,4 +487,13 @@ public interface IOfferRepository
///
///
Task<(bool IsSingleInstance, IEnumerable> ServiceAccountProfiles, string? OfferName)> GetServiceAccountProfileDataForSubscription(Guid subscriptionId);
+
+ ///
+ /// Gets the Active Offer DocumentType Data
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task?> GetActiveOfferDocumentTypeDataAsync(Guid offerId, Guid userCompanyId, OfferTypeId offerTypeId, IEnumerable documentTypeIds);
}
diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferRepository.cs
index fd451d0852..6404d394bc 100644
--- a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferRepository.cs
+++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferRepository.cs
@@ -822,4 +822,19 @@ public void AttachAndModifyAppInstanceSetup(Guid appInstanceSetupId, Guid offerI
o.Offer.Name
))
.SingleOrDefaultAsync();
+
+ ///
+ public Task?> GetActiveOfferDocumentTypeDataAsync(Guid offerId, Guid userCompanyId, OfferTypeId offerTypeId, IEnumerable documentTypeIds) =>
+ _context.Offers
+ .Where(o => o.Id == offerId &&
+ o.OfferStatusId == OfferStatusId.ACTIVE &&
+ o.OfferTypeId == offerTypeId &&
+ o.ProviderCompanyId == userCompanyId)
+ .Select(o => o.Documents.Where(doc => documentTypeIds.Contains(doc.DocumentTypeId))
+ .Select(doc => new DocumentTypeData(
+ doc.DocumentTypeId,
+ doc.Id,
+ doc.DocumentName)))
+ .SingleOrDefaultAsync();
+
}
diff --git a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs
index 77fdd705ba..28f32cfaff 100644
--- a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs
+++ b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppChangeBusinessLogicTest.cs
@@ -22,7 +22,10 @@
using AutoFixture.AutoFakeItEasy;
using FakeItEasy;
using FluentAssertions;
+using Flurl.Util;
using Microsoft.Extensions.Options;
+using MimeKit.Encodings;
+using Org.BouncyCastle.Utilities.Collections;
using Org.Eclipse.TractusX.Portal.Backend.Apps.Service.ViewModels;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration;
@@ -92,6 +95,13 @@ public AppChangeBusinessLogicTest()
CompanyAdminRoles = new[]
{
new UserRoleConfig(ClientId, new [] { "Company Admin" })
+ },
+ ActiveAppDocumentTypeIds = new[]
+ {
+ DocumentTypeId.APP_IMAGE,
+ DocumentTypeId.APP_TECHNICAL_INFORMATION,
+ DocumentTypeId.APP_CONTRACT,
+ DocumentTypeId.ADDITIONAL_DETAILS
}
};
A.CallTo(() => _portalRepositories.GetInstance()).Returns(_notificationRepository);
@@ -941,4 +951,35 @@ public async Task UpdateTenantUrlAsync_WithoutSubscriptionDetails_ThrowsConflict
}
#endregion
+
+ #region GetActiveAppDocumentTypeDataAsync
+
+ [Fact]
+ public async Task GetActiveAppDocumentTypeDataAsync_ReturnsExpected()
+ {
+ // Arrange
+ var appId = _fixture.Create();
+ var documentId1 = _fixture.Create();
+ var documenntData = new[] {
+ new DocumentTypeData(DocumentTypeId.APP_IMAGE, documentId1, "TestDoc1")
+ };
+
+ A.CallTo(() => _offerRepository.GetActiveOfferDocumentTypeDataAsync(A._, A._, OfferTypeId.APP, A>._))
+ .Returns(documenntData);
+
+ // Act
+ var result = await _sut.GetActiveAppDocumentTypeDataAsync(appId, _identity.CompanyId).ConfigureAwait(false);
+
+ // Assert
+ A.CallTo(() => _offerRepository.GetActiveOfferDocumentTypeDataAsync(A._, A._, OfferTypeId.APP, A>._)).MustHaveHappened();
+ result.Documents.Should().NotBeNull().And.HaveCount(4).And.Satisfy(
+ x => x.Key == DocumentTypeId.APP_IMAGE && x.Value.Any(y => y!.DocumentId == documentId1 && y.DocumentName == "TestDoc1"),
+ x => x.Key == DocumentTypeId.APP_TECHNICAL_INFORMATION && !x.Value.Any(),
+ x => x.Key == DocumentTypeId.APP_CONTRACT && !x.Value.Any(),
+ x => x.Key == DocumentTypeId.ADDITIONAL_DETAILS && !x.Value.Any()
+ );
+ }
+
+ #endregion
+
}
diff --git a/tests/marketplace/Apps.Service.Tests/Controllers/AppChangeControllerTest.cs b/tests/marketplace/Apps.Service.Tests/Controllers/AppChangeControllerTest.cs
index 4ac2a93396..9b76076546 100644
--- a/tests/marketplace/Apps.Service.Tests/Controllers/AppChangeControllerTest.cs
+++ b/tests/marketplace/Apps.Service.Tests/Controllers/AppChangeControllerTest.cs
@@ -147,4 +147,18 @@ public async Task UpdateTenantUrl_ReturnsExpected()
A.CallTo(() => _logic.UpdateTenantUrlAsync(appId, subscriptionId, data, _identity.CompanyId)).MustHaveHappened();
result.Should().BeOfType();
}
+
+ [Fact]
+ public async Task GetActiveAppDocuments_ReturnsExpected()
+ {
+ //Arrange
+ var appId = _fixture.Create();
+
+ //Act
+ await this._controller.GetActiveAppDocuments(appId).ConfigureAwait(false);
+
+ //Assert
+ A.CallTo(() => _logic.GetActiveAppDocumentTypeDataAsync(appId, _identity.CompanyId)).MustHaveHappened();
+
+ }
}
diff --git a/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json b/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json
index 643dcfd6a3..8e4a9b34f3 100644
--- a/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json
+++ b/tests/marketplace/Apps.Service.Tests/appsettings.IntegrationTests.json
@@ -111,6 +111,12 @@
"APP_TECHNICAL_INFORMATION",
"CONFORMITY_APPROVAL_BUSINESS_APPS"
],
+ "ActiveAppDocumentTypeIds": [
+ "APP_IMAGE",
+ "APP_TECHNICAL_INFORMATION",
+ "APP_CONTRACT",
+ "ADDITIONAL_DETAILS"
+ ],
"ITAdminRoles": [
{
"ClientId": "Cl2-CX-Portal",
diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferRepositoryTests.cs
index 10d41d9697..68ebba0675 100644
--- a/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferRepositoryTests.cs
+++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferRepositoryTests.cs
@@ -1377,6 +1377,31 @@ public async Task GetCompanyProvidedServiceStatusDataAsync_ReturnsExpectedResult
#endregion
+ #region GetActiveOfferDocumentTypeData
+
+ [Fact]
+ public async Task GetActiveOfferDocumentTypeDataAsync_ReturnsExpectedResult()
+ {
+ // Arrange
+ var activeDocumentType = new[]{
+ DocumentTypeId.APP_IMAGE,
+ DocumentTypeId.APP_TECHNICAL_INFORMATION,
+ DocumentTypeId.APP_CONTRACT,
+ DocumentTypeId.ADDITIONAL_DETAILS
+ };
+ var sut = await CreateSut().ConfigureAwait(false);
+
+ // Act
+ var result = await sut.GetActiveOfferDocumentTypeDataAsync(new("ac1cf001-7fbc-1f2f-817f-bce0572c0007"), new("2dc4249f-b5ca-4d42-bef1-7a7a950a4f87"), OfferTypeId.APP, activeDocumentType).ConfigureAwait(false);
+
+ // Assert
+ result.Should().NotBeNull().And.HaveCount(1).And.Satisfy(
+ x => x.DocumentId == new Guid("e020787d-1e04-4c0b-9c06-bd1cd44724b2") && x.DocumentName == "Default_App_Image.png" && x.DocumentTypeId == DocumentTypeId.APP_IMAGE
+ );
+ }
+
+ #endregion
+
#region Setup
private async Task CreateSut()