Beispiel #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());
        }
        public async Task <PublishedProvider> CreateVersion(PublishedProviderCreateVersionRequest publishedProviderCreateVersionRequest)
        {
            Guard.ArgumentNotNull(publishedProviderCreateVersionRequest.PublishedProvider, nameof(publishedProviderCreateVersionRequest.PublishedProvider));
            Guard.ArgumentNotNull(publishedProviderCreateVersionRequest.NewVersion, nameof(publishedProviderCreateVersionRequest.NewVersion));

            PublishedProviderVersion currentVersion = publishedProviderCreateVersionRequest.PublishedProvider.Current;

            PublishedProviderVersion newVersion = publishedProviderCreateVersionRequest.NewVersion;

            string partitionKey = currentVersion != null ? publishedProviderCreateVersionRequest.PublishedProvider.PartitionKey : string.Empty;

            try
            {
                publishedProviderCreateVersionRequest.PublishedProvider.Current =
                    await _versionRepositoryPolicy.ExecuteAsync(() => _versionRepository.CreateVersion(newVersion, currentVersion, partitionKey));
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"Failed to create new version for published provider version id: {newVersion.Id}");

                throw;
            }

            return(publishedProviderCreateVersionRequest.PublishedProvider);
        }
        public async Task <FundingTemplateValidationResult> ValidateFundingTemplate(string fundingTemplate, string fundingStreamId, string fundingPeriodId, string templateVersion = null)
        {
            Guard.IsNullOrWhiteSpace(fundingTemplate, nameof(fundingTemplate));

            FundingTemplateValidationResult fundingTemplateValidationResult = new FundingTemplateValidationResult()
            {
                FundingStreamId = fundingStreamId,
                FundingPeriodId = fundingPeriodId,
                TemplateVersion = templateVersion
            };

            JObject parsedFundingTemplate;

            try
            {
                parsedFundingTemplate = JObject.Parse(fundingTemplate);
            }
            catch (JsonReaderException jre)
            {
                fundingTemplateValidationResult.Errors.Add(new ValidationFailure("", jre.Message));

                return(fundingTemplateValidationResult);
            }

            if (parsedFundingTemplate["schemaVersion"] == null ||
                string.IsNullOrWhiteSpace(parsedFundingTemplate["schemaVersion"].Value <string>()))
            {
                fundingTemplateValidationResult.Errors.Add(new ValidationFailure("", "Missing schema version from funding template."));

                return(fundingTemplateValidationResult);
            }

            string schemaVersion = parsedFundingTemplate["schemaVersion"].Value <string>();

            fundingTemplateValidationResult.SchemaVersion = schemaVersion;

            string blobName = $"{fundingSchemaFolder}/{schemaVersion}.json";

            bool schemaExists = await _fundingSchemaRepositoryPolicy.ExecuteAsync(() => _fundingSchemaRepository.SchemaVersionExists(blobName));

            if (!schemaExists)
            {
                fundingTemplateValidationResult.Errors.Add(new ValidationFailure("", $"A valid schema could not be found for schema version '{schemaVersion}'."));

                return(fundingTemplateValidationResult);
            }

            await ValidateAgainstSchema(blobName, parsedFundingTemplate, fundingTemplateValidationResult);

            if (!fundingTemplateValidationResult.IsValid)
            {
                return(fundingTemplateValidationResult);
            }

            await ValidateFundingStream(fundingTemplateValidationResult);
            await ValidateFundingPeriod(fundingTemplateValidationResult);

            return(fundingTemplateValidationResult);
        }
Beispiel #4
0
        public async Task <IActionResult> GetLatestJobs(string specificationId, string jobTypes)
        {
            Guard.ArgumentNotNull(specificationId, nameof(specificationId));

            string[] jobDefinitionIds =
                !string.IsNullOrEmpty(jobTypes) ?
                jobTypes.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries)
                : Array.Empty <string>();

            if (!jobDefinitionIds.Any())
            {
                return(new BadRequestObjectResult("JobTypes must be provided to get latest jobs."));
            }

            ConcurrentDictionary <string, Job> jobsByDefinition = new ConcurrentDictionary <string, Job>();

            List <Task> allTasks = new List <Task>();

            foreach (string jobDefinitionId in jobDefinitionIds.Distinct())
            {
                allTasks.Add(
                    Task.Run(async() =>
                {
                    string cacheKey = $"{CacheKeys.LatestJobs}{specificationId}:{jobDefinitionId}";

                    Job job = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetAsync <Job>(cacheKey));

                    if (job != null)
                    {
                        jobsByDefinition[jobDefinitionId] = job;
                    }
                    else
                    {
                        job = await _jobRepository.GetLatestJobBySpecificationIdAndDefinitionId(specificationId, jobDefinitionId);

                        // create a new empty job if no job so we don't continually make calls as the cache will be invalidated in the create job and update job
                        // with a valid job so this will only be hit if redis is empty or a job has never been created
                        job ??= new Job();

                        await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetAsync(cacheKey, job));

                        jobsByDefinition[jobDefinitionId] = job;
                    }
                }));
            }

            await TaskHelper.WhenAllAndThrow(allTasks.ToArray());

            IEnumerable <JobSummary> jobSummaries = _mapper.Map <IEnumerable <JobSummary> >(jobsByDefinition.Values);

            JobSummary[] results = new JobSummary[jobDefinitionIds.Length];
            for (int i = 0; i < jobDefinitionIds.Length; i++)
            {
                results[i] = jobSummaries.FirstOrDefault(x => string.Equals(x.JobDefinitionId, jobDefinitionIds[i], StringComparison.InvariantCultureIgnoreCase));
            }

            return(new OkObjectResult(results));
        }
