@7365admin1/core 3.48.1-staging.176 → 3.48.1-staging.178

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,10 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ Scope the facility booking routes to the estate. `/api/facility-bookings` carried
6
+ `requireAuth` and nothing else on all five routes: any signed-in account could book
7
+ a facility at another estate, list another client's bookings, and read, rewrite or
8
+ cancel any booking by id alone — including moving a booking to a different estate.
9
+ Reach is now checked on the site named in the request, and on the stored row where
10
+ the request names only an id.
@@ -0,0 +1,12 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ Scope the visitor guest routes to the estate
6
+
7
+ `/api/visitor-guests` carried `requireAuth` and nothing more on all four
8
+ routes, so any signed-in account could add, read, edit or delete another
9
+ estate's expected-visitor list. `site` was optional on the list query and the
10
+ repository only applies it when valid, so omitting it returned every estate's
11
+ visitor records at once. All four handlers now ask the existing site-reach
12
+ rule, and `site` is required on the list query.
package/dist/index.d.ts CHANGED
@@ -4693,6 +4693,7 @@ declare function useGuestManagementRepo(): {
4693
4693
  org?: string | undefined;
4694
4694
  site?: string | undefined;
4695
4695
  }, session?: ClientSession) => Promise<{}>;
4696
+ getById: (_id: string | ObjectId, session?: ClientSession) => Promise<mongodb.WithId<bson.Document> | null>;
4696
4697
  updateVisitorGuestById: (_id: string | ObjectId, value: Partial<TGuestManagement>, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
4697
4698
  deleteVisitorGuest: (_id: string | ObjectId) => Promise<number>;
4698
4699
  createTextIndex: () => Promise<void>;
@@ -4703,6 +4704,25 @@ declare function useGuestManagementService(): {
4703
4704
  updateVisitorGuestById: (id: string | ObjectId, value: TGuestManagement) => Promise<string>;
4704
4705
  };
4705
4706
 
4707
+ /**
4708
+ * A visitor guest is a named person an estate expects at its gate: name,
4709
+ * contact, NRIC, vehicle plate, and the block/level/unit they are visiting.
4710
+ *
4711
+ * All four routes carried `requireAuth` and nothing more, and this controller
4712
+ * held no authorization identifier of any kind. `site` and `org` were read
4713
+ * straight off the caller — the body on `POST`, the query on `GET` — and never
4714
+ * compared to anything, and `PUT`/`DELETE` reached the row by id alone. Being
4715
+ * signed in ANYWHERE on the platform was therefore enough to read, edit or
4716
+ * delete any estate's guest list.
4717
+ *
4718
+ * The `GET` was the worst of the four: `site` and `org` were OPTIONAL, and the
4719
+ * repository only applies them `ObjectId.isValid(...)`. Omitting both left the
4720
+ * `$match` with no tenancy term at all, so one request returned every estate's
4721
+ * visitor records on the platform — names, NRIC, contact numbers and plates.
4722
+ *
4723
+ * The rule is the existing one, `requireSiteReach` (i.e. `entitleSite`), not a
4724
+ * second competing mechanism.
4725
+ */
4706
4726
  declare function useGuestManagementController(): {
4707
4727
  add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
4708
4728
  getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
package/dist/index.js CHANGED
@@ -50372,6 +50372,14 @@ function useGuestManagementRepo() {
50372
50372
  throw error;
50373
50373
  }
50374
50374
  }
50375
+ async function getById(_id, session) {
50376
+ try {
50377
+ _id = new import_mongodb86.ObjectId(_id);
50378
+ } catch (error) {
50379
+ throw new import_node_server_utils135.BadRequestError("Invalid visitor guest ID format.");
50380
+ }
50381
+ return await collection.findOne({ _id }, { session });
50382
+ }
50375
50383
  async function updateVisitorGuestById(_id, value, session) {
50376
50384
  try {
50377
50385
  _id = new import_mongodb86.ObjectId(_id);
@@ -50434,6 +50442,7 @@ function useGuestManagementRepo() {
50434
50442
  return {
50435
50443
  add,
50436
50444
  getAll,
50445
+ getById,
50437
50446
  updateVisitorGuestById,
50438
50447
  deleteVisitorGuest,
50439
50448
  createTextIndex
@@ -50483,7 +50492,11 @@ var import_joi67 = __toESM(require("joi"));
50483
50492
  var import_node_server_utils137 = require("@7365admin1/node-server-utils");
50484
50493
  function useGuestManagementController() {
50485
50494
  const { add: _add, updateVisitorGuestById: _updateVisitorGuestById } = useGuestManagementService();
50486
- const { getAll: _getAll, deleteVisitorGuest: _deleteVisitorGuest } = useGuestManagementRepo();
50495
+ const {
50496
+ getAll: _getAll,
50497
+ getById: _getById,
50498
+ deleteVisitorGuest: _deleteVisitorGuest
50499
+ } = useGuestManagementRepo();
50487
50500
  async function add(req, res, next) {
50488
50501
  const payload = { ...req.body };
50489
50502
  const { error } = schemaGuestManagement.validate(payload, {
@@ -50496,6 +50509,7 @@ function useGuestManagementController() {
50496
50509
  return;
50497
50510
  }
50498
50511
  try {
50512
+ await requireSiteReach(req, payload.site);
50499
50513
  const data = await _add(payload);
50500
50514
  res.status(201).json({ message: data });
50501
50515
  return;
@@ -50516,7 +50530,9 @@ function useGuestManagementController() {
50516
50530
  dateFrom: import_joi67.default.date().iso().optional().allow(null, ""),
50517
50531
  dateTo: import_joi67.default.date().iso().optional().allow(null, ""),
50518
50532
  org: import_joi67.default.string().optional().allow(null, ""),
50519
- site: import_joi67.default.string().optional().allow(null, "")
50533
+ // required, so the repository can never build a `$match` with no
50534
+ // tenancy term and return the whole platform's guest list
50535
+ site: import_joi67.default.string().hex().length(24).required()
50520
50536
  });
50521
50537
  const query2 = { ...req.query };
50522
50538
  const { error } = validation.validate(query2, {
@@ -50546,6 +50562,7 @@ function useGuestManagementController() {
50546
50562
  }
50547
50563
  });
50548
50564
  try {
50565
+ await requireSiteReach(req, site);
50549
50566
  const data = await _getAll({
50550
50567
  search,
50551
50568
  page,
@@ -50578,6 +50595,8 @@ function useGuestManagementController() {
50578
50595
  return;
50579
50596
  }
50580
50597
  try {
50598
+ const current = await _getById(_id);
50599
+ await requireSiteReach(req, current?.site);
50581
50600
  const result = await _updateVisitorGuestById(_id, req.body);
50582
50601
  res.status(200).json({ message: result });
50583
50602
  return;
@@ -50597,6 +50616,8 @@ function useGuestManagementController() {
50597
50616
  return;
50598
50617
  }
50599
50618
  try {
50619
+ const current = await _getById(_id);
50620
+ await requireSiteReach(req, current?.site);
50600
50621
  await _deleteVisitorGuest(_id);
50601
50622
  res.status(200).json({ message: "Successfully deleted visitor guest." });
50602
50623
  return;
@@ -55676,6 +55697,14 @@ function useSiteFacilityBookingController() {
55676
55697
  getSiteFacilityBookingById: _getSiteFacilityBookingById,
55677
55698
  deleteSiteFacilityBookingById: _deleteSiteFacilityBookingById
55678
55699
  } = useSiteFacilityBookingRepo();
55700
+ async function loadReachable(req, id) {
55701
+ const booking = await _getSiteFacilityBookingById(id);
55702
+ const { canReach } = await siteReachOf(req);
55703
+ if (!await canReach(booking)) {
55704
+ throw new import_node_server_utils168.NotFoundError("Site facility booking not found.");
55705
+ }
55706
+ return booking;
55707
+ }
55679
55708
  async function add(req, res, next) {
55680
55709
  try {
55681
55710
  const { error, value } = schemaSiteFacilityBooking.validate(req.body, {
@@ -55687,6 +55716,7 @@ function useSiteFacilityBookingController() {
55687
55716
  next(new import_node_server_utils168.BadRequestError(messages));
55688
55717
  return;
55689
55718
  }
55719
+ await requireSiteReach(req, value.site);
55690
55720
  const data = await _add(value);
55691
55721
  res.status(201).json(data);
55692
55722
  return;
@@ -55720,6 +55750,7 @@ function useSiteFacilityBookingController() {
55720
55750
  const sortObj = {
55721
55751
  [sort]: order === "asc" /* ASC */ ? 1 : -1
55722
55752
  };
55753
+ await requireSiteReach(req, site);
55723
55754
  const data = await _getAll({
55724
55755
  search,
55725
55756
  page,
@@ -55747,7 +55778,7 @@ function useSiteFacilityBookingController() {
55747
55778
  next(new import_node_server_utils168.BadRequestError(error.message));
55748
55779
  return;
55749
55780
  }
55750
- const data = await _getSiteFacilityBookingById(value._id);
55781
+ const data = await loadReachable(req, value._id);
55751
55782
  res.status(200).json(data);
55752
55783
  return;
55753
55784
  } catch (error) {
@@ -55771,6 +55802,9 @@ function useSiteFacilityBookingController() {
55771
55802
  }
55772
55803
  const { _id, ...rest } = value;
55773
55804
  try {
55805
+ await loadReachable(req, _id);
55806
+ if (rest.site)
55807
+ await requireSiteReach(req, rest.site);
55774
55808
  const result = await _updateSiteFacilityBookingById(_id, rest);
55775
55809
  res.status(200).json({ message: result });
55776
55810
  return;
@@ -55793,6 +55827,7 @@ function useSiteFacilityBookingController() {
55793
55827
  }
55794
55828
  const { _id } = value;
55795
55829
  try {
55830
+ await loadReachable(req, _id);
55796
55831
  await _deleteSiteFacilityBookingById(_id);
55797
55832
  res.status(200).json({ message: "Successfully deleted site facility booking." });
55798
55833
  return;