Skip to content

Commit c9ea486

Browse files
committed
add prison api client
1 parent f1185db commit c9ea486

File tree

10 files changed

+139
-10
lines changed

10 files changed

+139
-10
lines changed

assets/js/index.js

+35
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,38 @@ import * as mojFrontend from '@ministryofjustice/frontend'
33

44
govukFrontend.initAll()
55
mojFrontend.initAll()
6+
7+
document.addEventListener('DOMContentLoaded', function initPrisonerLookup() {
8+
const findPrisonerButton = document.getElementById('prisoner-number-lookup')
9+
const prisonerNumberInput = document.getElementById('prison-number')
10+
const prisonerNameInput = document.getElementById('prisoner-name')
11+
const prisonerNameDisplay = document.getElementById('prisoner-name-display')
12+
13+
async function handlePrisonerLookup(event) {
14+
event.preventDefault()
15+
16+
const prisonNumber = prisonerNumberInput.value.trim()
17+
if (!prisonNumber) {
18+
prisonerNameDisplay.innerText = 'Prisoner name: Not found'
19+
return
20+
}
21+
22+
try {
23+
const response = await fetch(`/log/prisoner-details/find?prisonNumber=${encodeURIComponent(prisonNumber)}`)
24+
const data = await response.json()
25+
26+
if (response.ok) {
27+
prisonerNameInput.value = data.prisonerName
28+
prisonerNameDisplay.innerText = `Prisoner name: ${data.prisonerName}`
29+
} else {
30+
prisonerNameInput.value = ''
31+
prisonerNameDisplay.innerText = 'Prisoner name: Not found'
32+
}
33+
} catch (e) {
34+
prisonerNameInput.value = ''
35+
prisonerNameDisplay.innerText = 'Prisoner name: Not found'
36+
}
37+
}
38+
39+
findPrisonerButton.addEventListener('click', handlePrisonerLookup)
40+
})

server/config.ts

+9
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ export default {
9393
agent: new AgentConfig(Number(get('TOKEN_VERIFICATION_API_TIMEOUT_RESPONSE', 5000))),
9494
enabled: get('TOKEN_VERIFICATION_ENABLED', 'false') === 'true',
9595
},
96+
prison: {
97+
url: get('PRISON_API_URL', 'http://localhost:8080', requiredInProduction),
98+
healthPath: '/health/ping',
99+
timeout: {
100+
response: Number(get('PRISONER_DETAILS_API_TIMEOUT_RESPONSE', 10000)),
101+
deadline: Number(get('PRISONER_DETAILS_API_TIMEOUT_DEADLINE', 10000)),
102+
},
103+
agent: new AgentConfig(Number(get('PRISONER_DETAILS_API_TIMEOUT_RESPONSE', 10000))),
104+
},
96105
},
97106
sqs: {
98107
audit: auditConfig(),

server/data/api/prisonApiClient.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import logger from '../../../logger'
2+
import config, { ApiConfig } from '../../config'
3+
import RestClient from '../restClient'
4+
5+
export default class PrisonApiClient {
6+
public restClient: RestClient
7+
8+
constructor(token: string) {
9+
this.restClient = new RestClient('prisonApiClient', config.apis.prison as ApiConfig, token)
10+
}
11+
12+
async getPrisonerByPrisonNumber(prisonNumber: string): Promise<{ firstName: string; lastName: string } | null> {
13+
try {
14+
return await this.restClient.get({
15+
path: `/api/prisoners/${prisonNumber}`,
16+
})
17+
} catch (error) {
18+
logger.error(`Error fetching prisoner`, error)
19+
return null
20+
}
21+
}
22+
}

server/data/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import RedisTokenStore from './tokenStore/redisTokenStore'
1616
import InMemoryTokenStore from './tokenStore/inMemoryTokenStore'
1717
import config from '../config'
1818
import HmppsAuditClient from './hmppsAuditClient'
19+
import PrisonApiClient from './api/prisonApiClient'
1920

2021
type RestClientBuilder<T> = (token: string) => T
2122

@@ -25,8 +26,9 @@ export const dataAccess = () => ({
2526
config.redis.enabled ? new RedisTokenStore(createRedisClient()) : new InMemoryTokenStore(),
2627
),
2728
hmppsAuditClient: new HmppsAuditClient(config.sqs.audit),
29+
prisonApiClientBuilder: ((token: string) => new PrisonApiClient(token)) as RestClientBuilder<PrisonApiClient>,
2830
})
2931

3032
export type DataAccess = ReturnType<typeof dataAccess>
3133

32-
export { HmppsAuthClient, RestClientBuilder, HmppsAuditClient }
34+
export { HmppsAuthClient, RestClientBuilder, HmppsAuditClient, PrisonApiClient }

server/routes/applications/index.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,15 @@ import AuditService, { Page } from '../../services/auditService'
44
import applicationTypeRoutes from './applicationTypeRoutes'
55
import prisonerDetailsRoutes from './prisonerDetailsRoutes'
66
import swapVosPinCreditDetailsRoutes from './swapVosPinCreditDetailsRoutes'
7+
import PrisonService from '../../services/prisonService'
78

