public DeletePunchOutCommandValidator(
            IInvitationValidator invitationValidator,
            IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => InvitationIsCanceled(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"IPO is not canceled! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => CurrentUserIsCreatorOrOfInvitationOrAdmin(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Current user is not the creator of the invitation and not ipo admin! Id={command.InvitationId}")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command =>
                         $"Invitation does not have valid rowVersion! RowVersion={command.RowVersion}");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> CurrentUserIsCreatorOrOfInvitationOrAdmin(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsAllowedToDeleteIpoAsync(invitationId, cancellationToken);

            async Task <bool> InvitationIsCanceled(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Canceled, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
        public AcceptPunchOutCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnInvitationInCompletedStage(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Invitation is not in completed stage, and thus cannot be accepted!")
            .Must(command => HaveAValidRowVersion(command.InvitationRowVersion))
            .WithMessage(command =>
                         $"Invitation row version is not valid! InvitationRowVersion={command.InvitationRowVersion}")
            .Must(command => HaveAValidRowVersion(command.ParticipantRowVersion))
            .WithMessage(command =>
                         $"Participant row version is not valid! ParticipantRowVersion={command.ParticipantRowVersion}")
            .MustAsync((command, cancellationToken) => BeAnAccepterOnIpo(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "The IPO does not have a construction company assigned to accept the IPO!")
            .MustAsync((command, cancellationToken) => BeTheAssignedPersonIfPersonParticipant(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Person signing is not the construction company assigned to accept this IPO, or there is not a valid construction company on the IPO!");

            RuleForEach(command => command.Participants)
            .MustAsync((command, participant, _, cancellationToken) => BeAnExistingParticipant(participant.Id, command.InvitationId, cancellationToken))
            .WithMessage((command, participant) =>
                         $"Participant with ID does not exist on invitation! Participant={participant.Id}")
            .Must((command, participant) => HaveAValidRowVersion(participant.RowVersion))
            .WithMessage((command, participant) =>
                         $"Participant doesn't have valid rowVersion! Participant={participant.Id}");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeAnInvitationInCompletedStage(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Completed, cancellationToken);

            async Task <bool> BeAnAccepterOnIpo(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoHasAccepterAsync(invitationId, cancellationToken);

            async Task <bool> BeTheAssignedPersonIfPersonParticipant(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsValidAccepterParticipantAsync(invitationId, cancellationToken);

            async Task <bool> BeAnExistingParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.ParticipantExistsAsync(participantId, invitationId, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
예제 #3
0
        public SignPunchOutCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnExistingParticipant(command.ParticipantId, command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Participant with ID does not exist on invitation! Id={command.ParticipantId}")
            .MustAsync((command, cancellationToken) => BeANonCanceledInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Invitation is canceled, and thus cannot be signed!")
            .Must(command => HaveAValidRowVersion(command.ParticipantRowVersion))
            .WithMessage(command =>
                         $"Participant row version is not valid! ParticipantRowVersion={command.ParticipantRowVersion}")
            .MustAsync((command, cancellationToken) => BeASigningParticipantOnIpo(command.InvitationId, command.ParticipantId, cancellationToken))
            .WithMessage(command =>
                         $"Participant is not assigned to sign this IPO! ParticipantId={command.ParticipantId}")
            .MustAsync((command, cancellationToken) => BeTheAssignedPersonIfPersonParticipant(command.InvitationId, command.ParticipantId, cancellationToken))
            .WithMessage(command =>
                         "Person signing is not assigned to sign IPO, or there is not a valid functional role on the IPO!")
            .MustAsync((command, cancellationToken) => BeUnsignedParticipant(command.ParticipantId, command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Participant is already signed!");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeANonCanceledInvitation(int invitationId, CancellationToken cancellationToken)
            => !await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Canceled, cancellationToken);

            async Task <bool> BeASigningParticipantOnIpo(int invitationId, int participantId, CancellationToken cancellationToken)
            => await invitationValidator.SignerExistsAsync(invitationId, participantId, cancellationToken);

            async Task <bool> BeTheAssignedPersonIfPersonParticipant(int invitationId, int participantId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsValidSigningParticipantAsync(invitationId, participantId, cancellationToken);

            async Task <bool> BeAnExistingParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.ParticipantExistsAsync(participantId, invitationId, cancellationToken);

            async Task <bool> BeUnsignedParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => !await invitationValidator.ParticipantIsSignedAsync(participantId, invitationId, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
예제 #4
0
        public UploadAttachmentCommandValidator(IInvitationValidator invitationValidator, IOptionsMonitor <BlobStorageOptions> options)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(x => x)
            .NotNull();

            RuleFor(x => x.FileName)
            .NotEmpty()
            .WithMessage("Filename not given!")
            .MaximumLength(Attachment.FileNameLengthMax)
            .WithMessage($"Filename too long! Max {Attachment.FileNameLengthMax} characters")
            .Must(BeAValidFile)
            .WithMessage(x => $"File {x.FileName} is not a valid file for upload!");

            RuleFor(x => x.Content.Length)
            .Must(BeSmallerThanMaxSize)
            .When(x => x.Content != null)
            .WithMessage($"Maximum file size is {options.CurrentValue.MaxSizeMb}MB!");

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitationAsync(command.InvitationId, cancellationToken))
            .WithMessage(command => $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => NotHaveAttachmentWithFileNameAsync(command.InvitationId, command.FileName, cancellationToken))
            .WithMessage(command => $"Invitation already has an attachment with filename {command.FileName}! Please rename file or choose to overwrite.")
            .When(c => !c.OverWriteIfExists, ApplyConditionTo.CurrentValidator);

            bool BeAValidFile(string fileName)
            {
                var suffix = Path.GetExtension(fileName?.ToLower());

                return(suffix != null && !options.CurrentValue.BlockedFileSuffixes.Contains(suffix) && fileName?.IndexOfAny(Path.GetInvalidFileNameChars()) == -1);
            }

            bool BeSmallerThanMaxSize(long fileSizeInBytes)
            {
                var maxSizeInBytes = options.CurrentValue.MaxSizeMb * 1024 * 1024;

                return(fileSizeInBytes < maxSizeInBytes);
            }

            async Task <bool> BeAnExistingInvitationAsync(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> NotHaveAttachmentWithFileNameAsync(int invitationId, string fileName, CancellationToken cancellationToken)
            => !await invitationValidator.AttachmentWithFileNameExistsAsync(invitationId, fileName, cancellationToken);
        }
예제 #5
0
        public UpdateAttendedStatusOnParticipantCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) =>
                       BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) =>
                       NotBeCancelledInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Cannot perform updates on cancelled invitation! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) =>
                       BeAnExistingParticipant(command.ParticipantId, command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Participant with ID does not exist on invitation! ParticipantId={command.ParticipantId}")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command =>
                         $"Participant doesn't have valid rowVersion! ParticipantRowVersion={command.RowVersion}")
            .MustAsync((command, cancellationToken) =>
                       HavePermissionToEdit(command.ParticipantId, command.InvitationId, cancellationToken))
            .WithMessage("The current user does not have sufficient privileges to edit this participant.")
            .MustAsync((command, cancellationToken) =>
                       HaveOppositeAttendedStatusIfTouched(command.ParticipantId, command.InvitationId, command.Attended, cancellationToken))
            .WithMessage("Cannot update participant to its current attendedStatus.");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> NotBeCancelledInvitation(int invitationId, CancellationToken cancellationToken)
            => !await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Canceled, cancellationToken);

            async Task <bool> BeAnExistingParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.ParticipantExistsAsync(participantId, invitationId, cancellationToken);

            async Task <bool> HavePermissionToEdit(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.HasPermissionToEditParticipantAsync(participantId, invitationId, cancellationToken);

            async Task <bool> HaveOppositeAttendedStatusIfTouched(int participantId, int invitationId, bool attended, CancellationToken cancellationToken)
            => await invitationValidator.HasOppositeAttendedStatusIfTouchedAsync(participantId, invitationId, attended, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
        public UpdateAttendedStatusAndNotesOnParticipantsCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnInvitationInCompletedStage(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Invitation is not in completed stage, and thus cannot change attended statuses or notes!")
            .MustAsync((command, cancellationToken) => BeAContractorOnIpo(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "The IPO does not have a contractor assigned to the IPO!")
            .MustAsync((command, cancellationToken) => BeTheAssignedContractorIfPersonParticipant(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "User is not the contractor assigned to complete this IPO, or there is not a valid contractor on the IPO!");

            RuleForEach(command => command.Participants)
            .MustAsync((command, participant, _, cancellationToken) => BeAnExistingParticipant(participant.Id, command.InvitationId, cancellationToken))
            .WithMessage((command, participant) =>
                         $"Participant with ID does not exist on invitation! ParticipantId={participant.Id}")
            .Must((command, participant) => HaveAValidRowVersion(participant.RowVersion))
            .WithMessage((command, participant) =>
                         $"Participant doesn't have valid rowVersion! ParticipantRowVersion={participant.RowVersion}");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeAnInvitationInCompletedStage(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Completed, cancellationToken);

            async Task <bool> BeAnExistingParticipant(int participantId, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.ParticipantExistsAsync(participantId, invitationId, cancellationToken);

            async Task <bool> BeTheAssignedContractorIfPersonParticipant(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsValidCompleterParticipantAsync(invitationId, cancellationToken);

            async Task <bool> BeAContractorOnIpo(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoHasCompleterAsync(invitationId, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
        public UnCompletePunchOutCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnInvitationInCompletedStage(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Invitation is not in completed stage, and thus cannot be uncompleted!")
            .Must(command => HaveAValidRowVersion(command.InvitationRowVersion))
            .WithMessage(command =>
                         $"Invitation row version is not valid! InvitationRowVersion={command.InvitationRowVersion}")
            .Must(command => HaveAValidRowVersion(command.ParticipantRowVersion))
            .WithMessage(command =>
                         $"Participant row version is not valid! ParticipantRowVersion={command.ParticipantRowVersion}")
            .MustAsync((command, cancellationToken) => BeACompleterOnIpo(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "The IPO does not have a contractor assigned to uncomplete the IPO!")
            .MustAsync((command, cancellationToken) => BeAdminOrThePersonWhoCompleted(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Person trying to uncomplete is not an admin and not the person who completed the IPO!");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeAnInvitationInCompletedStage(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Completed, cancellationToken);

            async Task <bool> BeACompleterOnIpo(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoHasCompleterAsync(invitationId, cancellationToken);

            async Task <bool> BeAdminOrThePersonWhoCompleted(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsAdminOrValidCompletorParticipantAsync(invitationId, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
        public DeleteAttachmentCommandValidator(
            IInvitationValidator invitationValidator,
            IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitationAsync(command.InvitationId, cancellationToken))
            .WithMessage(command => $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnExistingAttachmentAsync(command.InvitationId, command.AttachmentId, cancellationToken))
            .WithMessage(command => $"Attachment doesn't exist! Attachment={command.AttachmentId}.")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command => $"Not a valid row version! Row version={command.RowVersion}.");

            async Task <bool> BeAnExistingInvitationAsync(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);
            async Task <bool> BeAnExistingAttachmentAsync(int invitationId, int attachmentId, CancellationToken cancellationToken)
            => await invitationValidator.AttachmentExistsAsync(invitationId, attachmentId, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
예제 #9
0
        public CancelPunchOutCommandValidator(
            IInvitationValidator invitationValidator,
            IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => InvitationIsNotCanceled(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"IPO is already canceled! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => InvitationIsNotAccepted(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"IPO is in accepted stage! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => CurrentUserIsCreatorOrIsInContractorFunctionalRoleOfInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Current user is not the creator of the invitation and not in Contractor Functional Role! Id={command.InvitationId}")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command =>
                         $"Invitation does not have valid rowVersion! RowVersion={command.RowVersion}");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> CurrentUserIsCreatorOrIsInContractorFunctionalRoleOfInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.CurrentUserIsAllowedToCancelIpoAsync(invitationId, cancellationToken);

            async Task <bool> InvitationIsNotCanceled(int invitationId, CancellationToken cancellationToken)
            => !await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Canceled, cancellationToken);

            async Task <bool> InvitationIsNotAccepted(int invitationId, CancellationToken cancellationToken)
            => !await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Accepted, cancellationToken);

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);
        }
        public AddCommentCommandValidator(IInvitationValidator invitationValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            //input validators
            .Must((command) => command.Comment.Length <= Comment.CommentMaxLength)
            .WithMessage(command =>
                         $"Comment cannot be more than {Comment.CommentMaxLength} characters! Comment={command.Comment}")
            //business validators
            .MustAsync((command, cancellationToken) => BeAnExistingInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeANonCanceledInvitation(command.InvitationId, cancellationToken))
            .WithMessage(command =>
                         "Invitation is canceled, and thus cannot be commented on!");

            async Task <bool> BeAnExistingInvitation(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeANonCanceledInvitation(int invitationId, CancellationToken cancellationToken)
            => !await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Canceled, cancellationToken);
        }
        public EditInvitationCommandValidator(IInvitationValidator invitationValidator, IRowVersionValidator rowVersionValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            //input validators
            .Must(command => command.UpdatedParticipants != null)
            .WithMessage("Participants cannot be null!")
            .Must(command => command.Description == null || command.Description.Length < Invitation.DescriptionMaxLength)
            .WithMessage(command =>
                         $"Description cannot be more than {Invitation.DescriptionMaxLength} characters! Description={command.Description}")
            .Must(command => command.Location == null || command.Location.Length < Invitation.LocationMaxLength)
            .WithMessage(command =>
                         $"Location cannot be more than {Invitation.LocationMaxLength} characters! Location={command.Location}")
            .Must(command => command.StartTime < command.EndTime)
            .WithMessage(command =>
                         $"Start time must be before end time! Start={command.StartTime} End={command.EndTime}")
            .Must(command =>
                  command.Title != null &&
                  command.Title.Length >= Invitation.TitleMinLength &&
                  command.Title.Length < Invitation.TitleMaxLength)
            .WithMessage(command =>
                         $"Title must be between {Invitation.TitleMinLength} and {Invitation.TitleMaxLength} characters! Title={command.Title}")
            //business validators
            .MustAsync((command, cancellationToken) => BeAnExistingIpo(command.InvitationId, cancellationToken))
            .WithMessage(command => $"Invitation with this ID does not exist! Id={command.InvitationId}")
            .MustAsync((command, cancellationToken) => BeAnIpoInPlannedStage(command.InvitationId, cancellationToken))
            .WithMessage(command => $"IPO must be in planned stage to be edited! Id={command.InvitationId}")
            .Must(command => HaveAValidRowVersion(command.RowVersion))
            .WithMessage(command => $"Invitation does not have valid rowVersion! RowVersion={command.RowVersion}")
            .Must(command => MustHaveValidScope(command.Type, command.UpdatedMcPkgScope, command.UpdatedCommPkgScope))
            .WithMessage("Not a valid scope! Choose either DP with mc scope or MDP with comm pkg scope")
            .Must(command => TwoFirstParticipantsMustBeSetWithCorrectOrganization(command.UpdatedParticipants))
            .WithMessage("Contractor and Construction Company must be invited!")
            .Must(command => RequiredParticipantsHaveLowestSortKeys(command.UpdatedParticipants))
            .WithMessage("Contractor must be first and Construction Company must be second!")
            .Must(command => ParticipantListMustBeValid(command.UpdatedParticipants))
            .WithMessage("Each participant must contain an email or oid!");

            RuleForEach(command => command.UpdatedParticipants)
            .MustAsync((command, participant, _, cancellationToken) => ParticipantToBeUpdatedMustExist(participant, command.InvitationId, cancellationToken))
            .WithMessage(_ => $"Participant with ID does not exist on invitation!")
            .Must(participant => participant.SortKey >= 0)
            .WithMessage((_, participant) =>
                         $"Sort key for participant must be a non negative number! SortKey={participant.SortKey}")
            .Must(FunctionalRoleParticipantsMustBeValid)
            .WithMessage((_, participant) =>
                         $"Functional role code must be between 3 and {Participant.FunctionalRoleCodeMaxLength} characters! Code={participant.InvitedFunctionalRole.Code}")
            .Must((command, participant) => ParticipantsHaveValidRowVersions(participant))
            .WithMessage(_ => "Participant doesn't have valid rowVersion!");

            async Task <bool> BeAnExistingIpo(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoExistsAsync(invitationId, cancellationToken);

            async Task <bool> BeAnIpoInPlannedStage(int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.IpoIsInStageAsync(invitationId, IpoStatus.Planned, cancellationToken);

            bool MustHaveValidScope(
                DisciplineType type,
                IList <string> updatedMcPkgScope,
                IList <string> updatedCommPkgScope)
            => invitationValidator.IsValidScope(type, updatedMcPkgScope, updatedCommPkgScope);

            async Task <bool> ParticipantToBeUpdatedMustExist(ParticipantsForCommand participant, int invitationId, CancellationToken cancellationToken)
            => await invitationValidator.ParticipantWithIdExistsAsync(participant, invitationId, cancellationToken);

            bool TwoFirstParticipantsMustBeSetWithCorrectOrganization(IList <ParticipantsForEditCommand> participants)
            => invitationValidator.RequiredParticipantsMustBeInvited(participants.Cast <ParticipantsForCommand>().ToList());

            bool RequiredParticipantsHaveLowestSortKeys(IList <ParticipantsForEditCommand> participants)
            => invitationValidator.OnlyRequiredParticipantsHaveLowestSortKeys(participants.Cast <ParticipantsForCommand>().ToList());

            bool ParticipantListMustBeValid(IList <ParticipantsForEditCommand> participants)
            => invitationValidator.IsValidParticipantList(participants.Cast <ParticipantsForCommand>().ToList());

            bool HaveAValidRowVersion(string rowVersion)
            => rowVersionValidator.IsValid(rowVersion);

            bool ParticipantsHaveValidRowVersions(ParticipantsForEditCommand participant)
            {
                if (participant.InvitedExternalEmailToEdit?.Id != null)
                {
                    return(rowVersionValidator.IsValid(participant.InvitedExternalEmailToEdit.RowVersion));
                }
                if (participant.InvitedPersonToEdit?.Id != null)
                {
                    return(rowVersionValidator.IsValid(participant.InvitedPersonToEdit.RowVersion));
                }

                if (participant.InvitedFunctionalRoleToEdit != null)
                {
                    if (participant.InvitedFunctionalRoleToEdit.Id != null && !rowVersionValidator.IsValid(participant.InvitedFunctionalRoleToEdit.RowVersion))
                    {
                        return(false);
                    }

                    return(participant.InvitedFunctionalRoleToEdit.EditPersons.All(person => person.Id == null || rowVersionValidator.IsValid(person.RowVersion)));
                }

                return(true);
            }

            bool FunctionalRoleParticipantsMustBeValid(ParticipantsForCommand participant)
            {
                if (participant.InvitedFunctionalRole == null)
                {
                    return(true);
                }

                return(participant.InvitedFunctionalRole.Code != null &&
                       participant.InvitedFunctionalRole.Code.Length > 2 &&
                       participant.InvitedFunctionalRole.Code.Length < Participant.FunctionalRoleCodeMaxLength);
            }
        }
예제 #12
0
        public CreateInvitationCommandValidator(IInvitationValidator invitationValidator)
        {
            CascadeMode = CascadeMode.Stop;

            RuleFor(command => command)
            //input validators
            .Must(command => command.Participants != null)
            .WithMessage("Participants cannot be null!")
            .Must(command =>
                  command.ProjectName != null &&
                  command.ProjectName.Length >= Invitation.ProjectNameMinLength &&
                  command.ProjectName.Length < Invitation.ProjectNameMaxLength)
            .WithMessage(command =>
                         $"Project name must be between {Invitation.ProjectNameMinLength} and {Invitation.ProjectNameMaxLength} characters! ProjectName={command.ProjectName}")
            .Must(command => command.Description == null || command.Description.Length < Invitation.DescriptionMaxLength)
            .WithMessage(command =>
                         $"Description cannot be more than {Invitation.DescriptionMaxLength} characters! Description={command.Description}")
            .Must(command => command.Location == null || command.Location.Length < Invitation.LocationMaxLength)
            .WithMessage(command =>
                         $"Location cannot be more than {Invitation.LocationMaxLength} characters! Location={command.Location}")
            .Must(command => command.StartTime < command.EndTime)
            .WithMessage(command =>
                         $"Start time must be before end time! Start={command.StartTime} End={command.EndTime}")
            .Must(command =>
                  command.Title != null &&
                  command.Title.Length >= Invitation.TitleMinLength &&
                  command.Title.Length < Invitation.TitleMaxLength)
            .WithMessage(command =>
                         $"Title must be between {Invitation.TitleMinLength} and {Invitation.TitleMaxLength} characters! Title={command.Title}")
            //business validators
            .Must(command => MustHaveValidScope(command.Type, command.McPkgScope, command.CommPkgScope))
            .WithMessage("Not a valid scope! Choose either DP with mc scope or MDP with comm pkg scope")
            .Must(command => TwoFirstParticipantsMustBeSetWithCorrectOrganization(command.Participants))
            .WithMessage("Contractor and Construction Company must be invited!")
            .Must(command => RequiredParticipantsHaveLowestSortKeys(command.Participants))
            .WithMessage("Contractor must be first and Construction Company must be second!")
            .Must(command => ParticipantListMustBeValid(command.Participants))
            .WithMessage("Each participant must contain an email or oid!");

            RuleForEach(command => command.Participants)
            .Must(participant => participant.SortKey >= 0)
            .WithMessage((_, participant) =>
                         $"Sort key for participant must be a non negative number! SortKey={participant.SortKey}")
            .Must(FunctionalRoleParticipantsMustBeValid)
            .WithMessage((_, participant) =>
                         $"Functional role code must be between 3 and {Participant.FunctionalRoleCodeMaxLength} characters! Code={participant.InvitedFunctionalRole.Code}");

            bool MustHaveValidScope(DisciplineType type, IList <string> mcPkgScope, IList <string> commPkgScope)
            => invitationValidator.IsValidScope(type, mcPkgScope, commPkgScope);

            bool TwoFirstParticipantsMustBeSetWithCorrectOrganization(IList <ParticipantsForCommand> participants)
            => invitationValidator.RequiredParticipantsMustBeInvited(participants);

            bool RequiredParticipantsHaveLowestSortKeys(IList <ParticipantsForCommand> participants)
            => invitationValidator.OnlyRequiredParticipantsHaveLowestSortKeys(participants);

            bool ParticipantListMustBeValid(IList <ParticipantsForCommand> participants)
            => invitationValidator.IsValidParticipantList(participants);

            bool FunctionalRoleParticipantsMustBeValid(ParticipantsForCommand participant)
            {
                if (participant.InvitedFunctionalRole == null)
                {
                    return(true);
                }

                return(participant.InvitedFunctionalRole.Code != null &&
                       participant.InvitedFunctionalRole.Code.Length > 2 &&
                       participant.InvitedFunctionalRole.Code.Length < Participant.FunctionalRoleCodeMaxLength);
            }
        }