Beispiel #5
0
        public override async Task Process(Message message)
        {
            Guard.ArgumentNotNull(message, nameof(message));

            if (!_featureToggle.IsProcessDatasetDefinitionFieldChangesEnabled())
            {
                return;
            }

            DatasetDefinitionChanges datasetDefinitionChanges = message.GetPayloadAsInstanceOf <DatasetDefinitionChanges>();

            _logger.Information("Checking for dataset definition changes before proceeding");

            if (datasetDefinitionChanges == null)
            {
                throw new NonRetriableException("Message does not contain a valid dataset definition change model");
            }

            if (!datasetDefinitionChanges.HasChanges)
            {
                _logger.Information($"No dataset definition field changes for definition id '{datasetDefinitionChanges.Id}'");

                return;
            }

            IEnumerable <FieldDefinitionChanges> fieldChanges = datasetDefinitionChanges.TableDefinitionChanges.SelectMany(m => m.FieldChanges);

            if (fieldChanges.IsNullOrEmpty())
            {
                _logger.Information($"No dataset definition field changes for definition id '{datasetDefinitionChanges.Id}'");

                return;
            }

            ApiResponse <IEnumerable <string> > datasetsApiClientResponse = await _datasetsApiClientPolicy.ExecuteAsync(() => _datasetsApiClient.GetSpecificationIdsForRelationshipDefinitionId(datasetDefinitionChanges.Id));

            if (!datasetsApiClientResponse.StatusCode.IsSuccess())
            {
                string errorMessage = $"No Specification ids for relationship definition id {datasetDefinitionChanges.Id} were returned from the repository, result came back null";
                _logger.Error(errorMessage);

                throw new RetriableException(errorMessage);
            }

            IEnumerable <string> relationshipSpecificationIds = datasetsApiClientResponse.Content;

            if (relationshipSpecificationIds.IsNullOrEmpty())
            {
                _logger.Information($"No dataset definition specification relationships exists for definition id '{datasetDefinitionChanges.Id}'");

                return;
            }

            await ProcessFieldChanges(datasetDefinitionChanges.Id, fieldChanges, relationshipSpecificationIds);
        }
 private async Task SaveFundingTemplateVersion(string blobName, byte[] templateBytes)
 {
     try
     {
         await _fundingTemplateRepositoryPolicy.ExecuteAsync(() => _fundingTemplateRepository.SaveFundingTemplateVersion(blobName, templateBytes));
     }
     catch (Exception ex)
     {
         throw new NonRetriableException($"Failed to save funding template version: '{blobName}'", ex);
     }
 }
        public async Task <IActionResult> UpdatePermissionForUser(string userId, string fundingStreamId, FundingStreamPermissionUpdateModel updateModel, Reference author)
        {
            if (string.IsNullOrWhiteSpace(userId))
            {
                return(new BadRequestObjectResult($"{nameof(userId)} is empty or null"));
            }

            if (string.IsNullOrWhiteSpace(fundingStreamId))
            {
                return(new BadRequestObjectResult($"{nameof(fundingStreamId)} is empty or null"));
            }

            User user = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetUserById(userId));

            if (user == null)
            {
                return(new PreconditionFailedResult("userId not found"));
            }

            FundingStreamPermission existingPermissions = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetFundingStreamPermission(userId, fundingStreamId));

            FundingStreamPermission newPermissions = _mapper.Map <FundingStreamPermissionUpdateModel, FundingStreamPermission>(updateModel);

            newPermissions.FundingStreamId = fundingStreamId;
            newPermissions.UserId          = userId;

            if (existingPermissions == null || !existingPermissions.HasSamePermissions(newPermissions))
            {
                HttpStatusCode saveResult = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.UpdateFundingStreamPermission(newPermissions));

                if (saveResult != HttpStatusCode.OK && saveResult != HttpStatusCode.Created)
                {
                    return(new InternalServerErrorResult($"Saving funding stream permission to repository returned '{saveResult}'"));
                }

                FundingStreamPermissionVersion version = new FundingStreamPermissionVersion()
                {
                    Author        = author,
                    Permission    = newPermissions,
                    PublishStatus = Models.Versioning.PublishStatus.Updated,
                    Date          = DateTimeOffset.Now,
                    UserId        = userId,
                };

                version.Version = await _fundingStreamPermissionVersionRepositoryPolicy.ExecuteAsync(() => _fundingStreamPermissionVersionRepository.GetNextVersionNumber(version, partitionKeyId: userId));

                await _fundingStreamPermissionVersionRepositoryPolicy.ExecuteAsync(() => _fundingStreamPermissionVersionRepository.SaveVersion(version, userId));

                await ClearEffectivePermissionsForUser(userId);
            }

            return(new OkObjectResult(_mapper.Map <FundingStreamPermissionCurrent>(newPermissions)));
        }
        private async Task <bool> CheckIfFundingSchemaVersionExists(string blobName)
        {
            try
            {
                return(await _fundingSchemaRepositoryPolicy.ExecuteAsync(() => _fundingSchemaRepository.SchemaVersionExists(blobName)));
            }
            catch (Exception ex)
            {
                _logger.Error($"Failed to check if funding schema version: '{blobName}' exists");

                throw new NonRetriableException($"Failed to check if funding schema version: '{blobName}' exists", ex);
            }
        }
        private async Task ValidateFundingStream(FundingTemplateValidationResult fundingTemplateValidationResult)
        {
            if (!fundingTemplateValidationResult.FundingStreamId.IsNullOrEmpty())
            {
                FundingStream fundingStream = await _policyRepositoryPolicy.ExecuteAsync(() =>
                                                                                         _policyRepository.GetFundingStreamById(fundingTemplateValidationResult.FundingStreamId));

                if (fundingStream == null)
                {
                    fundingTemplateValidationResult.Errors
                    .Add(new ValidationFailure("", $"A funding stream could not be found for funding stream id '{fundingTemplateValidationResult.FundingStreamId}'"));
                }
            }
        }
        public async Task <IActionResult> GetFundingDate(
            string fundingStreamId,
            string fundingPeriodId,
            string fundingLineId)
        {
            if (string.IsNullOrWhiteSpace(fundingStreamId))
            {
                _logger.Error("No funding stream Id was provided to GetFundingDate");

                return(new BadRequestObjectResult("Null or empty funding stream Id provided"));
            }

            if (string.IsNullOrWhiteSpace(fundingPeriodId))
            {
                _logger.Error("No funding period Id was provided to GetFundingDate");

                return(new BadRequestObjectResult("Null or empty funding period Id provided"));
            }

            if (string.IsNullOrWhiteSpace(fundingLineId))
            {
                _logger.Error("No funding line Id was provided to GetFundingDate");

                return(new BadRequestObjectResult("Null or empty funding line Id provided"));
            }

            string fundingDateId = $"fundingdate-{fundingStreamId}-{fundingPeriodId}-{fundingLineId}";

            FundingDate fundingDate = null;

            try
            {
                fundingDate = await _policyRepositoryPolicy.ExecuteAsync(() => _policyRepository.GetFundingDate(fundingDateId));
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"No funding Dates were found for funding stream id : {fundingStreamId}");
            }

            if (fundingDate == null)
            {
                _logger.Error($"No funding Dates were found for funding stream id : {fundingStreamId}");

                return(new NotFoundResult());
            }

            return(new OkObjectResult(fundingDate));
        }
        public async Task <IActionResult> HasCalculationResults(string calculationId)
        {
            Guard.IsNullOrWhiteSpace(calculationId, nameof(calculationId));

            Common.ApiClient.Calcs.Models.Calculation calculation = await _calculationsRepositoryPolicy.ExecuteAsync(() => _calculationRepository.GetCalculationById(calculationId));

            if (calculation == null)
            {
                _logger.Error($"Calculation could not be found for calculation id '{calculationId}'");

                return(new NotFoundObjectResult($"Calculation could not be found for calculation id '{calculationId}'"));
            }

            ProviderResult providerResult = await _resultsRepositoryPolicy.ExecuteAsync(() => _resultsRepository.GetSingleProviderResultBySpecificationId(calculation.SpecificationId));

            CalculationResult calculationResult = providerResult?
                                                  .CalculationResults?
                                                  .FirstOrDefault(m =>
                                                                  string.Equals(m.Calculation.Id,
                                                                                calculationId,
                                                                                StringComparison.InvariantCultureIgnoreCase));

            if (calculationResult != null)
            {
                return(new OkObjectResult(true));
            }

            return(new OkObjectResult(false));
        }
