Пример #1
0
        public void Command_cannot_be_issued_earlier_than_24h_before_training()
        {
            // Arrange
            var id     = EnrollmentAggregate.EnrollmentId.New;
            var event1 = new DomainEvent <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, RecruitmentFormSubmitted>(
                new RecruitmentFormSubmitted(
                    NodaTime.SystemClock.Instance.GetCurrentInstant(),
                    "Andrzej", "Strzelba",
                    EmailAddress.Parse("*****@*****.**"), Consts.FakePhoneNumber,
                    "ala ma kota", 1, "Wolne Miasto Gdańsk", new[] { "Wadowice" }, new[] { 1 }, true),
                new Metadata(), DateTimeOffset.Now, id, 1
                );
            var event2 = new DomainEvent <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, CandidateAcceptedTrainingInvitation>(
                new CandidateAcceptedTrainingInvitation(Guid.NewGuid(), CommunicationChannel.OutgoingEmail, 1, string.Empty),
                new Metadata(), DateTimeOffset.Now, id, 2
                );
            var enrollment = new EnrollmentAggregate(id);

            enrollment.ApplyEvents(new IDomainEvent[] { event1, event2 });

            var command = new SendTrainingReminder.Command()
            {
                EnrollmentId = id.GetGuid(), TrainingId = 1
            };
            var training = CreateTrainingWithIdAndOffset(1, Duration.FromDays(3));

            // Act
            var result = enrollment.CanSendTrainingReminder(command, training, SystemClock.Instance.GetCurrentInstant());

            // Assert
            result.IsSuccess.Should().BeFalse();
            var error = result.Error.Should().BeOfType <Error.DomainError>().Subject;

            error.Message.Should().Be(SendTrainingReminder_Messages.Reminder_cannot_be_sent_earlier_than_24h_before_training);
        }
Пример #2
0
        public Result <Nothing, Error> CanSendTrainingReminder(SendTrainingReminder.Command command, Training training, NodaTime.Instant now)
        {
            Guard.Against.Null(command, nameof(command));
            Guard.Against.Null(training, nameof(training));
            ValidateIdMatchOrThrow(command.EnrollmentId);

            if (SelectedTrainingID != null && training.ID != SelectedTrainingID)
            {
                return(Result.Failure <Nothing, Error>(new Error.DomainError(SendTrainingReminder_Messages.Reminder_cannot_be_sent_if_the_candidate_is_not_invited_to_training)));
            }
            if (HasResignedEffectively(training.StartDateTime.ToInstant()) || HasResignedEffectively(now))
            {
                return(Result.Failure <Nothing, Error>(new Error.DomainError(SendTrainingReminder_Messages.Reminder_cannot_be_sent_if_the_candidate_resigned)));
            }
            if (SelectedTrainingID == null)
            {
                return(Result.Failure <Nothing, Error>(new Error.DomainError(SendTrainingReminder_Messages.Reminder_cannot_be_sent_if_the_candidate_is_not_invited_to_training)));
            }
            if (training.StartDateTime.ToInstant().Minus(now) > Duration.FromHours(24))
            {
                return(Result.Failure <Nothing, Error>(new Error.DomainError(SendTrainingReminder_Messages.Reminder_cannot_be_sent_earlier_than_24h_before_training)));
            }
            if (training.StartDateTime.ToInstant() < now)
            {
                return(Result.Failure <Nothing, Error>(new Error.DomainError(SendTrainingReminder_Messages.Reminder_cannot_be_sent_after_training_start)));
            }

            return(Result.Success <Nothing, Error>(Nothing.Value));
        }
Пример #3
0
        public void With_valid_command__CanSendTrainingReminder_returns_success()
        {
            // Arrange
            var id     = EnrollmentAggregate.EnrollmentId.New;
            var event1 = new DomainEvent <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, RecruitmentFormSubmitted>(
                new RecruitmentFormSubmitted(
                    SystemClock.Instance.GetCurrentInstant(),
                    "Andrzej", "Strzelba",
                    EmailAddress.Parse("*****@*****.**"), Consts.FakePhoneNumber,
                    "ala ma kota", 1, "Wolne Miasto Gdańsk", new[] { "Wadowice" }, new[] { 1 }, true),
                new Metadata(), DateTimeOffset.Now, id, 1
                );
            var event2 = new DomainEvent <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, CandidateAcceptedTrainingInvitation>(
                new CandidateAcceptedTrainingInvitation(Guid.NewGuid(), CommunicationChannel.OutgoingEmail, 1, string.Empty),
                new Metadata(), DateTimeOffset.Now, id, 2
                );
            var enrollment = new EnrollmentAggregate(id);

            enrollment.ApplyEvents(new IDomainEvent[] { event1, event2 });

            var command = new SendTrainingReminder.Command()
            {
                EnrollmentId = id.GetGuid(), TrainingId = 1
            };
            var training = CreateTrainingWithIdAndOffset(1, Duration.FromHours(12));

            // Act
            var result = enrollment.CanSendTrainingReminder(command, training, SystemClock.Instance.GetCurrentInstant());

            // Assert
            result.IsSuccess.Should().BeTrue();
        }
