Esempio n. 1
0
        private async Task RemoveUserFromExistingCosts(IList <string> removedLabels, UserBusinessRole userBusinessRole, CostUser user)
        {
            var costs = await GetQueryableCostsByUserObjectTypeAndLabels(userBusinessRole.ObjectType, removedLabels).ToListAsync();

            foreach (var cost in costs)
            {
                await _permissionService.RevokeAccessForSubjectWithRole(cost.Id, user.Id, userBusinessRole.BusinessRole.RoleId, null, false);
            }
        }
Esempio n. 2
0
        public async Task AddUserToExistingCosts(CostUser user, UserBusinessRole userBusinessRole)
        {
            if (userBusinessRole.BusinessRole.Key == Constants.BusinessRole.RegionalAgencyUser && userBusinessRole.ObjectType == core.Constants.AccessObjectType.Region)
            {
                var costs = await _efContext.Cost
                            .Where(c => c.Owner.Agency.GlobalAgencyRegionId != null)
                            .Where(c => userBusinessRole.LocationIds.Contains(c.Owner.Agency.GlobalAgencyRegion.Id.ToString()))
                            .Select(c => new { costId = c.Id, agencyRegion = c.Owner.Agency.GlobalAgencyRegion.Region })
                            .ToListAsync();

                foreach (var cost in costs)
                {
                    await _permissionService.GrantUserAccess <Cost>(
                        userBusinessRole.BusinessRole.RoleId, cost.costId, user, BuType.Pg, null, cost.agencyRegion, false);
                }
            }
            else
            {
                var queryableCosts = GetQueryableCostsByUserObjectTypeAndLabels(userBusinessRole.ObjectType, userBusinessRole.Labels);
                if (queryableCosts == null)
                {
                    return;
                }

                var costs = await queryableCosts
                            .Include(c => c.LatestCostStageRevision)
                            .ThenInclude(csr => csr.StageDetails)
                            .ToArrayAsync();

                foreach (var cost in costs)
                {
                    var costStageDetails = _costStageRevisionService.GetStageDetails <PgStageDetailsForm>(cost.LatestCostStageRevision);
                    switch (userBusinessRole.ObjectType)
                    {
                    case core.Constants.AccessObjectType.Smo:
                        if (!user.UserUserGroups.Any() || !user.UserUserGroups.Any(uug => uug.UserGroup.Label == costStageDetails.SmoName && uug.UserGroup.ObjectId == cost.Id))
                        {
                            await _permissionService.GrantUserAccess <Cost>(
                                userBusinessRole.BusinessRole.RoleId, cost.Id, user, BuType.Pg, null, costStageDetails.SmoName, false);
                        }
                        break;

                    case core.Constants.AccessObjectType.Region:
                        if (!user.UserUserGroups.Any() || user.UserUserGroups.Any(uug => uug.UserGroup.Label != costStageDetails.BudgetRegion.Name))
                        {
                            await _permissionService.GrantUserAccess <Cost>(
                                userBusinessRole.BusinessRole.RoleId, cost.Id, user, BuType.Pg, null, costStageDetails.BudgetRegion.Name, false);
                        }
                        break;
                    }
                }
            }
        }
        public async Task Add_When_UserIsAgencyAdmin_Should_HaveAccessToAssignRolesToUserInTheSameAgencyAsTheyAre()
        {
            // Arrange
            var usersBusinessRole    = _businessRoles.First(a => a.Value == Constants.BusinessRole.AgencyAdmin);
            var selectedBusinessRole = _businessRoles.First(a => a.Value == Constants.BusinessRole.AgencyAdmin);
            var userBeingUpdated     = _users.First(user => user.Id == _userNoRoles);
            var userPerformingAction = _users.First(u => u.Id == UserWithAgencyAdminRoleId);
            var updateUserModel      = new UpdateUserModel
            {
                AccessDetails = new List <AccessDetail>
                {
                    new AccessDetail
                    {
                        BusinessRoleId = selectedBusinessRole.Id
                    }
                }
            };

            userPerformingAction.Agency.Id = userBeingUpdated.Agency.Id;
            var userBusinessRole = new UserBusinessRole
            {
                CostUserId     = userPerformingAction.Id,
                BusinessRoleId = usersBusinessRole.Id,
                CostUser       = userPerformingAction
            };

            EfContext.AbstractType.AddRange(_abstractTypes);
            EfContext.Role.AddRange(_roles);
            EfContext.BusinessRole.AddRange(_businessRoles);
            EfContext.CostUser.AddRange(_users);
            EfContext.Cost.AddRange(_costs);
            EfContext.UserBusinessRole.Add(userBusinessRole);
            EfContext.SaveChanges();

            _permissionServiceMock.Setup(a => a.CheckHasAccess(UserWithAgencyAdminRoleId, userBeingUpdated.Id, AclActionType.Edit, "user")).ReturnsAsync(false);
            _pgAgencyServiceMock.Setup(a =>
                                       a.GetOrCreatePseudoAgencies(It.IsAny <Agency[]>()))
            .ReturnsAsync(
                _abstractTypes
                .Where(at => at.Type == core.Constants.AccessObjectType.Agency)
                .Select(a => new AbstractType())
                .ToList()
                );

            // Act
            await _pgUserService.UpdateUser(new UserIdentity { Id = UserWithAgencyAdminRoleId }, userBeingUpdated.Id, updateUserModel, BuType.Pg);

            // Assert
            userBeingUpdated.UserBusinessRoles.Count.Should().BeGreaterThan(0);
            userBeingUpdated.UserBusinessRoles.First().BusinessRole.Id.Should().Be(selectedBusinessRole.Id);
        }