Beispiel #12
0
        public override async Task Process(Message message)
        {
            Guard.ArgumentNotNull(message, nameof(message));

            string specificationId = UserPropertyFrom(message, "specification-id");

            IEnumerable <Calculation> calculations =
                (await _calculationRepositoryPolicy.ExecuteAsync(() =>
                                                                 _calculationsRepository.GetCalculationsBySpecificationId(specificationId)))
                .ToArraySafe();

            if (calculations.IsNullOrEmpty())
            {
                string calcNotFoundMessage = $"No calculations found for specification id: {specificationId}";

                _logger.Information(calcNotFoundMessage);

                return;
            }

            foreach (Calculation calculation in calculations)
            {
                calculation.Current.PublishStatus = Models.Versioning.PublishStatus.Approved;
            }

            ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse =
                await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId));

            if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null)
            {
                throw new NonRetriableException("Specification not found");
            }

            SpecModel.SpecificationSummary specificationSummary = specificationApiResponse.Content;

            await _calculationRepositoryPolicy.ExecuteAsync(() => _calculationsRepository.UpdateCalculations(calculations));

            await UpdateSearch(calculations, specificationSummary);

            IEnumerable <Task> tasks = calculations.Select(_ => UpdateCalculationInCache(_.ToResponseModel()));

            await TaskHelper.WhenAllAndThrow(tasks.ToArraySafe());

            await UpdateCalculationsInCache(specificationSummary);
        }
Beispiel #13
0
        public async Task <IEnumerable <PublishedFunding> > GetPublishedFundings(
            IEnumerable <KeyValuePair <string, string> > publishedFundingIds)
        {
            ConcurrentBag <PublishedFunding> concurrentObjects = new ConcurrentBag <PublishedFunding>();

            List <Task>   allTasks  = new List <Task>();
            SemaphoreSlim throttler = new SemaphoreSlim(initialCount: _publishingEngineOptions.PublishedFundingConcurrencyCount);

            foreach (IEnumerable <KeyValuePair <string, string> > batchPublishedFundingIds in publishedFundingIds.ToBatches(_publishingEngineOptions.MaxBatchSizePublishedFunding))
            {
                await throttler.WaitAsync();

                allTasks.Add(
                    Task.Run(async() =>
                {
                    try
                    {
                        List <Task <DocumentEntity <PublishedFunding> > > concurrentTasks = new List <Task <DocumentEntity <PublishedFunding> > >();

                        foreach (KeyValuePair <string, string> publishedFundingIdPair in batchPublishedFundingIds)
                        {
                            concurrentTasks.Add(
                                _publishedFundingRepositoryPolicy.ExecuteAsync(() =>
                                                                               _repository.ReadDocumentByIdPartitionedAsync <PublishedFunding>(
                                                                                   publishedFundingIdPair.Key,
                                                                                   publishedFundingIdPair.Value)));
                        }

                        await TaskHelper.WhenAllAndThrow(concurrentTasks.ToArraySafe());

                        concurrentTasks.ForEach(_ => concurrentObjects.Add(_.Result.Content));
                    }
                    finally
                    {
                        throttler.Release();
                    }
                }));
            }

            await TaskHelper.WhenAllAndThrow(allTasks.ToArray());

            return(concurrentObjects);
        }
        public async Task <IActionResult> GetFundingPeriodById(string fundingPeriodId)
        {
            if (string.IsNullOrWhiteSpace(fundingPeriodId))
            {
                _logger.Error("No funding period id was provided to GetFundingPeriodById");

                return(new BadRequestObjectResult("Null or empty funding period id provided"));
            }

            FundingPeriod fundingPeriod = await _policyRepositoryPolicy.ExecuteAsync(() => _policyRepository.GetFundingPeriodById(fundingPeriodId));

            if (fundingPeriod == null)
            {
                _logger.Error($"No funding period was returned for funding period id: '{fundingPeriodId}'");

                return(new NotFoundResult());
            }

            return(new OkObjectResult(fundingPeriod));
        }
Beispiel #15
0
        public async Task <IEnumerable <FundingStream> > GetAllFundingStreams()
        {
            IEnumerable <FundingStream> fundingStreams = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetAsync <FundingStream[]>(CacheKeys.AllFundingStreams));

            if (fundingStreams.IsNullOrEmpty())
            {
                fundingStreams = await _policyRepositoryPolicy.ExecuteAsync(() => _policyRepository.GetFundingStreams());

                if (fundingStreams.IsNullOrEmpty())
                {
                    _logger.Error("No funding streams were returned");

                    fundingStreams = new FundingStream[0];
                }

                await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetAsync <FundingStream[]>(CacheKeys.AllFundingStreams, fundingStreams.ToArray()));
            }

            return(fundingStreams);
        }
Beispiel #16
0
        public async Task <IActionResult> GetJobById(string jobId, bool includeChildJobs)
        {
            Guard.IsNullOrWhiteSpace(jobId, nameof(jobId));

            Job job = await _jobsRepositoryPolicy.ExecuteAsync(() => _jobRepository.GetJobById(jobId));

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

            JobViewModel jobViewModel = _mapper.Map <JobViewModel>(job);

            IEnumerable <Job> childJobs = await _jobsRepositoryPolicy.ExecuteAsync(() => _jobRepository.GetChildJobsForParent(jobId));

            if (!childJobs.IsNullOrEmpty())
            {
                foreach (Job childJob in childJobs)
                {
                    jobViewModel.ChildJobs.Add(_mapper.Map <JobViewModel>(childJob));
                }
            }

            return(new OkObjectResult(jobViewModel));
        }
