@7365admin1/core 3.48.1-staging.156 → 3.48.1-staging.158
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/feedback-site-scope.md +51 -0
- package/.changeset/site-entrypass-settings-scope.md +53 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.js +67 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +67 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/feedback-scope.e2e.test.mjs +512 -0
- package/test/e2e/harness.mjs +48 -0
- package/test/e2e/site-entrypass-settings-scope.e2e.test.mjs +535 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": minor
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the feedback routes to the estate the feedback was raised at, and take the
|
|
6
|
+
author's identity from the session.
|
|
7
|
+
|
|
8
|
+
A feedback row is a resident's complaint about their own estate: the subject,
|
|
9
|
+
the free-text description, the location inside the block, the attachments and
|
|
10
|
+
the name of the person who raised it. Every route on `/api/feedbacks` carried
|
|
11
|
+
`requireAuth` and nothing more, and the controller held no authorization
|
|
12
|
+
identifier of any kind, so being signed in anywhere on the platform was enough
|
|
13
|
+
to read another client's complaints, rewrite them, re-route them to a different
|
|
14
|
+
service line, close them, or delete them.
|
|
15
|
+
|
|
16
|
+
`DELETE /:id` is the sharp one, twice over. It is the **only** route on this
|
|
17
|
+
mount with a live caller — `layer-common`'s `useFeedback().deleteFeedback`,
|
|
18
|
+
wired to the delete button in `FeedbackDetail.vue` and `FeedbackMain.vue`, which
|
|
19
|
+
every web app draws — and it does not write to the v1 table at all. It writes to
|
|
20
|
+
`feedbacks2`, the authoritative table every client reads. So the one reachable
|
|
21
|
+
route on the legacy mount was an unguarded delete against live data. It is now
|
|
22
|
+
checked against the `feedbacks2` row it actually touches, not the v1 row that
|
|
23
|
+
happens to share the id.
|
|
24
|
+
|
|
25
|
+
All eight routes go through `requireSiteReach`, the rule
|
|
26
|
+
`/api/manpower-monitoring`, `/api/attendances`, `/api/remarks`,
|
|
27
|
+
`/api/vehicles`, `/api/documents` and `/api/incident-reports` already use:
|
|
28
|
+
|
|
29
|
+
- `GET /site/:site/status/:status` names the site in the URL, so it is checked
|
|
30
|
+
before the read.
|
|
31
|
+
- The six record routes name only a record, so the site is read off the
|
|
32
|
+
**stored** row and a `site` in the caller's own body cannot stand in for it.
|
|
33
|
+
Two readers are needed, because the two tables are not the same shape: v1
|
|
34
|
+
`feedbacks` rows keep the site at `metadata.site`, `feedbacks2` rows keep it
|
|
35
|
+
at the top level.
|
|
36
|
+
- `POST /` took the author from a `user` cookie the caller writes and never
|
|
37
|
+
compared it to the session, so a complaint could be filed in somebody else's
|
|
38
|
+
name. It comes from `callerId(req)` now, which also removes a latent crash:
|
|
39
|
+
`cookies?.["user"].toString()` short-circuits only on `cookies` being nullish
|
|
40
|
+
and threw on any request carrying cookies but no `user` cookie.
|
|
41
|
+
|
|
42
|
+
`requireSiteReach` matters here because the contracted service provider that
|
|
43
|
+
answers these complaints holds no membership in the estate's organisation and
|
|
44
|
+
reaches it through `customer.sites`.
|
|
45
|
+
|
|
46
|
+
Not fixed here, and reported separately: `POST /api/feedbacks` cannot succeed
|
|
47
|
+
and could not before this change either. `feedback.service.ts` replaces
|
|
48
|
+
`createdBy` with an `ObjectId` and `MFeedback` then re-validates the document
|
|
49
|
+
against a schema where `createdBy` is `Joi.string().hex()`, so the create always
|
|
50
|
+
answers 400. No client calls it — every client creates through
|
|
51
|
+
`/api/feedbacks2`.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": minor
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the entry pass settings routes to their site, and take the writer's
|
|
6
|
+
identity from the session.
|
|
7
|
+
|
|
8
|
+
These rows decide how a site issues visitor passes: whether passes are on at
|
|
9
|
+
all, whether a physical or NFC pass is used, which USB printer model the
|
|
10
|
+
gatehouse drives, and the header, disclaimer and URL printed on the pass a
|
|
11
|
+
visitor is handed at the gate. All seven routes on
|
|
12
|
+
`/api/site-entrypass-settings` carried `requireAuth` and nothing more — the
|
|
13
|
+
controller held no authorization identifier of any kind.
|
|
14
|
+
|
|
15
|
+
Two defects were fixed, not one.
|
|
16
|
+
|
|
17
|
+
**No scope.** `GET /` returned every row on the platform: it accepts `org` and
|
|
18
|
+
`site` query parameters and the repository never applies them, so a filter that
|
|
19
|
+
looked like scoping was not one. The record routes took an id and no site.
|
|
20
|
+
`GET|PUT /site/:site` took a site straight off the URL. All seven now go through
|
|
21
|
+
`requireSiteReach`, the rule `/api/access-management`,
|
|
22
|
+
`/api/manpower-monitoring`, `/api/attendances`, `/api/vehicles`,
|
|
23
|
+
`/api/documents` and `/api/incident-reports` already use:
|
|
24
|
+
|
|
25
|
+
- `POST /` and `GET|PUT /site/:site` name a site in the request; it is checked
|
|
26
|
+
before it is used.
|
|
27
|
+
- `GET|PUT|DELETE /:id` name only a record, so the site is read off the
|
|
28
|
+
**stored** row — a `site` in the caller's own body cannot stand in for it.
|
|
29
|
+
- `PUT /:id` and `PUT /site/:site` can also **move** a row, because the body's
|
|
30
|
+
`site` is `$set`, so the destination is checked as well as the origin.
|
|
31
|
+
- `GET /` is narrowed after the read. It cannot be narrowed in the repository:
|
|
32
|
+
the page is cached under a key built only from page/limit/status/sort, so a
|
|
33
|
+
per-caller filter there would be served to the next caller. The count in the
|
|
34
|
+
envelope stays the unfiltered one, as it does on the sibling lists.
|
|
35
|
+
|
|
36
|
+
**The writer's identity came from a cookie the caller writes.** `add`,
|
|
37
|
+
`updateEntryPassSettingsById` and `updateEntryPassSettingsBySiteId` each parsed
|
|
38
|
+
the raw `Cookie` header for a `user` value and stored it as `createdBy` /
|
|
39
|
+
`updatedBy` without ever comparing it to the session, so the audit trail on
|
|
40
|
+
these rows was whatever the caller typed. It now comes from `callerId(req)`.
|
|
41
|
+
That also removes a latent crash: `cookies?.["user"].toString()` short-circuits
|
|
42
|
+
only on `cookies` being nullish, so any request carrying cookies but no `user`
|
|
43
|
+
cookie called `.toString()` on `undefined` and threw.
|
|
44
|
+
|
|
45
|
+
`requireSiteReach` matters here because the contracted agency that runs the
|
|
46
|
+
gatehouse holds no membership in the estate's organisation and reaches its own
|
|
47
|
+
site through `customer.sites`.
|
|
48
|
+
|
|
49
|
+
Nothing on this mount has a live caller: `layer-common`'s
|
|
50
|
+
`useSiteEntryPassSettings` binds only `GET /:id` and no component calls it, and
|
|
51
|
+
the entry-pass screens read and write `/api/access-management/settings`, a
|
|
52
|
+
different mount over a different collection. The routes are guarded rather than
|
|
53
|
+
removed; whether this mount should exist at all is a product decision.
|
package/dist/index.d.ts
CHANGED
|
@@ -1621,6 +1621,8 @@ declare function useFeedbackRepo(): {
|
|
|
1621
1621
|
pageRange: string;
|
|
1622
1622
|
}>;
|
|
1623
1623
|
getFeedbackById: (_id: string | ObjectId) => Promise<bson.Document>;
|
|
1624
|
+
getRawFeedbackById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
1625
|
+
getRawFeedback2ById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
1624
1626
|
updateFeedback: (_id: string | ObjectId, value: TFeedbackUpdate) => Promise<number>;
|
|
1625
1627
|
updateFeedbackStatus: (_id: string | ObjectId, value: TFeedbackUpdateStatus) => Promise<number>;
|
|
1626
1628
|
updateFeedbackCreatedByName: (_id: string | ObjectId, value: string | ObjectId, session?: ClientSession) => Promise<number>;
|
|
@@ -1649,6 +1651,46 @@ declare function useFeedbackService(): {
|
|
|
1649
1651
|
}>;
|
|
1650
1652
|
};
|
|
1651
1653
|
|
|
1654
|
+
/**
|
|
1655
|
+
* Who may see, or change, a site's feedback.
|
|
1656
|
+
*
|
|
1657
|
+
* A feedback row is a resident's complaint about their own estate - the
|
|
1658
|
+
* subject, the free-text description, the location inside the block, the
|
|
1659
|
+
* attachments, and the name of the person who raised it. Every route on
|
|
1660
|
+
* `/api/feedbacks` carried `requireAuth` and nothing more, and this controller
|
|
1661
|
+
* held no authorization identifier of any kind, so being signed in anywhere on
|
|
1662
|
+
* the platform was enough to read another client's complaints, re-categorise
|
|
1663
|
+
* them, mark them completed, or delete them.
|
|
1664
|
+
*
|
|
1665
|
+
* `DELETE /:id` is the sharp one, for two reasons. It is the ONLY route on this
|
|
1666
|
+
* mount with a live caller - `layer-common`'s `useFeedback().deleteFeedback`,
|
|
1667
|
+
* wired to the delete button in `FeedbackDetail.vue` and `FeedbackMain.vue`,
|
|
1668
|
+
* which every web app draws - and it does not write to the v1 table at all. It
|
|
1669
|
+
* writes to `feedbacks2`, the authoritative one every client reads. So the one
|
|
1670
|
+
* reachable route on the legacy mount was an unguarded delete against live
|
|
1671
|
+
* data. It is guarded here against the row it actually touches.
|
|
1672
|
+
*
|
|
1673
|
+
* The estate is the scope. `requireSiteReach` is the rule
|
|
1674
|
+
* `/api/manpower-monitoring`, `/api/attendances`, `/api/remarks`,
|
|
1675
|
+
* `/api/vehicles`, `/api/documents` and `/api/incident-reports` already use, so
|
|
1676
|
+
* the contracted agency that answers these complaints reaches the estate
|
|
1677
|
+
* through `customer.sites` and needs no membership in its organisation.
|
|
1678
|
+
*
|
|
1679
|
+
* - `GET /site/:site/status/:status` names the site in the URL, so it is
|
|
1680
|
+
* checked before the read.
|
|
1681
|
+
* - The six record routes name only a record, so the site is read off the
|
|
1682
|
+
* STORED row and a `site` in the caller's own body cannot stand in for it.
|
|
1683
|
+
* - `POST /` took the author's identity from a `user` cookie the caller writes
|
|
1684
|
+
* and never compared it to the session, so a feedback could be filed in
|
|
1685
|
+
* somebody else's name. It comes from `callerId(req)` now - which also
|
|
1686
|
+
* removes a latent crash, because `cookies?.["user"].toString()`
|
|
1687
|
+
* short-circuits only on `cookies` being nullish and threw on any request
|
|
1688
|
+
* that carried cookies but no `user` cookie.
|
|
1689
|
+
*
|
|
1690
|
+
* Two readers, not one, because the two tables are not the same shape: v1
|
|
1691
|
+
* `feedbacks` rows keep the site at `metadata.site`, `feedbacks2` rows keep it
|
|
1692
|
+
* at the top level.
|
|
1693
|
+
*/
|
|
1652
1694
|
declare function useFeedbackController(): {
|
|
1653
1695
|
createFeedback: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
1654
1696
|
getFeedbacks: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
@@ -6954,6 +6996,7 @@ declare function MEntryPassSettings(value: TEntryPassSettings): {
|
|
|
6954
6996
|
};
|
|
6955
6997
|
|
|
6956
6998
|
declare function useEntryPassSettingsRepo(): {
|
|
6999
|
+
getRawEntryPassSettingsById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
6957
7000
|
add: (value: TEntryPassSettings, session?: ClientSession) => Promise<ObjectId>;
|
|
6958
7001
|
getAll: ({ search, page, limit, sort, status, org, site, }: {
|
|
6959
7002
|
search?: string | undefined;
|
|
@@ -6976,6 +7019,51 @@ declare function useEntryPassSettingsRepo(): {
|
|
|
6976
7019
|
updateEntryPassSettingsBySiteId: (site: string | ObjectId, value: TEntryPassSettings) => Promise<number>;
|
|
6977
7020
|
};
|
|
6978
7021
|
|
|
7022
|
+
/**
|
|
7023
|
+
* Who may see, or change, a site's entry-pass settings.
|
|
7024
|
+
*
|
|
7025
|
+
* These rows decide how a site issues visitor passes: whether passes are on at
|
|
7026
|
+
* all, whether a physical or NFC pass is used, which USB printer model the
|
|
7027
|
+
* gatehouse drives, and the header, disclaimer and URL printed on the pass
|
|
7028
|
+
* itself. All seven routes carried `requireAuth` and nothing more - the
|
|
7029
|
+
* controller held no authorization identifier of any kind - so being signed in
|
|
7030
|
+
* anywhere on the platform was enough to read every client's configuration, to
|
|
7031
|
+
* turn another estate's passes off, or to rewrite the text and URL printed on a
|
|
7032
|
+
* pass a visitor is handed at the gate.
|
|
7033
|
+
*
|
|
7034
|
+
* Two defects, not one:
|
|
7035
|
+
*
|
|
7036
|
+
* 1. **No scope.** `GET /` returns every row on the platform: it accepts `org`
|
|
7037
|
+
* and `site` query parameters and the repository never applies them, so a
|
|
7038
|
+
* filter that looks like scoping is not one. The record routes take an id
|
|
7039
|
+
* and no site. `GET|PUT /site/:site` take a site straight off the URL.
|
|
7040
|
+
* 2. **The writer's identity came from a cookie the caller writes.** `add`,
|
|
7041
|
+
* `updateEntryPassSettingsById` and `updateEntryPassSettingsBySiteId` each
|
|
7042
|
+
* parsed the raw `Cookie` header for a `user` value and stored it as
|
|
7043
|
+
* `createdBy` / `updatedBy` without ever comparing it to the session, so
|
|
7044
|
+
* the audit trail on these rows was whatever the caller typed. It now comes
|
|
7045
|
+
* from `callerId(req)`, the session, as the rest of the platform does. That
|
|
7046
|
+
* also removes a latent crash: `cookies?.["user"].toString()` threw a
|
|
7047
|
+
* TypeError on any request that carried cookies but no `user` cookie.
|
|
7048
|
+
*
|
|
7049
|
+
* The estate is the scope. `requireSiteReach` is the rule
|
|
7050
|
+
* `/api/access-management`, `/api/manpower-monitoring`, `/api/attendances`,
|
|
7051
|
+
* `/api/vehicles`, `/api/documents` and `/api/incident-reports` already use, so
|
|
7052
|
+
* the contracted agency that runs the gatehouse reaches its own site through
|
|
7053
|
+
* `customer.sites` and needs no membership in the estate's own organisation.
|
|
7054
|
+
*
|
|
7055
|
+
* Where a write can also MOVE a row - the body carries `site`, and the
|
|
7056
|
+
* repository `$set`s it - the destination is checked as well as the origin, so
|
|
7057
|
+
* a row cannot be re-parented into an estate the caller cannot reach.
|
|
7058
|
+
*
|
|
7059
|
+
* Nothing on this mount has a live caller. `layer-common`'s
|
|
7060
|
+
* `useSiteEntryPassSettings` binds only `GET /:id`, and no component calls it;
|
|
7061
|
+
* the entry-pass screens read and write `/api/access-management/settings`,
|
|
7062
|
+
* which is a different mount over a different collection
|
|
7063
|
+
* (`entrypass-settings`, not `site.entrypass-settings`). The routes are guarded
|
|
7064
|
+
* rather than removed - whether this mount should exist at all is a product
|
|
7065
|
+
* decision, not one to take inside an authorization fix.
|
|
7066
|
+
*/
|
|
6979
7067
|
declare function useEntryPassSettingsController(): {
|
|
6980
7068
|
add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
6981
7069
|
getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -7188,6 +7188,22 @@ function useFeedbackRepo() {
|
|
|
7188
7188
|
throw error;
|
|
7189
7189
|
}
|
|
7190
7190
|
}
|
|
7191
|
+
async function getRawFeedbackById(_id) {
|
|
7192
|
+
try {
|
|
7193
|
+
_id = new import_mongodb4.ObjectId(_id);
|
|
7194
|
+
} catch (error) {
|
|
7195
|
+
throw new import_node_server_utils5.BadRequestError("Invalid feedback ID format.");
|
|
7196
|
+
}
|
|
7197
|
+
return await collection.findOne({ _id });
|
|
7198
|
+
}
|
|
7199
|
+
async function getRawFeedback2ById(_id) {
|
|
7200
|
+
try {
|
|
7201
|
+
_id = new import_mongodb4.ObjectId(_id);
|
|
7202
|
+
} catch (error) {
|
|
7203
|
+
throw new import_node_server_utils5.BadRequestError("Invalid feedback ID format.");
|
|
7204
|
+
}
|
|
7205
|
+
return await feedbacks2Collection.findOne({ _id });
|
|
7206
|
+
}
|
|
7191
7207
|
async function updateFeedback(_id, value) {
|
|
7192
7208
|
try {
|
|
7193
7209
|
_id = new import_mongodb4.ObjectId(_id);
|
|
@@ -7414,6 +7430,8 @@ function useFeedbackRepo() {
|
|
|
7414
7430
|
createFeedback,
|
|
7415
7431
|
getFeedbacks,
|
|
7416
7432
|
getFeedbackById,
|
|
7433
|
+
getRawFeedbackById,
|
|
7434
|
+
getRawFeedback2ById,
|
|
7417
7435
|
updateFeedback,
|
|
7418
7436
|
updateFeedbackStatus,
|
|
7419
7437
|
updateFeedbackCreatedByName,
|
|
@@ -31708,18 +31726,24 @@ function useFeedbackController() {
|
|
|
31708
31726
|
const { createFeedback: _createFeedback, getFeedbacks: _getFeedbacks } = useFeedbackService();
|
|
31709
31727
|
const {
|
|
31710
31728
|
getFeedbackById: _getFeedbackById,
|
|
31729
|
+
getRawFeedbackById: _getRawFeedbackById,
|
|
31730
|
+
getRawFeedback2ById: _getRawFeedback2ById,
|
|
31711
31731
|
updateFeedback: _updateFeedback,
|
|
31712
31732
|
updateFeedbackStatus: _updateFeedbackStatus,
|
|
31713
31733
|
updateFeedbackCategory: _updateFeedbackCategory,
|
|
31714
31734
|
updateFeedbackToCompleted: _updateFeedbackToCompleted,
|
|
31715
31735
|
deleteFeedback: _deleteFeedback
|
|
31716
31736
|
} = useFeedbackRepo();
|
|
31737
|
+
async function requireFeedbackReach(req, _id) {
|
|
31738
|
+
const row = await _getRawFeedbackById(_id);
|
|
31739
|
+
await requireSiteReach(req, row?.metadata?.site ?? row?.site);
|
|
31740
|
+
}
|
|
31741
|
+
async function requireFeedback2Reach(req, _id) {
|
|
31742
|
+
const row = await _getRawFeedback2ById(_id);
|
|
31743
|
+
await requireSiteReach(req, row?.site ?? row?.metadata?.site);
|
|
31744
|
+
}
|
|
31717
31745
|
async function createFeedback(req, res, next) {
|
|
31718
|
-
const
|
|
31719
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
31720
|
-
{}
|
|
31721
|
-
);
|
|
31722
|
-
const createdBy = cookies?.["user"].toString() ?? "";
|
|
31746
|
+
const createdBy = callerId(req);
|
|
31723
31747
|
const payload = { ...req.body, createdBy };
|
|
31724
31748
|
const { error } = feedbackSchema.validate(payload);
|
|
31725
31749
|
if (error) {
|
|
@@ -31728,6 +31752,7 @@ function useFeedbackController() {
|
|
|
31728
31752
|
return;
|
|
31729
31753
|
}
|
|
31730
31754
|
try {
|
|
31755
|
+
await requireSiteReach(req, payload.metadata?.site ?? payload.site);
|
|
31731
31756
|
await _createFeedback(payload);
|
|
31732
31757
|
res.status(201).json({ message: "Successfully created feedback." });
|
|
31733
31758
|
return;
|
|
@@ -31768,6 +31793,7 @@ function useFeedbackController() {
|
|
|
31768
31793
|
const to = req.query.to ?? "";
|
|
31769
31794
|
const category = req.query.category ?? "";
|
|
31770
31795
|
try {
|
|
31796
|
+
await requireSiteReach(req, site);
|
|
31771
31797
|
const data = await _getFeedbacks({
|
|
31772
31798
|
search,
|
|
31773
31799
|
page,
|
|
@@ -31797,6 +31823,7 @@ function useFeedbackController() {
|
|
|
31797
31823
|
return;
|
|
31798
31824
|
}
|
|
31799
31825
|
try {
|
|
31826
|
+
await requireFeedbackReach(req, _id);
|
|
31800
31827
|
const data = await _getFeedbackById(_id);
|
|
31801
31828
|
res.json(data);
|
|
31802
31829
|
return;
|
|
@@ -31825,6 +31852,7 @@ function useFeedbackController() {
|
|
|
31825
31852
|
return;
|
|
31826
31853
|
}
|
|
31827
31854
|
try {
|
|
31855
|
+
await requireFeedbackReach(req, _id);
|
|
31828
31856
|
await _updateFeedback(_id, payload);
|
|
31829
31857
|
res.json({ message: "Successfully updated feedback." });
|
|
31830
31858
|
return;
|
|
@@ -31849,6 +31877,7 @@ function useFeedbackController() {
|
|
|
31849
31877
|
const _id = req.params.id;
|
|
31850
31878
|
const status = req.params.status;
|
|
31851
31879
|
try {
|
|
31880
|
+
await requireFeedbackReach(req, _id);
|
|
31852
31881
|
await _updateFeedbackStatus(_id, { status });
|
|
31853
31882
|
res.json({ message: "Successfully updated feedback status." });
|
|
31854
31883
|
return;
|
|
@@ -31872,6 +31901,7 @@ function useFeedbackController() {
|
|
|
31872
31901
|
return;
|
|
31873
31902
|
}
|
|
31874
31903
|
try {
|
|
31904
|
+
await requireFeedbackReach(req, _id);
|
|
31875
31905
|
await _updateFeedbackCategory(_id, { category });
|
|
31876
31906
|
res.json({ message: "Successfully updated feedback category." });
|
|
31877
31907
|
return;
|
|
@@ -31897,6 +31927,7 @@ function useFeedbackController() {
|
|
|
31897
31927
|
return;
|
|
31898
31928
|
}
|
|
31899
31929
|
try {
|
|
31930
|
+
await requireFeedbackReach(req, _id);
|
|
31900
31931
|
await _updateFeedbackToCompleted(_id, payload);
|
|
31901
31932
|
res.json({ message: "Successfully updated feedback to completed." });
|
|
31902
31933
|
return;
|
|
@@ -31916,6 +31947,7 @@ function useFeedbackController() {
|
|
|
31916
31947
|
return;
|
|
31917
31948
|
}
|
|
31918
31949
|
try {
|
|
31950
|
+
await requireFeedback2Reach(req, _id);
|
|
31919
31951
|
await _deleteFeedback(_id);
|
|
31920
31952
|
res.json({ message: "Successfully deleted feedback." });
|
|
31921
31953
|
return;
|
|
@@ -68316,6 +68348,14 @@ function useEntryPassSettingsRepo() {
|
|
|
68316
68348
|
throw error;
|
|
68317
68349
|
}
|
|
68318
68350
|
}
|
|
68351
|
+
async function getRawEntryPassSettingsById(_id) {
|
|
68352
|
+
try {
|
|
68353
|
+
_id = new import_mongodb129.ObjectId(_id);
|
|
68354
|
+
} catch (error) {
|
|
68355
|
+
throw new import_node_server_utils203.BadRequestError("Invalid entry pass settings ID format.");
|
|
68356
|
+
}
|
|
68357
|
+
return await collection.findOne({ _id });
|
|
68358
|
+
}
|
|
68319
68359
|
async function updateEntryPassSettingsById(_id, value) {
|
|
68320
68360
|
try {
|
|
68321
68361
|
_id = new import_mongodb129.ObjectId(_id);
|
|
@@ -68473,6 +68513,7 @@ function useEntryPassSettingsRepo() {
|
|
|
68473
68513
|
}
|
|
68474
68514
|
}
|
|
68475
68515
|
return {
|
|
68516
|
+
getRawEntryPassSettingsById,
|
|
68476
68517
|
add,
|
|
68477
68518
|
getAll,
|
|
68478
68519
|
getEntryPassSettingsById,
|
|
@@ -68492,17 +68533,18 @@ function useEntryPassSettingsController() {
|
|
|
68492
68533
|
add: _add,
|
|
68493
68534
|
getAll: _getAll,
|
|
68494
68535
|
getEntryPassSettingsById: _getEntryPassSettingsById,
|
|
68536
|
+
getRawEntryPassSettingsById: _getRawEntryPassSettingsById,
|
|
68495
68537
|
updateEntryPassSettingsById: _updateEntryPassSettingsById,
|
|
68496
68538
|
deleteEntryPassSettingsById: _deleteEntryPassSettingsById,
|
|
68497
68539
|
getEntryPassSettingsBySiteId: _getEntryPassSettingsBySiteId,
|
|
68498
68540
|
updateEntryPassSettingsBySiteId: _updateEntryPassSettingsBySiteId
|
|
68499
68541
|
} = useEntryPassSettingsRepo();
|
|
68542
|
+
async function requireEntryPassReach(req, _id) {
|
|
68543
|
+
const row = await _getRawEntryPassSettingsById(_id);
|
|
68544
|
+
await requireSiteReach(req, row?.site);
|
|
68545
|
+
}
|
|
68500
68546
|
async function add(req, res, next) {
|
|
68501
|
-
const
|
|
68502
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
68503
|
-
{}
|
|
68504
|
-
);
|
|
68505
|
-
const createdBy = cookies?.["user"].toString() ?? "";
|
|
68547
|
+
const createdBy = callerId(req);
|
|
68506
68548
|
const payload = { ...req.body, createdBy };
|
|
68507
68549
|
const { error } = schemaEntryPassSettings.validate(payload, {
|
|
68508
68550
|
abortEarly: false
|
|
@@ -68514,6 +68556,7 @@ function useEntryPassSettingsController() {
|
|
|
68514
68556
|
return;
|
|
68515
68557
|
}
|
|
68516
68558
|
try {
|
|
68559
|
+
await requireSiteReach(req, payload.site);
|
|
68517
68560
|
const data = await _add(payload);
|
|
68518
68561
|
res.status(201).json({ message: data });
|
|
68519
68562
|
return;
|
|
@@ -68548,7 +68591,9 @@ function useEntryPassSettingsController() {
|
|
|
68548
68591
|
const site = req.query.site ?? "";
|
|
68549
68592
|
try {
|
|
68550
68593
|
const data = await _getAll({ search, page, limit, status, org, site });
|
|
68551
|
-
|
|
68594
|
+
const { only } = await siteReachOf(req);
|
|
68595
|
+
const items = await only(data?.items ?? []);
|
|
68596
|
+
res.json({ ...data, items });
|
|
68552
68597
|
return;
|
|
68553
68598
|
} catch (error2) {
|
|
68554
68599
|
import_node_server_utils204.logger.log({ level: "error", message: error2.message });
|
|
@@ -68566,6 +68611,7 @@ function useEntryPassSettingsController() {
|
|
|
68566
68611
|
return;
|
|
68567
68612
|
}
|
|
68568
68613
|
try {
|
|
68614
|
+
await requireEntryPassReach(req, _id);
|
|
68569
68615
|
const data = await _getEntryPassSettingsById(_id);
|
|
68570
68616
|
res.json(data);
|
|
68571
68617
|
return;
|
|
@@ -68593,11 +68639,7 @@ function useEntryPassSettingsController() {
|
|
|
68593
68639
|
status: import_joi106.default.string().optional().allow("", null),
|
|
68594
68640
|
updatedBy: import_joi106.default.string().hex().optional().allow("", null)
|
|
68595
68641
|
});
|
|
68596
|
-
const
|
|
68597
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
68598
|
-
{}
|
|
68599
|
-
);
|
|
68600
|
-
const updatedBy = cookies?.["user"].toString() ?? "";
|
|
68642
|
+
const updatedBy = callerId(req);
|
|
68601
68643
|
const _id = req.params.id;
|
|
68602
68644
|
const payload = { ...req.body, updatedBy };
|
|
68603
68645
|
const { error } = validation.validate({ _id, ...payload });
|
|
@@ -68607,6 +68649,9 @@ function useEntryPassSettingsController() {
|
|
|
68607
68649
|
return;
|
|
68608
68650
|
}
|
|
68609
68651
|
try {
|
|
68652
|
+
await requireEntryPassReach(req, _id);
|
|
68653
|
+
if (payload.site)
|
|
68654
|
+
await requireSiteReach(req, payload.site);
|
|
68610
68655
|
await _updateEntryPassSettingsById(_id, payload);
|
|
68611
68656
|
res.json({ message: "Successfully updated entry pass settings." });
|
|
68612
68657
|
return;
|
|
@@ -68626,6 +68671,7 @@ function useEntryPassSettingsController() {
|
|
|
68626
68671
|
return;
|
|
68627
68672
|
}
|
|
68628
68673
|
try {
|
|
68674
|
+
await requireEntryPassReach(req, _id);
|
|
68629
68675
|
await _deleteEntryPassSettingsById(_id);
|
|
68630
68676
|
res.json({ message: "Successfully deleted entry pass settings." });
|
|
68631
68677
|
return;
|
|
@@ -68645,6 +68691,7 @@ function useEntryPassSettingsController() {
|
|
|
68645
68691
|
return;
|
|
68646
68692
|
}
|
|
68647
68693
|
try {
|
|
68694
|
+
await requireSiteReach(req, _id);
|
|
68648
68695
|
const data = await _getEntryPassSettingsBySiteId(_id);
|
|
68649
68696
|
res.json(data);
|
|
68650
68697
|
return;
|
|
@@ -68671,11 +68718,7 @@ function useEntryPassSettingsController() {
|
|
|
68671
68718
|
status: import_joi106.default.string().optional().allow("", null),
|
|
68672
68719
|
updatedBy: import_joi106.default.string().hex().optional().allow("", null)
|
|
68673
68720
|
});
|
|
68674
|
-
const
|
|
68675
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
68676
|
-
{}
|
|
68677
|
-
);
|
|
68678
|
-
const updatedBy = cookies?.["user"].toString() ?? "";
|
|
68721
|
+
const updatedBy = callerId(req);
|
|
68679
68722
|
const _id = req.params.site;
|
|
68680
68723
|
const payload = { ...req.body, updatedBy };
|
|
68681
68724
|
const { error } = validation.validate({ ...payload });
|
|
@@ -68685,6 +68728,9 @@ function useEntryPassSettingsController() {
|
|
|
68685
68728
|
return;
|
|
68686
68729
|
}
|
|
68687
68730
|
try {
|
|
68731
|
+
await requireSiteReach(req, _id);
|
|
68732
|
+
if (payload.site)
|
|
68733
|
+
await requireSiteReach(req, payload.site);
|
|
68688
68734
|
await _updateEntryPassSettingsBySiteId(_id, payload);
|
|
68689
68735
|
res.json({ message: "Successfully updated entry pass settings." });
|
|
68690
68736
|
return;
|