Esempio n. 1
0
        public async Task <GroupMemberPaging> GetGroupMembers([FromRoute] string groupId, [FromQuery] AdvancedBasicQueryParams queryParams)
        {
            var response = await _alfrescoHttpClient.GetGroupMembers(groupId, ImmutableList <Parameter> .Empty.AddQueryParams(queryParams));

            var responseList = response?.List?.Entries?.ToList();
            var systemUser   = responseList?.Find(x => x?.Entry?.Id == SpisumNames.SystemUsers.Spisum);

            if (systemUser != null)
            {
                responseList.Remove(systemUser);
                response.List.Entries = responseList;
            }

            return(response);
        }
Esempio n. 2
0
        public async Task <PersonGroup> GetCreateUserGroup()
        {
            if (string.IsNullOrWhiteSpace(_identityUser.RequestGroup))
            {
                throw new BadRequestException("", "User has not properties set");
            }

            GroupEntry groupInfo = null;

            var personGroupName = $"{SpisumNames.Prefixes.UserGroup}{_identityUser.Id}";

            try
            {
                groupInfo = await _alfrescoHttpClient.GetGroup(personGroupName);
            }
            catch
            {
                throw new BadRequestException("", "User group not found");
            }

            var groupMembers = await _alfrescoHttpClient.GetGroupMembers(personGroupName);

            if (groupMembers?.List?.Entries?.ToList().Find(x => x.Entry?.Id == _identityUser.Id) == null)
            {
                await _alfrescoHttpClient.CreateGroupMember(personGroupName, new GroupMembershipBodyCreate { Id = _identityUser.Id, MemberType = GroupMembershipBodyCreateMemberType.PERSON });
            }

            return(new PersonGroup {
                PersonId = _identityUser.Id, GroupId = groupInfo.Entry.Id, GroupPrefix = _identityUser.RequestGroup
            });
        }
        public DocumentToRepositoryValidator(IAlfrescoHttpClient alfrescoHttpClient, IIdentityUser identityUser)
        {
            RuleFor(o => o)
            .Cascade(CascadeMode.StopOnFirstFailure)
            .MustAsync(async(context, cancellationToken) =>
            {
                _groupMember = await alfrescoHttpClient.GetGroupMembers(SpisumNames.Groups.RepositoryGroup, ImmutableList <Parameter> .Empty
                                                                        .Add(new Parameter(AlfrescoNames.Headers.Where, AlfrescoNames.MemberType.Group, ParameterType.QueryString)));
                _groupPaging = await alfrescoHttpClient.GetPersonGroups(identityUser.Id);

                return(_groupMember != null && _groupPaging != null);
            })
            .WithName(x => nameof(x.Group))
            .WithMessage("Something went wrong with alfresco server.")
            .DependentRules(() =>
            {
                RuleFor(x => x)
                .Must(y => _groupPaging?.List?.Entries?.Any(q => q.Entry.Id == identityUser.RequestGroup) ?? false)
                .WithName(x => "Group")
                .WithMessage($"User isn't member of group {identityUser.RequestGroup}.");

                RuleFor(x => x)
                .Must(y => _groupMember?.List?.Entries?.Any(q => q.Entry.Id == y.Group) ?? false)
                .WithName(x => "Group")
                .WithMessage(x => $"Group {x.Group} does not exists.");
            });
        }
        public DocumentBorrowValidator(IAlfrescoHttpClient alfrescoHttpClient,
                                       IIdentityUser identityUser,
                                       IAlfrescoConfiguration alfrescoConfiguration,
                                       ISimpleMemoryCache simpleMemoryCache,
                                       ISystemLoginService systemLoginService)
        {
            var adminHttpClient = new AlfrescoHttpClient(alfrescoConfiguration, new AdminAuthentification(simpleMemoryCache, alfrescoConfiguration, systemLoginService));

            _identityUser = identityUser;

            RuleFor(o => o)
            .Cascade(CascadeMode.StopOnFirstFailure)
            .MustAsync(async(context, cancellationToken) =>
            {
                _nodeEntry = await alfrescoHttpClient.GetNodeInfo(context.NodeId, ImmutableList <Parameter> .Empty
                                                                  .Add(new Parameter(AlfrescoNames.Headers.Include, AlfrescoNames.Includes.Path, ParameterType.QueryString)));

                var documentProperties = _nodeEntry?.Entry?.Properties?.As <JObject>().ToDictionary();
                _borrowedUser          = documentProperties.GetNestedValueOrDefault(SpisumNames.Properties.Borrower)?.ToString();

                _groupPaging = await alfrescoHttpClient.GetPersonGroups(identityUser.Id);

                _groupRepository = await alfrescoHttpClient.GetGroupMembers(SpisumNames.Groups.RepositoryGroup,
                                                                            ImmutableList <Parameter> .Empty.Add(new Parameter(AlfrescoNames.Headers.Where, AlfrescoNames.MemberType.Group, ParameterType.QueryString)));

                _groupPagingNextOwner = await adminHttpClient.GetPersonGroups(context.Body.User);

                return(_nodeEntry?.Entry?.Id != null && _groupPaging != null && _groupPagingNextOwner != null && _groupRepository != null);
            })
            .WithName(x => nameof(x.NodeId))
            .WithMessage("Something went wrong with alfresco server.")
            .DependentRules(() =>
            {
                RuleFor(x => x)
                .Must(y =>
                {
                    return(_groupPagingNextOwner?.List?.Entries?.Any(q => q.Entry.Id == y.Body.Group) ?? false);
                })
                .WithName(x => "User")
                .WithMessage("User isn't member of the Group.");

                RuleFor(x => x)
                .Must(y =>
                {
                    return(_groupRepository?.List?.Entries?.Any(x => x.Entry.Id == identityUser.RequestGroup) ?? false);
                })
                .WithName(x => "User")
                .WithMessage("User isn't member of repository group");

                RuleFor(x => x)
                .Must(y => _groupPaging?.List?.Entries?.Any(q => q.Entry.Id == identityUser.RequestGroup) ?? false)
                .WithName(x => "Group")
                .WithMessage($"User isn't member of group {identityUser.RequestGroup}.");

                RuleFor(x => x.NodeId)
                .Must(x => _nodeEntry.Entry.NodeType == SpisumNames.NodeTypes.Document)
                .WithMessage($"NodeId must be type of {SpisumNames.NodeTypes.Document}.");

                RuleFor(x => x)
                .Must(x => _nodeEntry?.Entry?.Path?.Name?.StartsWith(AlfrescoNames.Prefixes.Path + SpisumNames.Paths.RepositoryDocuments, StringComparison.OrdinalIgnoreCase) == true)
                .OnAnyFailure(x => throw new BadRequestException("Document must be in repository site."));

                RuleFor(x => x)
                .Must(x => string.IsNullOrWhiteSpace(_borrowedUser))
                .WithMessage("Document is already borrowed");
            });
        }
        public ShipmentUpdatePersonallyValidator(IAlfrescoHttpClient alfrescoHttpClient, IIdentityUser identityUser, INodesService nodesService)
        {
            RuleFor(o => o)
            .Cascade(CascadeMode.StopOnFirstFailure)
            .MustAsync(async(context, cancellationToken) =>
            {
                _nodeEntry = await alfrescoHttpClient.GetNodeInfo(context.NodeId, ImmutableList <Parameter> .Empty
                                                                  .Add(new Parameter(AlfrescoNames.Headers.Include, AlfrescoNames.Includes.Path, ParameterType.QueryString)));
                _nodeParents = await nodesService.GetParentsByAssociation(context.NodeId, new List <string>
                {
                    SpisumNames.Associations.ShipmentsCreated,
                    SpisumNames.Associations.ShipmentsToReturn,
                    SpisumNames.Associations.ShipmentsToDispatch
                });
                _groupPaging = await alfrescoHttpClient.GetPersonGroups(identityUser.Id);

                if (_nodeParents?.Any(x => x?.Entry?.Association?.AssocType == SpisumNames.Associations.ShipmentsToDispatch) ?? false)
                {
                    _groupToDispatch = await alfrescoHttpClient.GetGroupMembers(SpisumNames.Groups.DispatchGroup,
                                                                                ImmutableList <Parameter> .Empty.Add(new Parameter(AlfrescoNames.Headers.Where, AlfrescoNames.MemberType.Group, ParameterType.QueryString)));
                }

                return(_nodeEntry?.Entry?.Id != null && _groupPaging != null && _nodeParents != null);
            })
            .WithName(x => nameof(x.NodeId))
            .WithMessage("Something went wrong with alfresco server.")
            .DependentRules(() =>
            {
                RuleFor(x => x)
                .Must(y => _groupPaging?.List?.Entries?.Any(q => q.Entry.Id == identityUser.RequestGroup) ?? false)
                .WithName(x => "Group")
                .WithMessage($"User isn't member of group {identityUser.RequestGroup}.");

                RuleFor(x => x.NodeId)
                .Must(x => _nodeEntry.Entry.NodeType == SpisumNames.NodeTypes.ShipmentPersonally)
                .WithMessage(x => $"Provided nodeId must be NodeType {SpisumNames.NodeTypes.ShipmentPersonally}");

                RuleFor(x => x)
                .Must(y => _nodeParents?.Any(q => q.Entry.NodeType == SpisumNames.NodeTypes.Document || q.Entry.NodeType == SpisumNames.NodeTypes.File) ?? false)
                .WithName(x => "Parent")
                .WithMessage($"Provided shipment does not have a parent type of {SpisumNames.NodeTypes.Document} or {SpisumNames.NodeTypes.File}");

                RuleFor(x => x)
                .Must(y => CheckDispatchGroup(identityUser.RequestGroup))
                .WithMessage(x => "Dispatch group")
                .WithMessage($"Requested group in not part of {SpisumNames.Groups.DispatchGroup}");
            });

            RuleFor(x => x.Body.Address1)
            .Must(x => CheckLength(x, 100))
            .When(x => x.Body != null)
            .WithMessage("Address1 is too long");

            RuleFor(x => x.Body.Address2)
            .Must(x => CheckLength(x, 100))
            .When(x => x.Body != null)
            .WithMessage("Address2 is too long");

            RuleFor(x => x.Body.Address3)
            .Must(x => CheckLength(x, 100))
            .When(x => x.Body != null)
            .WithMessage("Address3 is too long");

            RuleFor(x => x.Body.Address4)
            .Must(x => CheckLength(x, 100))
            .When(x => x.Body != null)
            .WithMessage("Address4 is too long");

            RuleFor(x => x.Body.AddressStreet)
            .Must(x => CheckLength(x, 100))
            .When(x => x.Body != null)
            .WithMessage("AddressStreet is too long");

            RuleFor(x => x.Body.AddressCity)
            .Must(x => CheckLength(x, 100))
            .When(x => x.Body != null)
            .WithMessage("AddressCity is too long");

            RuleFor(x => x.Body.AddressZip)
            .Must(x => CheckLength(x, 100))
            .When(x => x.Body != null)
            .WithMessage("AddressZip is too long");

            RuleFor(x => x.Body.AddressState)
            .Must(x => CheckLength(x, 100))
            .When(x => x.Body != null)
            .WithMessage("AddressState is too long");
        }