Beispiel #17
0
        public async Task ResetScenarioForFieldDefinitionChanges(IEnumerable <DatasetSpecificationRelationshipViewModel> relationships, string specificationId, IEnumerable <string> currentFieldDefinitionNames)
        {
            Guard.ArgumentNotNull(relationships, nameof(relationships));
            Guard.IsNullOrWhiteSpace(specificationId, nameof(specificationId));
            Guard.ArgumentNotNull(currentFieldDefinitionNames, nameof(currentFieldDefinitionNames));

            IEnumerable <TestScenario> scenarios = await _scenariosRepositoryPolicy.ExecuteAsync(() => _scenariosRepository.GetTestScenariosBySpecificationId(specificationId));

            if (scenarios.IsNullOrEmpty())
            {
                _logger.Information($"No scenarios found for specification id '{specificationId}'");
                return;
            }

            List <string> fieldIdentifiers = new List <string>();

            foreach (DatasetSpecificationRelationshipViewModel datasetSpecificationRelationshipViewModel in relationships)
            {
                fieldIdentifiers.AddRange(currentFieldDefinitionNames.Select(m => $"dataset {datasetSpecificationRelationshipViewModel.Name} field {_typeIdentifierGenerator.GenerateIdentifier(m)}"));
            }

            IEnumerable <TestScenario> scenariosToUpdate = scenarios.Where(m => SourceCodeHelpers.CodeContainsFullyQualifiedDatasetFieldIdentifier(m.Current.Gherkin.RemoveAllQuotes(), fieldIdentifiers));

            if (scenariosToUpdate.IsNullOrEmpty())
            {
                _logger.Information($"No test scenarios required resetting for specification id '{specificationId}'");
                return;
            }

            const string reasonForCommenting = "The dataset definition referenced by this scenario/spec has been updated and subsequently the code has been commented out";

            foreach (TestScenario scenario in scenariosToUpdate)
            {
                string gherkin = scenario.Current.Gherkin;

                string updatedGherkin = SourceCodeHelpers.CommentOutCode(gherkin, reasonForCommenting, commentSymbol: "#");

                await SaveVersion(scenario, updatedGherkin);
            }
        }
        public async Task <IEnumerable <FundingPeriod> > GetAllFundingPeriods()
        {
            IEnumerable <FundingPeriod> fundingPeriods = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetAsync <FundingPeriod[]>(CacheKeys.FundingPeriods));

            if (fundingPeriods.IsNullOrEmpty())
            {
                fundingPeriods = await _policyRepositoryPolicy.ExecuteAsync(() => _policyRepository.GetFundingPeriods());

                if (fundingPeriods.IsNullOrEmpty())
                {
                    _logger.Error("No funding periods were returned");

                    fundingPeriods = new FundingPeriod[0];
                }
                else
                {
                    await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetAsync(CacheKeys.FundingPeriods, fundingPeriods.ToArraySafe()));
                }
            }

            return(fundingPeriods);
        }
        public async Task <Job> QueueCsvGenerationMessageIfNewCalculationResults(string specificationId, string specificationName)
        {
            bool hasNewResults = false;

            bool blobExists = await _blobClientPolicy.ExecuteAsync(() =>
                                                                   _blobClient.DoesBlobExistAsync($"{CalculationResultsReportFilePrefix}-{specificationId}", CalcsResultsContainerName));

            if (blobExists)
            {
                ICloudBlob cloudBlob = await _blobClientPolicy.ExecuteAsync(() =>
                                                                            _blobClient.GetBlobReferenceFromServerAsync(
                                                                                $"{CalculationResultsReportFilePrefix}-{specificationId}",
                                                                                CalcsResultsContainerName));

                DateTimeOffset?lastModified = cloudBlob.Properties?.LastModified;

                hasNewResults = await _resultsRepositoryPolicy.ExecuteAsync(
                    () => _resultsRepository.CheckHasNewResultsForSpecificationIdAndTime(specificationId,
                                                                                         lastModified.GetValueOrDefault()));
            }
            else
            {
                // only queue the csv report job if there are calculation results for the specification
                hasNewResults = await _resultsRepositoryPolicy.ExecuteAsync(
                    () => _resultsRepository.ProviderHasResultsBySpecificationId(specificationId));
            }

            if (!hasNewResults)
            {
                _logger.Information(
                    $"No new calculation results for specification id '{specificationId}'. Not queueing report job");

                return(null);
            }

            _logger.Information($"Found new calculation results for specification id '{specificationId}'");

            return(await QueueCsvGenerationMessage(specificationId, specificationName));
        }
        public async Task <IActionResult> GetFundingConfiguration(string fundingStreamId, string fundingPeriodId)
        {
            if (string.IsNullOrWhiteSpace(fundingStreamId))
            {
                _logger.Error("No funding stream Id was provided to GetFundingConfiguration");

                return(new BadRequestObjectResult("Null or empty funding stream Id provided"));
            }

            if (string.IsNullOrWhiteSpace(fundingPeriodId))
            {
                _logger.Error("No funding period Id was provided to GetFundingConfiguration");

                return(new BadRequestObjectResult("Null or empty funding period Id provided"));
            }

            string cacheKey = $"{CacheKeys.FundingConfig}{fundingStreamId}-{fundingPeriodId}";
            string configId = $"config-{fundingStreamId}-{fundingPeriodId}";

            FundingConfiguration fundingConfiguration = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetAsync <FundingConfiguration>(cacheKey));

            if (fundingConfiguration == null)
            {
                fundingConfiguration = await _policyRepositoryPolicy.ExecuteAsync(() => _policyRepository.GetFundingConfiguration(configId));

                await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetAsync(cacheKey, fundingConfiguration));
            }

            if (fundingConfiguration == null)
            {
                _logger.Error($"No funding Configuration was found for funding stream id : {fundingStreamId} and funding period id : {fundingPeriodId}");

                return(new NotFoundResult());
            }

            return(new OkObjectResult(fundingConfiguration));
        }
        public async Task <IActionResult> SaveFundingTemplate(string actionName, string controllerName, string template, string fundingStreamId, string fundingPeriodId, string templateVersion)
        {
            Guard.IsNullOrWhiteSpace(actionName, nameof(actionName));
            Guard.IsNullOrWhiteSpace(controllerName, nameof(controllerName));
            Guard.IsNullOrWhiteSpace(fundingStreamId, nameof(fundingStreamId));
            Guard.IsNullOrWhiteSpace(fundingPeriodId, nameof(fundingPeriodId));
            Guard.IsNullOrWhiteSpace(templateVersion, nameof(templateVersion));

            //Already checked for null above when getting body
            if (template.Trim() == string.Empty)
            {
                return(new BadRequestObjectResult("Null or empty funding template was provided."));
            }

            FundingTemplateValidationResult validationResult = await _fundingTemplateValidationService.ValidateFundingTemplate(template, fundingStreamId, fundingPeriodId, templateVersion);

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

            ITemplateMetadataGenerator templateMetadataGenerator = _templateMetadataResolver.GetService(validationResult.SchemaVersion);

            ValidationResult validationGeneratorResult = templateMetadataGenerator.Validate(template);

            if (!validationGeneratorResult.IsValid)
            {
                return(validationGeneratorResult.PopulateModelState());
            }

            string blobName = GetBlobNameFor(validationResult.FundingStreamId, validationResult.FundingPeriodId, validationResult.TemplateVersion);

            try
            {
                byte[] templateFileBytes = Encoding.UTF8.GetBytes(template);

                await SaveFundingTemplateVersion(blobName, templateFileBytes);

                string cacheKey = $"{CacheKeys.FundingTemplatePrefix}{validationResult.FundingStreamId}-{validationResult.FundingPeriodId}-{validationResult.TemplateVersion}".ToLowerInvariant();
                await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.RemoveAsync <string>(cacheKey));

                await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.RemoveAsync <FundingTemplateContents>($"{CacheKeys.FundingTemplateContents}{validationResult.FundingStreamId}:{validationResult.FundingPeriodId}:{validationResult.TemplateVersion}".ToLowerInvariant()));

                await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.RemoveAsync <TemplateMetadataContents>($"{CacheKeys.FundingTemplateContentMetadata}{validationResult.FundingStreamId}:{validationResult.FundingPeriodId}:{validationResult.TemplateVersion}".ToLowerInvariant()));

                await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.RemoveAsync <TemplateMetadataDistinctContents>($"{CacheKeys.FundingTemplateContentMetadataDistinct}{validationResult.FundingStreamId}:{validationResult.FundingPeriodId}:{validationResult.TemplateVersion}".ToLowerInvariant()));

                return(new CreatedAtActionResult(actionName, controllerName, new { fundingStreamId = validationResult.FundingStreamId, fundingPeriodId = validationResult.FundingPeriodId, templateVersion = validationResult.TemplateVersion }, string.Empty));
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"Failed to save funding template '{blobName}' to blob storage");

                return(new InternalServerErrorResult("Error occurred uploading funding template"));
            }
        }
        public override async Task Process(Message message)
        {
            SpecificationVersionComparisonModel versionComparison = message.GetPayloadAsInstanceOf <SpecificationVersionComparisonModel>();

            if (versionComparison == null || versionComparison.Current == null || versionComparison.Previous == null)
            {
                _logger.Error($"A null versionComparison was provided to users");

                throw new InvalidModelException(nameof(SpecificationVersionComparisonModel), new[] { "Null or invalid model provided" });
            }

            string specificationId = versionComparison.Id;

            if (string.IsNullOrWhiteSpace(specificationId))
            {
                _logger.Error($"A null specificationId was provided to users in model");

                throw new InvalidModelException(nameof(SpecificationVersionComparisonModel), new[] { "Null or invalid specificationId on model" });
            }

            IEnumerable <string> previousFundingStreams = versionComparison.Previous.FundingStreams.OrderBy(c => c.Id).Select(f => f.Id);
            IEnumerable <string> currentFundingStreams  = versionComparison.Current.FundingStreams.OrderBy(c => c.Id).Select(f => f.Id);

            if (!previousFundingStreams.SequenceEqual(currentFundingStreams))
            {
                _logger.Information("Found changed funding streams for specification '{SpecificationId}' Previous: {PreviousFundingStreams} Current {CurrentFundingStreams}", specificationId, previousFundingStreams, currentFundingStreams);

                Dictionary <string, bool> userIds = new Dictionary <string, bool>();

                IEnumerable <string> allFundingStreamIds = previousFundingStreams.Union(currentFundingStreams);

                foreach (string fundingStreamId in allFundingStreamIds)
                {
                    IEnumerable <FundingStreamPermission> userPermissions = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetUsersWithFundingStreamPermissions(fundingStreamId));

                    foreach (FundingStreamPermission permission in userPermissions)
                    {
                        if (!userIds.ContainsKey(permission.UserId))
                        {
                            userIds.Add(permission.UserId, true);
                        }
                    }
                }

                foreach (string userId in userIds.Keys)
                {
                    _logger.Information("Clearing effective permissions for userId '{UserId}' for specification '{SpecificationId}'", userId, specificationId);
                    await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.DeleteHashKey <EffectiveSpecificationPermission>($"{CacheKeys.EffectivePermissions}:{userId}", specificationId));
                }
            }
            else
            {
                _logger.Information("No funding streams have changed for specification '{SpecificationId}' which require effective permission clearing.", specificationId);
            }
        }
