public async Task UpdatePermissionForUser_WhenPermissionsAreSetOnAFundingStreamAndNoneHaveBeenSetBefore_ThenPermissionsSaved()
        {
            // Arrange
            IUserRepository userRepository = CreateUserRepository();
            User            user           = new User()
            {
                UserId = UserId
            };

            userRepository
            .GetUserById(Arg.Is(UserId))
            .Returns(user);

            FundingStreamPermission existingPermission = null;

            userRepository
            .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is(FundingStreamId))
            .Returns(existingPermission);

            userRepository
            .UpdateFundingStreamPermission(Arg.Any <FundingStreamPermission>())
            .Returns(HttpStatusCode.Created);

            ICacheProvider cacheProvider = CreateCacheProvider();

            FundingStreamPermissionUpdateModel updateModel = new FundingStreamPermissionUpdateModel()
            {
                CanApproveFunding            = true,
                CanChooseFunding             = false,
                CanCreateSpecification       = false,
                CanEditCalculations          = false,
                CanEditSpecification         = false,
                CanMapDatasets               = false,
                CanReleaseFunding            = false,
                CanCreateTemplates           = true,
                CanEditTemplates             = true,
                CanDeleteTemplates           = true,
                CanApproveTemplates          = true,
                CanCreateProfilePattern      = true,
                CanEditProfilePattern        = true,
                CanDeleteProfilePattern      = true,
                CanAssignProfilePattern      = false,
                CanApplyCustomProfilePattern = false,
                CanApproveCalculations       = true,
                CanApproveAnyCalculations    = false,
                CanApproveAllCalculations    = false
            };

            IVersionRepository <FundingStreamPermissionVersion> versionRepository = CreateFundingStreamPermissionRepository();

            versionRepository
            .GetNextVersionNumber(Arg.Any <FundingStreamPermissionVersion>(), 0, Arg.Is(UserId))
            .Returns(1);

            FundingStreamPermissionService service = CreateService(
                userRepository,
                cacheProvider: cacheProvider,
                fundingStreamPermissionVersionRepository: versionRepository);

            // Act
            IActionResult result = await service.UpdatePermissionForUser(UserId, FundingStreamId, updateModel, null);

            // Assert
            result
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should()
            .BeEquivalentTo <FundingStreamPermissionCurrent>(new FundingStreamPermissionCurrent()
            {
                UserId                       = UserId,
                FundingStreamId              = FundingStreamId,
                CanApproveFunding            = true,
                CanChooseFunding             = false,
                CanCreateSpecification       = false,
                CanEditCalculations          = false,
                CanEditSpecification         = false,
                CanMapDatasets               = false,
                CanReleaseFunding            = false,
                CanCreateTemplates           = true,
                CanEditTemplates             = true,
                CanDeleteTemplates           = true,
                CanApproveTemplates          = true,
                CanCreateProfilePattern      = true,
                CanEditProfilePattern        = true,
                CanDeleteProfilePattern      = true,
                CanAssignProfilePattern      = false,
                CanApplyCustomProfilePattern = false,
                CanApproveCalculations       = true,
                CanApproveAnyCalculations    = false,
                CanApproveAllCalculations    = false,
            });

            await userRepository
            .Received(1)
            .UpdateFundingStreamPermission(Arg.Is <FundingStreamPermission>(p =>
                                                                            p.FundingStreamId == FundingStreamId &&
                                                                            p.UserId == UserId &&
                                                                            p.CanApproveFunding &&
                                                                            !p.CanChooseFunding &&
                                                                            !p.CanCreateSpecification &&
                                                                            !p.CanEditCalculations &&
                                                                            !p.CanEditSpecification &&
                                                                            !p.CanMapDatasets &&
                                                                            !p.CanReleaseFunding &&
                                                                            p.CanCreateTemplates &&
                                                                            p.CanEditTemplates &&
                                                                            p.CanDeleteTemplates &&
                                                                            p.CanApproveTemplates &&
                                                                            p.CanCreateProfilePattern &&
                                                                            p.CanEditProfilePattern &&
                                                                            p.CanDeleteProfilePattern &&
                                                                            !p.CanAssignProfilePattern &&
                                                                            !p.CanApplyCustomProfilePattern &&
                                                                            p.CanApproveCalculations &&
                                                                            !p.CanApproveAnyCalculations &&
                                                                            !p.CanApproveAllCalculations
                                                                            ));

            await cacheProvider
            .Received(1)
            .DeleteHashSet(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"));

            await versionRepository
            .Received(1)
            .GetNextVersionNumber(Arg.Is <FundingStreamPermissionVersion>(v => v.EntityId == $"{UserId}_{FundingStreamId}"), partitionKeyId: Arg.Is(UserId));

            await versionRepository
            .Received(1)
            .SaveVersion(Arg.Is <FundingStreamPermissionVersion>(v =>
                                                                 v.EntityId == $"{UserId}_{FundingStreamId}" &&
                                                                 v.Version == 1
                                                                 ), Arg.Is(UserId));
        }
