Skip to content

Commit

Permalink
Add readCookieService and language information to client context (#1780)
Browse files Browse the repository at this point in the history
* Add readCookieService and language information to client context

* Add version

* Add additional language setting on clientcontext

Event guard also sets it

* Make sonar advised change

* Add sonar suggested change

* Update npmpublish.yml

* Add change to make client context always appear with language

* version updated

* release notes updated

* version updated

* version updated

---------

Co-authored-by: Ritesh Dsouza <[email protected]>
  • Loading branch information
connorpgpmcelroy and RiteshHMCTS authored Nov 28, 2024
1 parent c86360f commit e73c77b
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 65 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/npmpublish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
name: code-coverage-report
path: coverage
- name: Analyze with SonarCloud
uses: sonarsource/sonarcloud-github-action@v3.0.0
uses: sonarsource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Expand Down
3 changes: 3 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## RELEASE NOTES

### Version 7.0.75-exui-2315
**EXUI-2315** etrieve current user language selection

### Version 7.0.75-exui-2515
**EXUI-2515** case-link-issue

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
"version": "7.0.75-exui-2515",
"version": "7.0.75-exui-2315",
"engines": {
"node": ">=18.19.0"
},
Expand Down
2 changes: 1 addition & 1 deletion projects/ccd-case-ui-toolkit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hmcts/ccd-case-ui-toolkit",
"version": "7.0.75-exui-2515",
"version": "7.0.75-exui-2315",
"engines": {
"node": ">=18.19.0"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,59 +406,9 @@ export class CasesService {
}

private updateClientContextStorage(headers: HttpHeaders): void {
// for mocking - TODO: Kasi Remove/Uncomment for testing
// headers = this.setMockClientContextHeader(headers);
if (headers && headers.get('Client-Context')) {
const clientContextString = window.atob(headers.get('Client-Context'));
this.sessionStorageService.setItem('clientContext', clientContextString);
}
}

// for mocking - TODO: Kasi Remove/Uncomment for testing
/* private setMockClientContextHeader(headers: HttpHeaders): HttpHeaders {
const mockClientContext = { client_context: {
user_task: {
task_data: {
// Replace with relevant task id to complete other/current task
id: "2c7e03cc-18e8-11ef-bfd0-763319b21cea",
// Can edit other details to check they update
name: "Review the appeal - Test mocked",
assignee: "dfd4c2d1-67b1-40f9-8680-c9551632f5d9",
type: "reviewTheAppeal",
task_state: "assigned",
task_system: "SELF",
security_classification: "PUBLIC",
task_title: "Review the appeal",
created_date: "2024-05-23T09:38:12+0000",
due_date: "2024-05-28T09:39:00+0000",
location_name: "Taylor House",
location: "765324",
execution_type: "Case Management Task",
jurisdiction: "IA",
region: "1",
case_type_id: "Asylum",
case_id: "1716456926502698",
case_category: "Protection",
case_name: "Aipp Check",
auto_assigned: false,
warnings: false,
warning_list: { values: [] },
case_management_category: "Protection",
work_type_id: "decision_making_work",
work_type_label: "Decision-making work",
permissions: { values : ["Read","Own","Manage","Execute","Cancel","Complete","Claim","Assign","Unassign"] },
description: "[Request respondent evidence](/case/IA/Asylum/${[CASE_REFERENCE]}/trigger/requestRespondentEvidence)",
role_category: "LEGAL_OPERATIONS",
minor_priority: 500,
major_priority: 5000,
priority_date: "2024-05-28T09:39:00+0000"
},
// determines whether task will be completed - sets default to true via EXUI
complete_task: true
}
}};
const encodedMockedClientContext = window.btoa(JSON.stringify(mockClientContext));
headers = headers.set('Client-Context', encodedMockedClientContext);
return headers;
} */
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class PageValidationService {
page.case_fields
.filter(caseField => !this.caseFieldService.isReadOnly(caseField))
.filter(caseField => !this.isHidden(caseField, editForm))
.map(caseField => {
.forEach(caseField => {
const theControl = FieldsUtils.isCaseFieldOfType(caseField, ['JudicialUser'])
? editForm.controls['data'].get(`${caseField.id}_judicialUserControl`)
: editForm.controls['data'].get(caseField.id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ActivatedRouteSnapshot, Router } from '@angular/router';
import { of } from 'rxjs';
import { TaskPayload } from '../../../domain/work-allocation/TaskPayload';
import { UserInfo } from '../../../domain/user/user-info.model';
import { SessionStorageService } from '../../../services';
import { ReadCookieService, SessionStorageService } from '../../../services';
import { WorkAllocationService } from '../../case-editor';
import { EventStartGuard } from './event-start.guard';
import { AbstractAppConfig } from '../../../../app.config';
Expand All @@ -30,12 +30,14 @@ describe('EventStartGuard', () => {
let service: jasmine.SpyObj<WorkAllocationService>;
let router: jasmine.SpyObj<Router>;
let sessionStorageService: jasmine.SpyObj<SessionStorageService>;
let mockCookieService: jasmine.SpyObj<ReadCookieService>;
let mockAbstractConfig: jasmine.SpyObj<AbstractAppConfig>;

beforeEach(() => {
service = jasmine.createSpyObj('WorkAllocationService', ['getTasksByCaseIdAndEventId']);
router = jasmine.createSpyObj('Router', ['navigate']);
sessionStorageService = jasmine.createSpyObj('SessionStorageService', ['getItem', 'setItem', 'removeItem']);
mockCookieService = jasmine.createSpyObj('readCookieService', ['getCookie']);
mockAbstractConfig = jasmine.createSpyObj('AbstractAppConfig', ['logMessage']);

TestBed.configureTestingModule({
Expand All @@ -44,7 +46,8 @@ describe('EventStartGuard', () => {
{ provide: WorkAllocationService, useValue: service },
{ provide: Router, useValue: router },
{ provide: SessionStorageService, useValue: sessionStorageService },
{ provide: AbstractAppConfig, useValue: mockAbstractConfig }
{ provide: AbstractAppConfig, useValue: mockAbstractConfig },
{ provide: ReadCookieService, useValue: mockCookieService }
]
});

Expand All @@ -64,6 +67,19 @@ describe('EventStartGuard', () => {
});
});

it('client context should be set with language regardless whether task is attached to event', () => {
sessionStorageService.getItem.and.returnValue(null);
const mockClientContext = { client_context: { user_language: { language: 'cookieString' } } };
mockCookieService.getCookie.and.returnValue('cookieString');
const route = createActivatedRouteSnapshot('caseId', 'eventId');
const result$ = guard.canActivate(route);
result$.subscribe(result => {
expect(result).toEqual(false);
// check client contesxt is set correctly
expect(sessionStorageService.setItem).toHaveBeenCalledWith('clientContext', JSON.stringify(mockClientContext));
});
});

it('should log a message and not call getTasksByCaseIdAndEventId when caseInfo is not available', () => {
sessionStorageService.getItem.and.returnValue(null);
const route = createActivatedRouteSnapshot('caseId', 'eventId');
Expand Down Expand Up @@ -136,17 +152,22 @@ describe('EventStartGuard', () => {
});

it('should return true and navigate to event trigger if one task is assigned to user', () => {
const mockLanguage = 'en';
const clientContext = {
client_context: {
user_task: {
task_data: tasks[0],
complete_task: true
},
user_language: {
language: mockLanguage
}
}
}
tasks[0].assignee = '1';
const mockPayload: TaskPayload = {task_required_for_event: false, tasks};
sessionStorageService.getItem.and.returnValue(JSON.stringify(getExampleUserInfo()));
mockCookieService.getCookie.and.returnValue(mockLanguage);
expect(guard.checkTaskInEventNotRequired(mockPayload, caseId, null)).toBe(true);
expect(sessionStorageService.setItem).toHaveBeenCalledWith('clientContext', JSON.stringify(clientContext));
});
Expand All @@ -161,18 +182,23 @@ describe('EventStartGuard', () => {
});

it('should return true and navigate to event trigger if navigated to via task next steps', () => {
const mockLanguage = 'cy';
const clientContext = {
client_context: {
user_task: {
task_data: tasks[0],
complete_task: true
},
user_language: {
language: mockLanguage
}
}
}
tasks[0].assignee = '1';
tasks.push(tasks[0]);
const mockPayload: TaskPayload = {task_required_for_event: false, tasks};
sessionStorageService.getItem.and.returnValue(JSON.stringify(getExampleUserInfo()));
mockCookieService.getCookie.and.returnValue(mockLanguage);
expect(guard.checkTaskInEventNotRequired(mockPayload, caseId, '0d22d838-b25a-11eb-a18c-f2d58a9b7bc6')).toBe(true);
expect(sessionStorageService.setItem).toHaveBeenCalledWith('clientContext', JSON.stringify(clientContext));
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { switchMap } from 'rxjs/operators';
import { AbstractAppConfig } from '../../../../app.config';
import { TaskEventCompletionInfo } from '../../../domain/work-allocation/Task';
import { TaskPayload } from '../../../domain/work-allocation/TaskPayload';
import { SessionStorageService } from '../../../services';
import { ReadCookieService, SessionStorageService } from '../../../services';
import { WorkAllocationService } from '../../case-editor';

@Injectable()
Expand All @@ -16,7 +16,8 @@ export class EventStartGuard implements CanActivate {
constructor(private readonly workAllocationService: WorkAllocationService,
private readonly router: Router,
private readonly sessionStorageService: SessionStorageService,
private readonly abstractConfig: AbstractAppConfig) {
private readonly abstractConfig: AbstractAppConfig,
private readonly cookieService: ReadCookieService) {
}

public canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
Expand All @@ -30,6 +31,16 @@ export class EventStartGuard implements CanActivate {
userId = userInfo.id ? userInfo.id : userInfo.uid;
}
const caseInfoStr = this.sessionStorageService.getItem('caseInfo');
const currentLanguage = this.cookieService.getCookie('exui-preferred-language');
// if one task assigned to user, allow user to complete event
const storeClientContext = {
client_context: {
user_language: {
language: currentLanguage
}
}
};
this.sessionStorageService.setItem(EventStartGuard.CLIENT_CONTEXT, JSON.stringify(storeClientContext));
if (caseInfoStr) {
const caseInfo = JSON.parse(caseInfoStr);
if (caseInfo && caseInfo.cid === caseId) {
Expand Down Expand Up @@ -75,12 +86,16 @@ export class EventStartGuard implements CanActivate {
} else {
task = tasksAssignedToUser[0];
}
const currentLanguage = this.cookieService.getCookie('exui-preferred-language');
// if one task assigned to user, allow user to complete event
const storeClientContext = {
client_context: {
user_task: {
task_data: task,
complete_task: true
},
user_language: {
language: currentLanguage
}
}
};
Expand All @@ -105,11 +120,15 @@ export class EventStartGuard implements CanActivate {
taskId: task.id,
createdTimestamp: Date.now()
};
const currentLanguage = this.cookieService.getCookie('exui-preferred-language');
const storeClientContext = {
client_context: {
user_task: {
task_data: task,
complete_task: true
},
user_language: {
language: currentLanguage
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { StateMachine } from '@edium/fsm';
import { Task } from '../../domain/work-allocation/Task';
import { ReadCookieService } from '../../services/cookie/read-cookie-service';
import { SessionStorageService } from '../../services/session/session-storage.service';
import { EventStartStateMachineContext } from './models/event-start-state-machine-context.model';
import { EventStartStateMachineService } from './services/event-start-state-machine.service';
Expand All @@ -18,7 +19,8 @@ export class EventStartComponent implements OnInit {
constructor(private service: EventStartStateMachineService,
private readonly router: Router,
private readonly route: ActivatedRoute,
private readonly sessionStorageService: SessionStorageService) {
private readonly sessionStorageService: SessionStorageService,
private readonly cookieService: ReadCookieService) {
}

public ngOnInit(): void {
Expand All @@ -36,7 +38,8 @@ export class EventStartComponent implements OnInit {
taskId,
router: this.router,
route: this.route,
sessionStorageService: this.sessionStorageService
sessionStorageService: this.sessionStorageService,
cookieService: this.cookieService
};

// Initialise state machine
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ActivatedRoute, Router } from '@angular/router';
import { Task } from '../../../domain/work-allocation/Task';
import { SessionStorageService } from '../../../services';
import { ReadCookieService, SessionStorageService } from '../../../services';

export interface EventStartStateMachineContext {
tasks: Task[];
Expand All @@ -10,4 +10,5 @@ export interface EventStartStateMachineContext {
router: Router;
route: ActivatedRoute;
sessionStorageService: SessionStorageService;
cookieService: ReadCookieService;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { ActivatedRoute, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { StateMachine } from '@edium/fsm';
import { Task } from '../../../domain/work-allocation/Task';
import { SessionStorageService } from '../../../services';
import { ReadCookieService, SessionStorageService } from '../../../services';
import { EventStartStateMachineContext, EventStartStates } from '../models';
import { EventStartStateMachineService } from './event-start-state-machine.service';
import createSpyObj = jasmine.createSpyObj;

describe('EventStartStateMachineService', () => {
let service: EventStartStateMachineService;
let stateMachine: StateMachine;
let mockReadCookieService: any;
let mockSessionStorageService: any;
// tslint:disable-next-line: prefer-const
let mockRoute: ActivatedRoute;
Expand Down Expand Up @@ -109,6 +110,7 @@ describe('EventStartStateMachineService', () => {
];

mockSessionStorageService = createSpyObj<SessionStorageService>('sessionStorageService', ['getItem', 'setItem']);
mockReadCookieService = createSpyObj<ReadCookieService>('readCookieService', ['getCookie']);
mockSessionStorageService.getItem.and.returnValue(`{"id": "test-user-id", "forename": "Test", "surname": "User",
"roles": ["caseworker-role1", "caseworker-role3"], "email": "[email protected]", "token": null}`);

Expand All @@ -119,7 +121,8 @@ describe('EventStartStateMachineService', () => {
taskId: '1122-3344-5566-7788',
router: mockRouter,
route: mockRoute,
sessionStorageService: mockSessionStorageService
sessionStorageService: mockSessionStorageService,
cookieService: mockReadCookieService
};

beforeEach(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,18 @@ export class EventStartStateMachineService {
task = context.tasks[0];
}

const taskStr= JSON.stringify(task);
const taskStr = JSON.stringify(task);
console.log('entryActionForStateOneTaskAssignedToUser: setting client context task_data to ' + taskStr);
// Store task to session
const currentLanguage = context.cookieService.getCookie('exui-preferred-language');
const clientContext = {
client_context: {
user_task: {
task_data: task,
complete_task: true
},
user_language: {
language: currentLanguage
}
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './read-cookie-service';
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ReadCookieService } from "./read-cookie-service";

describe('CookieService', () => {
const mockDocument: any = {
cookie: ''
};

const cookieService: ReadCookieService = new ReadCookieService(mockDocument);

afterEach(() => {
mockDocument.cookie = '';
});

it('should get a cookie', () => {

mockDocument.cookie = 'user=dummy';
const result = cookieService.getCookie('user');
expect(result).toBe('dummy');
});

});
Loading

0 comments on commit e73c77b

Please sign in to comment.