Esempio n. 4
0
        public async Task <OperationResponse> UpdateUser(UserIdentity userIdentity, Guid id, UpdateUserModel updateUserModel, BuType buType)
        {
            var xUserId = userIdentity.Id;
            var dbUser  = _efContext.CostUser
                          .Include(cu => cu.Agency)
                          .ThenInclude(a => a.GlobalAgencyRegion)
                          .ThenInclude(gar => gar.GlobalAgency)
                          .Include(a => a.UserBusinessRoles)
                          .ThenInclude(ubr => ubr.BusinessRole)
                          .Include(a => a.UserUserGroups)
                          .ThenInclude(uug => uug.UserGroup)
                          .SingleOrDefault(a => a.Id == id);

            var userPerformingAction = _efContext.CostUser
                                       .Include(cu => cu.Agency)
                                       .Include(a => a.UserBusinessRoles)
                                       .ThenInclude(ubr => ubr.BusinessRole)
                                       .ThenInclude(br => br.Role)
                                       .SingleOrDefault(a => a.Id == xUserId);

            var businessRoles = _efContext.BusinessRole.ToList();

            if (dbUser == null)
            {
                return(new OperationResponse(false, "User doesn't exist."));
            }

            var hasAccess = await _permissionService.CheckHasAccess(xUserId, id, AclActionType.Edit, "user");

            if (!hasAccess)
            {
                hasAccess = userPerformingAction.Agency.Id == dbUser.Agency.Id &&
                            userPerformingAction.UserBusinessRoles.Any(ubr => ubr.BusinessRole.Key == Constants.BusinessRole.AgencyAdmin);
            }

            SetMissingObjectId(updateUserModel.AccessDetails, businessRoles, out var abstractType);
            if (updateUserModel.AccessDetails.Count > 0 && dbUser.UserBusinessRoles.Count > 0)
            {
                updateUserModel.AccessDetails = GetAllAccessDetails(updateUserModel.AccessDetails, dbUser.UserBusinessRoles);
            }
            //This is done because if you dont it will keep its reference and cause issues lower in this function
            var toBeRemoved = dbUser.UserBusinessRoles
                              .Where(ubr =>
                                     !updateUserModel.AccessDetails.Any(ad =>
                                                                        ubr.BusinessRoleId == ad.BusinessRoleId &&
                                                                        ubr.ObjectType == ad.ObjectType &&
                                                                        (ubr.ObjectId == ad.ObjectId ||
                                                                         ubr.ObjectId == ad.OriginalObjectId ||
                                                                         ubr.Labels.Contains(ad.LabelName)
                                                                        ) ||
                                                                        ad.ObjectType == core.Constants.AccessObjectType.Client && ubr.ObjectType == ad.ObjectType && ubr.BusinessRoleId == ad.BusinessRoleId
                                                                        )
                                     )
                              .ToList();

            var entries = new List <IActivityLogEntry>();

            await _efContext.InTransactionAsync(async() =>
            {
                await RemoveUserFromExistingCosts(toBeRemoved, dbUser);
                await UpdateBusinessRoleLabels(updateUserModel.AccessDetails, dbUser);

                var agenciesToUpdateInElastic = new List <AbstractType>();
                //Add New Access Rules
                foreach (var accessDetail in updateUserModel.AccessDetails)
                {
                    if (!hasAccess)
                    {
                        hasAccess = userPerformingAction.UserBusinessRoles.Any(ubr =>
                                                                               new[]
                        {
                            Roles.PlatformOwner,
                            Roles.ClientAdmin,
                            Roles.AdstreamAdmin
                        }.Contains(ubr.BusinessRole.Role.Name) &&
                                                                               ubr.ObjectId == accessDetail.ObjectId &&
                                                                               ubr.CostUserId == xUserId
                                                                               );

                        if (!hasAccess)
                        {
                            // TODO: show the user which rules have been skipped
                            _logger.Warning(
                                $"User {userPerformingAction.Email}|{userPerformingAction.Id} does not have access to alter roles for {dbUser.Email}|{dbUser.Id} in scope of {accessDetail.ObjectType}|{accessDetail.ObjectId}, skipping this rule!");
                            continue;
                        }
                    }

                    var selectedBusinessRole = businessRoles.SingleOrDefault(a => a.Id == accessDetail.BusinessRoleId);

                    if (selectedBusinessRole == null)
                    {
                        throw new Exception($"Couldn't find business role with id {accessDetail.BusinessRoleId}");
                    }

                    if (dbUser.UserBusinessRoles.Any(userBusinessRole =>
                                                     userBusinessRole != null &&
                                                     userBusinessRole.BusinessRole.Id == accessDetail.BusinessRoleId &&
                                                     userBusinessRole.ObjectType == accessDetail.ObjectType &&
                                                     (string.IsNullOrEmpty(accessDetail.LabelName) || userBusinessRole.Labels.Contains(accessDetail.LabelName))))
                    {
                        //Break out if user already has access.
                        _logger.Information(
                            $"User {dbUser.Id} already has access to {accessDetail.ObjectType} | {accessDetail.ObjectId} with BusinessRole {selectedBusinessRole.Key}|{selectedBusinessRole.Id}");
                        continue;
                    }

                    if (accessDetail.ObjectType == core.Constants.AccessObjectType.Smo ||
                        accessDetail.ObjectType == core.Constants.AccessObjectType.Region &&
                        selectedBusinessRole.Key != Constants.BusinessRole.RegionalAgencyUser)
                    {
                        _logger.Information($"User {dbUser.Email}|{dbUser.Id} will be given access at cost creation.");
                        var userBusinessRole = dbUser.UserBusinessRoles.FirstOrDefault(ubr =>
                                                                                       ubr.ObjectType == accessDetail.ObjectType);
                        if (userBusinessRole != null)
                        {
                            var labels = userBusinessRole.Labels.ToList();
                            labels.Add(accessDetail.LabelName);
                            userBusinessRole.Labels = labels.Distinct().ToArray();
                        }
                        else
                        {
                            userBusinessRole = new UserBusinessRole(xUserId)
                            {
                                BusinessRole = selectedBusinessRole,
                                Labels       = new[] { accessDetail.LabelName },
                                ObjectType   = accessDetail.ObjectType
                            };
                            dbUser.UserBusinessRoles.Add(userBusinessRole);
                            entries.Add(new UserRoleAssigned(dbUser.Email, selectedBusinessRole.Key, userIdentity));
                            await AddUserToExistingCosts(dbUser, userBusinessRole);
                        }
                        continue;
                    }

                    if (accessDetail.ObjectType == core.Constants.AccessObjectType.Region &&
                        selectedBusinessRole.Key == Constants.BusinessRole.RegionalAgencyUser)
                    {
                        _logger.Information($"User {dbUser.Email}|{dbUser.Id} will be given access at cost creation.");
                        var userBusinessRole = dbUser.UserBusinessRoles.FirstOrDefault(ubr =>
                                                                                       ubr.ObjectType == accessDetail.ObjectType);
                        if (userBusinessRole != null)
                        {
                            var labelIds = userBusinessRole.LocationIds.ToList();
                            labelIds.Add(accessDetail.LabelId.ToString());
                            userBusinessRole.LocationIds = labelIds.Distinct().ToArray();

                            var labels = userBusinessRole.Labels.ToList();
                            labels.Add(accessDetail.LabelName);
                            userBusinessRole.Labels = labels.Distinct().ToArray();
                        }
                        else
                        {
                            userBusinessRole = new UserBusinessRole(xUserId)
                            {
                                BusinessRole = selectedBusinessRole,
                                Labels       = new[] { accessDetail.LabelName },
                                LocationIds  = new[] { accessDetail.LabelId?.ToString() },
                                ObjectType   = accessDetail.ObjectType
                            };
                            dbUser.UserBusinessRoles.Add(userBusinessRole);
                            entries.Add(new UserRoleAssigned(dbUser.Email, selectedBusinessRole.Key, userIdentity));
                            await AddUserToExistingCosts(dbUser, userBusinessRole);
                        }
                        continue;
                    }

                    if (selectedBusinessRole.Key == Constants.BusinessRole.AdstreamAdmin ||
                        dbUser.Agency.Labels.Contains(Constants.Agency.PgOwnerLabel) ||
                        dbUser.Agency.Labels.Contains(Constants.Agency.AdstreamOwnerLabel) ||
                        (abstractType.Module != null && abstractType.Module?.ClientType == ClientType.Root))
                    {
                        abstractType = await _efContext.AbstractType.FirstOrDefaultAsync(at => at.Id == accessDetail.ObjectId);
                        var labels   = abstractType.Module?.ClientType == ClientType.Root ? new[] { ClientType.Root.ToString() } : new[] { core.Constants.AccessObjectType.Client };
                        await GrantAccessToAbstractType(new [] { abstractType }, xUserId, buType, dbUser, selectedBusinessRole, accessDetail, labels);

                        entries.Add(new UserRoleAssigned(dbUser.Email, selectedBusinessRole.Key, userIdentity));
                        agenciesToUpdateInElastic.Add(abstractType);
                    }
                    else if (selectedBusinessRole.Key == Constants.BusinessRole.CostConsultant)
                    {
                        // If business role is "Cost Consultant" the user doesn't get access to any object at this stage.
                        dbUser.UserBusinessRoles.Add(new UserBusinessRole(xUserId)
                        {
                            BusinessRole = selectedBusinessRole,
                            ObjectType   = accessDetail.ObjectType
                        });
                        entries.Add(new UserRoleAssigned(dbUser.Email, selectedBusinessRole.Key, userIdentity));
                    }
                    else
                    {
                        var agencyToCreatePseudoAgencies = new[] { dbUser.Agency };
                        if (selectedBusinessRole.Key == Constants.BusinessRole.RegionalAgencyUser)
                        {
                            // TODO: use id of GlobalAgencyRegion in accessDetail rather then label because different Agencies can have regions with the same name. The same for Budget region.
                            agencyToCreatePseudoAgencies = await _efContext.GlobalAgencyRegion
                                                           .Where(gar =>
                                                                  gar.Region == accessDetail.LabelName &&
                                                                  gar.GlobalAgencyId == dbUser.Agency.GlobalAgencyRegion.GlobalAgencyId)
                                                           .SelectMany(gar => gar.GlobalAgency.GlobalAgencyRegions)
                                                           .SelectMany(gar => gar.Agencies)
                                                           .ToArrayAsync();
                        }

                        var pseudoAgencies = await _pgAgencyService.GetOrCreatePseudoAgencies(agencyToCreatePseudoAgencies);
                        await GrantAccessToAbstractType(pseudoAgencies, xUserId, buType, dbUser, selectedBusinessRole, accessDetail);
                        agenciesToUpdateInElastic.AddRange(pseudoAgencies);
                    }
                }

                dbUser.ApprovalLimit = updateUserModel.ApprovalLimit;
                dbUser.EmailUrl      = updateUserModel.EmailOverride;
                dbUser.NotificationBudgetRegionId = updateUserModel.NotificationBudgetRegionId;
                dbUser.UserGroups = await _permissionService.GetObjectUserGroups(dbUser.Id, null);

                await _activityLogService.LogRange(entries);

                _eventService.Add(new CostUsersUpdated(_mapper.Map <CostUserSearchItem[]>(new [] { dbUser })));
                if (agenciesToUpdateInElastic.Any())
                {
                    _eventService.Add(new AgenciesUpdated(_mapper.Map <AgencySearchItem[]>(agenciesToUpdateInElastic)));
                }
            }, async() => await _eventService.SendAllPendingAsync());

            return(new OperationResponse(true, "User updated."));
        }