Пример #2
0
        public async Task UpdatePermissionForUser_WhenPermissionsAreSetOnAFundingStreamAndNoneHaveBeenSetBefore_ThenPermissionsSaved()
        {
            // Arrange
            IUserRepository userRepository = CreateUserRepository();
            User            user           = new User()
            {
                UserId = UserId
            };

            userRepository
            .GetUserById(Arg.Is(UserId))
            .Returns(user);

            FundingStreamPermission existingPermission = null;

            userRepository
            .GetFundingStreamPermission(Arg.Is(UserId), Arg.Is(FundingStreamId))
            .Returns(existingPermission);

            userRepository
            .UpdateFundingStreamPermission(Arg.Any <FundingStreamPermission>())
            .Returns(HttpStatusCode.Created);

            ICacheProvider cacheProvider = CreateCacheProvider();

            FundingStreamPermissionUpdateModel updateModel = new FundingStreamPermissionUpdateModel()
            {
                CanApproveFunding      = true,
                CanChooseFunding       = false,
                CanCreateSpecification = false,
                CanEditCalculations    = false,
                CanEditSpecification   = false,
                CanMapDatasets         = false,
                CanPublishFunding      = false,
            };

            string json = JsonConvert.SerializeObject(updateModel);

            byte[]       byteArray = Encoding.UTF8.GetBytes(json);
            MemoryStream stream    = new MemoryStream(byteArray);

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Body
            .Returns(stream);

            IVersionRepository <FundingStreamPermissionVersion> versionRepository = CreateFundingStreamPermissionRepository();

            versionRepository
            .GetNextVersionNumber(Arg.Any <FundingStreamPermissionVersion>(), 0, Arg.Is(UserId))
            .Returns(1);

            FundingStreamPermissionService service = CreateService(
                userRepository,
                cacheProvider: cacheProvider,
                fundingStreamPermissionVersionRepository: versionRepository);

            // Act
            IActionResult result = await service.UpdatePermissionForUser(UserId, FundingStreamId, request);

            // Assert
            result
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should()
            .BeEquivalentTo <FundingStreamPermissionCurrent>(new FundingStreamPermissionCurrent()
            {
                UserId                 = UserId,
                FundingStreamId        = FundingStreamId,
                CanApproveFunding      = true,
                CanChooseFunding       = false,
                CanCreateSpecification = false,
                CanEditCalculations    = false,
                CanEditSpecification   = false,
                CanMapDatasets         = false,
                CanPublishFunding      = false,
            });

            await userRepository
            .Received(1)
            .UpdateFundingStreamPermission(Arg.Is <FundingStreamPermission>(p =>
                                                                            p.FundingStreamId == FundingStreamId &&
                                                                            p.UserId == UserId &&
                                                                            p.CanApproveFunding &&
                                                                            !p.CanChooseFunding &&
                                                                            !p.CanCreateSpecification &&
                                                                            !p.CanEditCalculations &&
                                                                            !p.CanEditSpecification &&
                                                                            !p.CanMapDatasets &&
                                                                            !p.CanPublishFunding
                                                                            ));

            await cacheProvider
            .Received(1)
            .DeleteHashSet(Arg.Is($"{CacheKeys.EffectivePermissions}:{UserId}"));

            await versionRepository
            .Received(1)
            .GetNextVersionNumber(Arg.Is <FundingStreamPermissionVersion>(v => v.EntityId == $"{UserId}_{FundingStreamId}"), partitionKeyId: Arg.Is(UserId));

            await versionRepository
            .Received(1)
            .SaveVersion(Arg.Is <FundingStreamPermissionVersion>(v =>
                                                                 v.EntityId == $"{UserId}_{FundingStreamId}" &&
                                                                 v.Version == 1
                                                                 ), Arg.Is(UserId));
        }
        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)));
        }
        public async Task <(IEnumerable <PublishedProviderResult>, IEnumerable <PublishedProviderResultExisting>)> GeneratePublishedProviderResultsToSave(IEnumerable <PublishedProviderResult> providerResults, IEnumerable <PublishedProviderResultExisting> existingResults)
        {
            Guard.ArgumentNotNull(providerResults, nameof(providerResults));
            Guard.ArgumentNotNull(existingResults, nameof(existingResults));

            ConcurrentBag <PublishedProviderResult> publishedProviderResultsToSave = new ConcurrentBag <PublishedProviderResult>();

            ConcurrentDictionary <string, ConcurrentDictionary <string, PublishedProviderResultExisting> > existingProviderResults = new ConcurrentDictionary <string, ConcurrentDictionary <string, PublishedProviderResultExisting> >();

            foreach (PublishedProviderResultExisting providerResult in existingResults)
            {
                if (!existingProviderResults.ContainsKey(providerResult.ProviderId))
                {
                    existingProviderResults.TryAdd(providerResult.ProviderId, new ConcurrentDictionary <string, PublishedProviderResultExisting>());
                }

                existingProviderResults[providerResult.ProviderId].TryAdd(providerResult.AllocationLineId, providerResult);
            }

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

            SemaphoreSlim throttler = new SemaphoreSlim(initialCount: 30);

            foreach (PublishedProviderResult providerResult in providerResults)
            {
                await throttler.WaitAsync();

                allTasks.Add(
                    Task.Run(async() =>
                {
                    try
                    {
                        if (existingProviderResults.ContainsKey(providerResult.ProviderId))
                        {
                            ConcurrentDictionary <string, PublishedProviderResultExisting> existingResultsForProvider = existingProviderResults[providerResult.ProviderId];

                            if (existingResultsForProvider.TryGetValue(providerResult.FundingStreamResult.AllocationLineResult.AllocationLine.Id, out PublishedProviderResultExisting existingResult))
                            {
                                existingResultsForProvider.TryRemove(providerResult.FundingStreamResult.AllocationLineResult.AllocationLine.Id, out var removedExistingResult);

                                if (!existingResultsForProvider.Any())
                                {
                                    existingProviderResults.TryRemove(providerResult.ProviderId, out var removedProviderResult);
                                }

                                if (providerResult.FundingStreamResult.AllocationLineResult.Current.Value == existingResult.Value)
                                {
                                    existingProviderResults.TryRemove(providerResult.ProviderId, out var removedProviderResult);

                                    return;
                                }

                                providerResult.FundingStreamResult.AllocationLineResult.Current.Version =
                                    await _allocationResultsVersionRepository.GetNextVersionNumber(providerResult.FundingStreamResult.AllocationLineResult.Current, existingResult.Version, incrementFromCurrentVersion: true);

                                providerResult.FundingStreamResult.AllocationLineResult.HasResultBeenVaried = existingResult.HasResultBeenVaried;

                                if (existingResult.Status != AllocationLineStatus.Held)
                                {
                                    providerResult.FundingStreamResult.AllocationLineResult.Current.Status = AllocationLineStatus.Updated;
                                }

                                if (existingResult.Published != null)
                                {
                                    providerResult.FundingStreamResult.AllocationLineResult.Published = existingResult.Published;
                                }

                                providerResult.FundingStreamResult.AllocationLineResult.Current.Major = existingResult.Major;
                                providerResult.FundingStreamResult.AllocationLineResult.Current.Minor = existingResult.Minor;
                            }
                            else
                            {
                                providerResult.FundingStreamResult.AllocationLineResult.Current.Version = 1;
                            }
                        }
                        else
                        {
                            providerResult.FundingStreamResult.AllocationLineResult.Current.Version = 1;
                        }

                        publishedProviderResultsToSave.Add(providerResult);
                    }
                    finally
                    {
                        throttler.Release();
                    }
                }));
            }
            await TaskHelper.WhenAllAndThrow(allTasks.ToArray());

            // Need to remove results that have been varied
            List <PublishedProviderResult> publishedProviderResultsToSaveList = publishedProviderResultsToSave.ToList();

            publishedProviderResultsToSaveList.RemoveAll(r => r.FundingStreamResult.AllocationLineResult.HasResultBeenVaried);

            List <PublishedProviderResultExisting> existingRecordsExclude = new List <PublishedProviderResultExisting>(existingProviderResults.Values.Count);

            foreach (ConcurrentDictionary <string, PublishedProviderResultExisting> existingList in existingProviderResults.Values)
            {
                existingRecordsExclude.AddRange(existingList.Values.Where(r => !r.HasResultBeenVaried));
            }

            return(publishedProviderResultsToSaveList, existingRecordsExclude);
        }