8-
export default function applicationsRoutes({ auditService }: { auditService: AuditService }): Router {
9+
export default function applicationsRoutes({
10+
auditService,
11+
prisonService,
12+
}: {
13+
auditService: AuditService
14+
prisonService: PrisonService
15+
}): Router {
916
const router = Router()
1017

1118
router.get(
@@ -50,7 +57,7 @@ export default function applicationsRoutes({ auditService }: { auditService: Aud
5057
)
5158

5259
router.use(applicationTypeRoutes({ auditService }))
53-
router.use(prisonerDetailsRoutes({ auditService }))
60+
router.use(prisonerDetailsRoutes({ auditService, prisonService }))
5461
router.use(swapVosPinCreditDetailsRoutes({ auditService }))
5562

5663
return router

server/routes/applications/prisonerDetailsRoutes.ts

+31-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@ import { Request, Response, Router } from 'express'
22
import asyncMiddleware from '../../middleware/asyncMiddleware'
33
import AuditService, { Page } from '../../services/auditService'
44
import { updateSessionData } from '../../utils/session'
5+
import PrisonService from '../../services/prisonService'
56

6-
export default function prisonerDetailsRoutes({ auditService }: { auditService: AuditService }): Router {
7+
export default function prisonerDetailsRoutes({
8+
auditService,
9+
prisonService,
10+
}: {
11+
auditService: AuditService
12+
prisonService: PrisonService
13+
}): Router {
714
const router = Router()
815

916
router.get(
@@ -25,6 +32,29 @@ export default function prisonerDetailsRoutes({ auditService }: { auditService:
2532
}),
2633
)
2734

35+
router.get(
36+
'/log/prisoner-details/find',
37+
asyncMiddleware(async (req: Request, res: Response) => {
38+
const { prisonNumber } = req.query
39+
40+
if (!prisonNumber) {
41+
res.status(400).json({ error: 'Prison number is required' })
42+
return
43+
}
44+
45+
const prisoner = await prisonService.getPrisonerByPrisonNumber(prisonNumber.toString())
46+
47+
if (!prisoner) {
48+
res.status(404).json({ error: 'Prisoner not found' })
49+
return
50+
}
51+
52+
res.json({
53+
prisonerName: `${prisoner.firstName} ${prisoner.lastName}`,
54+
})
55+
}),
56+
)
57+
2858
router.post(
2959
'/log/prisoner-details',
3060
asyncMiddleware(async (req: Request, res: Response) => {

server/routes/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import type { Services } from '../services'
44

55
import applicationsRoutes from './applications'
66

7-
export default function routes({ auditService }: Services): Router {
7+
export default function routes({ auditService, prisonService }: Services): Router {
88
const router = Router()
99

10-
router.use('/', applicationsRoutes({ auditService }))
10+
router.use('/', applicationsRoutes({ auditService, prisonService }))
1111

1212
return router
1313
}

server/services/index.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import { dataAccess } from '../data'
22
import AuditService from './auditService'
3+
import PrisonService from './prisonService'
34

45
export const services = () => {
5-
const { applicationInfo, hmppsAuditClient } = dataAccess()
6+
const { applicationInfo, hmppsAuditClient, hmppsAuthClient, prisonApiClientBuilder } = dataAccess()
67

78
const auditService = new AuditService(hmppsAuditClient)
9+
const prisonService = new PrisonService(hmppsAuthClient, prisonApiClientBuilder)
810

911
return {
1012
applicationInfo,
1113
auditService,
14+
prisonService,
1215
}
1316
}
1417

server/services/prisonService.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { HmppsAuthClient, RestClientBuilder } from '../data'
2+
import PrisonApiClient from '../data/api/prisonApiClient'
3+
4+
export default class PrisonService {
5+
constructor(
6+
private readonly hmppsAuthClient: HmppsAuthClient,
7+
private readonly prisonApiClientFactory: RestClientBuilder<PrisonApiClient>,
8+
) {}
9+
10+
async getPrisonerByPrisonNumber(prisonNumber: string): Promise<{ firstName: string; lastName: string }> {
11+
const token = await this.hmppsAuthClient.getSystemClientToken()
12+
const prisonApiClient = this.prisonApiClientFactory(token)
13+
14+
const prisoner = await prisonApiClient.getPrisonerByPrisonNumber(prisonNumber)
15+
return {
16+
firstName: prisoner.firstName,
17+
lastName: prisoner.lastName,
18+
}
19+
}
20+
}

server/views/pages/log/prisoner-details.njk

+4-3
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@
3636
</div>
3737

3838
{{ govukInsetText({
39-
text: "Prisoner name: Patel, Taj",
40-
classes: "govuk-!-margin-top-0"
39+
text: "Prisoner name: Not found",
40+
classes: "govuk-!-margin-top-0",
41+
attributes: { id: "prisoner-name-display" }
4142
}) }}
4243

43-
<input type="hidden" id="prisoner-name" name="prisonerName" value="Patel, Taj">
44+
<input type="hidden" id="prisoner-name" name="prisonerName" value="">
4445

4546
{{ mojDatePicker({
4647
id: "date",

0 commit comments

Comments
 (0)