Beispiel #1
0
        public async Task ApproveProvidersFundingJobForSuppliedSpecificationId()
        {
            ApiSpecificationSummary specificationSummary = NewApiSpecificationSummary(_ =>
                                                                                      _.WithIsSelectedForFunding(true));

            string approveFundingJobId = NewRandomString();
            ApiJob approveFundingJob   = NewJob(_ => _.WithId(approveFundingJobId));

            string filterIdOne = NewRandomString();
            string filterIdTwo = NewRandomString();

            GivenTheApiResponseDetailsForTheSuppliedId(specificationSummary);
            AndTheFilteredListOfPublishedProviderIds(filterIdOne, filterIdTwo);
            AndTheApiResponseDetailsForApproveProviderJob(approveFundingJob, JsonExtensions.AsJson(new PublishedProviderIdsRequest
            {
                PublishedProviderIds = new[]
                {
                    filterIdOne,
                    filterIdTwo
                }
            }));

            await WhenBatchProvidersAreApproved();

            JobCreationResponse expectedJobCreationResponse = NewJobCreationResponse(_ => _.WithJobId(approveFundingJobId));

            ActionResult
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should()
            .BeEquivalentTo(expectedJobCreationResponse);
        }
Beispiel #2
0
        public async Task WhenPartialFundingIsApproved(Table table)
        {
            Message message = new Message();

            string[] providerIds = table.AsStrings();
            PublishedProviderIdsRequest approveProvidersRequest = new PublishedProviderIdsRequest {
                PublishedProviderIds = providerIds
            };
            string approveProvidersRequestJson = JsonExtensions.AsJson(approveProvidersRequest);

            message.UserProperties.Add("user-id", _currentUserStepContext.UserId);
            message.UserProperties.Add("user-name", _currentUserStepContext.UserName);
            message.UserProperties.Add("specification-id", _currentSpecificationStepContext.SpecificationId);
            message.UserProperties.Add("jobId", _currentJobStepContext.JobId);
            message.Body = Encoding.UTF8.GetBytes(approveProvidersRequestJson);

            await _approveService.Run(message, async() =>
            {
                await _approveService.ApproveResults(message, batched: true);
            });
        }
        public async Task ApproveResults(Message message, bool batched = false)
        {
            Guard.ArgumentNotNull(message, nameof(message));
            _logger.Information("Starting approve provider funding job");
            string specificationId = message.GetUserProperty <string>("specification-id");

            PublishedProviderIdsRequest publishedProviderIdsRequest = null;

            string logApproveProcessingMessage = $"Processing approve specification funding job. JobId='{Job.Id}'. SpecificationId='{specificationId}'.";

            if (batched)
            {
                publishedProviderIdsRequest  = message.GetPayloadAsInstanceOf <PublishedProviderIdsRequest>();
                logApproveProcessingMessage += $" Request = {JsonExtensions.AsJson(publishedProviderIdsRequest)}.";
            }

            await PerformPrerequisiteChecks(specificationId,
                                            Job.Id,
                                            batched == true?PrerequisiteCheckerType.ApproveBatchProviders : PrerequisiteCheckerType.ApproveAllProviders);

            _logger.Information(logApproveProcessingMessage);

            _logger.Information("Fetching published providers for specification funding approval");

            IEnumerable <PublishedProvider> publishedProviders = await GetPublishedProvidersForApproval(specificationId, publishedProviderIdsRequest?.PublishedProviderIds?.ToArray());

            CheckPublishedProviderForErrors(specificationId, publishedProviders);

            Reference author        = message.GetUserDetails();
            string    correlationId = message.GetUserProperty <string>(SfaCorrelationId);

            await ApproveProviders(publishedProviders,
                                   specificationId,
                                   Job.Id,
                                   author,
                                   correlationId);
        }
Beispiel #4
0
        public async Task <IActionResult> PublishBatchProvidersFunding(string specificationId,
                                                                       PublishedProviderIdsRequest publishedProviderIdsRequest,
                                                                       Reference user,
                                                                       string correlationId)
        {
            ValidationResult specificationIdValidationResult = SpecificationIdValidator.Validate(specificationId);

            if (!specificationIdValidationResult.IsValid)
            {
                return(specificationIdValidationResult.AsBadRequest());
            }

            ValidationResult publishedProviderIdsValidationResult = PublishedProviderIdsValidator.Validate(publishedProviderIdsRequest.PublishedProviderIds.ToArray());

            if (!publishedProviderIdsValidationResult.IsValid)
            {
                return(publishedProviderIdsValidationResult.AsBadRequest());
            }

            IActionResult actionResult = await IsSpecificationReadyForPublish(specificationId, ApprovalMode.Batches);

            if (!actionResult.IsOk())
            {
                return(actionResult);
            }

            await FilterOutPublishedProvidersInError(publishedProviderIdsRequest);

            ApiJob job = await _createBatchPublishProviderFundingJobs.CreateJob(specificationId, user, correlationId, messageBody : JsonExtensions.AsJson(publishedProviderIdsRequest), compress : true);

            return(ProcessJobResponse(job, specificationId, JobConstants.DefinitionNames.PublishBatchProviderFundingJob));
        }