Esempio n. 6
0
        public ShipmentUpdateEmailValidator(IAlfrescoHttpClient alfrescoHttpClient, IIdentityUser identityUser, INodesService nodesService, IEmailHttpClient emailHttpClient)
        {
            RuleFor(o => o)
            .Cascade(CascadeMode.StopOnFirstFailure)
            .MustAsync(async(context, cancellationToken) =>
            {
                _nodeEntry = await alfrescoHttpClient.GetNodeInfo(context.NodeId, ImmutableList <Parameter> .Empty
                                                                  .Add(new Parameter(AlfrescoNames.Headers.Include, AlfrescoNames.Includes.Path, ParameterType.QueryString)));
                _nodeParents = await nodesService.GetParentsByAssociation(context.NodeId, new List <string>
                {
                    SpisumNames.Associations.ShipmentsCreated,
                    SpisumNames.Associations.ShipmentsToReturn,
                    SpisumNames.Associations.ShipmentsToDispatch
                });
                _groupPaging = await alfrescoHttpClient.GetPersonGroups(identityUser.Id);

                try { _accounts = await emailHttpClient.Accounts(); } catch { }


                if (_nodeParents?.Any(x => x?.Entry?.Association?.AssocType == SpisumNames.Associations.ShipmentsToDispatch) ?? false)
                {
                    _groupToDispatch = await alfrescoHttpClient.GetGroupMembers(SpisumNames.Groups.DispatchGroup,
                                                                                ImmutableList <Parameter> .Empty.Add(new Parameter(AlfrescoNames.Headers.Where, AlfrescoNames.MemberType.Group, ParameterType.QueryString)));
                }

                return(_nodeEntry?.Entry?.Id != null && _groupPaging != null && _nodeParents != null && _accounts != null);
            })
            .WithName(x => nameof(x.NodeId))
            .WithMessage("Something went wrong with alfresco server.")
            .DependentRules(() =>
            {
                RuleFor(x => x)
                .Must(y => _groupPaging?.List?.Entries?.Any(q => q.Entry.Id == identityUser.RequestGroup) ?? false)
                .WithName(x => "Group")
                .WithMessage($"User isn't member of group {identityUser.RequestGroup}.");

                RuleFor(x => x.NodeId)
                .Must(x => _nodeEntry.Entry.NodeType == SpisumNames.NodeTypes.ShipmentEmail)
                .WithMessage(x => $"Provided nodeId must be NodeType {SpisumNames.NodeTypes.ShipmentEmail}");

                RuleFor(x => x)
                .Must(y => _nodeParents?.Any(q => q.Entry.NodeType == SpisumNames.NodeTypes.Document) ?? false)
                .WithName(x => "Parent")
                .WithMessage($"Provided shipment does not have a parent type of {SpisumNames.NodeTypes.Document}");

                RuleFor(x => x)
                .Must(y => CheckDispatchGroup(identityUser.RequestGroup))
                .WithMessage(x => "Dispatch group")
                .WithMessage($"Requested group in not part of {SpisumNames.Groups.DispatchGroup}");

                RuleFor(x => x)
                .Must(x => _accounts.Count > 0)
                .WithMessage(x => "No email configuration on email server");

                RuleFor(x => x.Body.Sender)
                .Must(y => _accounts?.Any(x => x.Username == y) ?? false)
                .WithMessage(x => "Sender was not found in email configuration on email server");
            });

            RuleFor(x => x.Body.Recipient)
            .Must(x => EmailUtils.IsValidEmail(x))
            .When(x => x.Body != null)
            .WithName(x => "Recipient")
            .WithMessage("Recipient is not a valid email address");

            RuleFor(x => x.Body.Subject)
            .Must(x => CheckLength(x, 255))
            .When(x => x.Body != null)
            .WithName(x => "Subject")
            .WithMessage("Subject is too long");

            RuleFor(x => x.Body.Recipient)
            .Must(x => CheckLength(x, 254))
            .When(x => x.Body != null)
            .WithName(x => "Recipient")
            .WithMessage("Recipient is too long");

            RuleFor(x => x.Body.Components)
            .Must(y => y.Count > 0)
            .WithName(x => "Components")
            .WithMessage("Components cannot be empty");
        }
