public async Task AddParticipantLinks(Guid hearingId, EditHearingRequest request, HearingDetailsResponse hearing)
 {
     if (request.Participants.Any(x => x.LinkedParticipants != null && x.LinkedParticipants.Count > 0))
     {
         foreach (var requestParticipant in request.Participants.Where(x => x.LinkedParticipants.Any()))
         {
             if (requestParticipant.Id != null)
             {
                 continue;
             }
             var requests = new List <LinkedParticipantRequest>();
             foreach (var lp in requestParticipant.LinkedParticipants)
             {
                 requests.Add(new LinkedParticipantRequest
                 {
                     ParticipantContactEmail       = lp.ParticipantContactEmail,
                     LinkedParticipantContactEmail = lp.LinkedParticipantContactEmail
                 });
             }
             var updateParticipantRequest = new UpdateParticipantRequest
             {
                 LinkedParticipants = requests,
                 DisplayName        = requestParticipant.DisplayName,
                 OrganisationName   = requestParticipant.OrganisationName,
                 Representee        = requestParticipant.Representee,
                 TelephoneNumber    = requestParticipant.TelephoneNumber,
                 Title = requestParticipant.Title
             };
             var newParticipant = hearing.Participants.First(p => p.ContactEmail == requestParticipant.ContactEmail);
             await _bookingsApiClient.UpdateParticipantDetailsAsync(hearingId, newParticipant.Id, updateParticipantRequest);
         }
     }
 }
        public void Should_map_properties_for_update_hearing_request()
        {
            var username          = "******";
            var scheduledDateTime = new DateTime(2020, 12, 12);
            var caseRequest       = new CaseRequest {
                Name = "casename", Number = "casenumber"
            };

            var source = new EditHearingRequest
            {
                HearingRoomName   = "roomname",
                HearingVenueName  = "venuename",
                OtherInformation  = "other information",
                ScheduledDateTime = scheduledDateTime,
                ScheduledDuration = 45,
                Case = new EditCaseRequest {
                    Name = caseRequest.Name, Number = caseRequest.Number
                },
                QuestionnaireNotRequired = false,
                AudioRecordingRequired   = false
            };

            var result = HearingUpdateRequestMapper.MapTo(source, username);

            result.HearingRoomName.Should().Be(source.HearingRoomName);
            result.HearingVenueName.Should().Be(source.HearingVenueName);
            result.ScheduledDateTime.Should().Be(scheduledDateTime);
            result.ScheduledDuration.Should().Be(source.ScheduledDuration);
            result.OtherInformation.Should().Be(source.OtherInformation);
            result.Cases.Should().BeEquivalentTo(caseRequest);
            result.QuestionnaireNotRequired.Should().BeFalse();
            result.AudioRecordingRequired.Should().BeFalse();
        }
        public async Task ProcessEndpoints(Guid hearingId, EditHearingRequest request, HearingDetailsResponse hearing,
                                           List <ParticipantRequest> newParticipantList)
        {
            if (hearing.Endpoints == null)
            {
                return;
            }

            var listOfEndpointsToDelete = hearing.Endpoints.Where(e => request.Endpoints.All(re => re.Id != e.Id));

            await RemoveEndpointsFromHearing(hearing, listOfEndpointsToDelete);

            foreach (var endpoint in request.Endpoints)
            {
                var epToUpdate = newParticipantList
                                 .Find(p => p.ContactEmail.Equals(endpoint.DefenceAdvocateUsername,
                                                                  StringComparison.CurrentCultureIgnoreCase));
                if (epToUpdate != null)
                {
                    endpoint.DefenceAdvocateUsername = epToUpdate.Username;
                }

                if (endpoint.Id.HasValue)
                {
                    await UpdateEndpointInHearing(hearingId, hearing, endpoint);
                }
                else
                {
                    await AddEndpointToHearing(hearingId, hearing, endpoint);
                }
            }
        }
        public void Should_validate_participants_with_empty_list_as_error()
        {
            const string PARTICIPANT_MSG = "Please provide at least one participant";

            var testRequest = new EditHearingRequest {
                Participants = new List <EditParticipantRequest>()
            };
            var result = _validator.Validate(testRequest);

            Assert.That(result.Errors.Any(o => o.PropertyName == "Participants" && o.ErrorMessage == PARTICIPANT_MSG));
        }
        public void Should_validate_participants_as_valid()
        {
            var testRequest = new EditHearingRequest {
                Participants = new List <EditParticipantRequest> {
                    new EditParticipantRequest()
                },
                Case = new EditCaseRequest(),
            };
            var result = _validator.Validate(testRequest);

            Assert.That(!result.Errors.Any(o => o.PropertyName == "Participants"));
        }
        private async Task RemoveParticipantsFromHearing(Guid hearingId, EditHearingRequest request,
                                                         HearingDetailsResponse originalHearing)
        {
            var deleteParticipantList =
                originalHearing.Participants.Where(p => request.Participants.All(rp => rp.Id != p.Id));

            foreach (var participantToDelete in deleteParticipantList)
            {
                _logger.LogDebug("Removing existing participant {Participant} from hearing {Hearing}",
                                 participantToDelete.Id, hearingId);
                await _bookingsApiClient.RemoveParticipantFromHearingAsync(hearingId, participantToDelete.Id);
            }
        }
        public async Task UpdateParticipantLinks(Guid hearingId, EditHearingRequest request, HearingDetailsResponse hearing)
        {
            if (!request.Participants.SelectMany(x => x.LinkedParticipants).Any())
            {
                return;
            }

            var existingParticipantWithLinks = request.Participants.Where(x => x.LinkedParticipants.Any() && x.Id.HasValue);

            foreach (var participantRequest in existingParticipantWithLinks)
            {
                await UpdateLinksForExistingParticipant(request, hearing, participantRequest);
            }
        }
        private async Task UpdateLinksForExistingParticipant(EditHearingRequest request, HearingDetailsResponse hearing, EditParticipantRequest requestParticipant)
        {
            var participant = hearing.Participants.First(x => x.Id == requestParticipant.Id);
            var linkedParticipantsInRequest = request.Participants.First(x => x.Id == participant.Id)
                                              .LinkedParticipants.ToList();

            var requests =
                BuildLinkedParticipantRequestForExistingParticipant(hearing, participant, linkedParticipantsInRequest);

            var updateParticipantRequest = new UpdateParticipantRequest
            {
                LinkedParticipants = requests,
                DisplayName        = requestParticipant.DisplayName,
                OrganisationName   = requestParticipant.OrganisationName,
                Representee        = requestParticipant.Representee,
                TelephoneNumber    = requestParticipant.TelephoneNumber,
                Title = requestParticipant.Title
            };

            await _bookingsApiClient.UpdateParticipantDetailsAsync(hearing.Id, participant.Id,
                                                                   updateParticipantRequest);
        }
        public static UpdateHearingRequest MapTo(EditHearingRequest editHearingRequest, string userName)
        {
            var updateHearingRequest = new UpdateHearingRequest
            {
                HearingRoomName   = editHearingRequest.HearingRoomName,
                HearingVenueName  = editHearingRequest.HearingVenueName,
                OtherInformation  = editHearingRequest.OtherInformation,
                ScheduledDateTime = editHearingRequest.ScheduledDateTime,
                ScheduledDuration = editHearingRequest.ScheduledDuration,
                UpdatedBy         = userName,
                Cases             = new List <CaseRequest>
                {
                    new CaseRequest
                    {
                        Name   = editHearingRequest.Case.Name,
                        Number = editHearingRequest.Case.Number
                    }
                },
                QuestionnaireNotRequired = false,
                AudioRecordingRequired   = editHearingRequest.AudioRecordingRequired
            };

            return(updateHearingRequest);
        }
        public async Task <ActionResult <HearingDetailsResponse> > EditHearing(Guid hearingId,
                                                                               [FromBody] EditHearingRequest request)
        {
            var usernameAdIdDict = new Dictionary <string, User>();

            if (hearingId == Guid.Empty)
            {
                _logger.LogWarning("No hearing id found to edit");
                ModelState.AddModelError(nameof(hearingId), $"Please provide a valid {nameof(hearingId)}");
                return(BadRequest(ModelState));
            }

            _logger.LogDebug("Attempting to edit hearing {Hearing}", hearingId);

            var result = _editHearingRequestValidator.Validate(request);

            if (!result.IsValid)
            {
                _logger.LogWarning("Failed edit hearing validation");
                ModelState.AddFluentValidationErrors(result.Errors);
                return(BadRequest(ModelState));
            }

            HearingDetailsResponse originalHearing;

            try
            {
                originalHearing = await _bookingsApiClient.GetHearingDetailsByIdAsync(hearingId);
            }
            catch (BookingsApiException e)
            {
                _logger.LogError(e,
                                 "Failed to get hearing {Hearing}. Status Code {StatusCode} - Message {Message}",
                                 hearingId, e.StatusCode, e.Response);
                if (e.StatusCode != (int)HttpStatusCode.NotFound)
                {
                    throw;
                }

                return(NotFound($"No hearing with id found [{hearingId}]"));
            }

            try
            {
                //Save hearing details
                var updateHearingRequest =
                    HearingUpdateRequestMapper.MapTo(request, _userIdentity.GetUserIdentityName());
                await _bookingsApiClient.UpdateHearingDetailsAsync(hearingId, updateHearingRequest);

                var newParticipantList = new List <ParticipantRequest>();

                foreach (var participant in request.Participants)
                {
                    if (!participant.Id.HasValue)
                    {
                        await _hearingsService.ProcessNewParticipants(hearingId, participant, originalHearing,
                                                                      usernameAdIdDict, newParticipantList);
                    }
                    else
                    {
                        await _hearingsService.ProcessExistingParticipants(hearingId, originalHearing, participant);
                    }
                }

                // Delete existing participants if the request doesn't contain any update information
                originalHearing.Participants ??= new List <ParticipantResponse>();
                await RemoveParticipantsFromHearing(hearingId, request, originalHearing);

                // Add new participants
                await _hearingsService.SaveNewParticipants(hearingId, newParticipantList);

                var addedParticipantToHearing = await _bookingsApiClient.GetHearingDetailsByIdAsync(hearingId);

                await _hearingsService.UpdateParticipantLinks(hearingId, request, addedParticipantToHearing);

                // endpoints
                await _hearingsService.ProcessEndpoints(hearingId, request, originalHearing, newParticipantList);

                var updatedHearing = await _bookingsApiClient.GetHearingDetailsByIdAsync(hearingId);

                await _hearingsService.AddParticipantLinks(hearingId, request, updatedHearing);

                _logger.LogDebug("Attempting assign participants to the correct group");
                await _hearingsService.AssignParticipantToCorrectGroups(updatedHearing, usernameAdIdDict);

                _logger.LogDebug("Successfully assigned participants to the correct group");

                // Send a notification email to newly created participants
                var newParticipantEmails = newParticipantList.Select(p => p.ContactEmail).ToList();
                await SendEmailsToParticipantsAddedToHearing(newParticipantList, updatedHearing, usernameAdIdDict, newParticipantEmails);

                await SendJudgeEmailIfNeeded(updatedHearing, originalHearing);

                if (!updatedHearing.HasScheduleAmended(originalHearing))
                {
                    return(Ok(updatedHearing));
                }


                var participantsForAmendment = updatedHearing.Participants
                                               .Where(p => !newParticipantEmails.Contains(p.ContactEmail)).ToList();
                await _hearingsService.SendHearingUpdateEmail(originalHearing, updatedHearing,
                                                              participantsForAmendment);


                return(Ok(updatedHearing));
            }
            catch (BookingsApiException e)
            {
                _logger.LogError(e,
                                 "Failed to edit hearing {Hearing}. Status Code {StatusCode} - Message {Message}",
                                 hearingId, e.StatusCode, e.Response);
                if (e.StatusCode == (int)HttpStatusCode.BadRequest)
                {
                    return(BadRequest(e.Response));
                }

                throw;
            }
        }