Пример #4
0
        public async Task After_command_is_executed__if_email_service_encounters_error__aggregate_contains_EmailSendingFailed_event()
        {
            // Arrange
            var enrollmentId = EnrollmentAggregate.EnrollmentId.New;
            var event1       = new DomainEvent <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, RecruitmentFormSubmitted>(
                new RecruitmentFormSubmitted(
                    SystemClock.Instance.GetCurrentInstant(),
                    "Andrzej", "Strzelba",
                    EmailAddress.Parse("*****@*****.**"), Consts.FakePhoneNumber,
                    "ala ma kota", 1, "Wolne Miasto Gdańsk", new[] { "Wadowice" }, new[] { 1 }, true),
                new Metadata(), DateTimeOffset.Now, enrollmentId, 1
                );
            var event2 = new DomainEvent <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, CandidateAcceptedTrainingInvitation>(
                new CandidateAcceptedTrainingInvitation(Guid.NewGuid(), CommunicationChannel.OutgoingEmail, 1, string.Empty),
                new Metadata(), DateTimeOffset.Now, enrollmentId, 2
                );
            var enrollment = new EnrollmentAggregate(enrollmentId);

            enrollment.ApplyEvents(new IDomainEvent[] { event1, event2 });

            var aggregateStore = new MockAggregateStore <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId>(enrollment);
            var emailService   = new FailingEmailService();

            var options = Mock.Of <IOptions <Config> >(mock =>
                                                       mock.Value == new Config()
            {
                TrainingReminderEmail = new Config.EmailMessageConfig()
                {
                    Subject = "przypomnienie o szkoleniu", Body = "przypominamy o szkoleniu"
                }
            });


            // Act
            var training     = CreateTrainingWithIdAndOffset(1, Duration.FromHours(12));
            var trainingRepo = Mock.Of <ITrainingRepository>(repo => repo.GetById(1) == Task.FromResult(Maybe <Training> .From(training)));

            var handler = new SendTrainingReminderHandler(SystemClock.Instance, aggregateStore, trainingRepo, emailService, options, new FluidTemplateRenderer());

            var command = new SendTrainingReminder.Command()
            {
                EnrollmentId = enrollmentId.GetGuid(), TrainingId = 1
            };
            var result = await handler.Handle(command, CancellationToken.None);


            // Assert
            result.IsSuccess.Should().BeTrue();
            enrollment.UncommittedEvents.Should().ContainSingle().Which.AggregateEvent.Should().BeOfType <EmailSendingFailed>();
            var newEvent = enrollment.UncommittedEvents.Single().AggregateEvent as EmailSendingFailed;

            newEvent.Subject.Should().Be("przypomnienie o szkoleniu");
            newEvent.Body.Should().Be("przypominamy o szkoleniu");
            emailService.FailedMessages.Should().ContainSingle();
            var emailMessage = emailService.FailedMessages.Single();

            emailMessage.Subject.Should().Be("przypomnienie o szkoleniu");
            emailMessage.Body.Should().Be("przypominamy o szkoleniu");
            emailMessage.To.Should().ContainSingle().Which.Should().Be(EmailAddress.Parse("*****@*****.**"));
        }