Esempio n. 7
0
        public async Task <PersonEntryFixed> UpdateUser([FromRoute] string userId, [FromBody] UserUpdate body)
        {
            var update = new PersonBodyUpdate
            {
                Email      = body.Email,
                FirstName  = body.FirstName,
                LastName   = body.LastName,
                Properties = new Dictionary <string, object>
                {
                    { SpisumNames.Properties.Group, body.MainGroup },
                    { SpisumNames.Properties.UserJob, body.UserJob },
                    { SpisumNames.Properties.UserOrgAddress, body.UserOrgAddress },
                    { SpisumNames.Properties.UserOrgId, body.UserOrgId },
                    { SpisumNames.Properties.UserOrgName, body.UserOrgName },
                    { SpisumNames.Properties.UserOrgUnit, body.UserOrgUnit },
                    { SpisumNames.Properties.UserName, $"{body.FirstName} {body.LastName}".Trim() },
                    { SpisumNames.Properties.UserId, body.UserId }
                }
            };

            if (!string.IsNullOrWhiteSpace(body.Password))
            {
                update.Password = body.Password;
            }

            var userInfo = await _alfrescoHttpClient.UpdatePerson(userId, update);

            var userGroupsInfo = await _alfrescoHttpClient.GetPersonGroups(userId);

            var userGroups = userGroupsInfo?.List?.Entries?.Select(x => x.Entry?.Id)?.Where(
                x => Array.IndexOf(new[] { SpisumNames.Groups.MainGroup, SpisumNames.Groups.Everyone }, x) == -1 && !x.StartsWith(SpisumNames.Prefixes.UserGroup)
                )?.ToList() ?? new List <string>();

            var allGroupsInfo = await _alfrescoHttpClient.GetGroupMembers(SpisumNames.Groups.MainGroup,
                                                                          ImmutableList <Parameter> .Empty.Add(new Parameter(AlfrescoNames.Headers.Where, AlfrescoNames.MemberType.Group, ParameterType.QueryString)));

            var allGroups  = allGroupsInfo?.List?.Entries?.Select(x => x.Entry?.Id)?.ToList() ?? new List <string>();
            var signGroups = body.SignGroups ?? new List <string>();

            var groupList = body.Groups?.ToList() ?? new List <string>();

            groupList.AddUnique(body.MainGroup);
            groupList.AddRangeUnique(signGroups);

            // remove all groups included in main groups
            for (int i = userGroups.Count - 1; i >= 0; i--)
            {
                var group = userGroups[i];
                if (allGroups.Exists(x => x.StartsWith(@group)) && !groupList.Contains(@group) ||
                    @group.EndsWith(SpisumNames.Postfixes.Sign) && !signGroups.Contains(@group))
                {
                    try
                    {
                        await _alfrescoHttpClient.DeleteGroupMember(@group, userId);

                        userGroups.RemoveAt(i);
                    }
                    catch
                    {
                    }
                }
            }

            foreach (var group in groupList.Where(x => !userGroups.Contains(x)))
            {
                try
                {
                    await _alfrescoHttpClient.CreateGroupMember(@group, new GroupMembershipBodyCreate { Id = userInfo.Entry.Id, MemberType = GroupMembershipBodyCreateMemberType.PERSON });
                }
                catch
                {
                }
            }

            foreach (var group in signGroups.Where(x => !userGroups.Contains(x + SpisumNames.Postfixes.Sign)))
            {
                try
                {
                    await _initialUser.CheckCreateGroupAndAddPerson(userInfo.Entry.Id, @group + SpisumNames.Postfixes.Sign);
                }
                catch
                {
                }
            }

            return(userInfo);
        }