Beispiel #23
0
        public async Task <IDictionary <string, ProviderCalculationResult> > GetCalculationResultsBySpecificationId(string specificationId, IEnumerable <string> scopedProviderIds)
        {
            if (!scopedProviderIds.AnyWithNullCheck())
            {
                return(new Dictionary <string, ProviderCalculationResult>());;
            }

            List <string> providerIds = new List <string>(scopedProviderIds.Distinct());
            List <Task <IEnumerable <ProviderCalculationResult> > > allTasks = new List <Task <IEnumerable <ProviderCalculationResult> > >();

            foreach (var providerId in providerIds)
            {
                allTasks.Add(_resultsRepositoryPolicy.ExecuteAsync(() =>
                                                                   _calculationResultsRepository.GetCalculationResultsBySpecificationAndProvider(specificationId, providerId)));
            }

            await Task.WhenAll(allTasks);

            IEnumerable <ProviderCalculationResult> providerCalculationResults = allTasks.SelectMany(_ => _.Result);

            return(providerCalculationResults.ToDictionary(_ => _.ProviderId));
        }
        public async Task <IActionResult> GetFundingByFundingResultId(string id)
        {
            Guard.IsNullOrWhiteSpace(id, nameof(id));

            PublishedFundingIndex fundingIndexedDocument = await _fundingSearchRepositoryPolicy.ExecuteAsync(() => _fundingSearchRepository.SearchById(id));

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

            string fundingDocument = await _publishedFundingRetrievalService.GetFundingFeedDocument(fundingIndexedDocument.DocumentPath);

            if (string.IsNullOrWhiteSpace(fundingDocument))
            {
                _logger.Error("Failed to find blob with id {id} and document path: {documentPath}", id, fundingIndexedDocument.DocumentPath);
                return(new NotFoundResult());
            }

            return(new ContentResult()
            {
                Content = fundingDocument, ContentType = "application/json", StatusCode = (int)HttpStatusCode.OK
            });
        }
        public async Task <IActionResult> GetFundingStreamPermissionsForUser(string userId)
        {
            if (string.IsNullOrWhiteSpace(userId))
            {
                return(new BadRequestObjectResult($"{nameof(userId)} is null or empty"));
            }

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

            IEnumerable <FundingStreamPermission> permissions = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetFundingStreamPermissions(userId));

            if (permissions.AnyWithNullCheck())
            {
                foreach (FundingStreamPermission permission in permissions)
                {
                    results.Add(_mapper.Map <FundingStreamPermissionCurrent>(permission));
                }
            }

            return(new OkObjectResult(results));
        }
        public override async Task Process(Message message)
        {
            Guard.ArgumentNotNull(message, nameof(message));

            Reference user = message.GetUserDetails();

            _logger.Information($"{nameof(ReIndexCalculationResults)} initiated by: '{user.Name}'");

            ApiResponse <IEnumerable <SpecModel.SpecificationSummary> > specificationsApiResponse = await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaries());

            if (specificationsApiResponse == null || !specificationsApiResponse.StatusCode.IsSuccess() || specificationsApiResponse.Content == null)
            {
                return;
            }

            IEnumerable <SpecModel.SpecificationSummary> specifications = specificationsApiResponse.Content;

            foreach (SpecModel.SpecificationSummary specification in specifications)
            {
                await _resultsRepositoryPolicy.ExecuteAsync(() => _resultsRepository.ProviderResultsBatchProcessing(specification.Id, async(x) =>
                {
                    IList <ProviderCalculationResultsIndex> results = new List <ProviderCalculationResultsIndex>();

                    foreach (ProviderResult providerResult in x)
                    {
                        if (!providerResult.CalculationResults.IsNullOrEmpty())
                        {
                            ProviderCalculationResultsIndex calculationResult = new ProviderCalculationResultsIndex
                            {
                                SpecificationId   = providerResult.SpecificationId,
                                SpecificationName = specification?.Name,
                                ProviderId        = providerResult.Provider?.Id,
                                ProviderName      = providerResult.Provider?.Name,
                                ProviderType      = providerResult.Provider?.ProviderType,
                                ProviderSubType   = providerResult.Provider?.ProviderSubType,
                                LocalAuthority    = providerResult.Provider?.Authority,
                                LastUpdatedDate   = providerResult.CreatedAt,
                                UKPRN             = providerResult.Provider?.UKPRN,
                                URN  = providerResult.Provider?.URN,
                                UPIN = providerResult.Provider?.UPIN,
                                EstablishmentNumber = providerResult.Provider?.EstablishmentNumber,
                                OpenDate            = providerResult.Provider?.DateOpened,
                                CalculationId       = providerResult.CalculationResults.Select(m => m.Calculation.Id).ToArraySafe(),
                                CalculationName     = providerResult.CalculationResults.Select(m => m.Calculation.Name).ToArraySafe(),
                                CalculationResult   = providerResult.CalculationResults.Select(m => !string.IsNullOrEmpty(m.Value?.ToString()) ? m.Value.ToString() : "null").ToArraySafe()
                            };

                            if (providerResult.FundingLineResults != null)
                            {
                                calculationResult.FundingLineName            = providerResult.FundingLineResults?.Select(m => m.FundingLine.Name).ToArraySafe();
                                calculationResult.FundingLineFundingStreamId = providerResult.FundingLineResults?.Select(m => m.FundingLineFundingStreamId).ToArraySafe();
                                calculationResult.FundingLineId     = providerResult.FundingLineResults?.Select(m => m.FundingLine.Id).ToArraySafe();
                                calculationResult.FundingLineResult = providerResult.FundingLineResults?.Select(m => !string.IsNullOrEmpty(m.Value?.ToString()) ? m.Value.ToString() : "null").ToArraySafe();
                            }

                            if (_featureToggle.IsExceptionMessagesEnabled())
                            {
                                calculationResult.CalculationException = providerResult.CalculationResults
                                                                         .Where(m => !string.IsNullOrWhiteSpace(m.ExceptionType))
                                                                         .Select(e => e.Calculation.Id)
                                                                         .ToArraySafe();

                                calculationResult.CalculationExceptionType = providerResult.CalculationResults
                                                                             .Select(m => m.ExceptionType ?? string.Empty)
                                                                             .ToArraySafe();

                                calculationResult.CalculationExceptionMessage = providerResult.CalculationResults
                                                                                .Select(m => m.ExceptionMessage ?? string.Empty)
                                                                                .ToArraySafe();

                                if (providerResult.FundingLineResults != null)
                                {
                                    calculationResult.FundingLineException = providerResult.FundingLineResults
                                                                             .Where(m => !string.IsNullOrWhiteSpace(m.ExceptionType))
                                                                             .Select(e => e.FundingLine.Id)
                                                                             .ToArraySafe();

                                    calculationResult.FundingLineExceptionType = providerResult.FundingLineResults
                                                                                 .Select(m => m.ExceptionType ?? string.Empty)
                                                                                 .ToArraySafe();

                                    calculationResult.FundingLineExceptionMessage = providerResult.FundingLineResults
                                                                                    .Select(m => m.ExceptionMessage ?? string.Empty)
                                                                                    .ToArraySafe();
                                }
                            }

                            results.Add(calculationResult);
                        }
                    }

                    IEnumerable <IndexError> errors = await _resultsSearchRepositoryPolicy.ExecuteAsync(() => _providerCalculationResultsSearchRepository.Index(results));

                    if (errors.Any())
                    {
                        string errorMessage = $"Failed to index calculation provider result documents with errors: { string.Join(";", errors.Select(m => m.ErrorMessage)) }";

                        _logger.Error(errorMessage);

                        throw new RetriableException(errorMessage);
                    }
                }));
            }
        }
