@7365admin1/core 3.48.1-staging.153 → 3.48.1-staging.154
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/.changeset/manpower-monitoring-site-scope.md +37 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/harness.mjs +21 -0
- package/test/e2e/manpower-monitoring-scope.e2e.test.mjs +486 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": minor
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the manpower monitoring settings routes to the site they belong to.
|
|
6
|
+
|
|
7
|
+
Every route on `/api/manpower-monitoring` carried `requireAuth` and nothing more,
|
|
8
|
+
so being signed in anywhere on the platform was enough to read another client's
|
|
9
|
+
shift pattern and alert email recipients, to re-time their late-check-in alert, or
|
|
10
|
+
to switch their monitoring off entirely — which silences the alert that tells a
|
|
11
|
+
client nobody turned up for a shift.
|
|
12
|
+
|
|
13
|
+
Five of the six now go through `requireSiteReach`, the rule `/api/vehicles`,
|
|
14
|
+
`/api/documents`, `/api/service-providers` and `/api/incident-reports` already
|
|
15
|
+
use:
|
|
16
|
+
|
|
17
|
+
- `POST /`, `GET /sites/:id/:serviceProviderId` and `POST /multiple` name a site
|
|
18
|
+
in the request; that site is checked before it is used. `POST /multiple`
|
|
19
|
+
upserts **by** each item's own `siteId`, so every item is checked before any of
|
|
20
|
+
them is written.
|
|
21
|
+
- `PUT /:id` names only a record, so the site is read off the **stored** row —
|
|
22
|
+
a `siteId` in the caller's own body cannot stand in for it.
|
|
23
|
+
- `GET /search` names no site at all and returned every client's row on one page.
|
|
24
|
+
It is narrowed after the read, the way the people and vehicle lookups are.
|
|
25
|
+
|
|
26
|
+
`requireSiteReach` matters here because the contracted agency that actually runs
|
|
27
|
+
these shifts holds no membership in the estate's organisation and reaches its own
|
|
28
|
+
site through `customer.sites`.
|
|
29
|
+
|
|
30
|
+
`GET /sites/active` is deliberately unchanged. It reads nothing from our database
|
|
31
|
+
— it authenticates to the external HRM Labs directory and returns that system's
|
|
32
|
+
own site tree — and the only web caller sends a hard-coded service provider id
|
|
33
|
+
rather than the signed-in one, so scoping it on that id would close the screen for
|
|
34
|
+
its real users. It needs a product decision, not a guard chosen here.
|
|
35
|
+
|
|
36
|
+
A settings row the caller cannot reach answers exactly as one that does not exist,
|
|
37
|
+
so site ids cannot be enumerated by watching the difference.
|
package/dist/index.d.ts
CHANGED
|
@@ -7893,6 +7893,7 @@ declare function useManpowerMonitoringRepo(): {
|
|
|
7893
7893
|
pageRange: string;
|
|
7894
7894
|
}>;
|
|
7895
7895
|
getManpowerSettingsBySiteId: (_id: string | ObjectId, serviceProviderId?: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
7896
|
+
getManpowerSettingsById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
7896
7897
|
updateManpowerMonitoringSettings: (_id: string | ObjectId, value: TManpowerMonitoringUpdate) => Promise<number>;
|
|
7897
7898
|
multipleManpowerMonitoringSettings: (value: TManpowerMonitoring[]) => Promise<{
|
|
7898
7899
|
updated: number;
|
|
@@ -7908,6 +7909,25 @@ declare function useManpowerMonitoringSrvc(): {
|
|
|
7908
7909
|
createManpowerMonitoringSettings: (payload: any) => Promise<mongodb.InsertOneResult<bson.Document>>;
|
|
7909
7910
|
};
|
|
7910
7911
|
|
|
7912
|
+
/**
|
|
7913
|
+
* Who may see, or change, a site's manpower monitoring settings.
|
|
7914
|
+
*
|
|
7915
|
+
* Every route on this mount carried `requireAuth` and nothing else, so being
|
|
7916
|
+
* signed in anywhere on the platform was enough to read another client's shift
|
|
7917
|
+
* pattern and alert recipients, to re-time their late-check-in alerts, or to
|
|
7918
|
+
* switch their monitoring off entirely — which silences the alert that tells a
|
|
7919
|
+
* client nobody turned up for a shift.
|
|
7920
|
+
*
|
|
7921
|
+
* The estate is the scope. Where the request names a site (`POST /`,
|
|
7922
|
+
* `GET /sites/:id/:serviceProviderId`, `POST /multiple`) that site is checked
|
|
7923
|
+
* before it is used; `PUT /:id` names only a record, so the site is read off
|
|
7924
|
+
* the STORED row and a `siteId` in the body cannot stand in for it.
|
|
7925
|
+
*
|
|
7926
|
+
* `requireSiteReach` is the rule `/api/vehicles`, `/api/documents`,
|
|
7927
|
+
* `/api/service-providers` and `/api/incident-reports` already use, so the
|
|
7928
|
+
* contracted agency that actually runs these shifts reaches its own site
|
|
7929
|
+
* through `customer.sites` exactly as it does everywhere else.
|
|
7930
|
+
*/
|
|
7911
7931
|
declare function useManpowerMonitoringCtrl(): {
|
|
7912
7932
|
createManpowerMonitoringSettings: (req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7913
7933
|
getAllManpowerSettings: (req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>;
|
package/dist/index.js
CHANGED
|
@@ -75059,6 +75059,14 @@ function useManpowerMonitoringRepo() {
|
|
|
75059
75059
|
throw error;
|
|
75060
75060
|
}
|
|
75061
75061
|
}
|
|
75062
|
+
async function getManpowerSettingsById(_id) {
|
|
75063
|
+
try {
|
|
75064
|
+
_id = new import_mongodb144.ObjectId(_id);
|
|
75065
|
+
} catch (error) {
|
|
75066
|
+
throw new import_node_server_utils230.BadRequestError("Invalid ID format.");
|
|
75067
|
+
}
|
|
75068
|
+
return await collection.findOne({ _id });
|
|
75069
|
+
}
|
|
75062
75070
|
async function updateManpowerMonitoringSettings(_id, value) {
|
|
75063
75071
|
try {
|
|
75064
75072
|
_id = new import_mongodb144.ObjectId(_id);
|
|
@@ -75169,6 +75177,7 @@ function useManpowerMonitoringRepo() {
|
|
|
75169
75177
|
createManpowerMonitoringSettings,
|
|
75170
75178
|
getAllManpowerSettings,
|
|
75171
75179
|
getManpowerSettingsBySiteId,
|
|
75180
|
+
getManpowerSettingsById,
|
|
75172
75181
|
updateManpowerMonitoringSettings,
|
|
75173
75182
|
multipleManpowerMonitoringSettings,
|
|
75174
75183
|
getAllSites,
|
|
@@ -75481,6 +75490,7 @@ function useManpowerMonitoringCtrl() {
|
|
|
75481
75490
|
const {
|
|
75482
75491
|
getAllManpowerSettings: _getAllManpowerSettings,
|
|
75483
75492
|
getManpowerSettingsBySiteId: _getManpowerSettingsBySiteId,
|
|
75493
|
+
getManpowerSettingsById: _getManpowerSettingsById,
|
|
75484
75494
|
updateManpowerMonitoringSettings: _updateManpowerMonitoringSettings,
|
|
75485
75495
|
multipleManpowerMonitoringSettings: _multipleManpowerMonitoringSettings,
|
|
75486
75496
|
getAllSites: _getAllSites
|
|
@@ -75496,6 +75506,7 @@ function useManpowerMonitoringCtrl() {
|
|
|
75496
75506
|
next(new import_node_server_utils233.BadRequestError(error.message));
|
|
75497
75507
|
return;
|
|
75498
75508
|
}
|
|
75509
|
+
await requireSiteReach(req, payload.siteId);
|
|
75499
75510
|
const result = await _createManpowerMonitoringSettings(payload);
|
|
75500
75511
|
return res.json(result);
|
|
75501
75512
|
} catch (error) {
|
|
@@ -75522,7 +75533,17 @@ function useManpowerMonitoringCtrl() {
|
|
|
75522
75533
|
limit: Number(limit),
|
|
75523
75534
|
search
|
|
75524
75535
|
});
|
|
75525
|
-
|
|
75536
|
+
const { only } = await siteReachOf(req);
|
|
75537
|
+
const items = await only(
|
|
75538
|
+
(result?.items ?? []).map((row) => ({
|
|
75539
|
+
row,
|
|
75540
|
+
site: row?.siteId
|
|
75541
|
+
}))
|
|
75542
|
+
);
|
|
75543
|
+
return res.json({
|
|
75544
|
+
...result,
|
|
75545
|
+
items: items.map((entry) => entry.row)
|
|
75546
|
+
});
|
|
75526
75547
|
} catch (error) {
|
|
75527
75548
|
import_node_server_utils233.logger.log({ level: "error", message: error.message });
|
|
75528
75549
|
next(error);
|
|
@@ -75542,6 +75563,7 @@ function useManpowerMonitoringCtrl() {
|
|
|
75542
75563
|
next(new import_node_server_utils233.BadRequestError(error.message));
|
|
75543
75564
|
return;
|
|
75544
75565
|
}
|
|
75566
|
+
await requireSiteReach(req, _id);
|
|
75545
75567
|
const result = await _getManpowerSettingsBySiteId(_id, serviceProviderId);
|
|
75546
75568
|
return res.json(result);
|
|
75547
75569
|
} catch (error) {
|
|
@@ -75569,6 +75591,8 @@ function useManpowerMonitoringCtrl() {
|
|
|
75569
75591
|
next(new import_node_server_utils233.BadRequestError(error.message));
|
|
75570
75592
|
return;
|
|
75571
75593
|
}
|
|
75594
|
+
const existing = await _getManpowerSettingsById(_id);
|
|
75595
|
+
await requireSiteReach(req, existing?.siteId);
|
|
75572
75596
|
const result = await _updateManpowerMonitoringSettings(_id, payload);
|
|
75573
75597
|
return res.json(result);
|
|
75574
75598
|
} catch (error) {
|
|
@@ -75586,6 +75610,9 @@ function useManpowerMonitoringCtrl() {
|
|
|
75586
75610
|
next(new import_node_server_utils233.BadRequestError(error.message));
|
|
75587
75611
|
return;
|
|
75588
75612
|
}
|
|
75613
|
+
for (const item of payload) {
|
|
75614
|
+
await requireSiteReach(req, item?.siteId);
|
|
75615
|
+
}
|
|
75589
75616
|
const result = await _multipleManpowerMonitoringSettings(payload);
|
|
75590
75617
|
return res.json(result);
|
|
75591
75618
|
} catch (error) {
|