예제 #1
0
        public async Task <IActionResult> SaveDefinition(JobDefinition definition)
        {
            try
            {
                Guard.ArgumentNotNull(definition, nameof(definition));

                ValidationResult validationResult = await _validator.ValidateAsync(definition);

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

                HttpStatusCode result = await _jobDefinitionsRepositoryPolicy.ExecuteAsync(() => _jobDefinitionsRepository.SaveJobDefinition(definition));

                if (!result.IsSuccess())
                {
                    int statusCode = (int)result;

                    _logger.Error($"Failed to save json file: {definition.Id} to cosmos db with status {statusCode}");

                    return(new StatusCodeResult(statusCode));
                }
            }
            catch (Exception exception)
            {
                _logger.Error(exception, $"Exception occurred writing job definition {definition?.Id} to cosmos db");

                throw;
            }

            await _cachePolicy.ExecuteAsync(() => _cacheProvider.RemoveAsync <List <JobDefinition> >(CacheKeys.JobDefinitions));

            return(new NoContentResult());
        }
예제 #2
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));
        }
        public async Task <IActionResult> GetLatestPublishedProvidersForSpecificationId(string specificationId)
        {
            ValidationResult validationResults = _validator.Validate(specificationId);

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

            SpecificationSummary specificationSummary = await _specificationService.GetSpecificationSummaryById(specificationId);

            List <PublishedProviderVersion> results = new List <PublishedProviderVersion>();

            foreach (var fundingStream in specificationSummary.FundingStreams)
            {
                IEnumerable <PublishedProvider> publishedProviders = await _resiliencePolicy.ExecuteAsync(() =>
                                                                                                          _publishedFunding.GetCurrentPublishedProviders(fundingStream.Id, specificationSummary.FundingPeriod.Id));

                if (publishedProviders.AnyWithNullCheck())
                {
                    results.AddRange(publishedProviders.Select(_ => _.Current));
                }
            }

            return(new OkObjectResult(results));
        }
        public async Task <IActionResult> SetCurrentProviderVersionForFundingStream(string fundingStreamId,
                                                                                    string providerVersionId, int?providerSnapshotId)
        {
            ValidationResult validationResult = await _setCurrentRequestValidator.ValidateAsync(new SetFundingStreamCurrentProviderVersionRequest
            {
                FundingStreamId   = fundingStreamId,
                ProviderVersionId = providerVersionId
            });

            if (!validationResult.IsValid)
            {
                LogError("The set current provider version for funding stream request was invalid." +
                         $"\n{validationResult.Errors.Select(_ => _.ErrorMessage).Join("\n")}");

                return(validationResult.AsBadRequest());
            }

            await _providerVersionMetadataPolicy.ExecuteAsync(() => _providerVersionMetadata.UpsertCurrentProviderVersion(new CurrentProviderVersion
            {
                Id = $"Current_{fundingStreamId}",
                ProviderVersionId  = providerVersionId,
                ProviderSnapshotId = providerSnapshotId
            }));

            return(new NoContentResult());
        }
        public async Task <IActionResult> UpdateTemplateDescription(TemplateDescriptionUpdateCommand command)
        {
            ValidationResult validationResult = await _validatorFactory.Validate(command);

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

            Reference author = ControllerContext.HttpContext.Request?.GetUserOrDefault();

            CommandResult result = await _templateBuilderService.UpdateTemplateDescription(command, author);

            if (result.Succeeded)
            {
                return(Ok());
            }

            if (result.ValidationResult != null)
            {
                return(result.ValidationResult.AsBadRequest());
            }

            return(new InternalServerErrorResult(result.ErrorMessage ?? result.Exception?.Message ?? "Unknown error occurred"));
        }
        public async Task <IActionResult> QueueBatchUploadValidation(BatchUploadValidationRequest batchUploadValidationRequest,
                                                                     Reference user,
                                                                     string correlationId)
        {
            ValidationResult validationResult = await _requestValidation.ValidateAsync(batchUploadValidationRequest);

            if (!validationResult.IsValid)
            {
                BadRequestObjectResult badRequest = validationResult.AsBadRequest();

                _logger.Warning($"Unable to queue batch upload validation job as validation errors.\n{badRequest.Value}");

                return(badRequest);
            }

            BatchUploadValidationProperties properties = batchUploadValidationRequest;

            Job job = await QueueJob(new JobCreateModel
            {
                CorrelationId          = correlationId,
                InvokerUserId          = user?.Id,
                InvokerUserDisplayName = user?.Name,
                JobDefinitionId        = BatchPublishedProviderValidationJob,
                SpecificationId        = batchUploadValidationRequest.SpecificationId,
                Trigger    = new Trigger(),
                Properties = (Dictionary <string, string>)properties
            });

            return(new OkObjectResult(new
            {
                JobId = job.Id
            }));
        }
        public async Task <IActionResult> ApplyCustomProfile(ApplyCustomProfileRequest request, Reference author)
        {
            Guard.ArgumentNotNull(request, nameof(request));
            Guard.ArgumentNotNull(author, nameof(author));

            ValidationResult validationResult = await _requestValidation.ValidateAsync(request);

            if (!validationResult.IsValid)
            {
                string validationErrors = validationResult.Errors.Select(_ => _.ErrorMessage).Join(", ");

                _logger.Information(
                    $"Unable to process apply custom profile request. Request was invalid. \n{validationErrors}");

                return(validationResult.AsBadRequest());
            }

            string publishedProviderId = request.PublishedProviderId;
            string fundingLineCode     = request.FundingLineCode;

            PublishedProvider publishedProvider = await _publishedFundingResilience.ExecuteAsync(() =>
                                                                                                 _publishedFundingRepository.GetPublishedProviderById(publishedProviderId, publishedProviderId));

            PublishedProviderVersion currentProviderVersion = publishedProvider.Current;

            foreach (IGrouping <string, ProfilePeriod> profilePeriods in request.ProfilePeriods.GroupBy(_ => _.DistributionPeriodId))
            {
                string distributionPeriodId = profilePeriods.Key;

                currentProviderVersion.UpdateDistributionPeriodForFundingLine(
                    fundingLineCode,
                    distributionPeriodId,
                    profilePeriods);

                currentProviderVersion.AddOrUpdateCustomProfile(fundingLineCode, request.CarryOver, distributionPeriodId);
            }

            if (request.HasCarryOver)
            {
                currentProviderVersion.AddCarryOver(fundingLineCode,
                                                    ProfilingCarryOverType.CustomProfile,
                                                    request.CarryOver.GetValueOrDefault());
            }
            else
            {
                currentProviderVersion.RemoveCarryOver(fundingLineCode);
            }

            currentProviderVersion.AddProfilingAudit(fundingLineCode, author);

            await _publishedProviderVersionCreation.UpdatePublishedProviderStatus(new[] { publishedProvider },
                                                                                  author,
                                                                                  currentProviderVersion.Status switch
            {
                PublishedProviderStatus.Draft => PublishedProviderStatus.Draft,
                _ => PublishedProviderStatus.Updated
            },
        public async Task <IActionResult> CreateRefreshFundingJob(string specificationId,
                                                                  Reference user,
                                                                  string correlationId)
        {
            ValidationResult validationResult = SpecificationIdValidator.Validate(specificationId);

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

            ApiResponse <ApiSpecificationSummary> specificationIdResponse =
                await ResiliencePolicy.ExecuteAsync(() => Specifications.GetSpecificationSummaryById(specificationId));

            ApiSpecificationSummary specificationSummary = specificationIdResponse.Content;

            if (specificationSummary == null)
            {
                return(new NotFoundResult());
            }

            SpecificationFundingStatus chooseCheck = await _specificationFundingStatusService.CheckChooseForFundingStatus(specificationSummary);

            if (chooseCheck == SpecificationFundingStatus.SharesAlreadyChosenFundingStream)
            {
                return(new ConflictResult());
            }

            IDictionary <string, Provider> scopedProviders = await _providerService.GetScopedProvidersForSpecification(specificationSummary.Id, specificationSummary.ProviderVersionId);

            // Check prerequisites for this specification to be chosen/refreshed
            IPrerequisiteChecker prerequisiteChecker = _prerequisiteCheckerLocator.GetPreReqChecker(PrerequisiteCheckerType.Refresh);

            try
            {
                await prerequisiteChecker.PerformChecks(
                    specificationSummary,
                    null,
                    Array.Empty <PublishedProvider>(),
                    scopedProviders?.Values);
            }
            catch (JobPrereqFailedException ex)
            {
                return(new BadRequestObjectResult(new [] { $"Prerequisite check for refresh failed {ex.Message}" }.ToModelStateDictionary()));
            }

            ApiJob refreshFundingJob = await _refreshFundingJobs.CreateJob(specificationId, user, correlationId);

            Guard.ArgumentNotNull(refreshFundingJob, nameof(refreshFundingJob), "Failed to create RefreshFundingJob");

            JobCreationResponse jobCreationResponse = new JobCreationResponse()
            {
                JobId = refreshFundingJob.Id,
            };

            return(new OkObjectResult(jobCreationResponse));
        }
        public async Task <IActionResult> GetTemplateVersions(FindTemplateVersionQuery query)
        {
            ValidationResult validationResult = await _validatorFactory.Validate(query);

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

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

            IEnumerable <TemplateSummaryResponse> templateVersionResponses =
                await _templateBuilderService.FindVersionsByFundingStreamAndPeriod(query);

            return(Ok(templateVersionResponses));
        }
        public async Task <IActionResult> ProcessProfileAllocationBatchRequest(ProfileBatchRequest profileBatchRequest)
        {
            Guard.ArgumentNotNull(profileBatchRequest, nameof(ProfileBatchRequest));

            ValidationResult validationResult = await _batchRequestValidation.ValidateAsync(profileBatchRequest);

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

            try
            {
                FundingStreamPeriodProfilePattern profilePattern = await GetProfilePattern(profileBatchRequest);

                if (profilePattern == null)
                {
                    _logger.Error("Unable to find profile pattern for FundingStream = {fundingStreamId}, FundingPeriodId={FundingPeriodId}, FundingLineCode={FundingLineCode}, ProfilePatternKey={ProfilePatternKey}, ProviderType={ProviderType}, ProviderSubType={ProviderSubType}",
                                  profileBatchRequest.FundingStreamId,
                                  profileBatchRequest.FundingPeriodId,
                                  profileBatchRequest.FundingLineCode,
                                  profileBatchRequest.ProfilePatternKey,
                                  profileBatchRequest.ProviderType,
                                  profileBatchRequest.ProviderSubType);
                }

                BatchProfileRequestContext batchProfileRequestContext = new BatchProfileRequestContext(profilePattern,
                                                                                                       profileBatchRequest,
                                                                                                       5);

                IProducerConsumer producerConsumer = _producerConsumerFactory.CreateProducerConsumer(ProduceProviderFundingValues,
                                                                                                     ProfileProviderFundingValues,
                                                                                                     10,
                                                                                                     10,
                                                                                                     _logger);

                await producerConsumer.Run(batchProfileRequestContext);

                return(new OkObjectResult(batchProfileRequestContext.Responses.ToArray()));
            }
            catch (Exception ex)
            {
                LogError(ex, profileBatchRequest);

                throw;
            }
        }
예제 #11
0
        public async Task <IActionResult> UpdateFundingStructureLastModified(UpdateFundingStructureLastModifiedRequest request)
        {
            Guard.ArgumentNotNull(request, nameof(request));

            // ReSharper disable once MethodHasAsyncOverload
            ValidationResult validationResult = _validator.Validate(request);

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

            string cacheKey = GetCacheKeyFundingStructure(request.SpecificationId,
                                                          request.FundingStreamId,
                                                          request.FundingPeriodId);

            await _cacheResilience.ExecuteAsync(() => _cacheProvider.SetAsync(cacheKey, request.LastModified));

            return(new OkResult());
        }
        public async Task <IActionResult> ValidateSpecificationForRefresh(string specificationId)
        {
            List <string> prereqErrors = new List <string>();

            ValidationResult validationResult = SpecificationIdValidator.Validate(specificationId);

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

            ApiResponse <ApiSpecificationSummary> specificationIdResponse =
                await ResiliencePolicy.ExecuteAsync(() => Specifications.GetSpecificationSummaryById(specificationId));

            ApiSpecificationSummary specificationSummary = specificationIdResponse.Content;

            if (specificationSummary == null)
            {
                return(new NotFoundResult());
            }

            IDictionary <string, Provider> scopedProviders = await _providerService.GetScopedProvidersForSpecification(specificationSummary.Id, specificationSummary.ProviderVersionId);

            IPrerequisiteChecker prerequisiteChecker = _prerequisiteCheckerLocator.GetPreReqChecker(PrerequisiteCheckerType.Refresh);

            try
            {
                await prerequisiteChecker.PerformChecks(
                    specificationSummary,
                    null,
                    Array.Empty <PublishedProvider>(),
                    scopedProviders?.Values);
            }
            catch (JobPrereqFailedException ex)
            {
                return(new BadRequestObjectResult(ex.Errors.ToArray().ToModelStateDictionary()));
            }

            return(new NoContentResult());
        }
예제 #13
0
        public async Task <IActionResult> PublishAllProvidersFunding(string specificationId,
                                                                     Reference user,
                                                                     string correlationId)
        {
            ValidationResult validationResult = SpecificationIdValidator.Validate(specificationId);

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

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

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

            ApiJob job = await _createAllPublishProviderFundingJobs.CreateJob(specificationId, user, correlationId);

            return(ProcessJobResponse(job, specificationId, JobConstants.DefinitionNames.PublishAllProviderFundingJob));
        }
예제 #14
0
        public async Task <IActionResult> PublishIntegrityCheck(string specificationId,
                                                                Reference user,
                                                                string correlationId,
                                                                bool publishAll = false)
        {
            ValidationResult validationResult = SpecificationIdValidator.Validate(specificationId);

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

            ApiJob job = await _createPublishIntegrityJob.CreateJob(specificationId,
                                                                    user,
                                                                    correlationId,
                                                                    publishAll?new Dictionary <string, string>
            {
                { "publish-all", "True" }
            } :
                                                                    null);

            return(ProcessJobResponse(job, specificationId, JobConstants.DefinitionNames.PublishIntegrityCheckJob));
        }
예제 #15
0
        public async Task <IActionResult> GetProviderStatusCounts(string specificationId, string providerType, string localAuthority, string status)
        {
            ValidationResult validationResults = _validator.Validate(specificationId);

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

            SpecificationSummary specificationSummary =
                await _specificationsRepositoryPolicy.ExecuteAsync(() => _specificationService.GetSpecificationSummaryById(specificationId));

            IEnumerable <PublishedProviderFundingStreamStatus> publishedProviderFundingStreamStatuses =
                await _publishedFundingRepositoryResilience.ExecuteAsync(() => _publishedFundingRepository.GetPublishedProviderStatusCounts(specificationId, providerType, localAuthority, status));

            List <ProviderFundingStreamStatusResponse> response = new List <ProviderFundingStreamStatusResponse>();

            foreach (IGrouping <string, PublishedProviderFundingStreamStatus> publishedProviderFundingStreamGroup in publishedProviderFundingStreamStatuses.GroupBy(x => x.FundingStreamId))
            {
                if (!specificationSummary.FundingStreams.Select(x => x.Id).Contains(publishedProviderFundingStreamGroup.Key))
                {
                    continue;
                }

                response.Add(new ProviderFundingStreamStatusResponse
                {
                    FundingStreamId       = publishedProviderFundingStreamGroup.Key,
                    ProviderApprovedCount = GetCountValueOrDefault(publishedProviderFundingStreamGroup, "Approved"),
                    ProviderDraftCount    = GetCountValueOrDefault(publishedProviderFundingStreamGroup, "Draft"),
                    ProviderReleasedCount = GetCountValueOrDefault(publishedProviderFundingStreamGroup, "Released"),
                    ProviderUpdatedCount  = GetCountValueOrDefault(publishedProviderFundingStreamGroup, "Updated"),
                    TotalFunding          = publishedProviderFundingStreamGroup.Sum(x => x.TotalFunding)
                });
            }

            return(new OkObjectResult(response));
        }
        public async Task <IActionResult> RestoreContent(TemplateFundingLinesUpdateCommand command, [FromRoute] string templateId, [FromRoute] string version)
        {
            ValidationResult validationResult = await _validatorFactory.Validate(command);

            if (!validationResult.IsValid || command.TemplateId != templateId)
            {
                return(validationResult.AsBadRequest());
            }

            Reference author = ControllerContext.HttpContext.Request?.GetUserOrDefault();

            CommandResult result = await _templateBuilderService.RestoreTemplateContent(command, author);

            if (result.Succeeded)
            {
                return(Ok(result.Version));
            }
            if (result.ValidationModelState != null)
            {
                return(BadRequest(result.ValidationModelState));
            }

            return(new InternalServerErrorResult(result.ErrorMessage ?? result.Exception?.Message ?? "Unknown error occurred"));
        }
예제 #17
0
        private async Task <IActionResult> GetProviderDataAsCsv(PublishedProviderIdsRequest providerIds, string specificationId, string csvFileSuffix, params PublishedProviderStatus[] statuses)
        {
            ValidationResult validationResults = _validator.Validate(specificationId);

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

            if (providerIds.PublishedProviderIds.IsNullOrEmpty())
            {
                return(new BadRequestObjectResult("Provider ids must be provided"));
            }

            IEnumerable <PublishedProviderFundingCsvData> publishedProviderFundingData = await _fundingCsvDataProcessor.GetFundingData(
                providerIds.PublishedProviderIds,
                specificationId,
                statuses);

            if (publishedProviderFundingData.IsNullOrEmpty())
            {
                return(new NotFoundObjectResult("No data found for given specification and published provider ids."));
            }

            IEnumerable <dynamic> csvRows = publishedProviderFundingData.Select(x => new
            {
                UKPRN         = x.Ukprn,
                URN           = x.Urn,
                UPIN          = x.Upin,
                ProviderName  = x.ProviderName,
                FundingAmount = x.TotalFunding
            });

            string csvFileData     = _csvUtils.AsCsv(csvRows, true);
            string fundingStreamId = publishedProviderFundingData.First().FundingStreamId;
            string fundingPeriodId = publishedProviderFundingData.First().FundingPeriodId;
            string csvFileName     = $"{fundingStreamId}-{fundingPeriodId}-{csvFileSuffix}.csv";

            string blobName = $"{csvFileName}";
            string blobUrl  = string.Empty;

            await _blobClientPolicy.ExecuteAsync(async() =>
            {
                ICloudBlob blob = _blobClient.GetBlockBlobReference(blobName, BlobContainerName);
                blob.Properties.ContentDisposition = $"attachment; filename={csvFileName}";

                using (MemoryStream stream = new MemoryStream(csvFileData.AsUTF8Bytes()))
                {
                    await blob.UploadFromStreamAsync(stream);
                }

                blob.Metadata["fundingStreamId"] = fundingStreamId;
                blob.Metadata["fundingPeriodId"] = fundingPeriodId;
                blob.Metadata["specificationId"] = specificationId;
                blob.Metadata["fileName"]        = Path.GetFileNameWithoutExtension(csvFileName);
                blob.SetMetadata();

                blobUrl = _blobClient.GetBlobSasUrl(blobName, DateTimeOffset.Now.AddDays(1), SharedAccessBlobPermissions.Read, BlobContainerName);
            });

            return(new OkObjectResult(new PublishedProviderDataDownload()
            {
                Url = blobUrl
            }));
        }