@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.
@@ -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
- return res.json(result);
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) {