Beispiel #27
0
        public SpecificationCreateModelValidator(ISpecificationsRepository specificationsRepository,
                                                 IProvidersApiClient providersApiClient,
                                                 IPoliciesApiClient policiesApiClient,
                                                 ISpecificationsResiliencePolicies resiliencePolicies)
        {
            Guard.ArgumentNotNull(specificationsRepository, nameof(specificationsRepository));
            Guard.ArgumentNotNull(providersApiClient, nameof(providersApiClient));
            Guard.ArgumentNotNull(policiesApiClient, nameof(policiesApiClient));
            Guard.ArgumentNotNull(resiliencePolicies?.PoliciesApiClient, nameof(resiliencePolicies.PoliciesApiClient));

            _specificationsRepository = specificationsRepository;
            _providersApiClient       = providersApiClient;
            _policiesApiClient        = policiesApiClient;
            _policiesApiClientPolicy  = resiliencePolicies.PoliciesApiClient;

            RuleFor(model => model.FundingPeriodId)
            .NotEmpty()
            .WithMessage("Null or empty academic year id provided")
            .Custom((name, context) =>
            {
                SpecificationCreateModel specModel = context.ParentContext.InstanceToValidate as SpecificationCreateModel;
                if (!string.IsNullOrWhiteSpace(specModel.FundingPeriodId))
                {
                    ApiResponse <PolicyModels.FundingPeriod> fundingPeriodResponse =
                        _policiesApiClientPolicy.ExecuteAsync(() => _policiesApiClient.GetFundingPeriodById(specModel.FundingPeriodId)).GetAwaiter().GetResult();
                    if (fundingPeriodResponse?.StatusCode != HttpStatusCode.OK || fundingPeriodResponse?.Content == null)
                    {
                        context.AddFailure("Funding period not found");
                    }
                }
            });

            RuleFor(model => model.ProviderVersionId)
            .Custom((name, context) => {
                SpecificationCreateModel specModel = context.ParentContext.InstanceToValidate as SpecificationCreateModel;
                ApiResponse <PolicyModels.FundingConfig.FundingConfiguration> fundingConfigResponse =
                    _policiesApiClientPolicy.ExecuteAsync(() => _policiesApiClient.GetFundingConfiguration(specModel.FundingStreamIds.FirstOrDefault(), specModel.FundingPeriodId)).GetAwaiter().GetResult();

                if (fundingConfigResponse?.StatusCode != HttpStatusCode.OK || fundingConfigResponse?.Content == null)
                {
                    context.AddFailure("Funding config not found");
                    return;
                }

                switch (fundingConfigResponse.Content.ProviderSource)
                {
                case ProviderSource.CFS:
                    {
                        if (string.IsNullOrWhiteSpace(specModel.ProviderVersionId))
                        {
                            context.AddFailure($"Null or empty provider version id");
                        }

                        if (_providersApiClient.DoesProviderVersionExist(specModel.ProviderVersionId).Result == System.Net.HttpStatusCode.NotFound)
                        {
                            context.AddFailure($"Provider version id selected does not exist");
                        }

                        if (specModel.CoreProviderVersionUpdates != CoreProviderVersionUpdates.Manual)
                        {
                            context.AddFailure($"CoreProviderVersionUpdates - {specModel.CoreProviderVersionUpdates} is not valid for provider source - {fundingConfigResponse.Content.ProviderSource}");
                        }

                        break;
                    }

                case ProviderSource.FDZ:
                    {
                        if (!specModel.ProviderSnapshotId.HasValue)
                        {
                            context.AddFailure($"Null or empty provider snapshot id");
                        }

                        break;
                    }
                }
            });

            RuleFor(model => model.FundingStreamIds)
            .NotNull()
            .NotEmpty()
            .WithMessage("You must select at least one funding stream")
            .Custom((name, context) => {
                SpecificationCreateModel specModel = context.ParentContext.InstanceToValidate as SpecificationCreateModel;
                foreach (string fundingStreamId in specModel.FundingStreamIds)
                {
                    if (string.IsNullOrWhiteSpace(fundingStreamId))
                    {
                        context.AddFailure($"A null or empty string funding stream ID was provided");
                    }
                }
            });

            RuleFor(model => model.Name)
            .NotEmpty()
            .WithMessage("You must give a unique specification name")
            .Custom((name, context) => {
                SpecificationCreateModel specModel = context.ParentContext.InstanceToValidate as SpecificationCreateModel;
                Specification specification        = _specificationsRepository.GetSpecificationByQuery(m => m.Content.Name.ToLower() == specModel.Name.Trim().ToLower()).Result;
                if (specification != null)
                {
                    context.AddFailure($"You must give a unique specification name");
                }
            });
        }
        public async Task <IActionResult> GetEffectivePermissionsForUser(string userId, string specificationId)
        {
            if (string.IsNullOrWhiteSpace(userId))
            {
                return(new BadRequestObjectResult($"{nameof(userId)} is empty or null"));
            }

            if (string.IsNullOrWhiteSpace(specificationId))
            {
                return(new BadRequestObjectResult($"{nameof(specificationId)} is empty or null"));
            }

            EffectiveSpecificationPermission cachedPermissions = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.GetHashValue <EffectiveSpecificationPermission>($"{CacheKeys.EffectivePermissions}:{userId}", specificationId));

            if (cachedPermissions != null)
            {
                return(new OkObjectResult(cachedPermissions));
            }
            else
            {
                ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse =
                    await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(specificationId));

                if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null)
                {
                    return(new PreconditionFailedResult("Specification not found"));
                }

                SpecModel.SpecificationSummary specification = specificationApiResponse.Content;

                List <FundingStreamPermission> permissionsForUser = new List <FundingStreamPermission>();
                foreach (Reference fundingStream in specification.FundingStreams)
                {
                    FundingStreamPermission permission = await _userRepositoryPolicy.ExecuteAsync(() => _userRepository.GetFundingStreamPermission(userId, fundingStream.Id));

                    if (permission != null)
                    {
                        permissionsForUser.Add(permission);
                    }
                    else
                    {
                        // Add permission for this funding stream with no permissions - used further down to calculate permissions (required for pessimistic permissions)
                        permissionsForUser.Add(new FundingStreamPermission
                        {
                            UserId                       = userId,
                            FundingStreamId              = fundingStream.Id,
                            CanApproveFunding            = false,
                            CanChooseFunding             = false,
                            CanCreateSpecification       = false,
                            CanEditCalculations          = false,
                            CanEditSpecification         = false,
                            CanMapDatasets               = false,
                            CanReleaseFunding            = false,
                            CanAdministerFundingStream   = false,
                            CanApproveSpecification      = false,
                            CanCreateQaTests             = false,
                            CanDeleteCalculations        = false,
                            CanDeleteSpecification       = false,
                            CanDeleteQaTests             = false,
                            CanEditQaTests               = false,
                            CanRefreshFunding            = false,
                            CanCreateTemplates           = false,
                            CanEditTemplates             = false,
                            CanDeleteTemplates           = false,
                            CanApproveTemplates          = false,
                            CanCreateProfilePattern      = false,
                            CanEditProfilePattern        = false,
                            CanDeleteProfilePattern      = false,
                            CanAssignProfilePattern      = false,
                            CanApplyCustomProfilePattern = false,
                            CanApproveCalculations       = false,
                            CanApproveAnyCalculations    = false,
                            CanApproveAllCalculations    = false
                        });
                    }
                }

                EffectiveSpecificationPermission specificationPermissions = GeneratePermissions(permissionsForUser, specificationId, userId);

                string userPermissionHashKey = $"{CacheKeys.EffectivePermissions}:{userId}";

                // Does the hash set for this user already exist - used to determine the timeout for the hash set below
                bool existingHashSetExists = await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.HashSetExists(userPermissionHashKey));

                // Cache effective permissions for the specification / user
                await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashValue(userPermissionHashKey, specificationId, specificationPermissions));

                // If the hash set does not exist, then set an expiry for the whole hash set. This stops the users permissions being stored indefinitely
                if (!existingHashSetExists)
                {
                    await _cacheProviderPolicy.ExecuteAsync(() => _cacheProvider.SetHashExpiry(userPermissionHashKey, DateTime.UtcNow.AddHours(12)));
                }

                return(new OkObjectResult(specificationPermissions));
            }
        }
