diff --git a/helm_deploy/values-dev.yaml b/helm_deploy/values-dev.yaml index 7bd384f..244658d 100644 --- a/helm_deploy/values-dev.yaml +++ b/helm_deploy/values-dev.yaml @@ -21,7 +21,6 @@ generic-service: HMPPS_AUTH_URL: https://sign-in-dev.hmpps.service.justice.gov.uk/auth HMPPS_COOKIE_DOMAIN: digital-dev.prison.service.justice.gov.uk HMPPS_COOKIE_NAME: hmpps-session-dev - TODAY_CACHE_TTL: 10 # Maintainance mode KEYWORKER_MAINTENANCE_MODE: false @@ -86,7 +85,6 @@ generic-service: COMPONENT_API_LATEST: true COVID_UNITS_ENABLED: false ACCREDITED_PROGRAMMES_ENABLED: true - ESTABLISHMENT_ROLL_EXCLUDED: "" generic-prometheus-alerts: alertSeverity: hmpps-digital-prison-services-non-prod diff --git a/helm_deploy/values-preprod.yaml b/helm_deploy/values-preprod.yaml index da36599..8ab6664 100644 --- a/helm_deploy/values-preprod.yaml +++ b/helm_deploy/values-preprod.yaml @@ -21,7 +21,7 @@ generic-service: HMPPS_AUTH_URL: https://sign-in-preprod.hmpps.service.justice.gov.uk/auth HMPPS_COOKIE_DOMAIN: digital-preprod.prison.service.justice.gov.uk HMPPS_COOKIE_NAME: hmpps-session-preprod - TODAY_CACHE_TTL: 10 + # Maintainance mode KEYWORKER_MAINTENANCE_MODE: false @@ -84,7 +84,6 @@ generic-service: COMPONENT_API_LATEST: true COVID_UNITS_ENABLED: false ACCREDITED_PROGRAMMES_ENABLED: true - ESTABLISHMENT_ROLL_EXCLUDED: "" allowlist: sscl-blackpool: 31.121.5.27/32 diff --git a/helm_deploy/values-prod.yaml b/helm_deploy/values-prod.yaml index 87808b5..5dcd07b 100644 --- a/helm_deploy/values-prod.yaml +++ b/helm_deploy/values-prod.yaml @@ -24,7 +24,6 @@ generic-service: HMPPS_AUTH_URL: https://sign-in.hmpps.service.justice.gov.uk/auth HMPPS_COOKIE_DOMAIN: digital.prison.service.justice.gov.uk HMPPS_COOKIE_NAME: hmpps-session-preprod - TODAY_CACHE_TTL: 10 # Maintainance mode KEYWORKER_MAINTENANCE_MODE: false @@ -88,7 +87,6 @@ generic-service: COMPONENT_API_LATEST: false COVID_UNITS_ENABLED: false ACCREDITED_PROGRAMMES_ENABLED: false - ESTABLISHMENT_ROLL_EXCLUDED: "" allowlist: sscl-blackpool: 31.121.5.27/32 diff --git a/integration_tests/e2e/homepage.cy.ts b/integration_tests/e2e/homepage.cy.ts index 0036724..fc86060 100644 --- a/integration_tests/e2e/homepage.cy.ts +++ b/integration_tests/e2e/homepage.cy.ts @@ -1,7 +1,7 @@ import Page from '../pages/page' import IndexPage from '../pages' import { Role } from '../../server/enums/role' -import { todayDataMock } from '../../server/mocks/todayDataMock' +import { prisonEstablishmentRollSummaryMock } from '../../server/mocks/prisonRollCountSummaryMock' context('Homepage (with FE Components services)', () => { beforeEach(() => { @@ -12,12 +12,10 @@ context('Homepage (with FE Components services)', () => { { caseloadFunction: '', caseLoadId: 'LEI', currentlyActive: true, description: 'Leeds (HMP)', type: '' }, ], }) - cy.task('stubRollCount') - cy.task('stubRollCountUnassigned') - cy.task('stubMovements') cy.task('stubWhatsNewPosts') cy.task('stubOutageBanner') cy.task('stubFeComponents') + cy.task('stubPrisonRollCountSummary') cy.signIn() cy.visit('/') }) @@ -75,21 +73,28 @@ context('Homepage (with FE Components services)', () => { it('should display today data', () => { const page = Page.verifyOnPage(IndexPage) page.today().heading().should('be.visible').and('contain.text', 'Today in Leeds (HMP)') - page.today().lastUpdated().should('be.visible') page.today().unlockRollCard().should('be.visible').find('h3').contains("Today's unlock roll") - page.today().unlockRollCard().find('.today-card__count').contains(todayDataMock.unlockRollCount) + page + .today() + .unlockRollCard() + .find('.today-card__count') + .contains(prisonEstablishmentRollSummaryMock.numUnlockRollToday) page.today().populationCard().should('be.visible').find('h3').contains('Current population') - page.today().populationCard().find('.today-card__count').contains(todayDataMock.currentPopulationCount) + page + .today() + .populationCard() + .find('.today-card__count') + .contains(prisonEstablishmentRollSummaryMock.numCurrentPopulation) page.today().populationCard().find('a').contains('Establishment roll') page.today().inTodayCard().should('be.visible').find('h3').contains('Arrived today') - page.today().inTodayCard().find('.today-card__count').contains(todayDataMock.inTodayCount) + page.today().inTodayCard().find('.today-card__count').contains(prisonEstablishmentRollSummaryMock.numArrivedToday) page.today().inTodayCard().find('a').contains('Arrived today') page.today().outTodayCard().should('be.visible').find('h3').contains('Out today') - page.today().outTodayCard().find('.today-card__count').contains(todayDataMock.outTodayCount) + page.today().outTodayCard().find('.today-card__count').contains(prisonEstablishmentRollSummaryMock.numOutToday) page.today().outTodayCard().find('a').contains('People out today') }) }) @@ -125,9 +130,7 @@ context('Homepage - no global search', () => { { caseloadFunction: '', caseLoadId: 'LEI', currentlyActive: true, description: 'Leeds (HMP)', type: '' }, ], }) - cy.task('stubRollCount') - cy.task('stubRollCountUnassigned') - cy.task('stubMovements') + cy.task('stubPrisonRollCountSummary') cy.task('stubWhatsNewPosts') cy.task('stubOutageBanner') @@ -155,9 +158,7 @@ context('Homepage - no active caseload', () => { { caseloadFunction: '', caseLoadId: 'MOR', currentlyActive: false, description: 'Moorland', type: '' }, ], }) - cy.task('stubRollCount', { prisonCode: 'MOR' }) - cy.task('stubRollCountUnassigned', 'MOR') - cy.task('stubMovements', 'MOR') + cy.task('stubPrisonRollCountSummary', { prisonCode: 'MOR' }) cy.task('stubWhatsNewPosts') cy.task('stubOutageBanner') cy.task('stubSetActiveCaseload') @@ -200,9 +201,7 @@ context('Homepage (without FE Components services)', () => { { caseloadFunction: '', caseLoadId: 'LEI', currentlyActive: true, description: 'Leeds (HMP)', type: '' }, ], }) - cy.task('stubRollCount') - cy.task('stubRollCountUnassigned') - cy.task('stubMovements') + cy.task('stubPrisonRollCountSummary') cy.task('stubWhatsNewPosts') cy.task('stubOutageBanner') cy.signIn() diff --git a/integration_tests/e2e/login.cy.ts b/integration_tests/e2e/login.cy.ts index 0c41ba0..27e2e24 100644 --- a/integration_tests/e2e/login.cy.ts +++ b/integration_tests/e2e/login.cy.ts @@ -7,11 +7,9 @@ context('SignIn', () => { cy.task('reset') cy.task('stubUserCaseLoads') cy.task('stubUserLocations') - cy.task('stubRollCount') - cy.task('stubRollCountUnassigned') - cy.task('stubMovements') cy.task('stubWhatsNewPosts') cy.task('stubOutageBanner') + cy.task('stubPrisonRollCountSummary') cy.task('changeCaseload') cy.setupUserAuth() }) @@ -62,16 +60,4 @@ context('SignIn', () => { indexPage.headerUserName().contains('B. Brown') }) - - it('Page shown ok when roles are not found', () => { - cy.task('stubGetStaffRoles', 403) - cy.signIn() - Page.verifyOnPage(IndexPage) - }) - - it('Page shown ok when roles call is unauthorised', () => { - cy.task('stubGetStaffRoles', 404) - cy.signIn() - Page.verifyOnPage(IndexPage) - }) }) diff --git a/integration_tests/mockApis/prison.ts b/integration_tests/mockApis/prison.ts index c32b086..53055aa 100644 --- a/integration_tests/mockApis/prison.ts +++ b/integration_tests/mockApis/prison.ts @@ -2,9 +2,7 @@ import { stubFor } from './wiremock' import { CaseLoad } from '../../server/data/interfaces/caseLoad' import { Location } from '../../server/data/interfaces/location' import { locationMock, locationsMock } from '../../server/mocks/locationMock' -import { assignedRollCountMock, unassignedRollCountMock } from '../../server/mocks/rollCountMock' import { movementsMock } from '../../server/mocks/movementsMock' -import { mockStaffRoles } from '../../server/mocks/staffRolesMock' import { movementsInMock } from '../../server/test/mocks/movementsInMock' import { movementsOutMock } from '../../server/test/mocks/movementsOutMock' import { movementsEnRouteMock } from '../../server/test/mocks/movementsEnRouteMock' @@ -15,6 +13,7 @@ import { userDetailsMock } from '../../server/test/mocks/userDetailsMock' import { pagedListMock } from '../../server/test/mocks/pagedListMock' import { prisonRollCountMock } from '../../server/mocks/prisonRollCountMock' import { prisonRollCountForWingWithSpurMock } from '../../server/mocks/prisonRollCountForWingWithSpurMock' +import { prisonEstablishmentRollSummaryMock } from '../../server/mocks/prisonRollCountSummaryMock' export default { stubUserCaseLoads: (caseLoads: CaseLoad[] = []) => { @@ -49,11 +48,11 @@ export default { }) }, - stubRollCount: ({ prisonCode = 'LEI', payload = assignedRollCountMock, query = '' } = {}) => { + stubPrisonRollCount: ({ prisonCode = 'LEI', payload = prisonRollCountMock } = {}) => { return stubFor({ request: { method: 'GET', - url: `/prison/api/movements/rollcount/${prisonCode}${query}`, + url: `/prison/api/prison/roll-count/${prisonCode}`, }, response: { status: 200, @@ -65,18 +64,18 @@ export default { }) }, - stubPrisonRollCount: ({ prisonCode = 'LEI', payload = prisonRollCountMock } = {}) => { + stubPrisonRollCountSummary: ({ prisonCode = 'LEI' } = {}) => { return stubFor({ request: { method: 'GET', - url: `/prison/api/prison/roll-count/${prisonCode}`, + url: `/prison/api/prison/roll-count/${prisonCode}/summary`, }, response: { status: 200, headers: { 'Content-Type': 'application/json;charset=UTF-8', }, - jsonBody: payload, + jsonBody: { ...prisonEstablishmentRollSummaryMock, prisonId: prisonCode }, }, }) }, @@ -101,22 +100,6 @@ export default { }) }, - stubRollCountUnassigned: (prisonCode = 'LEI') => { - return stubFor({ - request: { - method: 'GET', - url: `/prison/api/movements/rollcount/${prisonCode}?unassigned=true`, - }, - response: { - status: 200, - headers: { - 'Content-Type': 'application/json;charset=UTF-8', - }, - jsonBody: unassignedRollCountMock, - }, - }) - }, - stubMovements: (prisonCode = 'LEI') => { return stubFor({ request: { @@ -247,38 +230,6 @@ export default { }) }, - stubEnrouteRollCount: (prisonCode = 'LEI') => { - return stubFor({ - request: { - method: 'GET', - urlPattern: `/prison/api/movements/rollcount/${prisonCode}/enroute`, - }, - response: { - status: 200, - headers: { - 'Content-Type': 'application/json;charset=UTF-8', - }, - jsonBody: 1, - }, - }) - }, - - stubGetLocationsForPrison: (prisonCode = 'LEI') => { - return stubFor({ - request: { - method: 'GET', - urlPattern: `/prison/api/agencies/${prisonCode}/locations`, - }, - response: { - status: 200, - headers: { - 'Content-Type': 'application/json;charset=UTF-8', - }, - jsonBody: [{ description: 'CSWAP', locationId: 1 }], - }, - }) - }, - stubGetLocation: ({ locationId = 123, payload = locationMock } = {}) => { return stubFor({ request: { @@ -295,38 +246,6 @@ export default { }) }, - getAttributesForLocation: (locationId = 1) => { - return stubFor({ - request: { - method: 'GET', - urlPattern: `/prison/api/cell/${locationId}/attributes`, - }, - response: { - status: 200, - headers: { - 'Content-Type': 'application/json;charset=UTF-8', - }, - jsonBody: { noOfOccupants: 31 }, - }, - }) - }, - - stubGetStaffRoles: (status = 200) => { - return stubFor({ - request: { - method: 'GET', - urlPattern: `/prison/api/staff/231232/LEI/roles`, - }, - response: { - status, - headers: { - 'Content-Type': 'application/json;charset=UTF-8', - }, - jsonBody: mockStaffRoles, - }, - }) - }, - stubSetActiveCaseload: (status = 200) => { return stubFor({ request: { diff --git a/integration_tests/pages/index.ts b/integration_tests/pages/index.ts index 9fa700b..e88ba40 100644 --- a/integration_tests/pages/index.ts +++ b/integration_tests/pages/index.ts @@ -48,7 +48,6 @@ export default class IndexPage extends Page { return { heading: () => todaySection().find('h2'), - lastUpdated: () => todaySection().find('.today-last-updated'), unlockRollCard: () => todaySection().find('[data-qa=today-unlock-roll-card]'), populationCard: () => todaySection().find('[data-qa=today-current-population-card]'), inTodayCard: () => todaySection().find('[data-qa=today-in-card]'), diff --git a/server/config.ts b/server/config.ts index b833437..153dba7 100755 --- a/server/config.ts +++ b/server/config.ts @@ -244,7 +244,6 @@ export default { changeSomeonesCell: get('CHANGE_SOMEONES_CELL_URL', 'http://localhost:3002', requiredInProduction), }, domain: get('INGRESS_URL', 'http://localhost:3000', requiredInProduction), - todayCacheTTL: Number(get('TODAY_CACHE_TTL', 0, requiredInProduction)), contentful: { host: get('CONTENTFUL_HOST', ''), // This is only required for Cypress testing spaceId: get('CONTENTFUL_SPACE_ID', 'spaceId', requiredInProduction), @@ -254,7 +253,4 @@ export default { analytics: { tagManagerContainerId: get('TAG_MANAGER_CONTAINER_ID', ''), }, - features: { - establishmentRollExcluded: get('ESTABLISHMENT_ROLL_EXCLUDED', ''), - }, } diff --git a/server/controllers/homepageController.test.ts b/server/controllers/homepageController.test.ts index 47fd771..cf6f45e 100644 --- a/server/controllers/homepageController.test.ts +++ b/server/controllers/homepageController.test.ts @@ -3,16 +3,14 @@ import { Response } from 'express' import { Role } from '../enums/role' import HomepageController from './homepageController' import config from '../config' -import HomepageService from '../services/homepageService' -import { todayDataMock } from '../mocks/todayDataMock' -import HmppsCache from '../middleware/hmppsCache' import ContentfulService from '../services/contentfulService' import { whatsNewPostsMock } from '../mocks/whatsNewPostsMock' import { whatsNewDataMock } from '../mocks/whatsNewDataMock' -import { mockStaffRoles } from '../mocks/staffRolesMock' import { CaseLoad } from '../data/interfaces/caseLoad' import { PrisonUser } from '../interfaces/prisonUser' import defaultServices from '../utils/defaultServices' +import EstablishmentRollService from '../services/establishmentRollService' +import { prisonEstablishmentRollSummaryMock } from '../mocks/prisonRollCountSummaryMock' const staffId = 487023 const activeCaseLoadId = 'LEI' @@ -30,10 +28,8 @@ let res: Partial = {} let controller: any -jest.mock('../services/homepageService.ts') - describe('Homepage Controller', () => { - let homepageService: HomepageService + let establishmentRollService: EstablishmentRollService let contentfulService: ContentfulService beforeEach(() => { @@ -53,32 +49,26 @@ describe('Homepage Controller', () => { redirect: jest.fn(), } - homepageService = new HomepageService(null, null, null) - homepageService.getTodaySection = jest.fn(async () => todayDataMock) + establishmentRollService = new EstablishmentRollService(null) - homepageService.getStaffRoles = jest.fn(async () => mockStaffRoles) + establishmentRollService.getEstablishmentRollSummary = jest.fn(async () => prisonEstablishmentRollSummaryMock) contentfulService = new ContentfulService(new ApolloClient({ cache: new InMemoryCache() })) contentfulService.getWhatsNewPosts = jest.fn(async () => whatsNewDataMock) contentfulService.getOutageBanner = jest.fn(async () => 'Banner') - controller = new HomepageController(homepageService, new HmppsCache(1), contentfulService) + controller = new HomepageController(contentfulService, establishmentRollService) }) describe('Display homepage', () => { const defaultOutput = { - currentPopulationCount: 1023, errors: undefined as string[], globalPreset: false, - inTodayCount: 17, - outTodayCount: 9, outageBanner: 'Banner', userHasPrisonCaseLoad: true, searchViewAllUrl: `http://localhost:3001/prisoner-search?keywords=&location=${activeCaseLoadId}`, showServicesOutage: true, services: defaultServices, - todayLastUpdated: '2023-07-20T12:45', - unlockRollCount: 1015, userHasGlobal: true, whatsNewPosts: [ { @@ -100,14 +90,14 @@ describe('Homepage Controller', () => { title: 'Whats new three', }, ], - establishmentRollExcluded: false, + todayData: prisonEstablishmentRollSummaryMock, } describe('With no feComponentsMeta', () => { it('should get homepage data', async () => { await controller.displayHomepage()(req, res) - expect(controller['homepageService'].getTodaySection).toHaveBeenCalled() + expect(controller['establishmentRollService'].getEstablishmentRollSummary).toHaveBeenCalled() expect(controller['contentfulService'].getWhatsNewPosts).toHaveBeenCalled() expect(controller['contentfulService'].getOutageBanner).toHaveBeenCalled() expect(res.render).toHaveBeenCalledWith('pages/index', defaultOutput) @@ -134,7 +124,7 @@ describe('Homepage Controller', () => { }, }) - expect(controller['homepageService'].getTodaySection).toHaveBeenCalled() + expect(controller['establishmentRollService'].getEstablishmentRollSummary).toHaveBeenCalled() expect(controller['contentfulService'].getWhatsNewPosts).toHaveBeenCalled() expect(controller['contentfulService'].getOutageBanner).toHaveBeenCalled() expect(res.render).toHaveBeenCalledWith('pages/index', { @@ -157,11 +147,10 @@ describe('Homepage Controller', () => { showServicesOutage: true, services: defaultServices, searchViewAllUrl: `${config.serviceUrls.digitalPrisons}/prisoner-search?keywords=&location=${res.locals.user.activeCaseLoadId}`, - ...todayDataMock, whatsNewPosts: whatsNewPostsMock, outageBanner: 'Banner', userHasPrisonCaseLoad: true, - establishmentRollExcluded: false, + todayData: prisonEstablishmentRollSummaryMock, }) }) }) @@ -228,7 +217,7 @@ describe('Homepage Controller', () => { } as PrisonUser, } await controller.displayHomepage()(req, res) - expect(controller['homepageService'].getTodaySection).not.toHaveBeenCalled() + expect(controller['establishmentRollService'].getEstablishmentRollSummary).not.toHaveBeenCalled() expect(controller['contentfulService'].getWhatsNewPosts).toHaveBeenCalled() expect(controller['contentfulService'].getOutageBanner).toHaveBeenCalled() expect(res.render).toHaveBeenCalledWith('pages/index', expect.objectContaining({ userHasPrisonCaseLoad: false })) diff --git a/server/controllers/homepageController.ts b/server/controllers/homepageController.ts index 93da33d..a7f6715 100644 --- a/server/controllers/homepageController.ts +++ b/server/controllers/homepageController.ts @@ -1,21 +1,19 @@ import { NextFunction, Request, RequestHandler, Response } from 'express' import { Role } from '../enums/role' import config from '../config' -import HomepageService from '../services/homepageService' -import HmppsCache from '../middleware/hmppsCache' import { userHasRoles } from '../utils/utils' import ContentfulService from '../services/contentfulService' import { Service } from '../data/interfaces/component' import defaultServices from '../utils/defaultServices' +import EstablishmentRollService from '../services/establishmentRollService' /** * Parse requests for homepage routes and orchestrate response */ export default class HomepageController { constructor( - private readonly homepageService: HomepageService, - private readonly todayCache: HmppsCache, private readonly contentfulService: ContentfulService, + private readonly establishmentRollService: EstablishmentRollService, ) {} private async getServiceData(res: Response): Promise<{ showServicesOutage: boolean; services: Service[] }> { @@ -25,16 +23,6 @@ export default class HomepageController { return { showServicesOutage: true, services: defaultServices } } - private async getTodayData(req: Request, userHasPrisonCaseLoad: boolean, activeCaseLoadId: string) { - if (userHasPrisonCaseLoad) { - return this.todayCache.wrap(activeCaseLoadId, () => - this.homepageService.getTodaySection(req.middleware.clientToken, activeCaseLoadId), - ) - } - - return {} - } - public displayHomepage(): RequestHandler { return async (req: Request, res: Response, next: NextFunction) => { const { activeCaseLoadId } = res.locals.user @@ -49,15 +37,15 @@ export default class HomepageController { ? `${config.serviceUrls.digitalPrisons}/prisoner-search?keywords=&location=${activeCaseLoadId}` : '' - // Today Section - wrapped with a caching function per prison to reduce API calls - // Outage Banner - filtered to active caseload if banner has been marked for specific prisons // Whats new Section - filtered to active caseload if post has been marked for specific prisons const [outageBanner, { showServicesOutage, services }, whatsNewData, todayData] = await Promise.all([ this.contentfulService.getOutageBanner(activeCaseLoadId), this.getServiceData(res), this.contentfulService.getWhatsNewPosts(1, 3, 0, activeCaseLoadId), - this.getTodayData(req, userHasPrisonCaseLoad, activeCaseLoadId), + userHasPrisonCaseLoad + ? this.establishmentRollService.getEstablishmentRollSummary(req.middleware.clientToken, activeCaseLoadId) + : {}, ]) res.render('pages/index', { @@ -66,12 +54,11 @@ export default class HomepageController { searchViewAllUrl, services, globalPreset: !!errors?.length && userHasGlobal, - ...todayData, + todayData, whatsNewPosts: whatsNewData.whatsNewPosts, outageBanner, userHasPrisonCaseLoad, showServicesOutage, - establishmentRollExcluded: config.features.establishmentRollExcluded.split(',').includes(activeCaseLoadId), }) } } diff --git a/server/controllers/managedPageController.test.ts b/server/controllers/managedPageController.test.ts index 3dd6d56..c5529b3 100644 --- a/server/controllers/managedPageController.test.ts +++ b/server/controllers/managedPageController.test.ts @@ -8,8 +8,6 @@ let req: any let res: any let controller: any -jest.mock('../services/homepageService.ts') - describe('Managed Page Controller', () => { let contentfulService: ContentfulService diff --git a/server/controllers/whatsNewController.test.ts b/server/controllers/whatsNewController.test.ts index 5e3fcde..227169d 100644 --- a/server/controllers/whatsNewController.test.ts +++ b/server/controllers/whatsNewController.test.ts @@ -10,8 +10,6 @@ let req: any let res: any let controller: any -jest.mock('../services/homepageService.ts') - describe('Whats New Controller', () => { let contentfulService: ContentfulService diff --git a/server/data/index.ts b/server/data/index.ts index a656b3f..485459a 100644 --- a/server/data/index.ts +++ b/server/data/index.ts @@ -11,10 +11,6 @@ import config, { ApiConfig } from '../config' import RestClient, { RestClientBuilder as CreateRestClientBuilder } from './restClient' import PrisonApiRestClient from './prisonApiClient' import { PrisonApiClient } from './interfaces/prisonApiClient' -import { WhereAboutsApiClient } from './interfaces/whereAboutsApiClient' -import WhereAboutsApiRestClient from './whereAboutsApiClient' -import { KeyWorkerApiClient } from './interfaces/keyWorkerApiClient' -import KeyWorkerApiRestClient from './keyWorkerApiClient' import PrisonerSearchRestClient from './prisonerSearchClient' import RedisTokenStore from './tokenStore/redisTokenStore' import InMemoryTokenStore from './tokenStore/inMemoryTokenStore' @@ -37,16 +33,6 @@ export default function restClientBuilder( export const dataAccess = { applicationInfo, prisonApiClientBuilder: restClientBuilder('Prison API', config.apis.prisonApi, PrisonApiRestClient), - whereAboutsApiClientBuilder: restClientBuilder( - 'Whereabouts API', - config.apis.whereabouts, - WhereAboutsApiRestClient, - ), - keyWorkerApiClientBuilder: restClientBuilder( - 'Keyworker API', - config.apis.keyworker, - KeyWorkerApiRestClient, - ), systemToken: systemTokenBuilder( config.redis.enabled ? new RedisTokenStore(createRedisClient()) : new InMemoryTokenStore(), ), diff --git a/server/data/interfaces/AvailableComponent.ts b/server/data/interfaces/AvailableComponent.ts deleted file mode 100644 index f78c1a9..0000000 --- a/server/data/interfaces/AvailableComponent.ts +++ /dev/null @@ -1,2 +0,0 @@ -type AvailableComponent = 'header' | 'footer' -export default AvailableComponent diff --git a/server/data/interfaces/blockRollCount.ts b/server/data/interfaces/blockRollCount.ts deleted file mode 100644 index 5e0f026..0000000 --- a/server/data/interfaces/blockRollCount.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface BlockRollCount { - currentlyInCell: number - outOfLivingUnits: number - livingUnitId: number - fullLocationPath: string - locationCode: string - livingUnitDesc: string - parentLocationId?: number - bedsInUse: number - currentlyOut: number - operationalCapacity?: number - netVacancies?: number - maximumCapacity: number - availablePhysical: number - outOfOrder: number -} diff --git a/server/data/interfaces/keyWorkerApiClient.ts b/server/data/interfaces/keyWorkerApiClient.ts deleted file mode 100644 index 254def6..0000000 --- a/server/data/interfaces/keyWorkerApiClient.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { KeyWorkerPrisonStatus } from './keyWorkerPrisonStatus' - -export interface KeyWorkerApiClient { - getPrisonMigrationStatus(prisonId: string): Promise -} diff --git a/server/data/interfaces/keyWorkerPrisonStatus.ts b/server/data/interfaces/keyWorkerPrisonStatus.ts deleted file mode 100644 index 7987dc3..0000000 --- a/server/data/interfaces/keyWorkerPrisonStatus.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface KeyWorkerPrisonStatus { - migrated: boolean -} diff --git a/server/data/interfaces/prisonApiClient.ts b/server/data/interfaces/prisonApiClient.ts index bc39010..fdf5c68 100644 --- a/server/data/interfaces/prisonApiClient.ts +++ b/server/data/interfaces/prisonApiClient.ts @@ -1,9 +1,7 @@ import { Readable } from 'stream' import { CaseLoad } from './caseLoad' import { Location } from './location' -import { BlockRollCount } from './blockRollCount' import { Movements } from './movements' -import { StaffRole } from './staffRole' import { OffenderCell } from './offenderCell' import { OffenderIn } from './offenderIn' import { OffenderOut } from './offenderOut' @@ -13,14 +11,11 @@ import { PagedList } from './pagedList' import { BedAssignment } from './bedAssignment' import { UserDetail } from './userDetail' import PrisonRollCount from './prisonRollCount' +import EstablishmentRollSummary from '../../services/interfaces/establishmentRollService/EstablishmentRollSummary' export interface PrisonApiClient { getUserCaseLoads(): Promise getUserLocations(): Promise - getRollCount( - prisonId: string, - options?: { unassigned?: boolean; wingOnly?: boolean; showCells?: boolean; parentLocationId?: number }, - ): Promise getLocation(locationId: string): Promise getAttributesForLocation(locationId: number): Promise getMovements(prisonId: string): Promise @@ -29,7 +24,6 @@ export interface PrisonApiClient { getMovementsOut(prisonId: string, movementDate: string): Promise getMovementsEnRoute(prisonId: string): Promise getMovementsInReception(prisonId: string): Promise - getStaffRoles(staffId: number, agencyId: string): Promise setActiveCaseload(caseLoad: CaseLoad): Promise> getPrisonerImage(offenderNumber: string, fullSizeImage: boolean): Promise getOffenderCellHistory(bookingId: number, params?: { page: number; size: number }): Promise> @@ -38,4 +32,5 @@ export interface PrisonApiClient { getPrisonersCurrentlyOutOfPrison(prisonId: string): Promise getPrisonRollCount(prisonId: string): Promise getPrisonRollCountForLocation(prisonId: string, locationId: string): Promise + getPrisonRollCountSummary(prisonId: string): Promise } diff --git a/server/data/interfaces/staffRole.ts b/server/data/interfaces/staffRole.ts deleted file mode 100644 index 9f66ad0..0000000 --- a/server/data/interfaces/staffRole.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface StaffRole { - role: string - roleDescription?: string -} diff --git a/server/data/interfaces/whereAboutsApiClient.ts b/server/data/interfaces/whereAboutsApiClient.ts deleted file mode 100644 index 297f25c..0000000 --- a/server/data/interfaces/whereAboutsApiClient.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { WhereAboutsConfig } from './whereAboutsConfig' - -export interface WhereAboutsApiClient { - getWhereaboutsConfig(activeCaseLoadId: string): Promise -} diff --git a/server/data/interfaces/whereAboutsConfig.ts b/server/data/interfaces/whereAboutsConfig.ts deleted file mode 100644 index 17b36e8..0000000 --- a/server/data/interfaces/whereAboutsConfig.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface WhereAboutsConfig { - enabled: boolean -} diff --git a/server/data/keyWorkerApiClient.test.ts b/server/data/keyWorkerApiClient.test.ts deleted file mode 100644 index 98fc8b2..0000000 --- a/server/data/keyWorkerApiClient.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import nock from 'nock' -import config from '../config' -import restClientBuilder from '.' -import { ApplicationInfo } from '../applicationInfo' -import { KeyWorkerApiClient } from './interfaces/keyWorkerApiClient' -import KeyWorkerApiRestClient from './keyWorkerApiClient' - -jest.mock('../applicationInfo.ts', () => { - return { - __esModule: true, - default: jest.fn(() => { - return { - applicationName: 'test', - buildNumber: '1', - gitRef: 'long ref', - gitShortHash: 'short ref', - } as ApplicationInfo - }), - } -}) - -const token = { access_token: 'token-1', expires_in: 300 } - -describe.skip('keyWorkerApiClient', () => { - let fakeKeyWorkerApi: nock.Scope - let keyWorkerApiClient: KeyWorkerApiClient - - beforeEach(() => { - fakeKeyWorkerApi = nock(config.apis.keyworker.url) - keyWorkerApiClient = restClientBuilder( - 'Key Worker API', - config.apis.keyworker, - KeyWorkerApiRestClient, - )(token.access_token) - }) - - afterEach(() => { - jest.resetAllMocks() - nock.cleanAll() - }) - - const mockSuccessfulKeyWorkerApiCall = (url: string, returnData: TReturnData) => { - fakeKeyWorkerApi.get(url).matchHeader('authorization', `Bearer ${token.access_token}`).reply(200, returnData) - } - - describe('getPrisonMigrationStatus', () => { - it('should return data from api', async () => { - mockSuccessfulKeyWorkerApiCall(`/key-worker/prison/MDI`, { migrated: true }) - const output = await keyWorkerApiClient.getPrisonMigrationStatus('MDI') - expect(output).toEqual({ migrated: true }) - }) - }) -}) diff --git a/server/data/keyWorkerApiClient.ts b/server/data/keyWorkerApiClient.ts deleted file mode 100644 index 10a36ae..0000000 --- a/server/data/keyWorkerApiClient.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { KeyWorkerApiClient } from './interfaces/keyWorkerApiClient' -import { KeyWorkerPrisonStatus } from './interfaces/keyWorkerPrisonStatus' -import RestClient from './restClient' - -export default class KeyWorkerApiRestClient implements KeyWorkerApiClient { - constructor(private restClient: RestClient) {} - - private async get(args: object): Promise { - return this.restClient.get(args) - } - - async getPrisonMigrationStatus(prisonId: string): Promise { - return this.get({ path: `/key-worker/prison/${prisonId}` }) - } -} diff --git a/server/data/prisonApiClient.test.ts b/server/data/prisonApiClient.test.ts index fe794f9..eba8833 100644 --- a/server/data/prisonApiClient.test.ts +++ b/server/data/prisonApiClient.test.ts @@ -4,7 +4,6 @@ import PrisonApiClient from './prisonApiClient' import restClientBuilder from '.' import { ApplicationInfo } from '../applicationInfo' import { locationMock } from '../mocks/locationMock' -import { mockStaffRoles } from '../mocks/staffRolesMock' jest.mock('../applicationInfo.ts', () => { return { @@ -67,16 +66,6 @@ describe('prisonApiClient', () => { }) }) - describe('getStaffRoles', () => { - it('Should return data from the API', async () => { - const staffNumber = 12345 - const agencyId = 'Agency' - mockSuccessfulPrisonApiCall(`/api/staff/${staffNumber}/${agencyId}/roles`, mockStaffRoles) - const output = await prisonApiClient.getStaffRoles(staffNumber, agencyId) - expect(output).toEqual(mockStaffRoles) - }) - }) - describe('setActiveCaseLoad', () => { it('Should return data from the API', async () => { const caseLoadMock = { diff --git a/server/data/prisonApiClient.ts b/server/data/prisonApiClient.ts index 4ebb675..e6f28f6 100644 --- a/server/data/prisonApiClient.ts +++ b/server/data/prisonApiClient.ts @@ -4,9 +4,7 @@ import RestClient from './restClient' import { PrisonApiClient } from './interfaces/prisonApiClient' import { CaseLoad } from './interfaces/caseLoad' import { Location } from './interfaces/location' -import { BlockRollCount } from './interfaces/blockRollCount' import { Movements } from './interfaces/movements' -import { StaffRole } from './interfaces/staffRole' import { OffenderCell } from './interfaces/offenderCell' import { OffenderIn } from './interfaces/offenderIn' import { OffenderOut } from './interfaces/offenderOut' @@ -16,6 +14,7 @@ import { UserDetail } from './interfaces/userDetail' import { BedAssignment } from './interfaces/bedAssignment' import { PagedList } from './interfaces/pagedList' import PrisonRollCount from './interfaces/prisonRollCount' +import EstablishmentRollSummary from '../services/interfaces/establishmentRollService/EstablishmentRollSummary' export default class PrisonApiRestClient implements PrisonApiClient { constructor(private restClient: RestClient) {} @@ -40,16 +39,6 @@ export default class PrisonApiRestClient implements PrisonApiClient { return this.get({ path: '/api/users/me/locations' }) } - getRollCount( - prisonId: string, - queryOptions: { unassigned?: boolean; wingOnly?: boolean; showCells?: boolean; parentLocationId?: number } = {}, - ): Promise { - return this.get({ - path: `/api/movements/rollcount/${prisonId}`, - query: querystring.stringify(queryOptions), - }) - } - getMovements(prisonId: string): Promise { return this.get({ path: `/api/movements/rollcount/${prisonId}/movements` }) } @@ -82,18 +71,6 @@ export default class PrisonApiRestClient implements PrisonApiClient { return this.get({ path: `/api/cell/${locationId}/attributes` }) } - async getStaffRoles(staffId: number, agencyId: string): Promise { - try { - return await this.get({ path: `/api/staff/${staffId}/${agencyId}/roles` }) - } catch (error) { - if (error.status === 403 || error.status === 404) { - // can happen for CADM (central admin) users - return [] - } - throw error - } - } - setActiveCaseload(caseLoad: CaseLoad): Promise> { return this.put>({ path: '/api/users/me/activeCaseLoad', data: caseLoad }) } @@ -133,4 +110,8 @@ export default class PrisonApiRestClient implements PrisonApiClient { getPrisonRollCountForLocation(prisonId: string, locationId: string): Promise { return this.get({ path: `/api/prison/roll-count/${prisonId}/cells-only/${locationId}` }) } + + getPrisonRollCountSummary(prisonId: string): Promise { + return this.get({ path: `/api/prison/roll-count/${prisonId}/summary` }) + } } diff --git a/server/data/whereAboutsApiClient.test.ts b/server/data/whereAboutsApiClient.test.ts deleted file mode 100644 index 2c0c96f..0000000 --- a/server/data/whereAboutsApiClient.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import nock from 'nock' -import config from '../config' -import restClientBuilder from '.' -import { ApplicationInfo } from '../applicationInfo' -import { WhereAboutsApiClient } from './interfaces/whereAboutsApiClient' -import WhereAboutsApiRestClient from './whereAboutsApiClient' - -jest.mock('../applicationInfo.ts', () => { - return { - __esModule: true, - default: jest.fn(() => { - return { - applicationName: 'test', - buildNumber: '1', - gitRef: 'long ref', - gitShortHash: 'short ref', - } as ApplicationInfo - }), - } -}) - -const token = { access_token: 'token-1', expires_in: 300 } - -describe.skip('whereAboutsApiClient', () => { - let fakeWhereAboutsApi: nock.Scope - let whereAboutsApiClient: WhereAboutsApiClient - - beforeEach(() => { - fakeWhereAboutsApi = nock(config.apis.whereabouts.url) - whereAboutsApiClient = restClientBuilder( - 'WhereAbouts API', - config.apis.whereabouts, - WhereAboutsApiRestClient, - )(token.access_token) - }) - - afterEach(() => { - jest.resetAllMocks() - nock.cleanAll() - }) - - const mockSuccessfulWhereAboutsApiCall = (url: string, returnData: TReturnData) => { - fakeWhereAboutsApi.get(url).matchHeader('authorization', `Bearer ${token.access_token}`).reply(200, returnData) - } - - describe('getWhereaboutsConfig', () => { - it('should return data from api', async () => { - mockSuccessfulWhereAboutsApiCall('/agencies/LEI/locations/whereabouts', { enabled: true }) - const output = await whereAboutsApiClient.getWhereaboutsConfig('MDI') - expect(output).toEqual({ enabled: true }) - }) - }) -}) diff --git a/server/data/whereAboutsApiClient.ts b/server/data/whereAboutsApiClient.ts deleted file mode 100644 index 8ffbca2..0000000 --- a/server/data/whereAboutsApiClient.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { WhereAboutsApiClient } from './interfaces/whereAboutsApiClient' -import { WhereAboutsConfig } from './interfaces/whereAboutsConfig' -import RestClient from './restClient' - -export default class WhereAboutsApiRestClient implements WhereAboutsApiClient { - constructor(private restClient: RestClient) {} - - private async get(args: object): Promise { - return this.restClient.get(args) - } - - async getWhereaboutsConfig(activeCaseLoadId: string): Promise { - return this.get({ path: `/agencies/${activeCaseLoadId}/locations/whereabouts` }) - } -} diff --git a/server/mocks/prisonRollCountSummaryMock.ts b/server/mocks/prisonRollCountSummaryMock.ts new file mode 100644 index 0000000..323fadf --- /dev/null +++ b/server/mocks/prisonRollCountSummaryMock.ts @@ -0,0 +1,9 @@ +import EstablishmentRollSummary from '../services/interfaces/establishmentRollService/EstablishmentRollSummary' + +export const prisonEstablishmentRollSummaryMock: EstablishmentRollSummary = { + prisonId: 'LEI', + numUnlockRollToday: 20, + numArrivedToday: 30, + numOutToday: 40, + numCurrentPopulation: 50, +} diff --git a/server/mocks/rollCountMock.ts b/server/mocks/rollCountMock.ts deleted file mode 100644 index 1c07d0d..0000000 --- a/server/mocks/rollCountMock.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { BlockRollCount } from '../data/interfaces/blockRollCount' - -export const assignedRollCountMock: BlockRollCount[] = [ - { - currentlyInCell: 900, - outOfLivingUnits: 0, - livingUnitId: 1, - fullLocationPath: 'CKI-A', - locationCode: 'A', - livingUnitDesc: 'A', - bedsInUse: 76, - currentlyOut: 5, - operationalCapacity: 60, - netVacancies: -16, - maximumCapacity: 97, - availablePhysical: 21, - outOfOrder: 0, - }, - { - currentlyInCell: 33, - outOfLivingUnits: 0, - livingUnitId: 2, - fullLocationPath: 'CKI-B', - locationCode: 'B', - livingUnitDesc: 'B', - bedsInUse: 64, - currentlyOut: 0, - operationalCapacity: 63, - netVacancies: -1, - maximumCapacity: 127, - availablePhysical: 63, - outOfOrder: 0, - }, - { - currentlyInCell: 45, - outOfLivingUnits: 0, - livingUnitId: 3, - fullLocationPath: 'CKI-B', - locationCode: 'C', - livingUnitDesc: 'C', - bedsInUse: 64, - currentlyOut: 0, - operationalCapacity: 63, - netVacancies: -1, - maximumCapacity: 127, - availablePhysical: 63, - outOfOrder: 0, - }, - { - currentlyInCell: 7, - outOfLivingUnits: 0, - livingUnitId: 4, - fullLocationPath: 'CKI-B', - locationCode: 'D', - livingUnitDesc: 'D', - bedsInUse: 64, - currentlyOut: 0, - operationalCapacity: 63, - netVacancies: -1, - maximumCapacity: 127, - availablePhysical: 63, - outOfOrder: 0, - }, - { - currentlyInCell: 15, - outOfLivingUnits: 0, - livingUnitId: 5, - fullLocationPath: 'CKI-B', - locationCode: 'E', - livingUnitDesc: 'E', - bedsInUse: 64, - currentlyOut: 0, - operationalCapacity: 63, - netVacancies: -1, - maximumCapacity: 127, - availablePhysical: 63, - outOfOrder: 0, - }, -] - -export const unassignedRollCountMock: BlockRollCount[] = [ - { - currentlyInCell: 7, - outOfLivingUnits: 0, - livingUnitId: 10, - fullLocationPath: 'CKI-COURT', - locationCode: 'COURT', - livingUnitDesc: 'COURT', - bedsInUse: 4, - currentlyOut: 4, - maximumCapacity: 50, - availablePhysical: 46, - outOfOrder: 0, - }, - { - currentlyInCell: 4, - outOfLivingUnits: 0, - livingUnitId: 11, - fullLocationPath: 'CKI-COURT', - locationCode: 'COURT', - livingUnitDesc: 'COURT', - bedsInUse: 4, - currentlyOut: 4, - maximumCapacity: 50, - availablePhysical: 46, - outOfOrder: 0, - }, - { - currentlyInCell: 12, - outOfLivingUnits: 0, - livingUnitId: 12, - fullLocationPath: 'CKI-COURT', - locationCode: 'COURT', - livingUnitDesc: 'COURT', - bedsInUse: 4, - currentlyOut: 4, - maximumCapacity: 50, - availablePhysical: 46, - outOfOrder: 0, - }, -] diff --git a/server/mocks/staffRolesMock.ts b/server/mocks/staffRolesMock.ts deleted file mode 100644 index a58f9c4..0000000 --- a/server/mocks/staffRolesMock.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { StaffRole } from '../data/interfaces/staffRole' - -// eslint-disable-next-line import/prefer-default-export -export const mockStaffRoles: StaffRole[] = [ - { role: 'KW', roleDescription: 'Key worker' }, - { role: 'EX', roleDescription: 'Example' }, -] diff --git a/server/mocks/todayDataMock.ts b/server/mocks/todayDataMock.ts deleted file mode 100644 index c83aa2c..0000000 --- a/server/mocks/todayDataMock.ts +++ /dev/null @@ -1,8 +0,0 @@ -// eslint-disable-next-line import/prefer-default-export -export const todayDataMock = { - unlockRollCount: 1015, - currentPopulationCount: 1023, - inTodayCount: 17, - outTodayCount: 9, - todayLastUpdated: '2023-07-20T12:45', -} diff --git a/server/routes/index.ts b/server/routes/index.ts index cc05b80..2f1e4a0 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -20,11 +20,7 @@ export default function routes(services: Services): Router { handlers.map(handler => asyncMiddleware(handler)), ) - const homepageController = new HomepageController( - services.homepageService, - services.todayCache, - services.contentfulService, - ) + const homepageController = new HomepageController(services.contentfulService, services.establishmentRollService) get('/', homepageController.displayHomepage()) post('/search', homepageController.search()) diff --git a/server/services/establishmentRollService.test.ts b/server/services/establishmentRollService.test.ts index 765f43e..86479d2 100644 --- a/server/services/establishmentRollService.test.ts +++ b/server/services/establishmentRollService.test.ts @@ -3,6 +3,8 @@ import prisonApiClientMock from '../test/mocks/prisonApiClientMock' import { prisonRollCountMock } from '../mocks/prisonRollCountMock' import { prisonRollCountForWingNoSpurMock } from '../mocks/prisonRollCountForWingNoSpurMock' import { prisonRollCountForWingWithSpurMock } from '../mocks/prisonRollCountForWingWithSpurMock' +import EstablishmentRollSummary from './interfaces/establishmentRollService/EstablishmentRollSummary' +import { prisonEstablishmentRollSummaryMock } from '../mocks/prisonRollCountSummaryMock' describe('establishmentRollService', () => { let establishmentRollService: EstablishmentRollService @@ -163,4 +165,17 @@ describe('establishmentRollService', () => { }) }) }) + + describe('getEstablishmentRollSummary', () => { + it('should call the prisonApiClient with the correct parameters', async () => { + await establishmentRollService.getEstablishmentRollSummary('token', 'LEI') + expect(prisonApiClientMock.getPrisonRollCountSummary).toBeCalledWith('LEI') + }) + + it('should return the data from the API', async () => { + prisonApiClientMock.getPrisonRollCountSummary = jest.fn().mockResolvedValue(prisonEstablishmentRollSummaryMock) + const establishmentRollSummary = await establishmentRollService.getEstablishmentRollSummary('token', 'LEI') + expect(establishmentRollSummary).toEqual(prisonEstablishmentRollSummaryMock) + }) + }) }) diff --git a/server/services/establishmentRollService.ts b/server/services/establishmentRollService.ts index 0b26536..316720d 100644 --- a/server/services/establishmentRollService.ts +++ b/server/services/establishmentRollService.ts @@ -1,6 +1,7 @@ import { RestClientBuilder } from '../data' import { PrisonApiClient } from '../data/interfaces/prisonApiClient' import EstablishmentRollCount from './interfaces/establishmentRollService/EstablishmentRollCount' +import EstablishmentRollSummary from './interfaces/establishmentRollService/EstablishmentRollSummary' export default class EstablishmentRollService { constructor(private readonly prisonApiClientBuilder: RestClientBuilder) {} @@ -52,4 +53,9 @@ export default class EstablishmentRollService { cellRollCounts: landing.subLocations, } } + + getEstablishmentRollSummary(clientToken: string, caseLoadId: string): Promise { + const prisonApi = this.prisonApiClientBuilder(clientToken) + return prisonApi.getPrisonRollCountSummary(caseLoadId) + } } diff --git a/server/services/homepageService.test.ts b/server/services/homepageService.test.ts deleted file mode 100644 index 1a38840..0000000 --- a/server/services/homepageService.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { assignedRollCountMock, unassignedRollCountMock } from '../mocks/rollCountMock' -import { movementsMock } from '../mocks/movementsMock' -import HomepageService from './homepageService' -import { todayDataMock } from '../mocks/todayDataMock' -import KeyWorkerApiRestClient from '../data/keyWorkerApiClient' -import { RestClientBuilder } from '../data' -import { WhereAboutsApiClient } from '../data/interfaces/whereAboutsApiClient' -import { PrisonApiClient } from '../data/interfaces/prisonApiClient' -import prisonApiClientMock from '../test/mocks/prisonApiClientMock' - -jest.mock('../data/prisonApiClient') - -const token = 'some token' -const activeCaseLoadId = 'LEI' - -describe('Homepage service', () => { - let service: HomepageService - let prisonApiClient: PrisonApiClient - let whereAboutsApiClient: RestClientBuilder - let keyWorkerApiClient: RestClientBuilder - - describe('getTodaySection', () => { - beforeEach(() => { - prisonApiClient = { - ...prisonApiClientMock, - getRollCount: jest.fn(async (_prisonId: string, { unassigned } = {}) => { - if (unassigned) { - return unassignedRollCountMock - } - return assignedRollCountMock - }), - } - prisonApiClient.getMovements = jest.fn(async prisonId => { - if (prisonId) return movementsMock - return movementsMock - }) - - service = new HomepageService(() => prisonApiClient, whereAboutsApiClient, keyWorkerApiClient) - }) - - it('should return today data', async () => { - const todayData = await service.getTodaySection(token, activeCaseLoadId) - - expect(prisonApiClient.getRollCount).toHaveBeenCalledWith(activeCaseLoadId) - expect(prisonApiClient.getRollCount).toHaveBeenCalledWith(activeCaseLoadId, { unassigned: true }) - expect(prisonApiClient.getMovements).toHaveBeenCalled() - expect(todayData).toEqual({ - ...todayDataMock, - todayLastUpdated: expect.stringContaining(new Date().toISOString().slice(0, -5)), - }) - }) - - it('Should add people outside of the living unit to the totals', async () => { - const assignedRollCountWithLivingUnits = assignedRollCountMock.map(i => ({ ...i, outOfLivingUnits: 10 })) - const unassignedRollCountWithLivingUnits = unassignedRollCountMock.map(i => ({ ...i, outOfLivingUnits: 10 })) - prisonApiClient.getRollCount = jest.fn(async (_prisonId: string, { unassigned } = {}) => { - if (unassigned) { - return unassignedRollCountWithLivingUnits - } - return assignedRollCountWithLivingUnits - }) - const todayData = await service.getTodaySection(token, activeCaseLoadId) - expect(todayData.unlockRollCount).toEqual(1095) - expect(todayData.currentPopulationCount).toEqual(1103) - }) - }) -}) diff --git a/server/services/homepageService.ts b/server/services/homepageService.ts deleted file mode 100644 index 38fa679..0000000 --- a/server/services/homepageService.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { PrisonApiClient } from '../data/interfaces/prisonApiClient' -import { RestClientBuilder } from '../data' -import { WhereAboutsApiClient } from '../data/interfaces/whereAboutsApiClient' -import { KeyWorkerApiClient } from '../data/interfaces/keyWorkerApiClient' - -export default class HomepageService { - constructor( - private readonly prisonApiClientBuilder: RestClientBuilder, - private readonly whereAboutsApiClientBuilder: RestClientBuilder, - private readonly keyWorkerApiClientBuilder: RestClientBuilder, - ) {} - - public async getTodaySection(clientToken: string, activeCaseLoadId: string) { - const [assignedRollCount, unassignedRollCount, movements] = await Promise.all([ - this.prisonApiClientBuilder(clientToken).getRollCount(activeCaseLoadId), - this.prisonApiClientBuilder(clientToken).getRollCount(activeCaseLoadId, { unassigned: true }), - this.prisonApiClientBuilder(clientToken).getMovements(activeCaseLoadId), - ]) - - const populationCount = - assignedRollCount.reduce((total, block) => total + block.currentlyInCell + block.outOfLivingUnits, 0) + - unassignedRollCount.reduce((total, block) => total + block.currentlyInCell + block.outOfLivingUnits, 0) - - return { - unlockRollCount: populationCount - movements.in + movements.out, - currentPopulationCount: populationCount, - inTodayCount: movements.in, - outTodayCount: movements.out, - todayLastUpdated: new Date().toISOString(), - } - } - - public getWhereaboutsConfig(clientToken: string, activeCaseLoadId: string) { - return this.whereAboutsApiClientBuilder(clientToken).getWhereaboutsConfig(activeCaseLoadId) - } - - public getPrisonMigrationStatus(clientToken: string, activeCaseLoadId: string) { - return this.keyWorkerApiClientBuilder(clientToken).getPrisonMigrationStatus(activeCaseLoadId) - } - - public getStaffRoles(clientToken: string, activeCaseLoadId: string, staffId: number) { - return this.prisonApiClientBuilder(clientToken).getStaffRoles(staffId, activeCaseLoadId) - } -} diff --git a/server/services/index.ts b/server/services/index.ts index 376d51d..63893a9 100644 --- a/server/services/index.ts +++ b/server/services/index.ts @@ -1,8 +1,6 @@ import { ApolloClient, InMemoryCache } from '@apollo/client/core' import { dataAccess } from '../data' import UserService from './userService' -import HomepageService from './homepageService' -import HmppsCache from '../middleware/hmppsCache' import config from '../config' import ContentfulService from './contentfulService' import EstablishmentRollService from './establishmentRollService' @@ -10,21 +8,9 @@ import MovementsService from './movementsService' import LocationService from './locationsService' export const services = () => { - const { - prisonApiClientBuilder, - whereAboutsApiClientBuilder, - keyWorkerApiClientBuilder, - prisonerSearchApiClientBuilder, - applicationInfo, - } = dataAccess + const { prisonApiClientBuilder, prisonerSearchApiClientBuilder, applicationInfo } = dataAccess - const todayCache = new HmppsCache(config.todayCacheTTL) const userService = new UserService(prisonApiClientBuilder) - const homepageService = new HomepageService( - prisonApiClientBuilder, - whereAboutsApiClientBuilder, - keyWorkerApiClientBuilder, - ) const establishmentRollService = new EstablishmentRollService(prisonApiClientBuilder) const movementsService = new MovementsService(prisonApiClientBuilder, prisonerSearchApiClientBuilder) const locationsService = new LocationService(prisonApiClientBuilder) @@ -49,8 +35,6 @@ export const services = () => { dataAccess, applicationInfo, userService, - homepageService, - todayCache, contentfulService, establishmentRollService, movementsService, diff --git a/server/services/interfaces/establishmentRollService/EstablishmentRollSummary.ts b/server/services/interfaces/establishmentRollService/EstablishmentRollSummary.ts new file mode 100644 index 0000000..63ef0b3 --- /dev/null +++ b/server/services/interfaces/establishmentRollService/EstablishmentRollSummary.ts @@ -0,0 +1,7 @@ +export default interface EstablishmentRollSummary { + prisonId: string + numUnlockRollToday: number + numArrivedToday: number + numOutToday: number + numCurrentPopulation: number +} diff --git a/server/test/mocks/prisonApiClientMock.ts b/server/test/mocks/prisonApiClientMock.ts index 5134f44..1fdfded 100644 --- a/server/test/mocks/prisonApiClientMock.ts +++ b/server/test/mocks/prisonApiClientMock.ts @@ -3,10 +3,8 @@ import { PrisonApiClient } from '../../data/interfaces/prisonApiClient' const prisonApiClientMock: PrisonApiClient = { getUserCaseLoads: jest.fn(), getUserLocations: jest.fn(), - getRollCount: jest.fn(), getAttributesForLocation: jest.fn(), getMovements: jest.fn(), - getStaffRoles: jest.fn(), setActiveCaseload: jest.fn(), getLocation: jest.fn(), getMovementsIn: jest.fn(), @@ -21,6 +19,7 @@ const prisonApiClientMock: PrisonApiClient = { getPrisonersCurrentlyOutOfPrison: jest.fn(), getPrisonRollCount: jest.fn(), getPrisonRollCountForLocation: jest.fn(), + getPrisonRollCountSummary: jest.fn(), } export default prisonApiClientMock diff --git a/server/views/partials/homepage/today.njk b/server/views/partials/homepage/today.njk index 973268f..06dc1bb 100644 --- a/server/views/partials/homepage/today.njk +++ b/server/views/partials/homepage/today.njk @@ -1,30 +1,29 @@

Today in {{ user.activeCaseLoad.description }}

-

Last updated at {{ todayLastUpdated | formatDateTime({ order: 'time-date', separator: 'on', style: 'long' }) }}

Today's unlock roll

-
{{ unlockRollCount }}
+
{{ todayData.numUnlockRollToday }}

Current population

-
{{ currentPopulationCount }}
+
{{ todayData.numCurrentPopulation }}

Arrived today

-
{{ inTodayCount }}
+
{{ todayData.numArrivedToday }}

Out today

-
{{ outTodayCount }}
+
{{ todayData.numOutToday }}