Skip to content

Commit

Permalink
VIH-10260 Support audio recording search with old and new file names (#…
Browse files Browse the repository at this point in the history
…1298)

* added manage new audio file format

* added test

* test fix

* Update AudioPlatformController.cs

* Update FeatureToggles.cs

* resolving sonar clou vulnerability

* added new feature toggle and guard to hide get audio file

* test fix

* update package

* update package

* lint fix
  • Loading branch information
marcogagliardi authored Nov 23, 2023
1 parent 1cdb598 commit 87e2167
Show file tree
Hide file tree
Showing 16 changed files with 225 additions and 34 deletions.
6 changes: 3 additions & 3 deletions AdminWebsite/AdminWebsite.IntegrationTests/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -2091,8 +2091,8 @@
},
"VideoApi.Client": {
"type": "Transitive",
"resolved": "1.44.3",
"contentHash": "DeifqS/Lbgy2GhMbZNPZwYB47zwp/rIlHK65J7gE7zLX/l+anfbz8FhyufM9AfjDTcDCEzMlu6XYmp+eDyTYJA==",
"resolved": "1.49.4",
"contentHash": "THMXshzCq8bHCsoU+p79Vmoyh0XoIfFkd13VFve8dzZC/wgE9Z6XmNSRt7SahDgkIlAhOucQVv2TE8avp869MQ==",
"dependencies": {
"Microsoft.AspNetCore.Mvc.Core": "2.2.5"
}
Expand Down Expand Up @@ -2125,7 +2125,7 @@
"TimeZoneConverter": "[6.0.1, )",
"UserApi.Client": "[1.44.2, )",
"VH.Core.Configuration": "[0.1.13, )",
"VideoApi.Client": "[1.44.3, )"
"VideoApi.Client": "[1.49.4, )"
}
},
"adminwebsite.testing.common": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="VideoApi.Client" Version="1.44.3" />
<PackageReference Include="VideoApi.Client" Version="1.49.4" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AdminWebsite.Configuration;
using AdminWebsite.Controllers;
using AdminWebsite.Models;
using BookingsApi.Client;
using BookingsApi.Contract.V2.Responses;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -19,12 +22,19 @@ public class AudioPlatformControllerTests
private readonly Mock<IVideoApiClient> _videoApiClientMock;

private readonly AudioPlatformController _controller;

private readonly Mock<IBookingsApiClient> _bookingsApiClientMock;
private readonly Mock<ILogger<AudioPlatformController>> _loggerMock;
private readonly Mock<IFeatureToggles> _featureTogglesMock;

public AudioPlatformControllerTests()
{
_videoApiClientMock = new Mock<IVideoApiClient>();
_bookingsApiClientMock = new Mock<IBookingsApiClient>();
_loggerMock = new Mock<ILogger<AudioPlatformController>>();
_featureTogglesMock = new Mock<IFeatureToggles>();

_controller = new AudioPlatformController(_videoApiClientMock.Object, new Mock<ILogger<AudioPlatformController>>().Object);
_controller = new AudioPlatformController(_videoApiClientMock.Object, _loggerMock.Object, _bookingsApiClientMock.Object, _featureTogglesMock.Object);
}

[Test]
Expand All @@ -35,7 +45,40 @@ public async Task Should_return_ok()
AudioFileLinks = new List<string> { "someLinkToFile" }
};

_videoApiClientMock.Setup(x => x.GetAudioRecordingLinkAsync(It.IsAny<Guid>())).ReturnsAsync(audioResponse);
_videoApiClientMock.Setup(x => x.GetAudioRecordingLinkAsync(It.IsAny<string>())).ReturnsAsync(audioResponse);
_featureTogglesMock.Setup(x => x.HrsEnabled()).Returns(false);

var result = await _controller.GetAudioRecordingLinkAsync(It.IsAny<Guid>());

var actionResult = result as OkObjectResult;
actionResult.Should().NotBeNull();
actionResult.StatusCode.Should().Be(200);
var item = actionResult.Value.As<HearingAudioRecordingResponse>();
item.Should().NotBeNull()
.And.Subject.As<HearingAudioRecordingResponse>().AudioFileLinks.Count.Should().Be(1);
item.AudioFileLinks[0].Should().Be(audioResponse.AudioFileLinks[0]);
}