Esempio n. 8
0
        public async Task <TransactionHistoryPdf> ToPdfModel(DateTime currentDate)
        {
            var mainGroup = await _alfrescoHttpClient.GetGroupMembers(JobsNames.MainGroup,
                                                                      ImmutableList <Parameter> .Empty.Add(new Parameter(AlfrescoNames.Headers.Where, AlfrescoNames.MemberType.Group, ParameterType.QueryString)));

            var pdfCount = await _alfrescoHttpClient.GetNodeChildren(AlfrescoNames.Aliases.Root, ImmutableList <Parameter> .Empty
                                                                     .Add(new Parameter(AlfrescoNames.Headers.MaxItems, 1, ParameterType.QueryString))
                                                                     .Add(new Parameter(AlfrescoNames.Headers.RelativePath, JobsNames.DailyFingerPrintPath, ParameterType.QueryString))
                                                                     .Add(new Parameter(AlfrescoNames.Headers.Where, $"(nodeType='{AlfrescoNames.ContentModel.Content}')", ParameterType.QueryString)));

            var transactionHistory = await _transactionHistoryRepository.GetTransactionHistoryByDate(currentDate.Date, currentDate.Date);

            var pdfCounter = pdfCount?.List?.Pagination?.TotalItems.HasValue == true ? pdfCount.List.Pagination.TotalItems.Value : 1;

            TransactionHistoryPdf transactionHistoryObj = new TransactionHistoryPdf
            {
                Header        = string.Format(PdfTranslations.PageHeader, _transactionHistoryConfiguration?.Originator, currentDate.ToString("dd.MM.yyyy")),
                Name          = string.Format(PdfTranslations.FirstPage.Name, currentDate.ToString("dd.MM.yyyy")),
                Originator    = string.Format(PdfTranslations.FirstPage.Originator, _transactionHistoryConfiguration?.Originator),
                Address       = string.Format(PdfTranslations.FirstPage.Address, _transactionHistoryConfiguration?.Address),
                SerialNumber  = string.Format(PdfTranslations.FirstPage.SerialNumber, ++pdfCounter),
                NumberOfPages = PdfTranslations.FirstPage.NumberOfPages,
                Rows          = new TableRows
                {
                    Pid           = PdfTranslations.Cells.Pid,
                    TypeOfObject  = PdfTranslations.Cells.TypeOfObject,
                    TypeOfChanges = PdfTranslations.Cells.TypeOfChanges,
                    Descriptions  = PdfTranslations.Cells.Descriptions,
                    Author        = PdfTranslations.Cells.Author,
                    Date          = PdfTranslations.Cells.Date
                },
                Columns = new List <TableColumns>()
            };

            foreach (var item in transactionHistory)
            {
                TransactionHistoryParameters eventParams = null;

                if (item.EventParameters != null)
                {
                    eventParams = JsonConvert.DeserializeObject <TransactionHistoryParameters>(item.EventParameters);
                }

                string requestGroup = mainGroup?.List?.Entries?.FirstOrDefault(u => u.Entry.Id == item.UserGroupId)?.Entry?.DisplayName ?? item.UserGroupId;

                if (eventParams != null)
                {
                    transactionHistoryObj.Columns.Add(new TableColumns
                    {
                        Pid           = item.Pid,
                        TypeOfObject  = item.FkNodeTypeCodeNavigation.Code,
                        TypeOfChanges = item.FkEventTypeCodeNavigation.Code,
                        Descriptions  = eventParams.Message,
                        Author        = string.Join("; ", item.UserId, requestGroup),
                        Date          = item.OccuredAt.ToString("dd.MM.yyyy hh:mm:ss")
                    });
                }
                else
                {
                    transactionHistoryObj.Columns.Add(new TableColumns
                    {
                        Pid           = item.Pid,
                        TypeOfObject  = item.FkNodeTypeCodeNavigation.Code,
                        TypeOfChanges = "",
                        Descriptions  = item.FkEventTypeCodeNavigation.Code,
                        Author        = string.Join(";", item.UserId, requestGroup),
                        Date          = item.OccuredAt.ToString("dd.MM.yyyy hh:mm:ss")
                    });
                }
            }

            return(transactionHistoryObj);
        }
        public ShipmentUpdatePublishValidator(IAlfrescoHttpClient alfrescoHttpClient, IIdentityUser identityUser, INodesService nodesService)
        {
            RuleFor(o => o)
            .Cascade(CascadeMode.StopOnFirstFailure)
            .MustAsync(async(context, cancellationToken) =>
            {
                _nodeEntry = await alfrescoHttpClient.GetNodeInfo(context.NodeId, ImmutableList <Parameter> .Empty
                                                                  .Add(new Parameter(AlfrescoNames.Headers.Include, AlfrescoNames.Includes.Path, ParameterType.QueryString)));
                _nodeParents = await nodesService.GetParentsByAssociation(context.NodeId, new List <string>
                {
                    SpisumNames.Associations.ShipmentsCreated,
                    SpisumNames.Associations.ShipmentsToReturn,
                    SpisumNames.Associations.ShipmentsToDispatch
                });
                _groupPaging = await alfrescoHttpClient.GetPersonGroups(identityUser.Id);

                if (_nodeParents?.Any(x => x?.Entry?.Association?.AssocType == SpisumNames.Associations.ShipmentsToDispatch) ?? false)
                {
                    _groupToDispatch = await alfrescoHttpClient.GetGroupMembers(SpisumNames.Groups.DispatchGroup,
                                                                                ImmutableList <Parameter> .Empty.Add(new Parameter(AlfrescoNames.Headers.Where, AlfrescoNames.MemberType.Group, ParameterType.QueryString)));
                }

                return(_nodeEntry?.Entry?.Id != null && _groupPaging != null && _nodeParents != null);
            })
            .WithName(x => nameof(x.NodeId))
            .WithMessage("Something went wrong with alfresco server.")
            .DependentRules(() =>
            {
                RuleFor(x => x)
                .Must(y => _groupPaging?.List?.Entries?.Any(q => q.Entry.Id == identityUser.RequestGroup) ?? false)
                .WithName(x => "Group")
                .WithMessage($"User isn't member of group {identityUser.RequestGroup}.");

                RuleFor(x => x.NodeId)
                .Must(x => _nodeEntry.Entry.NodeType == SpisumNames.NodeTypes.ShipmentPublish)
                .WithMessage(x => $"Provided nodeId must be NodeType {SpisumNames.NodeTypes.ShipmentPublish}");

                RuleFor(x => x)
                .Must(y => _nodeParents?.Any(q => q.Entry.NodeType == SpisumNames.NodeTypes.Document) ?? false)
                .WithName(x => "Parent")
                .WithMessage($"Provided shipment does not have a parent type of {SpisumNames.NodeTypes.Document}");

                RuleFor(x => x)
                .Must(y => CheckDispatchGroup(identityUser.RequestGroup))
                .WithName(x => "Dispatch group")
                .WithMessage($"Requested group in not part of {SpisumNames.Groups.DispatchGroup}");
            });

            RuleFor(x => x.Body.Components)
            .Must(y => y.Count > 0)
            .When(x => x.Body != null)
            .WithName(x => "Components")
            .WithMessage("Components cannot be empty");

            RuleFor(x => x.Body.DateFrom)
            .Must(y => y.HasValue && CompareDateTime(y.Value))
            .When(x => x.Body != null)
            .WithName(x => "DateFrom")
            .WithMessage("DateFrom cannot be in past");

            RuleFor(x => x.Body.Days)
            .Must(y => y.HasValue ? y.Value > 0 : true)
            .When(x => x.Body != null)
            .WithName(x => "Days")
            .WithMessage("Days must be greater than 0");

            RuleFor(x => x.Body.Note)
            .MaximumLength(255)
            .When(x => x.Body != null)
            .WithName(x => "Note")
            .WithMessage("Message cannot be longer than 255 characters");
        }