@ministryofjustice/hmpps-connect-dps-components 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -159,6 +159,7 @@ This includes:
159
159
  - activeCaseLoad (the active caseload of the user)
160
160
  - caseLoads (all caseloads the user has access to)
161
161
  - services (information on services the user has access to used for global navigation)
162
+ - allocationJobResponsibilities (the allocation policy codes the user has the associated job responsibility for. Allocation policy codes are: `KEY_WORKER`, meaning the user is a key worker and `PERSONAL_OFFICER`, meaning the user is a personal officer.)
162
163
 
163
164
  This can be useful e.g. for when your service needs access to activeCaseLoad information to prevent extra calls to the
164
165
  api and takes advantage of the caching that the micro frontend api does.
@@ -170,7 +171,7 @@ optional middleware which populates:
170
171
  - `res.locals.user.caseLoads` with all case loads the user has access to
171
172
  - `res.locals.user.activeCaseLoad` with the active case load of the user
172
173
  - `res.locals.user.activeCaseLoadId` with the id of the active case load
173
-
174
+
174
175
  It uses the `sharedData` object if it is present and caches in `req.session` so that any subsequent routes that do not
175
176
  use the component middleware can still use the data. If there is no data in the cache, it will fall back to making a
176
177
  call to Prison API to retrieve the data using the user token.
@@ -186,6 +187,30 @@ Again there are a [number of options](./src/index.ts) available depending on you
186
187
  This middleware checks the `res.locals.user.authSource` so ensure that any mock auth data used in tests includes
187
188
  `auth_source: 'nomis'` in the response.
188
189
 
190
+ ### Populating res.locals.user with the shared allocation job responsibilities
191
+
192
+ This library also provides an optional middleware which populates:
193
+ - `res.locals.user.allocationJobResponsibilities` the allocation policy codes the user has the associated job responsibility for. Allocation policy codes are: `KEY_WORKER`, meaning the user is a key worker and `PERSONAL_OFFICER`, meaning the user is a personal officer.
194
+
195
+ Similar to shared case load data, it uses the `sharedData` object if it is present and caches in `req.session` so that any subsequent routes that do not
196
+ use the component middleware can still use the data. If there is no data in the cache, it will fall back to making a
197
+ call to Allocations API to retrieve the data using the user token.
198
+
199
+ To enable this, add the middleware after the component middleware as follows:
200
+
201
+ ```javascript
202
+ app.use(dpsComponents.retrieveAllocationJobResponsibilities({ logger }))
203
+ ```
204
+
205
+ This should go after `dpsComponents.retrieveCaseLoadData` so that `res.locals.user.activeCaseLoadId` will be populated.
206
+ It also requires `ALLOCATIONS_API_URL` to be configured in the environment variables.
207
+
208
+ Again there are a [number of options](./src/index.ts) available depending on your requirements.
209
+
210
+ This middleware checks the `res.locals.user.authSource` so ensure that any mock auth data used in tests includes
211
+ `auth_source: 'nomis'` in the response. It also checks the `res.locals.user.activeCaseLoadId`, which is required for retrieving allocation job responsibilities.
212
+
213
+
189
214
  ### Note
190
215
 
191
216
  In the event of a failure to retrieve the components, the package will populate the html fields with fallback components.
