@7365admin1/core 3.48.1-staging.190 → 3.48.1-staging.192
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-designation-site-scope.md +11 -0
- package/.changeset/online-form-site-scope.md +15 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +61 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +117 -59
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/harness.mjs +38 -0
- package/test/e2e/manpower-designation-scope.e2e.test.mjs +407 -0
- package/test/e2e/online-form-scope.e2e.test.mjs +547 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the manpower designation routes to the estate, and stamp who filed the plan
|
|
6
|
+
from the session. `/api/manpower-designations` carried `requireAuth` and nothing
|
|
7
|
+
else on all three routes: any signed-in account could file a manning plan into
|
|
8
|
+
another estate, read any estate's guard-strength plan, or rewrite one by id alone.
|
|
9
|
+
`createdBy` and `createdByName` were taken from the request body, so the plan could
|
|
10
|
+
be attributed to anybody. Reach is now checked on the site named in the request and
|
|
11
|
+
on the stored row for the update, and the two identity fields come from the session.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the online form routes to the estate
|
|
6
|
+
|
|
7
|
+
All six `/api/online-forms` routes carried `requireAuth` and nothing more, so any
|
|
8
|
+
signed-in account on the platform could read, rewrite, move or archive another
|
|
9
|
+
estate's form templates. The controller now takes its verdict from the session:
|
|
10
|
+
a new `requireOnlineFormReach` for the by-id read, update and delete, a site
|
|
11
|
+
check on the add and on the by-site list, both tenancy filters closed on the
|
|
12
|
+
list query, and the update's destination `site` checked as well as the source.
|
|
13
|
+
`createdBy`/`updatedBy` are stamped from the session instead of the caller's
|
|
14
|
+
`user` cookie, and `getOnlineFormsBySiteId` now actually applies the estate
|
|
15
|
+
filter it was given.
|
package/dist/index.d.ts
CHANGED
|
@@ -8807,6 +8807,7 @@ declare class MManpowerDesignations implements Partial<TManpowerDesignations> {
|
|
|
8807
8807
|
declare function useManpowerDesignationRepo(): {
|
|
8808
8808
|
createManpowerDesignations: (value: TManpowerDesignations) => Promise<mongodb.InsertOneResult<bson.Document>>;
|
|
8809
8809
|
getManpowerDesignationsBySiteId: (_id: string | ObjectId, serviceProviderId?: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
8810
|
+
getManpowerDesignationsById: (_id: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
8810
8811
|
updateManpowerDesignations: (_id: string | ObjectId, value: TManpowerDesignationsUpdate) => Promise<number>;
|
|
8811
8812
|
createIndexes: () => Promise<string>;
|
|
8812
8813
|
};
|
package/dist/index.js
CHANGED
|
@@ -73090,8 +73090,9 @@ function useOnlineFormRepo() {
|
|
|
73090
73090
|
query2.$or = [{ name: { $regex: search, $options: "i" } }];
|
|
73091
73091
|
cacheOptions.search = search;
|
|
73092
73092
|
}
|
|
73093
|
+
query2.site = site;
|
|
73093
73094
|
cacheOptions.site = site;
|
|
73094
|
-
const cacheKey = (0, import_node_server_utils227.makeCacheKey)(namespace_collection,
|
|
73095
|
+
const cacheKey = (0, import_node_server_utils227.makeCacheKey)(namespace_collection, cacheOptions);
|
|
73095
73096
|
const cachedData = await getCache(cacheKey);
|
|
73096
73097
|
if (cachedData) {
|
|
73097
73098
|
import_node_server_utils227.logger.info(`Cache hit for key: ${cacheKey}`);
|
|
@@ -73147,12 +73148,16 @@ function useOnlineFormController() {
|
|
|
73147
73148
|
deleteOnlineFormById: _deleteOnlineFormById,
|
|
73148
73149
|
getOnlineFormsBySiteId: _getOnlineFormsBySiteId
|
|
73149
73150
|
} = useOnlineFormRepo();
|
|
73151
|
+
async function requireOnlineFormReach(req, id) {
|
|
73152
|
+
const form = await _getOnlineFormById(id);
|
|
73153
|
+
const { canReach } = await siteReachOf(req);
|
|
73154
|
+
if (!await canReach(form)) {
|
|
73155
|
+
throw new import_node_server_utils228.NotFoundError("Document not found.");
|
|
73156
|
+
}
|
|
73157
|
+
return form;
|
|
73158
|
+
}
|
|
73150
73159
|
async function add(req, res, next) {
|
|
73151
|
-
const
|
|
73152
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
73153
|
-
{}
|
|
73154
|
-
);
|
|
73155
|
-
const createdBy = cookies?.["user"].toString() ?? "";
|
|
73160
|
+
const createdBy = callerId(req);
|
|
73156
73161
|
const payload = { ...req.body, createdBy };
|
|
73157
73162
|
const { error } = schemaOnlineForm.validate(payload, {
|
|
73158
73163
|
abortEarly: false
|
|
@@ -73164,6 +73169,7 @@ function useOnlineFormController() {
|
|
|
73164
73169
|
return;
|
|
73165
73170
|
}
|
|
73166
73171
|
try {
|
|
73172
|
+
await requireSiteReach(req, payload.site);
|
|
73167
73173
|
const data = await _add(payload);
|
|
73168
73174
|
res.status(201).json({ message: data });
|
|
73169
73175
|
return;
|
|
@@ -73197,6 +73203,15 @@ function useOnlineFormController() {
|
|
|
73197
73203
|
const org = req.query.org ?? "";
|
|
73198
73204
|
const site = req.query.site ?? "";
|
|
73199
73205
|
try {
|
|
73206
|
+
const { actor } = await siteReachOf(req);
|
|
73207
|
+
if (site) {
|
|
73208
|
+
await requireSiteReach(req, site);
|
|
73209
|
+
} else if (!actor.isSuperAdmin) {
|
|
73210
|
+
throw new import_node_server_utils228.UnauthorizedError("Not authorized.");
|
|
73211
|
+
}
|
|
73212
|
+
if (org && !actor.isSuperAdmin && !actor.orgIds.includes(org)) {
|
|
73213
|
+
throw new import_node_server_utils228.UnauthorizedError("Not authorized.");
|
|
73214
|
+
}
|
|
73200
73215
|
const data = await _getAll({ search, page, limit, status, org, site });
|
|
73201
73216
|
res.json(data);
|
|
73202
73217
|
return;
|
|
@@ -73216,7 +73231,7 @@ function useOnlineFormController() {
|
|
|
73216
73231
|
return;
|
|
73217
73232
|
}
|
|
73218
73233
|
try {
|
|
73219
|
-
const data = await
|
|
73234
|
+
const data = await requireOnlineFormReach(req, _id);
|
|
73220
73235
|
res.json(data);
|
|
73221
73236
|
return;
|
|
73222
73237
|
} catch (error2) {
|
|
@@ -73243,11 +73258,7 @@ function useOnlineFormController() {
|
|
|
73243
73258
|
site: import_joi118.default.string().hex().optional().allow("", null),
|
|
73244
73259
|
updatedBy: import_joi118.default.string().hex().optional().allow("", null)
|
|
73245
73260
|
});
|
|
73246
|
-
const
|
|
73247
|
-
(acc, [key, value]) => ({ ...acc, [key]: value }),
|
|
73248
|
-
{}
|
|
73249
|
-
);
|
|
73250
|
-
const updatedBy = cookies?.["user"].toString() ?? "";
|
|
73261
|
+
const updatedBy = callerId(req);
|
|
73251
73262
|
const _id = req.params.id;
|
|
73252
73263
|
const payload = { ...req.body, updatedBy };
|
|
73253
73264
|
const { error } = validation.validate({ _id, ...payload });
|
|
@@ -73257,6 +73268,16 @@ function useOnlineFormController() {
|
|
|
73257
73268
|
return;
|
|
73258
73269
|
}
|
|
73259
73270
|
try {
|
|
73271
|
+
await requireOnlineFormReach(req, _id);
|
|
73272
|
+
if (payload.site) {
|
|
73273
|
+
await requireSiteReach(req, payload.site);
|
|
73274
|
+
}
|
|
73275
|
+
if (payload.org) {
|
|
73276
|
+
const { actor } = await siteReachOf(req);
|
|
73277
|
+
if (!actor.isSuperAdmin && !actor.orgIds.includes(payload.org)) {
|
|
73278
|
+
throw new import_node_server_utils228.UnauthorizedError("Not authorized.");
|
|
73279
|
+
}
|
|
73280
|
+
}
|
|
73260
73281
|
await _updateOnlineFormById(_id, payload);
|
|
73261
73282
|
res.json({ message: "Successfully updated online form." });
|
|
73262
73283
|
return;
|
|
@@ -73276,6 +73297,7 @@ function useOnlineFormController() {
|
|
|
73276
73297
|
return;
|
|
73277
73298
|
}
|
|
73278
73299
|
try {
|
|
73300
|
+
await requireOnlineFormReach(req, _id);
|
|
73279
73301
|
await _deleteOnlineFormById(_id);
|
|
73280
73302
|
res.json({ message: "Successfully deleted online form." });
|
|
73281
73303
|
return;
|
|
@@ -73297,6 +73319,7 @@ function useOnlineFormController() {
|
|
|
73297
73319
|
return;
|
|
73298
73320
|
}
|
|
73299
73321
|
try {
|
|
73322
|
+
await requireSiteReach(req, _id);
|
|
73300
73323
|
const data = await _getOnlineFormsBySiteId(_id, { ...query2 });
|
|
73301
73324
|
res.json(data);
|
|
73302
73325
|
return;
|
|
@@ -76993,6 +77016,14 @@ function useManpowerDesignationRepo() {
|
|
|
76993
77016
|
throw error;
|
|
76994
77017
|
}
|
|
76995
77018
|
}
|
|
77019
|
+
async function getManpowerDesignationsById(_id) {
|
|
77020
|
+
try {
|
|
77021
|
+
_id = new import_mongodb151.ObjectId(_id);
|
|
77022
|
+
} catch (error) {
|
|
77023
|
+
return null;
|
|
77024
|
+
}
|
|
77025
|
+
return await collection.findOne({ _id });
|
|
77026
|
+
}
|
|
76996
77027
|
async function updateManpowerDesignations(_id, value) {
|
|
76997
77028
|
try {
|
|
76998
77029
|
_id = new import_mongodb151.ObjectId(_id);
|
|
@@ -77016,6 +77047,7 @@ function useManpowerDesignationRepo() {
|
|
|
77016
77047
|
return {
|
|
77017
77048
|
createManpowerDesignations,
|
|
77018
77049
|
getManpowerDesignationsBySiteId,
|
|
77050
|
+
getManpowerDesignationsById,
|
|
77019
77051
|
updateManpowerDesignations,
|
|
77020
77052
|
createIndexes
|
|
77021
77053
|
};
|
|
@@ -77028,8 +77060,17 @@ function useManpowerDesignationCtrl() {
|
|
|
77028
77060
|
const {
|
|
77029
77061
|
createManpowerDesignations: _createManpowerDesignations,
|
|
77030
77062
|
getManpowerDesignationsBySiteId: _getManpowerDesignationsBySiteId,
|
|
77063
|
+
getManpowerDesignationsById: _getManpowerDesignationsById,
|
|
77031
77064
|
updateManpowerDesignations: _updateManpowerDesignations
|
|
77032
77065
|
} = useManpowerDesignationRepo();
|
|
77066
|
+
async function requireDesignationReach(req, _id) {
|
|
77067
|
+
const row = await _getManpowerDesignationsById(_id);
|
|
77068
|
+
const { canReach } = await siteReachOf(req);
|
|
77069
|
+
if (!row || !await canReach({ site: row.siteId })) {
|
|
77070
|
+
throw new import_node_server_utils241.NotFoundError("Manpower designations not found.");
|
|
77071
|
+
}
|
|
77072
|
+
return row;
|
|
77073
|
+
}
|
|
77033
77074
|
async function createManpowerDesignations(req, res, next) {
|
|
77034
77075
|
try {
|
|
77035
77076
|
const payload = { ...req.body };
|
|
@@ -77038,6 +77079,12 @@ function useManpowerDesignationCtrl() {
|
|
|
77038
77079
|
next(new import_node_server_utils241.BadRequestError(error.message));
|
|
77039
77080
|
return;
|
|
77040
77081
|
}
|
|
77082
|
+
const { actor, canReach } = await siteReachOf(req);
|
|
77083
|
+
if (!await canReach({ site: payload.siteId })) {
|
|
77084
|
+
throw new import_node_server_utils241.NotFoundError("Site not found.");
|
|
77085
|
+
}
|
|
77086
|
+
payload.createdBy = actor.id;
|
|
77087
|
+
payload.createdByName = actor.name;
|
|
77041
77088
|
const result = await _createManpowerDesignations(payload);
|
|
77042
77089
|
return res.json(result);
|
|
77043
77090
|
} catch (error) {
|
|
@@ -77058,6 +77105,7 @@ function useManpowerDesignationCtrl() {
|
|
|
77058
77105
|
next(new import_node_server_utils241.BadRequestError(error.message));
|
|
77059
77106
|
return;
|
|
77060
77107
|
}
|
|
77108
|
+
await requireSiteReach(req, id);
|
|
77061
77109
|
const result = await _getManpowerDesignationsBySiteId(
|
|
77062
77110
|
id,
|
|
77063
77111
|
serviceProviderId
|
|
@@ -77082,6 +77130,7 @@ function useManpowerDesignationCtrl() {
|
|
|
77082
77130
|
next(new import_node_server_utils241.BadRequestError(error.message));
|
|
77083
77131
|
return;
|
|
77084
77132
|
}
|
|
77133
|
+
await requireDesignationReach(req, _id);
|
|
77085
77134
|
const result = await _updateManpowerDesignations(_id, payload);
|
|
77086
77135
|
return res.json(result);
|
|
77087
77136
|
} catch (error) {
|