Beispiel #29
0
        private async Task <Build> CheckDatasetValidAggregations(PreviewRequest previewRequest)
        {
            Build build = null;

            IEnumerable <string> aggregateParameters = SourceCodeHelpers.GetDatasetAggregateFunctionParameters(previewRequest.SourceCode);

            if (aggregateParameters.IsNullOrEmpty())
            {
                return(build);
            }

            string cacheKey = $"{CacheKeys.DatasetRelationshipFieldsForSpecification}{previewRequest.SpecificationId}";

            IEnumerable <DatasetSchemaRelationshipModel> datasetSchemaRelationshipModels = Enumerable.Empty <DatasetSchemaRelationshipModel>();

            datasetSchemaRelationshipModels = await _cacheProvider.GetAsync <List <DatasetSchemaRelationshipModel> >(cacheKey);

            if (datasetSchemaRelationshipModels.IsNullOrEmpty())
            {
                ApiResponse <IEnumerable <Common.ApiClient.DataSets.Models.DatasetSchemaRelationshipModel> > datasetsApiClientResponse = await _datasetsApiClientPolicy.ExecuteAsync(() => _datasetsApiClient.GetDatasetSchemaRelationshipModelsForSpecificationId(previewRequest.SpecificationId));

                if (!datasetsApiClientResponse.StatusCode.IsSuccess())
                {
                    string message = $"No dataset schema relationship found for specificationId '{previewRequest.SpecificationId}'.";
                    _logger.Error(message);
                    throw new RetriableException(message);
                }

                if (datasetsApiClientResponse.Content != null)
                {
                    datasetSchemaRelationshipModels = _mapper.Map <IEnumerable <DatasetSchemaRelationshipModel> >(datasetsApiClientResponse.Content);
                }

                await _cacheProvider.SetAsync <List <DatasetSchemaRelationshipModel> >(cacheKey, datasetSchemaRelationshipModels.ToList());
            }

            HashSet <string> compilerErrors = new HashSet <string>();

            IEnumerable <string> datasetAggregationFields = datasetSchemaRelationshipModels?.SelectMany(m => m.Fields?.Where(f => f.IsAggregable).Select(f => f.FullyQualifiedSourceName));

            foreach (string aggregateParameter in aggregateParameters)
            {
                if (datasetAggregationFields.IsNullOrEmpty() || !datasetAggregationFields.Any(m => string.Equals(m.Trim(), aggregateParameter.Trim(), StringComparison.CurrentCultureIgnoreCase)))
                {
                    compilerErrors.Add($"{aggregateParameter} is not an aggregable field");
                }
            }

            if (compilerErrors.Any())
            {
                build = new Build
                {
                    CompilerMessages = compilerErrors.Select(m => new CompilerMessage {
                        Message = m, Severity = Severity.Error
                    }).ToList()
                };
            }

            return(build);
        }
