@@ -30,6 +30,7 @@ public class with_the_chat_channel_service : TestBase
3030 protected Mock < IDepartmentGroupsService > _departmentGroupsServiceMock ;
3131 protected Mock < IUnitsService > _unitsServiceMock ;
3232 protected Mock < IUserProfileService > _userProfileServiceMock ;
33+ protected Mock < ICallsService > _callsServiceMock ;
3334 protected Mock < IEventAggregator > _eventAggregatorMock ;
3435 protected Mock < ICacheProvider > _cacheProviderMock ;
3536 protected Mock < IUnitOfWork > _unitOfWorkMock ;
@@ -57,6 +58,7 @@ private void BuildService()
5758 _departmentGroupsServiceMock = new Mock < IDepartmentGroupsService > ( ) ;
5859 _unitsServiceMock = new Mock < IUnitsService > ( ) ;
5960 _userProfileServiceMock = new Mock < IUserProfileService > ( ) ;
61+ _callsServiceMock = new Mock < ICallsService > ( ) ;
6062 _eventAggregatorMock = new Mock < IEventAggregator > ( ) ;
6163 _cacheProviderMock = new Mock < ICacheProvider > ( ) ;
6264 _unitOfWorkMock = new Mock < IUnitOfWork > ( ) ;
@@ -93,6 +95,7 @@ private void BuildService()
9395 _departmentGroupsServiceMock . Object ,
9496 _unitsServiceMock . Object ,
9597 _userProfileServiceMock . Object ,
98+ _callsServiceMock . Object ,
9699 _eventAggregatorMock . Object ,
97100 _cacheProviderMock . Object ,
98101 _unitOfWorkMock . Object ) ;
@@ -667,6 +670,134 @@ public async Task without_an_active_unit_no_unit_membership_lookup_happens()
667670
668671 _chatChannelMemberRepositoryMock . Verify ( x => x . GetActiveByUnitIdAsync ( It . IsAny < int > ( ) , It . IsAny < int > ( ) ) , Times . Never ) ;
669672 }
673+
674+ [ Test ]
675+ public async Task an_active_unit_should_get_its_dispatch_line_provisioned_into_the_list ( )
676+ {
677+ SetupDepartmentChannel ( ) ;
678+ _chatPermissionServiceMock . Setup ( x => x . IsDepartmentAdminAsync ( 1 , "user-a" ) ) . ReturnsAsync ( false ) ;
679+ _chatPermissionServiceMock . Setup ( x => x . CanSendAsUnitAsync ( "user-a" , 7 , 1 ) ) . ReturnsAsync ( true ) ;
680+ _unitsServiceMock . Setup ( x => x . GetUnitByIdAsync ( 7 ) ) . ReturnsAsync ( new Unit { UnitId = 7 , DepartmentId = 1 , Name = "Engine 6" } ) ;
681+ _chatChannelRepositoryMock . Setup ( x => x . GetByDmKeyAsync ( 1 , "unitdispatch:7" ) ) . ReturnsAsync ( ( ChatChannel ) null ) ;
682+
683+ var result = await _chatChannelService . GetChannelsForUserAsync ( 1 , "user-a" , 7 ) ;
684+
685+ result . Should ( ) . Contain ( c => c . ChannelType == ( int ) ChatChannelType . UnitDispatch && c . Name == "Engine 6 Dispatch" ) ;
686+ }
687+
688+ [ Test ]
689+ public async Task a_unit_dispatch_provisioning_failure_should_not_abort_the_channel_list ( )
690+ {
691+ SetupDepartmentChannel ( ) ;
692+ _chatPermissionServiceMock . Setup ( x => x . IsDepartmentAdminAsync ( 1 , "user-a" ) ) . ReturnsAsync ( false ) ;
693+ _chatPermissionServiceMock . Setup ( x => x . CanSendAsUnitAsync ( "user-a" , 7 , 1 ) ) . ReturnsAsync ( true ) ;
694+ _unitsServiceMock . Setup ( x => x . GetUnitByIdAsync ( 7 ) ) . ThrowsAsync ( new InvalidOperationException ( "units down" ) ) ;
695+
696+ var result = await _chatChannelService . GetChannelsForUserAsync ( 1 , "user-a" , 7 ) ;
697+
698+ result . Should ( ) . Contain ( c => c . ChannelType == ( int ) ChatChannelType . DepartmentDefault ) ;
699+ }
700+
701+ [ Test ]
702+ public async Task incident_leads_and_dispatch_channels_should_be_listed_for_users_with_access ( )
703+ {
704+ SetupDepartmentChannel ( ) ;
705+ _chatPermissionServiceMock . Setup ( x => x . IsDepartmentAdminAsync ( 1 , "user-a" ) ) . ReturnsAsync ( false ) ;
706+
707+ var leads = new ChatChannel { ChatChannelId = "leads-1" , DepartmentId = 1 , ChannelType = ( int ) ChatChannelType . IncidentLeads , CallId = 42 , Name = "Barn Fire All Leads" } ;
708+ var dispatch = new ChatChannel { ChatChannelId = "dispatch-1" , DepartmentId = 1 , ChannelType = ( int ) ChatChannelType . IncidentDispatch , CallId = 42 , Name = "Barn Fire Dispatch" } ;
709+ var unitDispatch = new ChatChannel { ChatChannelId = "unit-dispatch-7" , DepartmentId = 1 , ChannelType = ( int ) ChatChannelType . UnitDispatch , DmKey = "unitdispatch:7" , Name = "Engine 6 Dispatch" } ;
710+ _chatChannelRepositoryMock . Setup ( x => x . GetAllByDepartmentIdAsync ( 1 , false ) ) . ReturnsAsync ( new List < ChatChannel > { leads , dispatch , unitDispatch } ) ;
711+
712+ _chatPermissionServiceMock . Setup ( x => x . CanAccessChannelAsync ( leads , "user-a" , null ) ) . ReturnsAsync ( true ) ;
713+ _chatPermissionServiceMock . Setup ( x => x . CanAccessChannelAsync ( dispatch , "user-a" , null ) ) . ReturnsAsync ( true ) ;
714+ _chatPermissionServiceMock . Setup ( x => x . CanAccessChannelAsync ( unitDispatch , "user-a" , null ) ) . ReturnsAsync ( true ) ;
715+
716+ var result = await _chatChannelService . GetChannelsForUserAsync ( 1 , "user-a" , null ) ;
717+
718+ result . Should ( ) . Contain ( c => c . ChatChannelId == "leads-1" ) ;
719+ result . Should ( ) . Contain ( c => c . ChatChannelId == "dispatch-1" ) ;
720+ result . Should ( ) . Contain ( c => c . ChatChannelId == "unit-dispatch-7" ) ;
721+ }
722+
723+ [ Test ]
724+ public async Task incident_leads_and_dispatch_channels_should_stay_hidden_without_access ( )
725+ {
726+ SetupDepartmentChannel ( ) ;
727+ _chatPermissionServiceMock . Setup ( x => x . IsDepartmentAdminAsync ( 1 , "user-a" ) ) . ReturnsAsync ( false ) ;
728+
729+ var leads = new ChatChannel { ChatChannelId = "leads-1" , DepartmentId = 1 , ChannelType = ( int ) ChatChannelType . IncidentLeads , CallId = 42 } ;
730+ var unitDispatch = new ChatChannel { ChatChannelId = "unit-dispatch-7" , DepartmentId = 1 , ChannelType = ( int ) ChatChannelType . UnitDispatch , DmKey = "unitdispatch:7" } ;
731+ _chatChannelRepositoryMock . Setup ( x => x . GetAllByDepartmentIdAsync ( 1 , false ) ) . ReturnsAsync ( new List < ChatChannel > { leads , unitDispatch } ) ;
732+
733+ var result = await _chatChannelService . GetChannelsForUserAsync ( 1 , "user-a" , null ) ;
734+
735+ result . Should ( ) . NotContain ( c => c . ChatChannelId == "leads-1" ) ;
736+ result . Should ( ) . NotContain ( c => c . ChatChannelId == "unit-dispatch-7" ) ;
737+ }
738+ }
739+
740+ [ TestFixture ]
741+ public class when_ensuring_unit_dispatch_channels : with_the_chat_channel_service
742+ {
743+ [ Test ]
744+ public async Task a_missing_channel_should_be_created_with_the_unit_as_the_member ( )
745+ {
746+ _unitsServiceMock . Setup ( x => x . GetUnitByIdAsync ( 7 ) ) . ReturnsAsync ( new Unit { UnitId = 7 , DepartmentId = 1 , Name = "Engine 6" } ) ;
747+ _chatChannelRepositoryMock . Setup ( x => x . GetByDmKeyAsync ( 1 , "unitdispatch:7" ) ) . ReturnsAsync ( ( ChatChannel ) null ) ;
748+
749+ List < ChatChannelMember > capturedMembers = null ;
750+ _chatChannelRepositoryMock
751+ . Setup ( x => x . CreateDirectMessageChannelAsync ( It . IsAny < ChatChannel > ( ) , It . IsAny < IEnumerable < ChatChannelMember > > ( ) , It . IsAny < CancellationToken > ( ) ) )
752+ . Callback ( ( ChatChannel c , IEnumerable < ChatChannelMember > m , CancellationToken t ) => capturedMembers = m . ToList ( ) )
753+ . ReturnsAsync ( ( ChatChannel c , IEnumerable < ChatChannelMember > m , CancellationToken t ) => c ) ;
754+
755+ var result = await _chatChannelService . EnsureUnitDispatchChannelAsync ( 1 , 7 ) ;
756+
757+ result . Should ( ) . NotBeNull ( ) ;
758+ result . ChannelType . Should ( ) . Be ( ( int ) ChatChannelType . UnitDispatch ) ;
759+ result . Name . Should ( ) . Be ( "Engine 6 Dispatch" ) ;
760+ result . DmKey . Should ( ) . Be ( "unitdispatch:7" ) ;
761+ capturedMembers . Should ( ) . ContainSingle ( m => m . ParticipantType == ( int ) ChatParticipantType . Unit && m . UnitId == 7 ) ;
762+ }
763+
764+ [ Test ]
765+ public async Task an_existing_channel_should_be_returned_without_creating_another ( )
766+ {
767+ var existing = new ChatChannel { ChatChannelId = "ud-7" , DepartmentId = 1 , ChannelType = ( int ) ChatChannelType . UnitDispatch , DmKey = "unitdispatch:7" , Name = "Engine 6 Dispatch" } ;
768+ _unitsServiceMock . Setup ( x => x . GetUnitByIdAsync ( 7 ) ) . ReturnsAsync ( new Unit { UnitId = 7 , DepartmentId = 1 , Name = "Engine 6" } ) ;
769+ _chatChannelRepositoryMock . Setup ( x => x . GetByDmKeyAsync ( 1 , "unitdispatch:7" ) ) . ReturnsAsync ( existing ) ;
770+
771+ var result = await _chatChannelService . EnsureUnitDispatchChannelAsync ( 1 , 7 ) ;
772+
773+ result . Should ( ) . BeSameAs ( existing ) ;
774+ _chatChannelRepositoryMock . Verify ( x => x . CreateDirectMessageChannelAsync ( It . IsAny < ChatChannel > ( ) , It . IsAny < IEnumerable < ChatChannelMember > > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Never ) ;
775+ _chatChannelRepositoryMock . Verify ( x => x . UpdateChannelInfoAsync ( It . IsAny < string > ( ) , It . IsAny < string > ( ) , It . IsAny < string > ( ) , It . IsAny < DateTime > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Never ) ;
776+ }
777+
778+ [ Test ]
779+ public async Task a_renamed_unit_should_refresh_the_channel_name ( )
780+ {
781+ var existing = new ChatChannel { ChatChannelId = "ud-7" , DepartmentId = 1 , ChannelType = ( int ) ChatChannelType . UnitDispatch , DmKey = "unitdispatch:7" , Name = "Engine 6 Dispatch" } ;
782+ _unitsServiceMock . Setup ( x => x . GetUnitByIdAsync ( 7 ) ) . ReturnsAsync ( new Unit { UnitId = 7 , DepartmentId = 1 , Name = "Rescue 1" } ) ;
783+ _chatChannelRepositoryMock . Setup ( x => x . GetByDmKeyAsync ( 1 , "unitdispatch:7" ) ) . ReturnsAsync ( existing ) ;
784+
785+ var result = await _chatChannelService . EnsureUnitDispatchChannelAsync ( 1 , 7 ) ;
786+
787+ result . Name . Should ( ) . Be ( "Rescue 1 Dispatch" ) ;
788+ _chatChannelRepositoryMock . Verify ( x => x . UpdateChannelInfoAsync ( "ud-7" , "Rescue 1 Dispatch" , It . IsAny < string > ( ) , It . IsAny < DateTime > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Once ) ;
789+ }
790+
791+ [ Test ]
792+ public async Task a_unit_from_another_department_should_not_get_a_channel ( )
793+ {
794+ _unitsServiceMock . Setup ( x => x . GetUnitByIdAsync ( 7 ) ) . ReturnsAsync ( new Unit { UnitId = 7 , DepartmentId = 2 , Name = "Engine 6" } ) ;
795+
796+ var result = await _chatChannelService . EnsureUnitDispatchChannelAsync ( 1 , 7 ) ;
797+
798+ result . Should ( ) . BeNull ( ) ;
799+ _chatChannelRepositoryMock . Verify ( x => x . CreateDirectMessageChannelAsync ( It . IsAny < ChatChannel > ( ) , It . IsAny < IEnumerable < ChatChannelMember > > ( ) , It . IsAny < CancellationToken > ( ) ) , Times . Never ) ;
800+ }
670801 }
671802
672803 [ TestFixture ]
0 commit comments