@7365admin1/core 3.48.1-staging.157 → 3.48.1-staging.159
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/work-order-site-scope.md +77 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +76 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +76 -10
- 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 +51 -1
- package/test/e2e/work-order-scope.e2e.test.mjs +536 -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,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": minor
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the work order routes to the estate the job was raised at, and take the
|
|
6
|
+
author's identity from the session.
|
|
7
|
+
|
|
8
|
+
A work order is a job at one estate: the subject, the description, the block and
|
|
9
|
+
unit it sits in, the attachments, the assigned provider, and the name and
|
|
10
|
+
signature captured when it is signed off. Every route on `/api/work-orders`
|
|
11
|
+
carried `requireAuth` and nothing more, and `work-order.controller.ts` held no
|
|
12
|
+
authorization identifier of any kind. `requireAuth` proves a session exists; it
|
|
13
|
+
makes no organisation or site decision. So being signed in ANYWHERE on the
|
|
14
|
+
platform was enough to read another client's jobs, rewrite them, drive them
|
|
15
|
+
between columns, sign them off in a stranger's name, or delete them.
|
|
16
|
+
|
|
17
|
+
`DELETE /:id` is the sharp one, and for the same reason it was sharp on
|
|
18
|
+
`/api/feedbacks`: **it does not write to the v1 table at all.** `deleteWorkOrder`
|
|
19
|
+
in `work-order.repo.ts` updates `workOrders2Collection` — `work-orders2`, the
|
|
20
|
+
authoritative table every client actually reads. A guard written against the v1
|
|
21
|
+
row would have been the wrong guard, so this one is written against the row the
|
|
22
|
+
write really touches. `DELETE /:id` and `PUT /:id` are also the only two routes
|
|
23
|
+
on this mount with a live caller: `layer-common`'s
|
|
24
|
+
`useWorkOrder().deleteWorkOrder` and `updateWorkOrder`, behind the shared
|
|
25
|
+
`WorkOrder/Main.vue` and `WorkOrder/Detail.vue` screens that every web app draws.
|
|
26
|
+
|
|
27
|
+
All seven handlers now decide before any work is done:
|
|
28
|
+
|
|
29
|
+
- `GET /site/:site/status/:status` names the site in the URL, so it is checked
|
|
30
|
+
directly with `requireSiteReach`.
|
|
31
|
+
- `GET /:id`, `PUT /:id`, `PUT /:id/:status` and `PATCH /:id/completed` name only
|
|
32
|
+
a record, so the site is read off the STORED row through the new
|
|
33
|
+
`requireWorkOrderReach`. A `site` in the caller's own body or query cannot
|
|
34
|
+
stand in for it.
|
|
35
|
+
- `DELETE /:id` uses `requireWorkOrder2Reach`, against the `work-orders2` row.
|
|
36
|
+
- `POST /` reads the destination from the body.
|
|
37
|
+
|
|
38
|
+
Two readers were needed, not one, because the tables are not the same shape: v1
|
|
39
|
+
`work-orders` rows keep the site at `metadata.site`, `work-orders2` rows keep it
|
|
40
|
+
at the top level. Both are new raw readers on the repository —
|
|
41
|
+
`getRawWorkOrderById` and `getRawWorkOrder2ById`. The existing `getWorkOrderById`
|
|
42
|
+
is CACHED and shaped for the screen, so a reach check built on it would have
|
|
43
|
+
decided who may touch a job from a cache entry.
|
|
44
|
+
|
|
45
|
+
Two further defects fixed in the same pass:
|
|
46
|
+
|
|
47
|
+
1. **Identity from a cookie the caller writes.** `POST /` parsed `createdBy` out
|
|
48
|
+
of the raw `Cookie` header and never compared it to the session, so a job
|
|
49
|
+
could be raised in somebody else's name. It comes from `callerId(req)` now.
|
|
50
|
+
That also closes a latent crash: `cookies?.["user"].toString()`
|
|
51
|
+
short-circuits only on `cookies` being nullish, so any request carrying
|
|
52
|
+
cookies but no `user` cookie threw a TypeError.
|
|
53
|
+
2. **A body that names the site twice, with unequal weight.** `POST /` accepts
|
|
54
|
+
`metadata.site` AND a top-level `site`, and `work-order.service.ts` copies the
|
|
55
|
+
top-level one OVER `metadata.site` (`if (value.site) value.metadata.site =
|
|
56
|
+
value.site`). A caller could therefore name their own estate in `metadata`
|
|
57
|
+
while the row landed at somebody else's. The guard reads them in the order the
|
|
58
|
+
service resolves them.
|
|
59
|
+
|
|
60
|
+
`PUT /:id` is a write that can MOVE a record — the repository `$set`s whatever
|
|
61
|
+
the body carries, including `site` — so the DESTINATION is checked as well as the
|
|
62
|
+
origin. Without that, a legacy row carrying no `metadata.site` could be given a
|
|
63
|
+
top-level `site` of the caller's own and become theirs.
|
|
64
|
+
|
|
65
|
+
Each guard is placed AFTER the handler's own Joi validation, so a malformed id
|
|
66
|
+
still answers 400 exactly as before. A row that does not exist has no site, and
|
|
67
|
+
`requireSiteReach` refuses a missing site, so an id matching nothing is refused
|
|
68
|
+
rather than falling through.
|
|
69
|
+
|
|
70
|
+
The rule is the existing one, `requireSiteReach` -> `entitleSite`, already used
|
|
71
|
+
by `/api/feedbacks`, `/api/manpower-monitoring`, `/api/attendances`,
|
|
72
|
+
`/api/remarks`, `/api/vehicles`, `/api/documents` and `/api/incident-reports`.
|
|
73
|
+
The `customer.sites` branch is required, not incidental: the contracted provider
|
|
74
|
+
that does this work holds no membership in the estate's own organisation.
|
|
75
|
+
|
|
76
|
+
`/api/work-orders2` is a different mount, lives in API-core's own controller, and
|
|
77
|
+
is not touched here.
|
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>;
|
|
@@ -1755,6 +1797,8 @@ declare function useWorkOrderRepo(): {
|
|
|
1755
1797
|
category?: string | undefined;
|
|
1756
1798
|
}) => Promise<{}>;
|
|
1757
1799
|
getWorkOrderById: (_id: string | ObjectId) => Promise<{}>;
|
|
1800
|
+
getRawWorkOrderById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
1801
|
+
getRawWorkOrder2ById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
1758
1802
|
updateWorkOrder: (_id: string | ObjectId, value: TWorkOrderUpdate) => Promise<number>;
|
|
1759
1803
|
updateWorkOrderStatus: (_id: string | ObjectId, value: TWorkOrderUpdateStatus) => Promise<number>;
|
|
1760
1804
|
updateWorkOrderCreatedByName: (_id: string | ObjectId, value: string | ObjectId, session?: ClientSession) => Promise<number>;
|
|
@@ -1776,6 +1820,55 @@ declare function useWorkOrderService(): {
|
|
|
1776
1820
|
}) => Promise<{}>;
|
|
1777
1821
|
};
|
|
1778
1822
|
|
|
1823
|
+
/**
|
|
1824
|
+
* Who may see, or change, a site's work orders.
|
|
1825
|
+
*
|
|
1826
|
+
* A work order is a job raised at one estate - the subject, the description,
|
|
1827
|
+
* the block and unit it sits in, the attachments, the assigned provider, and
|
|
1828
|
+
* the name and signature captured when it is signed off. Every route on
|
|
1829
|
+
* `/api/work-orders` carried `requireAuth` and nothing more, and this
|
|
1830
|
+
* controller held no authorization identifier of any kind, so being signed in
|
|
1831
|
+
* anywhere on the platform was enough to read another client's jobs, edit
|
|
1832
|
+
* them, drive their status, sign them off in a stranger's name, or delete them.
|
|
1833
|
+
*
|
|
1834
|
+
* `DELETE /:id` is the sharp one, and for the same reason it was sharp on
|
|
1835
|
+
* `/api/feedbacks`: it does not write to the v1 table at all. `deleteWorkOrder`
|
|
1836
|
+
* in the repository updates `workOrders2Collection` - `work-orders2`, the
|
|
1837
|
+
* authoritative table every client actually reads. A guard written against the
|
|
1838
|
+
* v1 row would have been the wrong guard, so this one is written against the
|
|
1839
|
+
* row the write really touches.
|
|
1840
|
+
*
|
|
1841
|
+
* The estate is the scope. `requireSiteReach` is the rule `/api/feedbacks`,
|
|
1842
|
+
* `/api/manpower-monitoring`, `/api/attendances`, `/api/remarks`,
|
|
1843
|
+
* `/api/vehicles`, `/api/documents` and `/api/incident-reports` already use, so
|
|
1844
|
+
* the contracted provider that does this work reaches the estate through
|
|
1845
|
+
* `customer.sites` and needs no membership in its organisation.
|
|
1846
|
+
*
|
|
1847
|
+
* - `GET /site/:site/status/:status` names the site in the URL, so it is
|
|
1848
|
+
* checked before the read.
|
|
1849
|
+
* - The five record routes name only a record, so the site is read off the
|
|
1850
|
+
* STORED row and a `site` in the caller's own body cannot stand in for it.
|
|
1851
|
+
* - `POST /` names the site in the body - possibly twice. `metadata.site`
|
|
1852
|
+
* and a top-level `site` are not equal: the service copies the top-level one
|
|
1853
|
+
* OVER `metadata.site`, so the guard reads them in that order and a caller
|
|
1854
|
+
* cannot name their own site at the top level while the row lands somewhere
|
|
1855
|
+
* else. A create naming no site at all is refused.
|
|
1856
|
+
* - `POST /` also took the author's identity from a `user` cookie the caller
|
|
1857
|
+
* writes and never compared it to the session, so a job could be raised in
|
|
1858
|
+
* somebody else's name. It comes from `callerId(req)` now - which also
|
|
1859
|
+
* removes a latent crash, because `cookies?.["user"].toString()`
|
|
1860
|
+
* short-circuits only on `cookies` being nullish and threw on any request
|
|
1861
|
+
* that carried cookies but no `user` cookie.
|
|
1862
|
+
* - `PUT /:id` accepts `site` and `organization` in the body and the
|
|
1863
|
+
* repository `$set`s them, so where the body names a destination it is
|
|
1864
|
+
* checked as well as the origin. That closes the one way the fallback below
|
|
1865
|
+
* could be walked: a legacy row with no `metadata.site` would otherwise let
|
|
1866
|
+
* a caller write a top-level `site` of their own and make the row reachable.
|
|
1867
|
+
*
|
|
1868
|
+
* Two readers, not one, because the two tables are not the same shape: v1
|
|
1869
|
+
* `work_orders` rows keep the site at `metadata.site`, `work-orders2` rows keep
|
|
1870
|
+
* it at the top level.
|
|
1871
|
+
*/
|
|
1779
1872
|
declare function useWorkOrderController(): {
|
|
1780
1873
|
createWorkOrder: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
1781
1874
|
getWorkOrders: (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,
|
|
@@ -7837,6 +7855,22 @@ function useWorkOrderRepo() {
|
|
|
7837
7855
|
throw error;
|
|
7838
7856
|
}
|
|
7839
7857
|
}
|
|
7858
|
+
async function getRawWorkOrderById(_id) {
|
|
7859
|
+
try {
|
|
7860
|
+
_id = new import_mongodb6.ObjectId(_id);
|
|
7861
|
+
} catch (error) {
|
|
7862
|
+
throw new import_node_server_utils7.BadRequestError("Invalid work order ID format.");
|
|
7863
|
+
}
|
|
7864
|
+
return await collection.findOne({ _id });
|
|
7865
|
+
}
|
|
7866
|
+
async function getRawWorkOrder2ById(_id) {
|
|
7867
|
+
try {
|
|
7868
|
+
_id = new import_mongodb6.ObjectId(_id);
|
|
7869
|
+
} catch (error) {
|
|
7870
|
+
throw new import_node_server_utils7.BadRequestError("Invalid work order ID format.");
|
|
7871
|
+
}
|
|
7872
|
+
return await workOrders2Collection.findOne({ _id });
|
|
7873
|
+
}
|
|
7840
7874
|
async function updateWorkOrder(_id, value) {
|
|
7841
7875
|
try {
|
|
7842
7876
|
_id = new import_mongodb6.ObjectId(_id);
|
|
@@ -8028,6 +8062,8 @@ function useWorkOrderRepo() {
|
|
|
8028
8062
|
createWorkOrder,
|
|
8029
8063
|
getWorkOrders,
|
|
8030
8064
|
getWorkOrderById,
|
|
8065
|
+
getRawWorkOrderById,
|
|
8066
|
+
getRawWorkOrder2ById,
|
|
8031
8067
|
updateWorkOrder,
|
|
8032
8068
|
updateWorkOrderStatus,
|
|
8033
8069
|
updateWorkOrderCreatedByName,
|
|
@@ -31708,18 +31744,24 @@ function useFeedbackController() {
|
|
|
31708
31744
|
const { createFeedback: _createFeedback, getFeedbacks: _getFeedbacks } = useFeedbackService();
|
|
31709
31745
|
const {
|
|
31710
31746
|
getFeedbackById: _getFeedbackById,
|
|
31747
|
+
getRawFeedbackById: _getRawFeedbackById,
|
|
31748
|
+
getRawFeedback2ById: _getRawFeedback2ById,
|
|
31711
31749
|
updateFeedback: _updateFeedback,
|
|
31712
31750
|
updateFeedbackStatus: _updateFeedbackStatus,
|
|
31713
31751
|
updateFeedbackCategory: _updateFeedbackCategory,
|
|
31714
31752
|
updateFeedbackToCompleted: _updateFeedbackToCompleted,
|
|
31715
31753
|
deleteFeedback: _deleteFeedback
|
|
31716
31754
|
} = useFeedbackRepo();
|
|
31755
|
+
async function requireFeedbackReach(req, _id) {
|
|
31756
|
+
const row = await _getRawFeedbackById(_id);
|
|
31757
|
+
await requireSiteReach(req, row?.metadata?.site ?? row?.site);
|
|
31758
|
+
}
|
|
31759
|
+
async function requireFeedback2Reach(req, _id) {
|
|
31760
|
+
const row = await _getRawFeedback2ById(_id);
|
|
31761
|
+
await requireSiteReach(req, row?.site ?? row?.metadata?.site);
|
|
31762
|
+
}
|
|
31717
31763
|
async function createFeedback(req, res, next) {
|
|
31718
|
-
const
|
|
31719
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
31720
|
-
{}
|
|
31721
|
-
);
|
|
31722
|
-
const createdBy = cookies?.["user"].toString() ?? "";
|
|
31764
|
+
const createdBy = callerId(req);
|
|
31723
31765
|
const payload = { ...req.body, createdBy };
|
|
31724
31766
|
const { error } = feedbackSchema.validate(payload);
|
|
31725
31767
|
if (error) {
|
|
@@ -31728,6 +31770,7 @@ function useFeedbackController() {
|
|
|
31728
31770
|
return;
|
|
31729
31771
|
}
|
|
31730
31772
|
try {
|
|
31773
|
+
await requireSiteReach(req, payload.metadata?.site ?? payload.site);
|
|
31731
31774
|
await _createFeedback(payload);
|
|
31732
31775
|
res.status(201).json({ message: "Successfully created feedback." });
|
|
31733
31776
|
return;
|
|
@@ -31768,6 +31811,7 @@ function useFeedbackController() {
|
|
|
31768
31811
|
const to = req.query.to ?? "";
|
|
31769
31812
|
const category = req.query.category ?? "";
|
|
31770
31813
|
try {
|
|
31814
|
+
await requireSiteReach(req, site);
|
|
31771
31815
|
const data = await _getFeedbacks({
|
|
31772
31816
|
search,
|
|
31773
31817
|
page,
|
|
@@ -31797,6 +31841,7 @@ function useFeedbackController() {
|
|
|
31797
31841
|
return;
|
|
31798
31842
|
}
|
|
31799
31843
|
try {
|
|
31844
|
+
await requireFeedbackReach(req, _id);
|
|
31800
31845
|
const data = await _getFeedbackById(_id);
|
|
31801
31846
|
res.json(data);
|
|
31802
31847
|
return;
|
|
@@ -31825,6 +31870,7 @@ function useFeedbackController() {
|
|
|
31825
31870
|
return;
|
|
31826
31871
|
}
|
|
31827
31872
|
try {
|
|
31873
|
+
await requireFeedbackReach(req, _id);
|
|
31828
31874
|
await _updateFeedback(_id, payload);
|
|
31829
31875
|
res.json({ message: "Successfully updated feedback." });
|
|
31830
31876
|
return;
|
|
@@ -31849,6 +31895,7 @@ function useFeedbackController() {
|
|
|
31849
31895
|
const _id = req.params.id;
|
|
31850
31896
|
const status = req.params.status;
|
|
31851
31897
|
try {
|
|
31898
|
+
await requireFeedbackReach(req, _id);
|
|
31852
31899
|
await _updateFeedbackStatus(_id, { status });
|
|
31853
31900
|
res.json({ message: "Successfully updated feedback status." });
|
|
31854
31901
|
return;
|
|
@@ -31872,6 +31919,7 @@ function useFeedbackController() {
|
|
|
31872
31919
|
return;
|
|
31873
31920
|
}
|
|
31874
31921
|
try {
|
|
31922
|
+
await requireFeedbackReach(req, _id);
|
|
31875
31923
|
await _updateFeedbackCategory(_id, { category });
|
|
31876
31924
|
res.json({ message: "Successfully updated feedback category." });
|
|
31877
31925
|
return;
|
|
@@ -31897,6 +31945,7 @@ function useFeedbackController() {
|
|
|
31897
31945
|
return;
|
|
31898
31946
|
}
|
|
31899
31947
|
try {
|
|
31948
|
+
await requireFeedbackReach(req, _id);
|
|
31900
31949
|
await _updateFeedbackToCompleted(_id, payload);
|
|
31901
31950
|
res.json({ message: "Successfully updated feedback to completed." });
|
|
31902
31951
|
return;
|
|
@@ -31916,6 +31965,7 @@ function useFeedbackController() {
|
|
|
31916
31965
|
return;
|
|
31917
31966
|
}
|
|
31918
31967
|
try {
|
|
31968
|
+
await requireFeedback2Reach(req, _id);
|
|
31919
31969
|
await _deleteFeedback(_id);
|
|
31920
31970
|
res.json({ message: "Successfully deleted feedback." });
|
|
31921
31971
|
return;
|
|
@@ -32096,17 +32146,23 @@ function useWorkOrderController() {
|
|
|
32096
32146
|
const { createWorkOrder: _createWorkOrder, getWorkOrders: _getWorkOrders } = useWorkOrderService();
|
|
32097
32147
|
const {
|
|
32098
32148
|
getWorkOrderById: _getWorkOrderById,
|
|
32149
|
+
getRawWorkOrderById: _getRawWorkOrderById,
|
|
32150
|
+
getRawWorkOrder2ById: _getRawWorkOrder2ById,
|
|
32099
32151
|
updateWorkOrder: _updateWorkOrder,
|
|
32100
32152
|
updateWorkOrderStatus: _updateWorkOrderStatus,
|
|
32101
32153
|
updateWorkOrderToCompleted: _updateWorkOrderToCompleted,
|
|
32102
32154
|
deleteWorkOrder: _deleteWorkOrder
|
|
32103
32155
|
} = useWorkOrderRepo();
|
|
32156
|
+
async function requireWorkOrderReach(req, _id) {
|
|
32157
|
+
const row = await _getRawWorkOrderById(_id);
|
|
32158
|
+
await requireSiteReach(req, row?.metadata?.site ?? row?.site);
|
|
32159
|
+
}
|
|
32160
|
+
async function requireWorkOrder2Reach(req, _id) {
|
|
32161
|
+
const row = await _getRawWorkOrder2ById(_id);
|
|
32162
|
+
await requireSiteReach(req, row?.site ?? row?.metadata?.site);
|
|
32163
|
+
}
|
|
32104
32164
|
async function createWorkOrder(req, res, next) {
|
|
32105
|
-
const
|
|
32106
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
32107
|
-
{}
|
|
32108
|
-
);
|
|
32109
|
-
const createdBy = cookies?.["user"].toString() ?? "";
|
|
32165
|
+
const createdBy = callerId(req);
|
|
32110
32166
|
const payload = { ...req.body, createdBy };
|
|
32111
32167
|
const { error } = workOrderSchema.validate({ ...payload });
|
|
32112
32168
|
if (error) {
|
|
@@ -32116,6 +32172,7 @@ function useWorkOrderController() {
|
|
|
32116
32172
|
}
|
|
32117
32173
|
const fullHost = req.headers.origin;
|
|
32118
32174
|
try {
|
|
32175
|
+
await requireSiteReach(req, payload.site || payload.metadata?.site);
|
|
32119
32176
|
const workOrder = await _createWorkOrder(payload, fullHost);
|
|
32120
32177
|
res.status(201).json({
|
|
32121
32178
|
message: "Successfully created work order.",
|
|
@@ -32156,6 +32213,7 @@ function useWorkOrderController() {
|
|
|
32156
32213
|
const serviceProvider = req.query.serviceProvider ?? "";
|
|
32157
32214
|
const category = req.query.category ?? "";
|
|
32158
32215
|
try {
|
|
32216
|
+
await requireSiteReach(req, site);
|
|
32159
32217
|
const data = await _getWorkOrders({
|
|
32160
32218
|
search,
|
|
32161
32219
|
page,
|
|
@@ -32183,6 +32241,7 @@ function useWorkOrderController() {
|
|
|
32183
32241
|
return;
|
|
32184
32242
|
}
|
|
32185
32243
|
try {
|
|
32244
|
+
await requireWorkOrderReach(req, _id);
|
|
32186
32245
|
const data = await _getWorkOrderById(_id);
|
|
32187
32246
|
res.json(data);
|
|
32188
32247
|
return;
|
|
@@ -32214,6 +32273,10 @@ function useWorkOrderController() {
|
|
|
32214
32273
|
return;
|
|
32215
32274
|
}
|
|
32216
32275
|
try {
|
|
32276
|
+
await requireWorkOrderReach(req, _id);
|
|
32277
|
+
if (payload.site) {
|
|
32278
|
+
await requireSiteReach(req, payload.site);
|
|
32279
|
+
}
|
|
32217
32280
|
await _updateWorkOrder(_id, payload);
|
|
32218
32281
|
res.json({ message: "Successfully updated work order." });
|
|
32219
32282
|
return;
|
|
@@ -32237,6 +32300,7 @@ function useWorkOrderController() {
|
|
|
32237
32300
|
const _id = req.params.id;
|
|
32238
32301
|
const status = req.params.status;
|
|
32239
32302
|
try {
|
|
32303
|
+
await requireWorkOrderReach(req, _id);
|
|
32240
32304
|
await _updateWorkOrderStatus(_id, { status });
|
|
32241
32305
|
res.json({ message: "Successfully updated work order status." });
|
|
32242
32306
|
return;
|
|
@@ -32262,6 +32326,7 @@ function useWorkOrderController() {
|
|
|
32262
32326
|
return;
|
|
32263
32327
|
}
|
|
32264
32328
|
try {
|
|
32329
|
+
await requireWorkOrderReach(req, _id);
|
|
32265
32330
|
await _updateWorkOrderToCompleted(_id, payload);
|
|
32266
32331
|
res.json({ message: "Successfully updated work order to completed." });
|
|
32267
32332
|
return;
|
|
@@ -32280,6 +32345,7 @@ function useWorkOrderController() {
|
|
|
32280
32345
|
return;
|
|
32281
32346
|
}
|
|
32282
32347
|
try {
|
|
32348
|
+
await requireWorkOrder2Reach(req, _id);
|
|
32283
32349
|
await _deleteWorkOrder(_id);
|
|
32284
32350
|
res.json({ message: "Successfully deleted work order." });
|
|
32285
32351
|
return;
|