Beispiel #30
0
        public async Task <IActionResult> SaveVersion(CreateNewTestScenarioVersion scenarioVersion, Reference user, string correlationId)
        {
            if (scenarioVersion == null)
            {
                _logger.Error("A null scenario version was provided");

                return(new BadRequestObjectResult("Null or empty calculation Id provided"));
            }

            BadRequestObjectResult validationResult = (await _createNewTestScenarioVersionValidator.ValidateAsync(scenarioVersion)).PopulateModelState();

            if (validationResult != null)
            {
                return(validationResult);
            }

            TestScenario testScenario = null;

            if (!string.IsNullOrEmpty(scenarioVersion.Id))
            {
                testScenario = await _scenariosRepository.GetTestScenarioById(scenarioVersion.Id);
            }

            bool saveAsVersion = true;

            Common.ApiClient.Models.ApiResponse <SpecModel.SpecificationSummary> specificationApiResponse =
                await _specificationsApiClientPolicy.ExecuteAsync(() => _specificationsApiClient.GetSpecificationSummaryById(scenarioVersion.SpecificationId));

            if (!specificationApiResponse.StatusCode.IsSuccess() || specificationApiResponse.Content == null)
            {
                _logger.Error($"Unable to find a specification for specification id : {scenarioVersion.SpecificationId}");
                return(new StatusCodeResult(412));
            }

            SpecModel.SpecificationSummary specification = specificationApiResponse.Content;

            if (testScenario == null)
            {
                string Id = Guid.NewGuid().ToString();

                testScenario = new TestScenario
                {
                    Id = Id,
                    SpecificationId = specification.Id,
                    Name            = scenarioVersion.Name,
                    Current         = new TestScenarioVersion
                    {
                        Date             = DateTimeOffset.Now.ToLocalTime(),
                        TestScenarioId   = Id,
                        PublishStatus    = PublishStatus.Draft,
                        Version          = 1,
                        Author           = user,
                        Gherkin          = scenarioVersion.Scenario,
                        Description      = scenarioVersion.Description,
                        FundingPeriodId  = specification.FundingPeriod.Id,
                        FundingStreamIds = specification.FundingStreams.Select(s => s.Id).ToArraySafe(),
                    }
                };
            }
            else
            {
                testScenario.Name = scenarioVersion.Name;

                saveAsVersion = !string.Equals(scenarioVersion.Scenario, testScenario.Current.Gherkin) ||
                                scenarioVersion.Description != testScenario.Current.Description;

                TestScenarioVersion newVersion = testScenario.Current.Clone() as TestScenarioVersion;

                if (saveAsVersion == true)
                {
                    newVersion.Author           = user;
                    newVersion.Gherkin          = scenarioVersion.Scenario;
                    newVersion.Description      = scenarioVersion.Description;
                    newVersion.FundingStreamIds = specification.FundingStreams.Select(s => s.Id).ToArraySafe();
                    newVersion.FundingPeriodId  = specification.FundingPeriod.Id;

                    newVersion = await _versionRepository.CreateVersion(newVersion, testScenario.Current);

                    testScenario.Current = newVersion;
                }
            }

            HttpStatusCode statusCode = await _scenariosRepository.SaveTestScenario(testScenario);

            if (!statusCode.IsSuccess())
            {
                _logger.Error($"Failed to save test scenario with status code: {statusCode}");

                return(new StatusCodeResult((int)statusCode));
            }

            await _versionRepository.SaveVersion(testScenario.Current);

            ScenarioIndex scenarioIndex = CreateScenarioIndexFromScenario(testScenario, specification);

            await _searchRepository.Index(new List <ScenarioIndex> {
                scenarioIndex
            });

            await _cacheProvider.RemoveAsync <List <TestScenario> >($"{CacheKeys.TestScenarios}{testScenario.SpecificationId}");

            await _cacheProvider.RemoveAsync <GherkinParseResult>($"{CacheKeys.GherkinParseResult}{testScenario.Id}");

            IEnumerable <Common.ApiClient.Calcs.Models.Calculation> calculations = await _calcsRepositoryPolicy.ExecuteAsync(() => _calcsRepository.GetCurrentCalculationsBySpecificationId(specification.Id));

            if (calculations.IsNullOrEmpty())
            {
                _logger.Information($"No calculations found to test for specification id: '{specification.Id}'");
            }
            else
            {
                try
                {
                    JobsModels.Trigger trigger = new JobsModels.Trigger
                    {
                        EntityId   = testScenario.Id,
                        EntityType = nameof(TestScenario),
                        Message    = $"Saving test scenario: '{testScenario.Id}'"
                    };

                    bool generateCalculationAggregations = SourceCodeHelpers.HasCalculationAggregateFunctionParameters(calculations.Select(m => m.SourceCode));

                    JobsModels.Job job = await SendInstructAllocationsToJobService(specification.Id, user, trigger, correlationId, generateCalculationAggregations);

                    _logger.Information($"New job of type '{job.JobDefinitionId}' created with id: '{job.Id}'");
                }
                catch (Exception ex)
                {
                    _logger.Error(ex, $"Failed to create job of type '{JobConstants.DefinitionNames.CreateInstructAllocationJob}' on specification '{specification.Id}'");

                    return(new InternalServerErrorResult($"An error occurred attempting to execute calculations prior to running tests on specification '{specification.Id}'"));
                }
            }

            CurrentTestScenario testScenarioResult = await _scenariosRepository.GetCurrentTestScenarioById(testScenario.Id);

            return(new OkObjectResult(testScenarioResult));
        }