Beispiel #5
0
 private void GivenTheMessageHasTheApproveProvidersRequest(PublishedProviderIdsRequest approveProvidersRequest)
 {
     _message.Body = Encoding.UTF8.GetBytes(JsonExtensions.AsJson(approveProvidersRequest));
 }
        private async Task PublishFundingStream(Reference fundingStream,
                                                SpecificationSummary specification,
                                                string jobId,
                                                Reference author,
                                                string correlationId,
                                                PrerequisiteCheckerType prerequisiteCheckerType,
                                                string[] batchPublishedProviderIds = null)
        {
            _logger.Information($"Processing Publish Funding for {fundingStream.Id} in specification {specification.Id}");

            if (!specification.TemplateIds.ContainsKey(fundingStream.Id) || string.IsNullOrWhiteSpace(specification.TemplateIds[fundingStream.Id]))
            {
                _logger.Information($"Skipped publishing {fundingStream.Id} as no template exists");

                return;
            }

            // we always need to get every provider in scope whether it is released or otherwise so that we always genarate the contents
            // this is just in case an error has occurred during a release so we never get a case where we don't get blobs generated for the published providers
            (IDictionary <string, PublishedProvider> publishedProvidersForFundingStream,
             IDictionary <string, PublishedProvider> scopedPublishedProviders) = await _providerService.GetPublishedProviders(fundingStream,
                                                                                                                              specification);

            IDictionary <string, PublishedProvider> publishedProvidersByPublishedProviderId = publishedProvidersForFundingStream.Values.ToDictionary(_ => _.PublishedProviderId);

            IEnumerable <PublishedProvider> selectedPublishedProviders =
                batchPublishedProviderIds.IsNullOrEmpty() ?
                publishedProvidersForFundingStream.Values :
                batchPublishedProviderIds.Where(_ => publishedProvidersByPublishedProviderId.ContainsKey(_)).Select(_ => publishedProvidersByPublishedProviderId[_]);

            AddInitialPublishVariationReasons(selectedPublishedProviders);

            _logger.Information($"Verifying prerequisites for funding publish");

            IPrerequisiteChecker prerequisiteChecker = _prerequisiteCheckerLocator.GetPreReqChecker(prerequisiteCheckerType);

            try
            {
                await prerequisiteChecker.PerformChecks(specification, jobId, selectedPublishedProviders?.ToList());
            }
            catch (JobPrereqFailedException ex)
            {
                throw new NonRetriableException(ex.Message, ex);
            }

            _logger.Information("Prerequisites for publish passed");

            TemplateMapping templateMapping = await GetTemplateMapping(fundingStream, specification.Id);

            PublishedFundingInput publishedFundingInput = await _publishedFundingService.GeneratePublishedFundingInput(publishedProvidersForFundingStream,
                                                                                                                       scopedPublishedProviders?.Values.Select(_ => _.Current.Provider),
                                                                                                                       fundingStream,
                                                                                                                       specification,
                                                                                                                       batchPublishedProviderIds.IsNullOrEmpty()?null : selectedPublishedProviders);

            using Transaction transaction = _transactionFactory.NewTransaction <PublishService>();
            try
            {
                // if any error occurs while updating or indexing then we need to re-index all published providers and persist published funding for consistency
                transaction.Enroll(async() =>
                {
                    await _publishedProviderVersionService.CreateReIndexJob(author, correlationId, specification.Id, jobId);
                    await _createPublishIntegrityJob.CreateJob(specification.Id,
                                                               author,
                                                               correlationId,
                                                               batchPublishedProviderIds.IsNullOrEmpty() ? null : new Dictionary <string, string>
                    {
                        { "providers-batch", JsonExtensions.AsJson(selectedPublishedProviders.Select(_ => _.PublishedProviderId)) }
                    },
                                                               parentJobId: jobId);
                });

                await SavePublishedProvidersAsReleased(jobId, author, selectedPublishedProviders, correlationId);

                ICollection <PublishedProvider> publishedProviders = publishedProvidersForFundingStream?.Values;

                _logger.Information($"Generating published funding");
                IEnumerable <(PublishedFunding PublishedFunding, PublishedFundingVersion PublishedFundingVersion)> publishedFundingToSave =
                    _publishedFundingGenerator.GeneratePublishedFunding(publishedFundingInput, publishedProviders).ToList();
                _logger.Information($"A total of {publishedFundingToSave.Count()} published funding versions created to save.");

                foreach ((PublishedFunding PublishedFunding, PublishedFundingVersion PublishedFundingVersion)publishedFundingItems in publishedFundingToSave)
                {
                    PropagateProviderVariationReasons(publishedFundingItems.PublishedFundingVersion, publishedProviders);
                }

                // if any error occurs while updating then we still need to run the indexer to be consistent
                transaction.Enroll(async() =>
                {
                    await _publishedIndexSearchResiliencePolicy.ExecuteAsync(() => _publishedFundingSearchRepository.RunIndexer());
                });

                // Save a version of published funding and set this version to current
                _logger.Information($"Saving published funding");
                await _publishedFundingStatusUpdateService.UpdatePublishedFundingStatus(publishedFundingToSave, author, PublishedFundingStatus.Released, jobId, correlationId);

                _logger.Information($"Finished saving published funding");

                // Save contents to blob storage and search for the feed
                _logger.Information($"Saving published funding contents");
                await _publishedFundingContentsPersistanceService.SavePublishedFundingContents(publishedFundingToSave.Select(_ => _.PublishedFundingVersion),
                                                                                               publishedFundingInput.TemplateMetadataContents);

                _logger.Information($"Finished saving published funding contents");

                if (!selectedPublishedProviders.IsNullOrEmpty())
                {
                    // Generate contents JSON for provider and save to blob storage
                    IPublishedProviderContentsGenerator generator = _publishedProviderContentsGeneratorResolver.GetService(publishedFundingInput.TemplateMetadataContents.SchemaVersion);
                    await _publishedProviderContentsPersistanceService.SavePublishedProviderContents(publishedFundingInput.TemplateMetadataContents, templateMapping,
                                                                                                     selectedPublishedProviders, generator);
                }

                transaction.Complete();
            }
            catch (Exception ex)
            {
                await transaction.Compensate();

                throw;
            }
        }