From 181b0c99e74cf05abf12ee8ff67533bd4ada477c Mon Sep 17 00:00:00 2001 From: Oliver Scott Date: Mon, 21 Oct 2024 16:11:40 +0100 Subject: [PATCH] VIH-11052 Fix for audio recording setting not updating in waiting room (#2275) * Fetch conference when conference is updated * Push conference object as part of HearingDetailsUpdated event * Formatting * Remove ConferenceDto * Set conference from the hearing details updated message --- .../VideoWeb.EventHub/Hub/IEventHubClient.cs | 2 +- ...HearingDetailsUpdatedEventNotifierTests.cs | 13 +++++++-- .../src/app/services/events.service.spec.ts | 10 ++++--- .../src/app/services/events.service.ts | 5 ++-- .../models/hearing-details-updated-message.ts | 4 ++- ...oom-base.component.eventhub-events.spec.ts | 29 ++++++++++++++++++- .../waiting-room-base.component.ts | 26 +++++++++++++---- .../HearingDetailsUpdatedEventNotifier.cs | 9 ++++-- 8 files changed, 78 insertions(+), 20 deletions(-) diff --git a/VideoWeb/VideoWeb.EventHub/Hub/IEventHubClient.cs b/VideoWeb/VideoWeb.EventHub/Hub/IEventHubClient.cs index a66062aeec..b31cac0920 100644 --- a/VideoWeb/VideoWeb.EventHub/Hub/IEventHubClient.cs +++ b/VideoWeb/VideoWeb.EventHub/Hub/IEventHubClient.cs @@ -48,7 +48,7 @@ public interface IEventHubClient Task AllocationHearings(string csoUserName, List hearings); Task EndpointsUpdated(Guid conferenceId, UpdateEndpointsDto endpoints); Task HearingCancelledMessage(Guid conferenceId); - Task HearingDetailsUpdatedMessage(Guid conferenceId); + Task HearingDetailsUpdatedMessage(ConferenceResponse conference); /// /// Request a participant's local mute be update. Not to be confused with remote mute (and lock). /// diff --git a/VideoWeb/VideoWeb.UnitTests/Helpers/HearingDetailsUpdatedEventNotifierTests.cs b/VideoWeb/VideoWeb.UnitTests/Helpers/HearingDetailsUpdatedEventNotifierTests.cs index da034a6e3d..1f7585a4ef 100644 --- a/VideoWeb/VideoWeb.UnitTests/Helpers/HearingDetailsUpdatedEventNotifierTests.cs +++ b/VideoWeb/VideoWeb.UnitTests/Helpers/HearingDetailsUpdatedEventNotifierTests.cs @@ -6,6 +6,7 @@ using Moq; using NUnit.Framework; using VideoWeb.Common.Models; +using VideoWeb.Contract.Responses; using VideoWeb.EventHub.Hub; using VideoWeb.Helpers; using VideoWeb.UnitTests.Builders; @@ -40,7 +41,8 @@ public async Task should_publish_message() // Assert const int vhoCount = 1; const int staffMemberCount = 1; - _eventHelper.EventHubClientMock.Verify(x => x.HearingDetailsUpdatedMessage(_conference.Id), Times.Exactly(_conference.Participants.Count + vhoCount + staffMemberCount)); + var expectedMessageCount = _conference.Participants.Count + vhoCount + staffMemberCount; + VerifyHearingDetailsUpdatedMessagePublished(expectedMessageCount); } [Test] @@ -57,7 +59,7 @@ public async Task should_only_publish_one_message_to_staff_member_participants() const int nonParticipantStaffMemberCount = 1; // Non-participant staff member = a staff member who is not a participant on the conference var nonStaffMemberParticipantCount = _conference.Participants.Count(p => p.Role != Role.StaffMember); // Non-staff member participants = participants minus staff members var expectedMessageCount = nonParticipantStaffMemberCount + vhoCount + nonStaffMemberParticipantCount; - _eventHelper.EventHubClientMock.Verify(x => x.HearingDetailsUpdatedMessage(_conference.Id), Times.Exactly(expectedMessageCount)); + VerifyHearingDetailsUpdatedMessagePublished(expectedMessageCount); } private void AddParticipantToConference(Role role) @@ -70,5 +72,12 @@ private void AddParticipantToConference(Role role) _conference.Participants.Add(staffMemberParticipant); _eventHelper.RegisterParticipantForHubContext(staffMemberParticipant); } + + private void VerifyHearingDetailsUpdatedMessagePublished(int times) + { + _eventHelper.EventHubClientMock.Verify(x => x.HearingDetailsUpdatedMessage(It.Is(r => + r.Id == _conference.Id)), + Times.Exactly(times)); + } } } diff --git a/VideoWeb/VideoWeb/ClientApp/src/app/services/events.service.spec.ts b/VideoWeb/VideoWeb/ClientApp/src/app/services/events.service.spec.ts index fa901b8929..ac2d52051c 100644 --- a/VideoWeb/VideoWeb/ClientApp/src/app/services/events.service.spec.ts +++ b/VideoWeb/VideoWeb/ClientApp/src/app/services/events.service.spec.ts @@ -10,7 +10,7 @@ import { EventsHubService } from './events-hub.service'; import { Heartbeat } from '../shared/models/heartbeat'; import { TransferDirection } from './models/hearing-transfer'; import { ParticipantMediaStatus } from '../shared/models/participant-media-status'; -import { ParticipantResponse, VideoEndpointResponse } from './clients/api-client'; +import { ConferenceResponse, ParticipantResponse, VideoEndpointResponse } from './clients/api-client'; import { UpdateEndpointsDto } from '../shared/models/update-endpoints-dto'; import { createMockStore, MockStore } from '@ngrx/store/testing'; import { ConferenceState, initialState as initialConferenceState } from '../waiting-space/store/reducers/conference.reducer'; @@ -290,17 +290,19 @@ describe('EventsService', () => { }); it('should handle event', () => { - const conferenceId = 'TestConferenceId'; + const conference = new ConferenceResponse({ + id: 'TestConferenceId' + }); const hubConnectionSpy = jasmine.createSpyObj('HubConnection', ['on']); hubConnectionSpy.on.withArgs(jasmine.any(String), jasmine.any(Function)).and.callFake((eventType: string, func: any) => { if (eventType === eventName) { - func(conferenceId); + func(conference); } }); serviceUnderTest.getHearingDetailsUpdated().subscribe(message => { - expect(message.conferenceId).toBe(conferenceId); + expect(message.conference.id).toBe(conference.id); }); spyPropertyGetter(eventsHubServiceSpy, 'connection').and.returnValue(hubConnectionSpy); diff --git a/VideoWeb/VideoWeb/ClientApp/src/app/services/events.service.ts b/VideoWeb/VideoWeb/ClientApp/src/app/services/events.service.ts index ee8fd5c38e..bec4ed6e67 100644 --- a/VideoWeb/VideoWeb/ClientApp/src/app/services/events.service.ts +++ b/VideoWeb/VideoWeb/ClientApp/src/app/services/events.service.ts @@ -11,6 +11,7 @@ import { EndpointsUpdatedMessage } from '../shared/models/endpoints-updated-mess import { Room } from '../shared/models/room'; import { RoomTransfer } from '../shared/models/room-transfer'; import { + ConferenceResponse, ConferenceStatus, ConsultationAnswer, EndpointStatus, @@ -106,8 +107,8 @@ export class EventsService { this.newConferenceAddedSubject.next(message); }, - HearingDetailsUpdatedMessage: (conferenceId: string) => { - const message = new HearingDetailsUpdatedMessage(conferenceId); + HearingDetailsUpdatedMessage: (conference: ConferenceResponse) => { + const message = new HearingDetailsUpdatedMessage(conference); this.logger.debug('[EventsService] - HearingDetailsUpdatedMessage received', message); this.hearingDetailsUpdatedSubject.next(message); }, diff --git a/VideoWeb/VideoWeb/ClientApp/src/app/services/models/hearing-details-updated-message.ts b/VideoWeb/VideoWeb/ClientApp/src/app/services/models/hearing-details-updated-message.ts index 84515cc08e..ad68dad425 100644 --- a/VideoWeb/VideoWeb/ClientApp/src/app/services/models/hearing-details-updated-message.ts +++ b/VideoWeb/VideoWeb/ClientApp/src/app/services/models/hearing-details-updated-message.ts @@ -1,3 +1,5 @@ +import { ConferenceResponse } from '../clients/api-client'; + export class HearingDetailsUpdatedMessage { - constructor(public conferenceId: string) {} + constructor(public conference: ConferenceResponse) {} } diff --git a/VideoWeb/VideoWeb/ClientApp/src/app/waiting-space/waiting-room-shared/tests/waiting-room-base.component.eventhub-events.spec.ts b/VideoWeb/VideoWeb/ClientApp/src/app/waiting-space/waiting-room-shared/tests/waiting-room-base.component.eventhub-events.spec.ts index 6651d3fb04..3f9f0a4313 100644 --- a/VideoWeb/VideoWeb/ClientApp/src/app/waiting-space/waiting-room-shared/tests/waiting-room-base.component.eventhub-events.spec.ts +++ b/VideoWeb/VideoWeb/ClientApp/src/app/waiting-space/waiting-room-shared/tests/waiting-room-base.component.eventhub-events.spec.ts @@ -39,7 +39,8 @@ import { hearingLayoutChangedSubjectMock, getEndpointLinkedUpdatedMock, getEndpointUnlinkedUpdatedMock, - getEndpointDisconnectUpdatedMock + getEndpointDisconnectUpdatedMock, + getHearingDetailsUpdatedMock } from 'src/app/testing/mocks/mock-events-service'; import { clockService, @@ -94,6 +95,8 @@ import { EndpointRepMessage } from '../../../shared/models/endpoint-rep-message' import { provideMockStore } from '@ngrx/store/testing'; import { FEATURE_FLAGS, LaunchDarklyService } from 'src/app/services/launch-darkly.service'; import { of } from 'rxjs'; +import { HearingDetailsUpdatedMessage } from 'src/app/services/models/hearing-details-updated-message'; +import { videoWebServiceSpy } from 'src/app/vh-officer/vho-shared/tests/participant-status-base-setup'; describe('WaitingRoomComponent EventHub Call', () => { let fixture: ComponentFixture; @@ -1999,4 +2002,28 @@ describe('WaitingRoomComponent EventHub Call', () => { }); }); }); + + describe('getHearingDetailsUpdated', () => { + it('should update the conference', () => { + // Arrange + const newScheduledDateTime = new Date(globalConference.scheduled_date_time); + newScheduledDateTime.setHours(newScheduledDateTime.getHours() + 2); + const updatedConference = new ConferenceResponse({ + id: globalConference.id, + scheduled_date_time: newScheduledDateTime, + audio_recording_required: !globalConference.audio_recording_required + }); + updatedConference.audio_recording_required = !updatedConference.audio_recording_required; + + const hearingDetailsUpdatedMessage = new HearingDetailsUpdatedMessage(updatedConference); + + // Act + getHearingDetailsUpdatedMock.next(hearingDetailsUpdatedMessage); + + // Assert + expect(component.conference.id).toBe(updatedConference.id); + expect(component.conference.scheduled_date_time).toBe(updatedConference.scheduled_date_time); + expect(component.conference.audio_recording_required).toBe(updatedConference.audio_recording_required); + }); + }); }); diff --git a/VideoWeb/VideoWeb/ClientApp/src/app/waiting-space/waiting-room-shared/waiting-room-base.component.ts b/VideoWeb/VideoWeb/ClientApp/src/app/waiting-space/waiting-room-shared/waiting-room-base.component.ts index 28272d8236..452806eee6 100644 --- a/VideoWeb/VideoWeb/ClientApp/src/app/waiting-space/waiting-room-shared/waiting-room-base.component.ts +++ b/VideoWeb/VideoWeb/ClientApp/src/app/waiting-space/waiting-room-shared/waiting-room-base.component.ts @@ -277,12 +277,7 @@ export abstract class WaitingRoomBaseDirective implements AfterContentChecked { }); try { const data = await this.videoWebService.getConferenceById(this.conferenceId); - this.hearingVenueFlagsService.setHearingVenueIsScottish(data.hearing_venue_is_scottish); - this.errorCount = 0; - this.loadingData = false; - this.countdownComplete = data.status === ConferenceStatus.InSession; - this.hearing = new Hearing(data); - this.conference = this.hearing.getConference(); + this.setConference(data); this.videoWebService.getAllowedEndpointsForConference(this.conferenceId).then((endpoints: AllowedEndpointResponse[]) => { this.participantEndpoints = endpoints; }); @@ -616,6 +611,16 @@ export abstract class WaitingRoomBaseDirective implements AfterContentChecked { this.handleHearingLayoutUpdatedMessage(hearingLayout); }) ); + + this.logger.debug('[WR] - Subscribing to hearing details updated message'); + this.eventHubSubscription$.add( + this.eventService.getHearingDetailsUpdated().subscribe(hearingDetailsUpdatedMessage => { + hearingDetailsUpdatedMessage.conference.scheduled_date_time = new Date( + hearingDetailsUpdatedMessage.conference.scheduled_date_time + ); + this.setConference(hearingDetailsUpdatedMessage.conference); + }) + ); } resolveParticipant(participantId: any): Participant { @@ -1475,4 +1480,13 @@ export abstract class WaitingRoomBaseDirective implements AfterContentChecked { this.logger.debug('[WR] - Hearing Layout Changed showing notification', participant); this.notificationToastrService.showHearingLayoutchanged(participant, this.isParticipantInConference); } + + private setConference(conferenceResponse: ConferenceResponse) { + this.hearingVenueFlagsService.setHearingVenueIsScottish(conferenceResponse.hearing_venue_is_scottish); + this.errorCount = 0; + this.loadingData = false; + this.countdownComplete = conferenceResponse.status === ConferenceStatus.InSession; + this.hearing = new Hearing(conferenceResponse); + this.conference = this.hearing.getConference(); + } } diff --git a/VideoWeb/VideoWeb/Helpers/HearingDetailsUpdatedEventNotifier.cs b/VideoWeb/VideoWeb/Helpers/HearingDetailsUpdatedEventNotifier.cs index 52fd8fcc89..a988a37b59 100644 --- a/VideoWeb/VideoWeb/Helpers/HearingDetailsUpdatedEventNotifier.cs +++ b/VideoWeb/VideoWeb/Helpers/HearingDetailsUpdatedEventNotifier.cs @@ -4,6 +4,7 @@ using VideoWeb.Common.Models; using VideoWeb.EventHub.Hub; using VideoWeb.Helpers.Interfaces; +using VideoWeb.Mappings; using Hub = VideoWeb.EventHub.Hub; namespace VideoWeb.Helpers @@ -13,17 +14,19 @@ public class HearingDetailsUpdatedEventNotifier(IHubContext participant.Role != Role.StaffMember)) { await hubContext.Clients.Group(participant.Username.ToLowerInvariant()) - .HearingDetailsUpdatedMessage(conference.Id); + .HearingDetailsUpdatedMessage(conferenceResponse); } await hubContext.Clients.Group(Hub.EventHub.VhOfficersGroupName) - .HearingDetailsUpdatedMessage(conference.Id); + .HearingDetailsUpdatedMessage(conferenceResponse); await hubContext.Clients.Group(Hub.EventHub.StaffMembersGroupName) - .HearingDetailsUpdatedMessage(conference.Id); + .HearingDetailsUpdatedMessage(conferenceResponse); } } }