From 586a5954124b270154ce3209b9f96c81b5c37c76 Mon Sep 17 00:00:00 2001 From: AnuragNagpure <145100366+AnuragNagpure@users.noreply.github.com> Date: Mon, 15 Jan 2024 16:57:19 +0530 Subject: [PATCH] feat(search): offer subscription enable search by company name (#373) Refs: CPLP-3459 Co-authored-by: Phil Schneider Reviewed-by: Phil Schneider --- .../Framework.Models/ValidationExpressions.cs | 1 + .../BusinessLogic/AppsBusinessLogic.cs | 11 ++++- .../BusinessLogic/IAppsBusinessLogic.cs | 2 +- .../Controllers/AppsController.cs | 4 +- .../BusinessLogic/IServiceBusinessLogic.cs | 2 +- .../BusinessLogic/ServiceBusinessLogic.cs | 10 +++- .../Controllers/ServicesController.cs | 4 +- .../IOfferSubscriptionsRepository.cs | 2 +- .../OfferSubscriptionsRepository.cs | 7 ++- .../BusinessLogic/AppBusinessLogicTests.cs | 18 +++---- .../Controllers/AppsControllerTests.cs | 4 +- .../ServiceBusinessLogicTests.cs | 18 +++---- .../Controllers/ServiceControllerTest.cs | 4 +- .../OfferSubscriptionRepositoryTest.cs | 49 ++++++++++++------- .../OfferSubscriptionViewTests.cs | 2 +- .../Seeder/Data/offer_subscriptions.test.json | 10 ++++ 16 files changed, 95 insertions(+), 53 deletions(-) diff --git a/src/framework/Framework.Models/ValidationExpressions.cs b/src/framework/Framework.Models/ValidationExpressions.cs index e65b0f3757..94d446ded3 100644 --- a/src/framework/Framework.Models/ValidationExpressions.cs +++ b/src/framework/Framework.Models/ValidationExpressions.cs @@ -24,4 +24,5 @@ public static class ValidationExpressions { public const string Name = @"^.+$"; // TODO: should be @"^(([A-Za-zÀ-ÿ]{1,40}?([-,.'\s]?[A-Za-zÀ-ÿ]{1,40}?)){1,8})$"; public const string Bpn = @"^(BPNL|bpnl)[\w|\d]{12}$"; + public const string Company = @"^\d*?[A-Za-zÀ-ÿ]\d?([A-Za-z0-9À-ÿ-_+=.,:;!?'\x22&#@()]\s?){3,80}$"; } diff --git a/src/marketplace/Apps.Service/BusinessLogic/AppsBusinessLogic.cs b/src/marketplace/Apps.Service/BusinessLogic/AppsBusinessLogic.cs index cc65343a83..ce7ef41776 100644 --- a/src/marketplace/Apps.Service/BusinessLogic/AppsBusinessLogic.cs +++ b/src/marketplace/Apps.Service/BusinessLogic/AppsBusinessLogic.cs @@ -31,6 +31,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.PortalBackend.PortalEntities.Identities; +using System.Text.RegularExpressions; namespace Org.Eclipse.TractusX.Portal.Backend.Apps.Service.BusinessLogic; @@ -39,6 +40,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Apps.Service.BusinessLogic; /// public class AppsBusinessLogic : IAppsBusinessLogic { + private static readonly Regex Company = new(ValidationExpressions.Company, RegexOptions.Compiled, TimeSpan.FromSeconds(1)); private readonly IPortalRepositories _portalRepositories; private readonly IOfferSubscriptionService _offerSubscriptionService; private readonly AppsSettings _settings; @@ -159,12 +161,17 @@ public async Task AddFavouriteAppForUserAsync(Guid appId) _offerService.GetCompanySubscribedOfferSubscriptionStatusesForUserAsync(page, size, OfferTypeId.APP, DocumentTypeId.APP_LEADIMAGE); /// - public async Task> GetCompanyProvidedAppSubscriptionStatusesForUserAsync(int page, int size, SubscriptionStatusSorting? sorting, OfferSubscriptionStatusId? statusId, Guid? offerId) + public async Task> GetCompanyProvidedAppSubscriptionStatusesForUserAsync(int page, int size, SubscriptionStatusSorting? sorting, OfferSubscriptionStatusId? statusId, Guid? offerId, string? companyName) { + if (!string.IsNullOrWhiteSpace(companyName) && !Company.IsMatch(companyName)) + { + throw new ControllerArgumentException("CompanyName length must be 3-40 characters and *+=#%\\s not used as one of the first three characters in the company name"); + } + async Task?> GetCompanyProvidedAppSubscriptionStatusData(int skip, int take) { var offerCompanySubscriptionResponse = await _portalRepositories.GetInstance() - .GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identityData.CompanyId, OfferTypeId.APP, sorting, OfferSubscriptionService.GetOfferSubscriptionFilterStatusIds(statusId), offerId)(skip, take).ConfigureAwait(false); + .GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identityData.CompanyId, OfferTypeId.APP, sorting, OfferSubscriptionService.GetOfferSubscriptionFilterStatusIds(statusId), offerId, companyName)(skip, take).ConfigureAwait(false); return offerCompanySubscriptionResponse == null ? null diff --git a/src/marketplace/Apps.Service/BusinessLogic/IAppsBusinessLogic.cs b/src/marketplace/Apps.Service/BusinessLogic/IAppsBusinessLogic.cs index 8d3dc1f1b4..c8901ebf5e 100644 --- a/src/marketplace/Apps.Service/BusinessLogic/IAppsBusinessLogic.cs +++ b/src/marketplace/Apps.Service/BusinessLogic/IAppsBusinessLogic.cs @@ -87,7 +87,7 @@ public interface IAppsBusinessLogic /// /// /// Async enumberable of user's company's provided apps' statuses. - public Task> GetCompanyProvidedAppSubscriptionStatusesForUserAsync(int page, int size, SubscriptionStatusSorting? sorting, OfferSubscriptionStatusId? statusId, Guid? offerId); + public Task> GetCompanyProvidedAppSubscriptionStatusesForUserAsync(int page, int size, SubscriptionStatusSorting? sorting, OfferSubscriptionStatusId? statusId, Guid? offerId, string? companyName = null); /// /// Adds a subscription relation between an application and a user's company. diff --git a/src/marketplace/Apps.Service/Controllers/AppsController.cs b/src/marketplace/Apps.Service/Controllers/AppsController.cs index 0a933629d7..b710f0f5e4 100644 --- a/src/marketplace/Apps.Service/Controllers/AppsController.cs +++ b/src/marketplace/Apps.Service/Controllers/AppsController.cs @@ -176,8 +176,8 @@ public async Task RemoveFavouriteAppForCurrentUserAsync([FromRout [Authorize(Roles = "view_app_subscription")] [Authorize(Policy = PolicyTypes.ValidCompany)] [ProducesResponseType(typeof(Pagination.Response), StatusCodes.Status200OK)] - public Task> GetCompanyProvidedAppSubscriptionStatusesForCurrentUserAsync([FromQuery] int page = 0, [FromQuery] int size = 15, [FromQuery] SubscriptionStatusSorting? sorting = null, [FromQuery] OfferSubscriptionStatusId? statusId = null, [FromQuery] Guid? offerId = null) => - _appsBusinessLogic.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(page, size, sorting, statusId, offerId); + public Task> GetCompanyProvidedAppSubscriptionStatusesForCurrentUserAsync([FromQuery] int page = 0, [FromQuery] int size = 15, [FromQuery] SubscriptionStatusSorting? sorting = null, [FromQuery] OfferSubscriptionStatusId? statusId = null, [FromQuery] Guid? offerId = null, [FromQuery] string? companyName = null) => + _appsBusinessLogic.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(page, size, sorting, statusId, offerId, companyName); /// /// Adds an app to current user's company's subscriptions. diff --git a/src/marketplace/Services.Service/BusinessLogic/IServiceBusinessLogic.cs b/src/marketplace/Services.Service/BusinessLogic/IServiceBusinessLogic.cs index 4f6079b9d4..0bffea2a40 100644 --- a/src/marketplace/Services.Service/BusinessLogic/IServiceBusinessLogic.cs +++ b/src/marketplace/Services.Service/BusinessLogic/IServiceBusinessLogic.cs @@ -90,7 +90,7 @@ public interface IServiceBusinessLogic /// /// /// Pagination of user's company's provided service' statuses. - Task> GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(int page, int size, SubscriptionStatusSorting? sorting, OfferSubscriptionStatusId? statusId, Guid? offerId); + Task> GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(int page, int size, SubscriptionStatusSorting? sorting, OfferSubscriptionStatusId? statusId, Guid? offerId, string? companyName = null); /// /// Get the document content by given Id for Service diff --git a/src/marketplace/Services.Service/BusinessLogic/ServiceBusinessLogic.cs b/src/marketplace/Services.Service/BusinessLogic/ServiceBusinessLogic.cs index b54edfa844..3b5b28acb2 100644 --- a/src/marketplace/Services.Service/BusinessLogic/ServiceBusinessLogic.cs +++ b/src/marketplace/Services.Service/BusinessLogic/ServiceBusinessLogic.cs @@ -30,6 +30,7 @@ using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Identities; using Org.Eclipse.TractusX.Portal.Backend.Services.Service.ViewModels; +using System.Text.RegularExpressions; namespace Org.Eclipse.TractusX.Portal.Backend.Services.Service.BusinessLogic; @@ -38,6 +39,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Services.Service.BusinessLogic; /// public class ServiceBusinessLogic : IServiceBusinessLogic { + private static readonly Regex Company = new(ValidationExpressions.Company, RegexOptions.Compiled, TimeSpan.FromSeconds(1)); private readonly IPortalRepositories _portalRepositories; private readonly IOfferService _offerService; private readonly IOfferSubscriptionService _offerSubscriptionService; @@ -136,12 +138,16 @@ public Task AutoSetupServiceAsync(OfferAutoSetupData _offerSetupService.AutoSetupOfferAsync(data, _settings.ITAdminRoles, OfferTypeId.SERVICE, _settings.UserManagementAddress, _settings.ServiceManagerRoles); /// - public async Task> GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(int page, int size, SubscriptionStatusSorting? sorting, OfferSubscriptionStatusId? statusId, Guid? offerId) + public async Task> GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(int page, int size, SubscriptionStatusSorting? sorting, OfferSubscriptionStatusId? statusId, Guid? offerId, string? companyName) { + if (!string.IsNullOrEmpty(companyName) && !Company.IsMatch(companyName)) + { + throw new ControllerArgumentException("CompanyName length must be 3-40 characters and *+=#%\\s not used as one of the first three characters in the company name"); + } async Task?> GetCompanyProvidedAppSubscriptionStatusData(int skip, int take) { var offerCompanySubscriptionResponse = await _portalRepositories.GetInstance() - .GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identityData.CompanyId, OfferTypeId.SERVICE, sorting, OfferSubscriptionService.GetOfferSubscriptionFilterStatusIds(statusId), offerId)(skip, take).ConfigureAwait(false); + .GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identityData.CompanyId, OfferTypeId.SERVICE, sorting, OfferSubscriptionService.GetOfferSubscriptionFilterStatusIds(statusId), offerId, companyName)(skip, take).ConfigureAwait(false); return offerCompanySubscriptionResponse == null ? null diff --git a/src/marketplace/Services.Service/Controllers/ServicesController.cs b/src/marketplace/Services.Service/Controllers/ServicesController.cs index b5729418fc..372337d55c 100644 --- a/src/marketplace/Services.Service/Controllers/ServicesController.cs +++ b/src/marketplace/Services.Service/Controllers/ServicesController.cs @@ -204,8 +204,8 @@ public async Task StartAutoSetupServiceProcess([FromBody] Offer [Authorize(Policy = PolicyTypes.ValidCompany)] [ProducesResponseType(typeof(Pagination.Response), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)] - public Task> GetCompanyProvidedServiceSubscriptionStatusesForCurrentUserAsync([FromQuery] int page = 0, [FromQuery] int size = 15, [FromQuery] SubscriptionStatusSorting? sorting = null, [FromQuery] OfferSubscriptionStatusId? statusId = null, [FromQuery] Guid? offerId = null) => - _serviceBusinessLogic.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(page, size, sorting, statusId, offerId); + public Task> GetCompanyProvidedServiceSubscriptionStatusesForCurrentUserAsync([FromQuery] int page = 0, [FromQuery] int size = 15, [FromQuery] SubscriptionStatusSorting? sorting = null, [FromQuery] OfferSubscriptionStatusId? statusId = null, [FromQuery] Guid? offerId = null, [FromQuery] string? companyName = null) => + _serviceBusinessLogic.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(page, size, sorting, statusId, offerId, companyName); /// /// Retrieve Document Content for Service by ID diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs index c4fa36d1c6..2b08abaeda 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IOfferSubscriptionsRepository.cs @@ -49,7 +49,7 @@ public interface IOfferSubscriptionsRepository /// /// /// Returns a func with skip, take and the pagination of the source - Func?>> GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(Guid userCompanyId, OfferTypeId offerTypeId, SubscriptionStatusSorting? sorting, IEnumerable statusIds, Guid? offerId); + Func?>> GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(Guid userCompanyId, OfferTypeId offerTypeId, SubscriptionStatusSorting? sorting, IEnumerable statusIds, Guid? offerId, string? companyName); Task<(OfferSubscriptionStatusId OfferSubscriptionStatusId, bool IsSubscribingCompany, bool IsValidSubscriptionId, IEnumerable ConnectorIds, IEnumerable ServiceAccounts)> GetCompanyAssignedOfferSubscriptionDataForCompanyUserAsync(Guid subscriptionId, Guid userCompanyId); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs index 45115b49c2..4b04e3d930 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/OfferSubscriptionsRepository.cs @@ -19,6 +19,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; @@ -47,7 +48,7 @@ public OfferSubscription CreateOfferSubscription(Guid offerId, Guid companyId, O _context.OfferSubscriptions.Add(new OfferSubscription(Guid.NewGuid(), offerId, companyId, offerSubscriptionStatusId, requesterId, DateTimeOffset.UtcNow)).Entity; /// - public Func?>> GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(Guid userCompanyId, OfferTypeId offerTypeId, SubscriptionStatusSorting? sorting, IEnumerable statusIds, Guid? offerId) => + public Func?>> GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(Guid userCompanyId, OfferTypeId offerTypeId, SubscriptionStatusSorting? sorting, IEnumerable statusIds, Guid? offerId, string? companyName) => (skip, take) => Pagination.CreateSourceQueryAsync( skip, take, @@ -72,7 +73,9 @@ public OfferSubscription CreateOfferSubscription(Guid offerId, Guid companyId, O OfferId = g.Id, ServiceName = g.Name, CompanySubscriptionStatuses = g.OfferSubscriptions - .Where(os => statusIds.Contains(os.OfferSubscriptionStatusId)) + .Where(os => + statusIds.Contains(os.OfferSubscriptionStatusId) && + (companyName == null || EF.Functions.ILike(os.Company!.Name, $"%{companyName.EscapeForILike()}%"))) .Select(s => new CompanySubscriptionStatusData( s.CompanyId, diff --git a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppBusinessLogicTests.cs b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppBusinessLogicTests.cs index 4782111fa5..7611987f82 100644 --- a/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppBusinessLogicTests.cs +++ b/tests/marketplace/Apps.Service.Tests/BusinessLogic/AppBusinessLogicTests.cs @@ -286,7 +286,7 @@ public async Task GetCompanyProvidedAppSubscriptionStatusesForUserAsync_ReturnsE var iamUserId = _fixture.Create(); Guid? offerId = offerIdTxt == null ? null : new Guid(offerIdTxt); var data = _fixture.CreateMany(5).ToImmutableArray(); - A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._)) + A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._, A._)) .Returns((skip, take) => Task.FromResult(new Pagination.Source(data.Length, data.Skip(skip).Take(take)))!); var appsSettings = new AppsSettings @@ -297,7 +297,7 @@ public async Task GetCompanyProvidedAppSubscriptionStatusesForUserAsync_ReturnsE var sut = new AppsBusinessLogic(_portalRepositories, null!, null!, null!, Options.Create(appsSettings), _identityService, _logger); // Act - var result = await sut.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(0, 10, null, null, offerId).ConfigureAwait(false); + var result = await sut.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(0, 10, null, null, offerId, null).ConfigureAwait(false); // Assert result.Meta.NumberOfElements.Should().Be(5); @@ -308,7 +308,7 @@ public async Task GetCompanyProvidedAppSubscriptionStatusesForUserAsync_ReturnsE x => x.OfferId == data[3].OfferId && x.OfferName == data[3].ServiceName && x.CompanySubscriptionStatuses.Count() == data[3].CompanySubscriptionStatuses.Count() && x.Image == data[3].Image, x => x.OfferId == data[4].OfferId && x.OfferName == data[4].ServiceName && x.CompanySubscriptionStatuses.Count() == data[4].CompanySubscriptionStatuses.Count() && x.Image == data[4].Image ); - A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(CompanyId, OfferTypeId.APP, default, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId)) + A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identity.CompanyId, OfferTypeId.APP, default, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId, null)) .MustHaveHappenedOnceExactly(); } @@ -322,7 +322,7 @@ public async Task GetCompanyProvidedAppSubscriptionStatusesForUserAsync_EmptyIma _fixture.Build().With(x => x.Image, Guid.Empty).Create(), _fixture.Build().With(x => x.Image, Guid.NewGuid()).Create() }; - A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._)) + A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._, A._)) .Returns((skip, take) => Task.FromResult(new Pagination.Source(data.Length, data.Skip(skip).Take(take)))!); var appsSettings = new AppsSettings @@ -333,7 +333,7 @@ public async Task GetCompanyProvidedAppSubscriptionStatusesForUserAsync_EmptyIma var sut = new AppsBusinessLogic(_portalRepositories, null!, null!, null!, Options.Create(appsSettings), _identityService, _logger); // Act - var result = await sut.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(0, 10, null, null, offerId).ConfigureAwait(false); + var result = await sut.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(0, 10, null, null, offerId, null).ConfigureAwait(false); // Assert result.Meta.NumberOfElements.Should().Be(2); @@ -341,7 +341,7 @@ public async Task GetCompanyProvidedAppSubscriptionStatusesForUserAsync_EmptyIma x => x.OfferId == data[0].OfferId && x.OfferName == data[0].ServiceName && x.CompanySubscriptionStatuses.Count() == data[0].CompanySubscriptionStatuses.Count() && x.Image == null, x => x.OfferId == data[1].OfferId && x.OfferName == data[1].ServiceName && x.CompanySubscriptionStatuses.Count() == data[1].CompanySubscriptionStatuses.Count() && x.Image == data[1].Image ); - A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(CompanyId, OfferTypeId.APP, default, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId)) + A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identity.CompanyId, OfferTypeId.APP, default, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId, null)) .MustHaveHappenedOnceExactly(); } @@ -355,7 +355,7 @@ public async Task GetCompanyProvidedAppSubscriptionStatusesForUserAsync_QueryNul _fixture.Build().With(x => x.Image, Guid.Empty).Create(), _fixture.Build().With(x => x.Image, Guid.NewGuid()).Create() }; - A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._)) + A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._, A._)) .Returns((skip, take) => Task.FromResult((Pagination.Source?)null)); var appsSettings = new AppsSettings @@ -366,12 +366,12 @@ public async Task GetCompanyProvidedAppSubscriptionStatusesForUserAsync_QueryNul var sut = new AppsBusinessLogic(_portalRepositories, null!, null!, null!, Options.Create(appsSettings), _identityService, _logger); // Act - var result = await sut.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(0, 10, null, null, offerId).ConfigureAwait(false); + var result = await sut.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(0, 10, null, null, offerId, null).ConfigureAwait(false); // Assert result.Meta.NumberOfElements.Should().Be(0); result.Content.Should().BeEmpty(); - A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(CompanyId, OfferTypeId.APP, default, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId)) + A.CallTo(() => _offerSubscriptionRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identity.CompanyId, OfferTypeId.APP, default, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId, null)) .MustHaveHappenedOnceExactly(); } diff --git a/tests/marketplace/Apps.Service.Tests/Controllers/AppsControllerTests.cs b/tests/marketplace/Apps.Service.Tests/Controllers/AppsControllerTests.cs index 975bc60c43..8b438b9c9e 100644 --- a/tests/marketplace/Apps.Service.Tests/Controllers/AppsControllerTests.cs +++ b/tests/marketplace/Apps.Service.Tests/Controllers/AppsControllerTests.cs @@ -182,14 +182,14 @@ public async Task GetCompanyProvidedAppSubscriptionStatusesForCurrentUserAsync_R var data = _fixture.CreateMany(5); Guid? offerId = offerIdTxt == null ? null : new Guid(offerIdTxt); var pagination = new Pagination.Response(new Pagination.Metadata(data.Count(), 1, 0, data.Count()), data); - A.CallTo(() => _logic.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(A._, A._, A._, A._, A._)) + A.CallTo(() => _logic.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(A._, A._, A._, A._, A._, A._)) .Returns(pagination); //Act var result = await _controller.GetCompanyProvidedAppSubscriptionStatusesForCurrentUserAsync(offerId: offerId).ConfigureAwait(false); //Assert - A.CallTo(() => _logic.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(0, 15, null, null, offerId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _logic.GetCompanyProvidedAppSubscriptionStatusesForUserAsync(0, 15, null, null, offerId, null)).MustHaveHappenedOnceExactly(); result.Content.Should().HaveCount(5); } diff --git a/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs b/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs index 7668b03220..d809270105 100644 --- a/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs +++ b/tests/marketplace/Services.Service.Tests/BusinessLogic/ServiceBusinessLogicTests.cs @@ -198,7 +198,7 @@ public async Task GetCompanyProvidedServiceSubscriptionStatusesForUserAsync_Retu // Arrange Guid? offerId = offerIdTxt == null ? null : new Guid(offerIdTxt); var data = _fixture.CreateMany(5).ToImmutableArray(); - A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._)) + A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._, A._)) .Returns((skip, take) => Task.FromResult(new Pagination.Source(data.Length, data.Skip(skip).Take(take)))!); var serviceSettings = new ServiceSettings @@ -208,7 +208,7 @@ public async Task GetCompanyProvidedServiceSubscriptionStatusesForUserAsync_Retu var sut = new ServiceBusinessLogic(_portalRepositories, null!, null!, null!, _identityService, Options.Create(serviceSettings), _logger); // Act - var result = await sut.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(0, 10, null, null, offerId).ConfigureAwait(false); + var result = await sut.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(0, 10, null, null, offerId, null).ConfigureAwait(false); // Assert result.Meta.NumberOfElements.Should().Be(5); @@ -219,7 +219,7 @@ public async Task GetCompanyProvidedServiceSubscriptionStatusesForUserAsync_Retu x => x.OfferId == data[3].OfferId && x.OfferName == data[3].ServiceName && x.CompanySubscriptionStatuses.Count() == data[3].CompanySubscriptionStatuses.Count() && x.Image == data[3].Image, x => x.OfferId == data[4].OfferId && x.OfferName == data[4].ServiceName && x.CompanySubscriptionStatuses.Count() == data[4].CompanySubscriptionStatuses.Count() && x.Image == data[4].Image ); - A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identity.CompanyId, OfferTypeId.SERVICE, null, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId)) + A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identity.CompanyId, OfferTypeId.SERVICE, null, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId, null)) .MustHaveHappenedOnceExactly(); } @@ -232,7 +232,7 @@ public async Task GetCompanyProvidedServiceSubscriptionStatusesForUserAsync_Empt _fixture.Build().With(x => x.Image, Guid.Empty).Create(), _fixture.Build().With(x => x.Image, Guid.NewGuid()).Create() }; - A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._)) + A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._, A._)) .Returns((skip, take) => Task.FromResult(new Pagination.Source(data.Length, data.Skip(skip).Take(take)))!); var serviceSettings = new ServiceSettings @@ -242,7 +242,7 @@ public async Task GetCompanyProvidedServiceSubscriptionStatusesForUserAsync_Empt var sut = new ServiceBusinessLogic(_portalRepositories, null!, null!, null!, _identityService, Options.Create(serviceSettings), _logger); // Act - var result = await sut.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(0, 10, null, null, offerId).ConfigureAwait(false); + var result = await sut.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(0, 10, null, null, offerId, null).ConfigureAwait(false); // Assert result.Meta.NumberOfElements.Should().Be(2); @@ -250,7 +250,7 @@ public async Task GetCompanyProvidedServiceSubscriptionStatusesForUserAsync_Empt x => x.OfferId == data[0].OfferId && x.OfferName == data[0].ServiceName && x.CompanySubscriptionStatuses.Count() == data[0].CompanySubscriptionStatuses.Count() && x.Image == null, x => x.OfferId == data[1].OfferId && x.OfferName == data[1].ServiceName && x.CompanySubscriptionStatuses.Count() == data[1].CompanySubscriptionStatuses.Count() && x.Image == data[1].Image ); - A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identity.CompanyId, OfferTypeId.SERVICE, null, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId)) + A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identity.CompanyId, OfferTypeId.SERVICE, null, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId, null)) .MustHaveHappenedOnceExactly(); } @@ -263,7 +263,7 @@ public async Task GetCompanyProvidedServiceSubscriptionStatusesForUserAsync_Quer _fixture.Build().With(x => x.Image, Guid.Empty).Create(), _fixture.Build().With(x => x.Image, Guid.NewGuid()).Create() }; - A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._)) + A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(A._, A._, A._, A>._, A._, A._)) .Returns((skip, take) => Task.FromResult((Pagination.Source?)null)); var serviceSettings = new ServiceSettings @@ -273,12 +273,12 @@ public async Task GetCompanyProvidedServiceSubscriptionStatusesForUserAsync_Quer var sut = new ServiceBusinessLogic(_portalRepositories, null!, null!, null!, _identityService, Options.Create(serviceSettings), _logger); // Act - var result = await sut.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(0, 10, null, null, offerId).ConfigureAwait(false); + var result = await sut.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(0, 10, null, null, offerId, null).ConfigureAwait(false); // Assert result.Meta.NumberOfElements.Should().Be(0); result.Content.Should().BeEmpty(); - A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identity.CompanyId, OfferTypeId.SERVICE, null, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId)) + A.CallTo(() => _offerSubscriptionsRepository.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_identity.CompanyId, OfferTypeId.SERVICE, null, A>.That.IsSameSequenceAs(new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.INACTIVE }), offerId, null)) .MustHaveHappenedOnceExactly(); } diff --git a/tests/marketplace/Services.Service.Tests/Controllers/ServiceControllerTest.cs b/tests/marketplace/Services.Service.Tests/Controllers/ServiceControllerTest.cs index 6acd1b3c17..b3e30a2377 100644 --- a/tests/marketplace/Services.Service.Tests/Controllers/ServiceControllerTest.cs +++ b/tests/marketplace/Services.Service.Tests/Controllers/ServiceControllerTest.cs @@ -197,14 +197,14 @@ public async Task GetCompanyProvidedServiceSubscriptionStatusesForCurrentUserAsy Guid? offerId = offerIdTxt == null ? null : new Guid(offerIdTxt); var data = _fixture.CreateMany(5); var pagination = new Pagination.Response(new Pagination.Metadata(data.Count(), 1, 0, data.Count()), data); - A.CallTo(() => _logic.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(A._, A._, A._, A._, A._)) + A.CallTo(() => _logic.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(A._, A._, A._, A._, A._, A._)) .Returns(pagination); //Act var result = await _controller.GetCompanyProvidedServiceSubscriptionStatusesForCurrentUserAsync(offerId: offerId).ConfigureAwait(false); //Assert - A.CallTo(() => _logic.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(0, 15, null, null, offerId)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _logic.GetCompanyProvidedServiceSubscriptionStatusesForUserAsync(0, 15, null, null, offerId, null)).MustHaveHappenedOnceExactly(); result.Content.Should().HaveCount(5); } diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferSubscriptionRepositoryTest.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferSubscriptionRepositoryTest.cs index 42f513be92..405915fb80 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferSubscriptionRepositoryTest.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferSubscriptionRepositoryTest.cs @@ -136,26 +136,26 @@ public async Task GetAllBusinessAppDataForUserIdAsync_WithValidUser_ReturnsExpec #region GetOwnCompanyProvidedOfferSubscriptionStatusesUntracked [Theory] - [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 2, true)] - [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.SERVICE, new OfferSubscriptionStatusId[] { }, 0, false)] - [InlineData(SubscriptionStatusSorting.OfferIdDesc, null, OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 2, false)] - [InlineData(SubscriptionStatusSorting.CompanyNameAsc, null, OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 2, true)] - [InlineData(SubscriptionStatusSorting.CompanyNameDesc, null, OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 2, true)] - [InlineData(SubscriptionStatusSorting.OfferIdAsc, "a16e73b9-5277-4b69-9f8d-3b227495dfea", OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 1, false)] - [InlineData(SubscriptionStatusSorting.OfferIdAsc, "a16e73b9-5277-4b69-9f8d-3b227495dfae", OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 1, true)] - [InlineData(SubscriptionStatusSorting.OfferIdAsc, "deadbeef-dead-beef-dead-beefdeadbeef", OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 0, false)] - [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.APP, new[] { OfferSubscriptionStatusId.ACTIVE }, 1, false)] - [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.APP, new[] { OfferSubscriptionStatusId.INACTIVE }, 1, false)] - [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.APP, new[] { OfferSubscriptionStatusId.PENDING }, 1, false)] - [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.APP, new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE }, 2, false)] - public async Task GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync_ReturnsExpectedNotificationDetailData(SubscriptionStatusSorting sorting, string? offerIdTxt, OfferTypeId offerTypeId, IEnumerable offerSubscriptionStatusIds, int count, bool technicalUser) + [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 2, true, 2)] + [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.SERVICE, new OfferSubscriptionStatusId[] { }, 0, false, 1)] + [InlineData(SubscriptionStatusSorting.OfferIdDesc, null, OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 2, false, 1)] + [InlineData(SubscriptionStatusSorting.CompanyNameAsc, null, OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 2, true, 2)] + [InlineData(SubscriptionStatusSorting.CompanyNameDesc, null, OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 2, true, 2)] + [InlineData(SubscriptionStatusSorting.OfferIdAsc, "a16e73b9-5277-4b69-9f8d-3b227495dfea", OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 1, false, 1)] + [InlineData(SubscriptionStatusSorting.OfferIdAsc, "a16e73b9-5277-4b69-9f8d-3b227495dfae", OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 1, true, 2)] + [InlineData(SubscriptionStatusSorting.OfferIdAsc, "deadbeef-dead-beef-dead-beefdeadbeef", OfferTypeId.SERVICE, new[] { OfferSubscriptionStatusId.ACTIVE }, 0, false, 1)] + [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.APP, new[] { OfferSubscriptionStatusId.ACTIVE }, 1, false, 1)] + [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.APP, new[] { OfferSubscriptionStatusId.INACTIVE }, 1, false, 1)] + [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.APP, new[] { OfferSubscriptionStatusId.PENDING }, 1, false, 1)] + [InlineData(SubscriptionStatusSorting.OfferIdAsc, null, OfferTypeId.APP, new[] { OfferSubscriptionStatusId.PENDING, OfferSubscriptionStatusId.ACTIVE }, 2, false, 1)] + public async Task GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync_ReturnsExpectedNotificationDetailData(SubscriptionStatusSorting sorting, string? offerIdTxt, OfferTypeId offerTypeId, IEnumerable offerSubscriptionStatusIds, int count, bool technicalUser, int companySubscriptionCount) { // Arrange Guid? offerId = offerIdTxt == null ? null : new Guid(offerIdTxt); var (sut, _) = await CreateSut().ConfigureAwait(false); // Act - var results = await sut.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_userCompanyId, offerTypeId, sorting, offerSubscriptionStatusIds, offerId)(0, 15).ConfigureAwait(false); + var results = await sut.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_userCompanyId, offerTypeId, sorting, offerSubscriptionStatusIds, offerId, null)(0, 15).ConfigureAwait(false); // Assert if (count > 0) @@ -163,9 +163,8 @@ public async Task GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync_R results.Should().NotBeNull(); results!.Count.Should().Be(count); results.Data.Should().HaveCount(count); - results.Data.Should().AllBeOfType().Which.First().CompanySubscriptionStatuses.Should().HaveCount(1); - results.Data.Should().AllBeOfType().Which.First().CompanySubscriptionStatuses.Should().Match(x => x.Count() == 1 && x.First().TechnicalUser == technicalUser); - results.Data.Should().AllBeOfType().Which.First().CompanySubscriptionStatuses.Should().Match(x => x.Count() == 1); + results.Data.Should().AllBeOfType().Which.First().CompanySubscriptionStatuses.Should().HaveCount(companySubscriptionCount); + results.Data.Should().AllBeOfType().Which.First().CompanySubscriptionStatuses.Should().Match(x => x.Count() == companySubscriptionCount && x.First().TechnicalUser == technicalUser); } else { @@ -173,6 +172,22 @@ public async Task GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync_R } } + [Fact] + public async Task GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync_WithCompanyFilter_ReturnsExpected() + { + // Arrange + var (sut, _) = await CreateSut().ConfigureAwait(false); + + // Act + var results = await sut.GetOwnCompanyProvidedOfferSubscriptionStatusesUntrackedAsync(_userCompanyId, OfferTypeId.SERVICE, SubscriptionStatusSorting.CompanyNameAsc, new[] { OfferSubscriptionStatusId.ACTIVE, OfferSubscriptionStatusId.PENDING }, null, "catena")(0, 15).ConfigureAwait(false); + + // Assert + results.Should().NotBeNull(); + results!.Count.Should().Be(2); + results.Data.Should().HaveCount(2); + results.Data.Should().AllBeOfType().Which.First().CompanySubscriptionStatuses.Should().HaveCount(1); + } + #endregion #region GetOfferDetailsAndCheckUser diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferSubscriptionViewTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferSubscriptionViewTests.cs index d5eecb2922..04b83acd9d 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferSubscriptionViewTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/OfferSubscriptionViewTests.cs @@ -50,7 +50,7 @@ public async Task OfferSubscriptionView_GetAll_ReturnsExpected() // Act var result = await sut.OfferSubscriptionView.ToListAsync().ConfigureAwait(false); - result.Should().HaveCount(13); + result.Should().HaveCount(14); } [Fact] diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/offer_subscriptions.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/offer_subscriptions.test.json index 506ac513b2..ea2ebc79f8 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/offer_subscriptions.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/offer_subscriptions.test.json @@ -42,6 +42,16 @@ "description": null, "process_id": "0cc208c3-bdf6-456c-af81-6c3ebe14fe10" }, + { + "company_id": "ac861325-bc54-4583-bcdc-9e9f2a38ff84", + "offer_id": "a16e73b9-5277-4b69-9f8d-3b227495dfae", + "offer_subscription_status_id": 2, + "requester_id": "ac1cf001-7fbc-1f2f-817f-bce058020001", + "id": "e80b5f5c-3a16-480b-b82e-1cc06a71fdde", + "last_editor_id": null, + "display_name": null, + "description": null + }, { "company_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87", "offer_id": "ac1cf001-7fbc-1f2f-817f-bce0572c0007",