[Test]
public async Task Should_return_hrs_file_format_with_hrs_toggle_on()
{
var audioResponse = new AudioRecordingResponse
{
AudioFileLinks = new List<string> { "someLinkToFile" }
};

var hearing = new HearingDetailsResponseV2()
{
ServiceId = "AAA",
Cases = new List<CaseResponseV2>
{
new CaseResponseV2() {Number = "Case Number"}
}
};

_videoApiClientMock.Setup(x => x.GetAudioRecordingLinkAsync(It.IsAny<string>())).ReturnsAsync(audioResponse);
_featureTogglesMock.Setup(x => x.HrsEnabled()).Returns(true);
_bookingsApiClientMock.Setup(x => x.GetHearingDetailsByIdV2Async(It.IsAny<Guid>())).ReturnsAsync(hearing);

var result = await _controller.GetAudioRecordingLinkAsync(It.IsAny<Guid>());

Expand All @@ -52,7 +95,7 @@ public async Task Should_return_ok()
public async Task Should_return_not_found()
{
_videoApiClientMock
.Setup(x => x.GetAudioRecordingLinkAsync(It.IsAny<Guid>()))
.Setup(x => x.GetAudioRecordingLinkAsync(It.IsAny<string>()))
.ThrowsAsync(new VideoApiException("not found", StatusCodes.Status404NotFound, "", null, null));

var result = await _controller.GetAudioRecordingLinkAsync(It.IsAny<Guid>());
Expand Down
8 changes: 4 additions & 4 deletions AdminWebsite/AdminWebsite.UnitTests/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@
},
"VideoApi.Client": {
"type": "Direct",
"requested": "[1.44.3, )",
"resolved": "1.44.3",
"contentHash": "DeifqS/Lbgy2GhMbZNPZwYB47zwp/rIlHK65J7gE7zLX/l+anfbz8FhyufM9AfjDTcDCEzMlu6XYmp+eDyTYJA==",
"requested": "[1.49.4, )",
"resolved": "1.49.4",
"contentHash": "THMXshzCq8bHCsoU+p79Vmoyh0XoIfFkd13VFve8dzZC/wgE9Z6XmNSRt7SahDgkIlAhOucQVv2TE8avp869MQ==",
"dependencies": {
"Microsoft.AspNetCore.Mvc.Core": "2.2.5"
}
Expand Down Expand Up @@ -2003,7 +2003,7 @@
"TimeZoneConverter": "[6.0.1, )",
"UserApi.Client": "[1.44.2, )",
"VH.Core.Configuration": "[0.1.13, )",
"VideoApi.Client": "[1.44.3, )"
"VideoApi.Client": "[1.49.4, )"
}
},
"adminwebsite.testing.common": {
Expand Down
2 changes: 1 addition & 1 deletion AdminWebsite/AdminWebsite/AdminWebsite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
<PackageReference Include="TimeZoneConverter" Version="6.0.1" />
<PackageReference Include="UserApi.Client" Version="1.44.2" />
<PackageReference Include="VH.Core.Configuration" Version="0.1.13" />
<PackageReference Include="VideoApi.Client" Version="1.44.3" />
<PackageReference Include="VideoApi.Client" Version="1.49.4" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { WorkAllocationFeatureGuard } from './security/work-allocation-feature.g
import { HomeComponent } from './home/home.component';
import { AuthGuard } from './security/auth.guard';
import { ManageTeamFeatureGuard } from './security/manage-team-feature.guard';
import { AudioSearchGuard } from './security/audio-search.guard';

export const routes: Routes = [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
Expand All @@ -28,7 +29,7 @@ export const routes: Routes = [
{ path: 'error', component: ErrorComponent },
{ path: 'unsupported-browser', component: UnsupportedBrowserComponent },
{ path: 'change-password', component: ChangePasswordComponent, canActivate: [AuthGuard, AdminGuard] },
{ path: 'get-audio-file', component: GetAudioFileComponent, canActivate: [AuthGuard, AdminGuard] },
{ path: 'get-audio-file', component: GetAudioFileComponent, canActivate: [AuthGuard, AdminGuard, AudioSearchGuard] },
{ path: 'delete-participant', component: DeleteParticipantSearchComponent, canActivate: [AuthGuard, AdminGuard] },
{ path: 'edit-participant-search', component: EditParticipantSearchComponent, canActivate: [AuthGuard, AdminGuard] },
{ path: 'edit-participant', component: EditParticipantComponent, canActivate: [AuthGuard, AdminGuard] },
Expand Down
4 changes: 3 additions & 1 deletion AdminWebsite/AdminWebsite/ClientApp/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { UnallocatedHearingsComponent } from './dashboard/unallocated-hearings/unallocated-hearings.component';
import { HomeComponent } from './home/home.component';
import { ManageTeamFeatureGuard } from './security/manage-team-feature.guard';
import { AudioSearchGuard } from './security/audio-search.guard';

export function loadConfig(configService: ConfigService) {
return () => configService.loadConfig();
Expand Down Expand Up @@ -99,7 +100,8 @@ export function loadConfig(configService: ConfigService) {
AppInsightsLogger,
WindowRef,
WorkAllocationFeatureGuard,
ManageTeamFeatureGuard
ManageTeamFeatureGuard,
AudioSearchGuard
],
exports: [UnallocatedHearingsComponent],
bootstrap: [AppComponent]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('DashboardComponent', () => {

beforeEach(waitForAsync(() => {
launchDarklyServiceSpy.getFlag.withArgs(FeatureFlags.vhoWorkAllocation).and.returnValue(of(true));
launchDarklyServiceSpy.getFlag.withArgs(FeatureFlags.hrsIntegration).and.returnValue(of(false));
launchDarklyServiceSpy.getFlag.withArgs(FeatureFlags.audioSearch).and.returnValue(of(false));
launchDarklyServiceSpy.getFlag.withArgs(FeatureFlags.dom1Integration).and.returnValue(of(false));

TestBed.configureTestingModule({
Expand Down Expand Up @@ -191,7 +191,7 @@ describe('DashboardComponent', () => {
)
);

launchDarklyServiceSpy.getFlag.withArgs(FeatureFlags.hrsIntegration).and.returnValue(of(true));
launchDarklyServiceSpy.getFlag.withArgs(FeatureFlags.audioSearch).and.returnValue(of(true));
await component.ngOnInit();
expect(component.showAudioFileLink).toBeFalsy();
});
Expand All @@ -205,7 +205,7 @@ describe('DashboardComponent', () => {
)
);

launchDarklyServiceSpy.getFlag.withArgs(FeatureFlags.hrsIntegration).and.returnValue(of(false));
launchDarklyServiceSpy.getFlag.withArgs(FeatureFlags.audioSearch).and.returnValue(of(false));
await component.ngOnInit();
expect(component.showAudioFileLink).toBeTruthy();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
showWorkAllocation = false;
vhoWorkAllocationFeature = false;
dom1Feature = false;
hrsIntegrationFeature: boolean;
audioSearchFeature: boolean;

showManageTeam = false;
showAudioFileLink = false;
Expand All @@ -37,18 +37,19 @@ export class DashboardComponent implements OnInit, OnDestroy {
const workAllocationFlag$ = this.launchDarklyService
.getFlag<boolean>(FeatureFlags.vhoWorkAllocation)
.pipe(takeUntil(this.destroyed$));
const hrsIntegrationFlag$ = this.launchDarklyService.getFlag<boolean>(FeatureFlags.hrsIntegration).pipe(takeUntil(this.destroyed$));
const audioSearchFlag$ = this.launchDarklyService.getFlag<boolean>(FeatureFlags.audioSearch).pipe(takeUntil(this.destroyed$));
const dom1FeatureFlag$ = this.launchDarklyService.getFlag<boolean>(FeatureFlags.dom1Integration).pipe(takeUntil(this.destroyed$));

combineLatest([workAllocationFlag$, hrsIntegrationFlag$, dom1FeatureFlag$]).subscribe(
([workAllocationFlag, hrsIntegrationFlag, dom1FeatureFlag]) => {
combineLatest([workAllocationFlag$, audioSearchFlag$, dom1FeatureFlag$]).subscribe(
([workAllocationFlag, audioSearchFlag, dom1FeatureFlag]) => {
this.vhoWorkAllocationFeature = workAllocationFlag;
this.hrsIntegrationFeature = hrsIntegrationFlag;
this.audioSearchFeature = audioSearchFlag;
console.log('################### ' + audioSearchFlag);
this.dom1Feature = dom1FeatureFlag;
lastValueFrom(this.userIdentityService.getUserInformation()).then(profile => {
this.showCheckList = profile.is_vh_officer_administrator_role;
this.showWorkAllocation = profile.is_vh_team_leader && this.vhoWorkAllocationFeature;
this.showAudioFileLink = this.showCheckList && !this.hrsIntegrationFeature;
this.showAudioFileLink = this.showCheckList && !this.audioSearchFeature;
this.showBooking = profile.is_case_administrator || profile.is_vh_officer_administrator_role;
this.showManageTeam = profile.is_vh_team_leader && this.dom1Feature;
this.logger.debug(`${this.loggerPrefix} Landed on dashboard`, {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { fakeAsync, TestBed } from '@angular/core/testing';
import { AuthGuard } from './auth.guard';
import { Router } from '@angular/router';
import { MockOidcSecurityService } from '../testing/mocks/MockOidcSecurityService';
import { OidcSecurityService } from 'angular-auth-oidc-client';
import { Logger } from '../services/logger';
import { AudioSearchGuard } from './audio-search.guard';
import { LaunchDarklyService } from '../services/launch-darkly.service';
import { MockLaunchDarklyService } from '../testing/mocks/MockLaunchDarklyService';

describe('audiosearchguard', () => {
let audioSearchGuard: AudioSearchGuard;
let launchDarklyService;
const loggerSpy = jasmine.createSpyObj<Logger>('Logger', ['error', 'debug', 'warn']);
const router = {
navigate: jasmine.createSpy('navigate')
};

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
AudioSearchGuard,
{ provide: LaunchDarklyService, useClass: MockLaunchDarklyService },
{ provide: Router, useValue: router },
{ provide: Logger, useValue: loggerSpy }
]
}).compileComponents();
launchDarklyService = TestBed.inject(LaunchDarklyService);
audioSearchGuard = TestBed.inject(AudioSearchGuard);
});

describe('when toggle off with successful authentication', () => {
it('canActivate should return true', () => {
launchDarklyService.setAudioSearchFlag(false);
audioSearchGuard.canActivate().subscribe(result => expect(result).toBeTruthy());
});
});

describe('when toggle is on with successful authentication', () => {
it('canActivate should return false', fakeAsync(() => {
launchDarklyService.setAudioSearchFlag(true);
audioSearchGuard.canActivate().subscribe(result => expect(result).toBeFalsy());
}));
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthenticatedResult, OidcSecurityService } from 'angular-auth-oidc-client';
import { Observable, takeUntil } from 'rxjs';
import { map } from 'rxjs/operators';
import { PageUrls } from '../shared/page-url.constants';
import { Logger } from '../services/logger';
import { FeatureFlags, LaunchDarklyService } from '../services/launch-darkly.service';

@Injectable()
export class AudioSearchGuard implements CanActivate {
private readonly loggerPrefix = '[AudioSearchGuard] -';
constructor(private launchDarklyService: LaunchDarklyService, private router: Router, private logger: Logger) {}

canActivate(): Observable<boolean> {
return this.launchDarklyService.getFlag<boolean>(FeatureFlags.audioSearch).pipe(
map(result => {
if (result) {
this.logger.warn(`${this.loggerPrefix} - canActivate isAuthorized: ` + !result);
this.router.navigate([`/${PageUrls.Login}`]);
return false;
}
this.logger.debug(`${this.loggerPrefix} - canActivate isAuthorized: ` + !result);
return true;
})
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const FeatureFlags = {
dom1Integration: 'dom1',
hrsIntegration: 'hrs-integration',
referenceData: 'reference-data',
audioSearch: 'hide-audio-search-tile',
useV2Api: 'use-bookings-api-v2'
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { OpenIdConfiguration, LoginResponse, AuthenticatedResult, ConfigAuthenticatedResult } from 'angular-auth-oidc-client';
import { LDFlagValue } from 'launchdarkly-js-client-sdk';
import { Observable, of } from 'rxjs';

class MockLoginResponse implements LoginResponse {
constructor(isAuthenticated: boolean) {
this.isAuthenticated = isAuthenticated;
}

isAuthenticated: boolean;
userData: any;
accessToken: string;
idToken: string;
configId: string;
errorMessage?: string;
}
export class MockLaunchDarklyService {
audioSearchFlag: boolean;

setAudioSearchFlag(flag: boolean) {
this.audioSearchFlag = flag;
}
getFlag<T>(flagKey: string, defaultValue: LDFlagValue = false): Observable<T> {
return of(this.audioSearchFlag as T);
}
}
15 changes: 15 additions & 0 deletions AdminWebsite/AdminWebsite/Configuration/FeatureToggles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public interface IFeatureToggles
public bool ReferenceDataToggle();
public bool UseV2Api();
public bool EJudEnabled();
public bool HrsEnabled();
public bool AudioSearchEnabled();
}

public class FeatureToggles : IFeatureToggles
Expand All @@ -25,6 +27,9 @@ public class FeatureToggles : IFeatureToggles
private const string ReferenceDataToggleKey = "reference-data";
private const string UseV2ApiToggleKey = "use-bookings-api-v2";
private const string EJudFeatureToggleKey = "ejud-feature";
private const string HrsFeatureToggleKey = "hrs-integration";
private const string AudioSearchToggleKey = "hide-audio-search-tile";


public FeatureToggles(string sdkKey, string environmentName)
{
Expand Down Expand Up @@ -53,6 +58,16 @@ public bool EJudEnabled()
{
return GetBoolValueWithKey(EJudFeatureToggleKey);
}

public bool HrsEnabled()
{
return GetBoolValueWithKey(HrsFeatureToggleKey);
}

public bool AudioSearchEnabled()
{
return GetBoolValueWithKey(AudioSearchToggleKey);
}

public bool UseV2Api()
{
Expand Down
Loading

0 comments on commit 87e2167

Please sign in to comment.