@@ -0,0 +1,3 @@
1
+ import { type RequestHandler } from 'express';
2
+ import CaseLoadOptions from './types/CaseLoadOptions';
3
+ export default function retrieveAllocationJobResponsibilities(options?: CaseLoadOptions): RequestHandler;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const allocationsApiClient_1 = __importDefault(require("./data/allocationsApi/allocationsApiClient"));
7
+ const config_1 = __importDefault(require("./config"));
8
+ const defaultOptions = {
9
+ logger: console,
10
+ timeoutOptions: { response: 2500, deadline: 2500 },
11
+ };
12
+ function retrieveAllocationJobResponsibilities(options) {
13
+ const { logger, timeoutOptions } = {
14
+ ...defaultOptions,
15
+ ...options,
16
+ };
17
+ if (!config_1.default.apis.allocationsApi.url)
18
+ throw new Error('Environment variable ALLOCATIONS_API_URL must be defined for this middleware to work correctly');
19
+ return async (req, res, next) => {
20
+ if (!req.session)
21
+ throw new Error('User session required in order to cache allocation job responsibilities');
22
+ if (!res.locals.user.token)
23
+ throw new Error('Caseload details needs to be populated before retrieving allocation job responsibilities. Please run retrieveCaseLoadData before retrieveAllocationJobResponsibilities.');
24
+ if (res.locals.user && res.locals.user.authSource === 'nomis') {
25
+ try {
26
+ // Update cache with values from res.feComponents.sharedData if present
27
+ if (res.locals.feComponents && res.locals.feComponents.sharedData) {
28
+ req.session.allocationJobResponsibilities = res.locals.feComponents.sharedData.allocationJobResponsibilities;
29
+ }
30
+ // If cache is empty, fetch data from Prison API
31
+ if (!req.session.allocationJobResponsibilities) {
32
+ logger.info(`Falling back to Allocations API to retrieve job responsibilities for: ${res.locals.user.username}`);
33
+ const allocationPolicies = await allocationsApiClient_1.default.getStaffAllocationPolicies(res.locals.user, timeoutOptions, logger);
34
+ req.session.allocationJobResponsibilities = allocationPolicies.policies;
35
+ }
36
+ // Populate res.locals.user with values from cache
37
+ res.locals.user.allocationJobResponsibilities = req.session.allocationJobResponsibilities;
38
+ }
39
+ catch (error) {
40
+ logger.error(error, `Failed to retrieve allocation job responsibilities for: ${res.locals.user.username}`);
41
+ return next(error);
42
+ }
43
+ }
44
+ return next();
45
+ };
46
+ }
47
+ exports.default = retrieveAllocationJobResponsibilities;
48
+ //# sourceMappingURL=allocationService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allocationService.js","sourceRoot":"","sources":["../src/allocationService.ts"],"names":[],"mappings":";;;;;AAEA,sGAA6E;AAC7E,sDAA6B;AAE7B,MAAM,cAAc,GAAoB;IACtC,MAAM,EAAE,OAAO;IACf,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;CACnD,CAAA;AAED,SAAwB,qCAAqC,CAAC,OAAyB;IACrF,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG;QACjC,GAAG,cAAc;QACjB,GAAG,OAAO;KACX,CAAA;IAED,IAAI,CAAC,gBAAM,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG;QACjC,MAAM,IAAI,KAAK,CAAC,gGAAgG,CAAC,CAAA;IAEnH,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC9B,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAA;QAC5G,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK;YACxB,MAAM,IAAI,KAAK,CACb,yKAAyK,CAC1K,CAAA;QAEH,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;YAC9D,IAAI,CAAC;gBACH,uEAAuE;gBACvE,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;oBAClE,GAAG,CAAC,OAAO,CAAC,6BAA6B,GAAG,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,6BAA6B,CAAA;gBAC9G,CAAC;gBAED,gDAAgD;gBAChD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,6BAA6B,EAAE,CAAC;oBAC/C,MAAM,CAAC,IAAI,CACT,yEAAyE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CACpG,CAAA;oBACD,MAAM,kBAAkB,GAAG,MAAM,8BAAoB,CAAC,0BAA0B,CAC9E,GAAG,CAAC,MAAM,CAAC,IAAI,EACf,cAAc,EACd,MAAM,CACP,CAAA;oBACD,GAAG,CAAC,OAAO,CAAC,6BAA6B,GAAG,kBAAkB,CAAC,QAAQ,CAAA;gBACzE,CAAC;gBAED,kDAAkD;gBAClD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,GAAG,GAAG,CAAC,OAAO,CAAC,6BAA6B,CAAA;YAC3F,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,2DAA2D,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;gBAC1G,OAAO,IAAI,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;QACH,CAAC;QAED,OAAO,IAAI,EAAE,CAAA;IACf,CAAC,CAAA;AACH,CAAC;AA9CD,wDA8CC"}
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const prisonApiClient_1 = __importDefault(require("./data/prisonApi/prisonApiClient"));
7
+ const config_1 = __importDefault(require("./config"));
7
8
  const defaultOptions = {
8
9
  logger: console,
9
10
  timeoutOptions: { response: 2500, deadline: 2500 },
@@ -13,6 +14,8 @@ function retrieveCaseLoadData(caseLoadOptions) {
13
14
  ...defaultOptions,
14
15
  ...caseLoadOptions,
15
16
  };
17
+ if (!config_1.default.apis.prisonApi.url)
18
+ throw new Error('Environment variable PRISON_API_URL must be defined for this middleware to work correctly');
16
19
  return async (req, res, next) => {
17
20
  var _a;
18
21
  if (!req.session)
@@ -1 +1 @@
1
- {"version":3,"file":"caseLoadService.js","sourceRoot":"","sources":["../src/caseLoadService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"caseLoadService.js","sourceRoot":"","sources":["../src/caseLoadService.ts"],"names":[],"mappings":"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"}
@@ -10,21 +10,30 @@ const defaultOptions = {
10
10
  logger: console,
11
11
  timeoutOptions: { response: 2500, deadline: 2500 },
12
12
  includeSharedData: false,
13
+ useFallbacksByDefault: false,
13
14
  };
14
15
  function getFrontendComponents(requestOptions) {
15
- const { logger, timeoutOptions, includeSharedData } = {
16
+ const { logger, timeoutOptions, includeSharedData, useFallbacksByDefault } = {
16
17
  ...defaultOptions,
17
18
  ...requestOptions,
18
19
  };
19
20
  return async (_req, res, next) => {
20
- if (!res.locals.user) {
21
- logger.info('Using logged out user header');
21
+ const useFallbacks = (user) => {
22
22
  res.locals.feComponents = {
23
- header: (0, fallbacks_1.getFallbackHeader)(null, requestOptions),
24
- footer: (0, fallbacks_1.getFallbackFooter)(null, requestOptions),
23
+ header: (0, fallbacks_1.getFallbackHeader)(user, requestOptions),
24
+ footer: (0, fallbacks_1.getFallbackFooter)(user, requestOptions),
25
25
  cssIncludes: [],
26
26
  jsIncludes: [],
27
27
  };
28
+ };
29
+ if (!res.locals.user) {
30
+ logger.info('Using fallback frontend components when no user in context');
31
+ useFallbacks(null);
32
+ return next();
33
+ }
34
+ if (useFallbacksByDefault) {
35
+ logger.info('Using fallback frontend components by default');
36
+ useFallbacks(res.locals.user);
28
37
  return next();
29
38
  }
30
39
  try {
@@ -43,12 +52,7 @@ function getFrontendComponents(requestOptions) {
43
52
  }
44
53
  catch (error) {
45
54
  logger.error('Failed to retrieve front end components, using fallbacks');
46
- res.locals.feComponents = {
47
- header: (0, fallbacks_1.getFallbackHeader)(res.locals.user, requestOptions),
48
- footer: (0, fallbacks_1.getFallbackFooter)(res.locals.user, requestOptions),
49
- cssIncludes: [],
50
- jsIncludes: [],
51
- };
55
+ useFallbacks(res.locals.user);
52
56
  return next();
53
57
  }
54
58
  };
@@ -1 +1 @@
1
- {"version":3,"file":"componentsService.js","sourceRoot":"","sources":["../src/componentsService.ts"],"names":[],"mappings":";;;;;AACA,gGAAuE;AACvE,iDAAwE;AAExE,kEAAyC;AAEzC,MAAM,cAAc,GAA4B;IAC9C,MAAM,EAAE,OAAO;IACf,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAClD,iBAAiB,EAAE,KAAK;CACzB,CAAA;AAED,SAAwB,qBAAqB,CAAC,cAA+B;IAC3E,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,iBAAiB,EAAE,GAAG;QACpD,GAAG,cAAc;QACjB,GAAG,cAAc;KAClB,CAAA;IAED,OAAO,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC/B,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAA;YAC3C,GAAG,CAAC,MAAM,CAAC,YAAY,GAAG;gBACxB,MAAM,EAAE,IAAA,6BAAiB,EAAC,IAAI,EAAE,cAAc,CAAC;gBAC/C,MAAM,EAAE,IAAA,6BAAiB,EAAC,IAAI,EAAE,cAAc,CAAC;gBAC/C,WAAW,EAAE,EAAE;gBACf,UAAU,EAAE,EAAE;aACf,CAAA;YACD,OAAO,IAAI,EAAE,CAAA;QACf,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,4BAAkB,CAAC,aAAa,CACrE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EACrB,cAAc,EACd,MAAM,CACP,CAAA;YAED,GAAG,CAAC,MAAM,CAAC,YAAY,GAAG;gBACxB,MAAM,EAAE,MAAM,CAAC,IAAI;gBACnB,MAAM,EAAE,MAAM,CAAC,IAAI;gBACnB,WAAW,EAAE,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC;gBAC3C,UAAU,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC;aACzD,CAAA;YAED,IAAI,iBAAiB,EAAE,CAAC;gBACtB,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,GAAG,IAAI,CAAA;YAC3C,CAAC;YAED,IAAA,mBAAS,EAAC,GAAG,CAAC,CAAA;YAEd,OAAO,IAAI,EAAE,CAAA;QACf,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAA;YAExE,GAAG,CAAC,MAAM,CAAC,YAAY,GAAG;gBACxB,MAAM,EAAE,IAAA,6BAAiB,EAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC;gBAC1D,MAAM,EAAE,IAAA,6BAAiB,EAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC;gBAC1D,WAAW,EAAE,EAAE;gBACf,UAAU,EAAE,EAAE;aACf,CAAA;YAED,OAAO,IAAI,EAAE,CAAA;QACf,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AApDD,wCAoDC"}
1
+ {"version":3,"file":"componentsService.js","sourceRoot":"","sources":["../src/componentsService.ts"],"names":[],"mappings":";;;;;AACA,gGAAuE;AACvE,iDAAwE;AAExE,kEAAyC;AAGzC,MAAM,cAAc,GAA4B;IAC9C,MAAM,EAAE,OAAO;IACf,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAClD,iBAAiB,EAAE,KAAK;IACxB,qBAAqB,EAAE,KAAK;CAC7B,CAAA;AAED,SAAwB,qBAAqB,CAAC,cAA+B;IAC3E,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,GAAG;QAC3E,GAAG,cAAc;QACjB,GAAG,cAAc;KAClB,CAAA;IAED,OAAO,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC/B,MAAM,YAAY,GAAG,CAAC,IAAe,EAAE,EAAE;YACvC,GAAG,CAAC,MAAM,CAAC,YAAY,GAAG;gBACxB,MAAM,EAAE,IAAA,6BAAiB,EAAC,IAAI,EAAE,cAAc,CAAC;gBAC/C,MAAM,EAAE,IAAA,6BAAiB,EAAC,IAAI,EAAE,cAAc,CAAC;gBAC/C,WAAW,EAAE,EAAE;gBACf,UAAU,EAAE,EAAE;aACf,CAAA;QACH,CAAC,CAAA;QAED,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAA;YACzE,YAAY,CAAC,IAAI,CAAC,CAAA;YAClB,OAAO,IAAI,EAAE,CAAA;QACf,CAAC;QAED,IAAI,qBAAqB,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAA;YAC5D,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAC7B,OAAO,IAAI,EAAE,CAAA;QACf,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,4BAAkB,CAAC,aAAa,CACrE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EACrB,cAAc,EACd,MAAM,CACP,CAAA;YAED,GAAG,CAAC,MAAM,CAAC,YAAY,GAAG;gBACxB,MAAM,EAAE,MAAM,CAAC,IAAI;gBACnB,MAAM,EAAE,MAAM,CAAC,IAAI;gBACnB,WAAW,EAAE,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC;gBAC3C,UAAU,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC;aACzD,CAAA;YAED,IAAI,iBAAiB,EAAE,CAAC;gBACtB,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,GAAG,IAAI,CAAA;YAC3C,CAAC;YAED,IAAA,mBAAS,EAAC,GAAG,CAAC,CAAA;YAEd,OAAO,IAAI,EAAE,CAAA;QACf,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAA;YACxE,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAC7B,OAAO,IAAI,EAAE,CAAA;QACf,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAvDD,wCAuDC"}
package/dist/config.d.ts CHANGED
@@ -6,6 +6,9 @@ declare const _default: {
6
6
  prisonApi: {
7
7
  url: string;
8
8
  };
9
+ allocationsApi: {
10
+ url: string;
11
+ };
9
12
  };
10
13
  };
11
14
  export default _default;
package/dist/config.js CHANGED
@@ -20,6 +20,9 @@ exports.default = {
20
20
  prisonApi: {
21
21
  url: get('PRISON_API_URL', null),
22
22
  },
23
+ allocationsApi: {
24
+ url: get('ALLOCATIONS_API_URL', null),
25
+ },
23
26
  },
24
27
  };
25
28
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;AAAA,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAA;AAExD,SAAS,GAAG,CAAC,IAAY,EAAE,QAAgB,EAAE,OAAO,GAAG,EAAE,mBAAmB,EAAE,KAAK,EAAE;IACnF,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACrC,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAA;IACpB,CAAC;IACD,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC5E,OAAO,QAAQ,CAAA;IACjB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAA;AAC5C,CAAC;AAED,MAAM,oBAAoB,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAA;AAE1D,kBAAe;IACb,IAAI,EAAE;QACJ,YAAY,EAAE;YACZ,GAAG,EAAE,GAAG,CAAC,mBAAmB,EAAE,sBAAsB,EAAE,oBAAoB,CAAC;SAC5E;QACD,SAAS,EAAE;YACT,GAAG,EAAE,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC;SACjC;KACF;CACF,CAAA"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;AAAA,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAA;AAExD,SAAS,GAAG,CAAC,IAAY,EAAE,QAAgB,EAAE,OAAO,GAAG,EAAE,mBAAmB,EAAE,KAAK,EAAE;IACnF,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACrC,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAA;IACpB,CAAC;IACD,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC5E,OAAO,QAAQ,CAAA;IACjB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAA;AAC5C,CAAC;AAED,MAAM,oBAAoB,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAA;AAE1D,kBAAe;IACb,IAAI,EAAE;QACJ,YAAY,EAAE;YACZ,GAAG,EAAE,GAAG,CAAC,mBAAmB,EAAE,sBAAsB,EAAE,oBAAoB,CAAC;SAC5E;QACD,SAAS,EAAE;YACT,GAAG,EAAE,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC;SACjC;QACD,cAAc,EAAE;YACd,GAAG,EAAE,GAAG,CAAC,qBAAqB,EAAE,IAAI,CAAC;SACtC;KACF;CACF,CAAA"}
@@ -0,0 +1,10 @@
1
+ import type bunyan from 'bunyan';
2
+ import TimeoutOptions from '../../types/TimeoutOptions';
3
+ import { PrisonUser } from '../../types/HmppsUser';
4
+ import { AllocationJobResponsibility } from '../../types/AllocationJobResponsibility';
5
+ declare const _default: {
6
+ getStaffAllocationPolicies(user: PrisonUser, timeoutOptions: TimeoutOptions, log: bunyan | typeof console): Promise<{
7
+ policies: AllocationJobResponsibility[];
8
+ }>;
9
+ };
10
+ export default _default;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const superagent_1 = __importDefault(require("superagent"));
7
+ const config_1 = __importDefault(require("../../config"));
8
+ exports.default = {
9
+ async getStaffAllocationPolicies(user, timeoutOptions, log) {
10
+ const result = await superagent_1.default
11
+ .get(`${config_1.default.apis.allocationsApi.url}/prisons/${user.activeCaseLoadId}/staff/${user.userId}/job-classifications`)
12
+ .agent(this.agent)
13
+ .retry(2, (err, _res) => {
14
+ if (err)
15
+ log.info(`Retry handler found API error with ${err.code} ${err.message}`);
16
+ return undefined; // retry handler only for logging retries, not to influence retry logic
17
+ })
18
+ .auth(user.token, { type: 'bearer' })
19
+ .timeout(timeoutOptions);
20
+ return result.body;
21
+ },
22
+ };
23
+ //# sourceMappingURL=allocationsApiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allocationsApiClient.js","sourceRoot":"","sources":["../../../src/data/allocationsApi/allocationsApiClient.ts"],"names":[],"mappings":";;;;;AACA,4DAAmC;AAEnC,0DAAiC;AAIjC,kBAAe;IACb,KAAK,CAAC,0BAA0B,CAC9B,IAAgB,EAChB,cAA8B,EAC9B,GAA4B;QAE5B,MAAM,MAAM,GAAG,MAAM,oBAAU;aAC5B,GAAG,CACF,GAAG,gBAAM,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,YAAY,IAAI,CAAC,gBAAgB,UAAU,IAAI,CAAC,MAAM,sBAAsB,CAC9G;aACA,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;aACjB,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YACtB,IAAI,GAAG;gBAAE,GAAG,CAAC,IAAI,CAAC,sCAAsC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;YAClF,OAAO,SAAS,CAAA,CAAC,uEAAuE;QAC1F,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;aACpC,OAAO,CAAC,cAAc,CAAC,CAAA;QAE1B,OAAO,MAAM,CAAC,IAAI,CAAA;IACpB,CAAC;CACF,CAAA"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import getPageComponents from './componentsService';
2
2
  import retrieveCaseLoadData from './caseLoadService';
3
+ import retrieveAllocationJobResponsibilities from './allocationService';
3
4
  declare const _default: {
4
5
  /**
5
6
  * Returns a request handler for adding header and footer frontend components to res.locals
@@ -16,6 +17,7 @@ declare const _default: {
16
17
  * @param requestOptions.logger - pass in the bunyen logger if you want to use it. Falls back to console if not provided
17
18
  * @param requestOptions.timeoutOptions - timeout object for superagent. Defaults to 2500ms
18
19
  * @param requestOptions.includeSharedData - adds sharedData to res.locals.feComponents if true. Contains data that the components have collected in order to render, including: activeCaseLoad, caseLoads and available services for user
20
+ * @param requestOptions.useFallbacksByDefault - if your service requires only the basic fallback header and footer to be used by default, set this to true, it will not attempt to fetch the components from the frontend components service
19
21
  */
20
22
  getPageComponents: typeof getPageComponents;
21
23
  /**
@@ -41,5 +43,25 @@ declare const _default: {
41
43
  * @param caseLoadOptions.timeoutOptions - timeout object for superagent. Defaults to 2500ms
42
44
  */
43
45
  retrieveCaseLoadData: typeof retrieveCaseLoadData;
46
+ /**
47
+ * Ensures that:
48
+ * - `res.locals.user.allocationJobResponsibilities`
49
+ * is set for NOMIS users (or will propagate an error). It will also attempt to cache in `req.session.allocationJobResponsibilities`
50
+ * (this is so that extra requests to Allocations API are not required for routes that do not need frontend components,
51
+ * such as image data, or if the frontend component API errors or is temporarily down).
52
+ *
53
+ * It will do the following in priority order, and will attempt the next if the previous fails:
54
+ *
55
+ * * Use values from `res.feComponents.sharedData` if present (and cache in `req.session`)
56
+ * * Use cached data from `req.session`
57
+ * * Fetch data from Allocations API as a fallback and cache in `req.session`
58
+ *
59
+ * Expects res.locals.user to be set up inline with the hmpps-template-typescript project
60
+ *
61
+ * @param caseLoadOptions - config object for request
62
+ * @param caseLoadOptions.logger - pass in the bunyen logger if you want to use it. Falls back to console if not provided
63
+ * @param caseLoadOptions.timeoutOptions - timeout object for superagent. Defaults to 2500ms
64
+ */
65
+ retrieveAllocationJobResponsibilities: typeof retrieveAllocationJobResponsibilities;
44
66
  };
45
67
  export default _default;
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const componentsService_1 = __importDefault(require("./componentsService"));
7
7
  const caseLoadService_1 = __importDefault(require("./caseLoadService"));
8
+ const allocationService_1 = __importDefault(require("./allocationService"));
8
9
  exports.default = {
9
10
  /**
10
11
  * Returns a request handler for adding header and footer frontend components to res.locals
@@ -21,6 +22,7 @@ exports.default = {
21
22
  * @param requestOptions.logger - pass in the bunyen logger if you want to use it. Falls back to console if not provided
22
23
  * @param requestOptions.timeoutOptions - timeout object for superagent. Defaults to 2500ms
23
24
  * @param requestOptions.includeSharedData - adds sharedData to res.locals.feComponents if true. Contains data that the components have collected in order to render, including: activeCaseLoad, caseLoads and available services for user
25
+ * @param requestOptions.useFallbacksByDefault - if your service requires only the basic fallback header and footer to be used by default, set this to true, it will not attempt to fetch the components from the frontend components service
24
26
  */
25
27
  getPageComponents: componentsService_1.default,
26
28
  /**
@@ -46,5 +48,25 @@ exports.default = {
46
48
  * @param caseLoadOptions.timeoutOptions - timeout object for superagent. Defaults to 2500ms
47
49
  */
48
50
  retrieveCaseLoadData: caseLoadService_1.default,
51
+ /**
52
+ * Ensures that:
53
+ * - `res.locals.user.allocationJobResponsibilities`
54
+ * is set for NOMIS users (or will propagate an error). It will also attempt to cache in `req.session.allocationJobResponsibilities`
55
+ * (this is so that extra requests to Allocations API are not required for routes that do not need frontend components,
56
+ * such as image data, or if the frontend component API errors or is temporarily down).
57
+ *
58
+ * It will do the following in priority order, and will attempt the next if the previous fails:
59
+ *
60
+ * * Use values from `res.feComponents.sharedData` if present (and cache in `req.session`)
61
+ * * Use cached data from `req.session`
62
+ * * Fetch data from Allocations API as a fallback and cache in `req.session`
63
+ *
64
+ * Expects res.locals.user to be set up inline with the hmpps-template-typescript project
65
+ *
66
+ * @param caseLoadOptions - config object for request
67
+ * @param caseLoadOptions.logger - pass in the bunyen logger if you want to use it. Falls back to console if not provided
68
+ * @param caseLoadOptions.timeoutOptions - timeout object for superagent. Defaults to 2500ms
69
+ */
70
+ retrieveAllocationJobResponsibilities: allocationService_1.default,
49
71
  };
50
72
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,4EAAmD;AACnD,wEAAoD;AAEpD,kBAAe;IACb;;;;;;;;;;;;;;;OAeG;IACH,iBAAiB,EAAjB,2BAAiB;IAEjB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,oBAAoB,EAApB,yBAAoB;CACrB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,4EAAmD;AACnD,wEAAoD;AACpD,4EAAuE;AAEvE,kBAAe;IACb;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAiB,EAAjB,2BAAiB;IAEjB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,oBAAoB,EAApB,yBAAoB;IAEpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,qCAAqC,EAArC,2BAAqC;CACtC,CAAA"}
@@ -0,0 +1 @@
1
+ export type AllocationJobResponsibility = 'KEY_WORKER' | 'PERSONAL_OFFICER';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=AllocationJobResponsibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AllocationJobResponsibility.js","sourceRoot":"","sources":["../../src/types/AllocationJobResponsibility.ts"],"names":[],"mappings":""}
@@ -1,9 +1,11 @@
1
1
  import CaseLoad from './CaseLoad';
2
2
  import Service from './Service';
3
+ import { AllocationJobResponsibility } from './AllocationJobResponsibility';
3
4
  export default interface HeaderFooterSharedData {
4
5
  activeCaseLoad?: CaseLoad;
5
6
  caseLoads: CaseLoad[];
6
7
  services: Service[];
8
+ allocationJobResponsibilities: AllocationJobResponsibility[];
7
9
  }
8
10
  export interface ComponentsSharedData {
9
11
  header: HeaderFooterSharedData;
@@ -1,4 +1,5 @@
1
1
  import CaseLoad from './CaseLoad';
2
+ import { AllocationJobResponsibility } from './AllocationJobResponsibility';
2
3
  export type AuthSource = 'nomis' | 'delius' | 'external' | 'azuread';
3
4
  /**
4
5
  * These are the details that all user types share.
@@ -26,6 +27,7 @@ export interface PrisonUser extends BaseUser {
26
27
  caseLoads: CaseLoad[];
27
28
  activeCaseLoad?: CaseLoad;
28
29
  activeCaseLoadId?: string;
30
+ allocationJobResponsibilities?: AllocationJobResponsibility[];
29
31
  }
30
32
  /**
31
33
  * Probation users are those that have a user account in nDelius.
@@ -7,5 +7,6 @@ export default interface RequestOptions {
7
7
  environmentName?: 'DEV' | 'PRE-PRODUCTION' | 'PRODUCTION';
8
8
  logger?: bunyan | typeof console;
9
9
  includeSharedData?: boolean;
10
+ useFallbacksByDefault?: boolean;
10
11
  timeoutOptions?: TimeoutOptions;
11
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ministryofjustice/hmpps-connect-dps-components",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "A package to allow the inclusion of connect dps micro frontend components within dps applications",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -63,31 +63,31 @@
63
63
  "homepage": "https://github.com/ministryofjustice/hmpps-connect-dps-components#readme",
64
64
  "devDependencies": {
65
65
  "@types/bunyan": "^1.8.11",
66
- "@types/express": "^4.17.21",
66
+ "@types/express": "^4.17.22",
67
67
  "@types/jest": "^29.5.14",
68
68
  "@types/superagent": "^8.1.9",
69
- "@types/supertest": "^6.0.2",
69
+ "@types/supertest": "^6.0.3",
70
70
  "@typescript-eslint/eslint-plugin": "^6.21.0",
71
71
  "cheerio": "^1.0.0",
72
72
  "eslint": "^8.57.1",
73
73
  "eslint-config-airbnb-base": "^15.0.0",
74
74
  "eslint-config-prettier": "^9.1.0",
75
- "eslint-import-resolver-typescript": "^3.6.3",
75
+ "eslint-import-resolver-typescript": "^3.10.1",
76
76
  "eslint-plugin-cypress": "^2.15.2",
77
77
  "eslint-plugin-import": "^2.31.0",
78
78
  "eslint-plugin-no-only-tests": "^3.3.0",
79
- "eslint-plugin-prettier": "^5.2.1",
80
- "express": "^4.21.1",
81
- "govuk-frontend": "^5.7.1",
79
+ "eslint-plugin-prettier": "^5.4.0",
80
+ "express": "^4.21.2",
81
+ "govuk-frontend": "^5.10.1",
82
82
  "jest": "^29.7.0",
83
83
  "jest-html-reporter": "^3.10.2",
84
84
  "jest-junit": "^16.0.0",
85
85
  "nock": "^13.5.6",
86
- "supertest": "^7.0.0",
87
- "ts-jest": "^29.2.5"
86
+ "supertest": "^7.1.1",
87
+ "ts-jest": "^29.3.4"
88
88
  },
89
89
  "dependencies": {
90
- "@types/node": "^20.17.6",
90
+ "@types/node": "^20.17.48",
91
91
  "@types/nunjucks": "^3.2.6",
92
92
  "nunjucks": "^3.2.4",
93
93
  "superagent": "^9.0.2"