Пример #5
0
        public void Command_is_invalid_if_candidate_was_not_invited()
        {
            // Arrange
            var id     = EnrollmentAggregate.EnrollmentId.New;
            var event1 = new DomainEvent <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, RecruitmentFormSubmitted>(
                new RecruitmentFormSubmitted(
                    NodaTime.SystemClock.Instance.GetCurrentInstant(),
                    "Andrzej", "Strzelba",
                    EmailAddress.Parse("*****@*****.**"), Consts.FakePhoneNumber,
                    "ala ma kota", 1, "Wolne Miasto Gdańsk", new[] { "Wadowice" }, new[] { 1 }, true),
                new Metadata(), DateTimeOffset.Now, id, 1
                );
            var enrollment = new EnrollmentAggregate(id);

            enrollment.ApplyEvents(new IDomainEvent[] { event1 });

            var command = new SendTrainingReminder.Command()
            {
                EnrollmentId = id.GetGuid(), TrainingId = 1
            };
            var training = CreateTrainingWithIdAndOffset(1, Duration.FromHours(12));

            // Act
            var result = enrollment.CanSendTrainingReminder(command, training, SystemClock.Instance.GetCurrentInstant());

            // Assert
            result.IsSuccess.Should().BeFalse();
            var error = result.Error.Should().BeOfType <Error.DomainError>().Subject;

            error.Message.Should().Be(SendTrainingReminder_Messages.Reminder_cannot_be_sent_if_the_candidate_is_not_invited_to_training);
        }
        public async Task <Result <Nothing, Error> > Handle(SendTrainingReminder.Command command, CancellationToken cancellationToken)
        {
            var training = await _repo.GetById(command.TrainingId);

            if (training.HasNoValue)
            {
                return(Result.Failure <Nothing, Error>(new Error.ResourceNotFound(SendTrainingReminder_Messages.Training_not_found)));
            }

            var options      = _options.Value.TrainingReminderEmail;
            var enrollmentId = EnrollmentAggregate.EnrollmentId.With(command.EnrollmentId);

            var result = await _aggregateStore.Update <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, Result <Nothing, Error> >(
                enrollmentId, EventFlow.Core.SourceId.New,
                async (aggregate, token) => {
                return(await aggregate.CanSendTrainingReminder(command, training.Value, _clock.GetCurrentInstant())
                       .Tap(async _ => {
                    var body = await BuildMessageBody(options, aggregate, training.Value);
                    var message = _emailService.CreateMessage(aggregate.Email, options.Subject, body, isBodyHtml: options.IsBodyHtml);
                    await _emailService.Send(message, token)
                    .Tap(() => aggregate.RecordEmailSent(_clock.GetCurrentInstant(), message))
                    .OnFailure(() => aggregate.RecordEmailSendingFailed(_clock.GetCurrentInstant(), message));
                }));
            },
                cancellationToken);

            return(result.Unwrap());
        }
Пример #7
0
        public async Task After_command_is_executed__email_is_sent_and_aggregate_contains_EmailSent_event()
        {
            // Arrange
            var enrollmentId = EnrollmentAggregate.EnrollmentId.New;
            var event1       = new DomainEvent <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, RecruitmentFormSubmitted>(
                new RecruitmentFormSubmitted(
                    SystemClock.Instance.GetCurrentInstant(),
                    "Andrzej", "Strzelba",
                    EmailAddress.Parse("*****@*****.**"), Consts.FakePhoneNumber,
                    "ala ma kota", 1, "Wolne Miasto Gdańsk", new[] { "Wadowice" }, new[] { 1 }, true),
                new Metadata(), DateTimeOffset.Now, enrollmentId, 1
                );
            var event2 = new DomainEvent <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId, CandidateAcceptedTrainingInvitation>(
                new CandidateAcceptedTrainingInvitation(Guid.NewGuid(), CommunicationChannel.OutgoingEmail, 1, string.Empty),
                new Metadata(), DateTimeOffset.Now, enrollmentId, 2
                );
            var enrollment = new EnrollmentAggregate(enrollmentId);

            enrollment.ApplyEvents(new IDomainEvent[] { event1, event2 });

            var aggregateStore = new MockAggregateStore <EnrollmentAggregate, EnrollmentAggregate.EnrollmentId>(enrollment);
            var training       = CreateTrainingWithIdAndOffset(1, Duration.FromHours(12));
            var trainingRepo   = Mock.Of <ITrainingRepository>(repo => repo.GetById(1) == Task.FromResult(Maybe <Training> .From(training)));
            var emailService   = new SucceedingEmailService();

            var options = Mock.Of <IOptions <Config> >(mock =>
                                                       mock.Value == new Config()
            {
                TrainingReminderEmail = new Config.EmailMessageConfig()
                {
                    Subject = "przypomnienie o szkoleniu",
                    Body    = "{{ Candidate.FullName }} przypominamy o szkoleniu w {{ Training.City }} w dniu {{ Training.StartDate }}" +
                              " o godzinie {{ Training.StartTime }} trwającym {{ Training.Duration }} godzin!"
                }
            });

            // Act
            var handler = new SendTrainingReminderHandler(SystemClock.Instance, aggregateStore, trainingRepo, emailService, options, new FluidTemplateRenderer());

            var command = new SendTrainingReminder.Command()
            {
                EnrollmentId = enrollmentId.GetGuid(), TrainingId = 1
            };
            var result = await handler.Handle(command, CancellationToken.None);


            // Assert
            result.IsSuccess.Should().BeTrue();
            enrollment.UncommittedEvents.Should().ContainSingle();
            enrollment.UncommittedEvents.Single().AggregateEvent.Should().BeOfType <EmailSent>();
            emailService.SentMessages.Should().ContainSingle();
            emailService.SentMessages.Single().Should().BeEquivalentTo(new {
                Subject = "przypomnienie o szkoleniu",
                Body    = $"Andrzej Strzelba przypominamy o szkoleniu w Wadowice w dniu {training.StartDateTime.Date}" +
                          $" o godzinie {training.StartDateTime.TimeOfDay} trwającym {training.Duration.ToString("HH':'mm", null)} godzin!"
            });
        }