Example #1
0
        private async Task SaveResponse(PgPurchaseOrderResponse payload, Cost cost, SystemAdminUserIdentity adminUser)
        {
            var purchaseOrderData = await _customDataService
                                    .GetCustomData <PgPurchaseOrderResponse>(cost.LatestCostStageRevisionId.Value, CustomObjectDataKeys.PgPurchaseOrderResponse)
                                    ?? new PgPurchaseOrderResponse();

            _mapper.Map(payload, purchaseOrderData);
            if (string.Compare(payload.ApprovalStatus, ApprovalStatuses.Rejected, StringComparison.OrdinalIgnoreCase) == 0)
            {
                //null requisition ID should be allowed here
                purchaseOrderData.Requisition    = payload.Requisition;
                purchaseOrderData.ApprovalStatus = payload.ApprovalStatus;
            }

            await _customDataService.Save(cost.LatestCostStageRevisionId.Value, CustomObjectDataKeys.PgPurchaseOrderResponse, purchaseOrderData, adminUser);

            await UpdatePaymentDetails(cost.LatestCostStageRevisionId.Value, purchaseOrderData, adminUser);

            var logEntries = new List <IActivityLogEntry>
            {
                new PoCreated(cost.CostNumber, purchaseOrderData.PoNumber, adminUser),
                new GoodsReceiptAllocated(cost.CostNumber, purchaseOrderData.GrNumber, adminUser),
                new RequisitionNumber(cost.CostNumber, purchaseOrderData.Requisition, adminUser)
            };

            await _activityLogService.LogRange(logEntries);
        }
Example #2
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."));
        }