@7365admin1/core 3.64.3-staging.288 → 3.64.3-staging.290
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/module-gate-foundation.md +20 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +53 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +53 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/test/module-gate.test.mjs +237 -0
- package/test/org-modules.test.mjs +78 -0
- package/test/site-modules.test.mjs +84 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Lay the groundwork for module lists becoming a gate, without narrowing anyone.
|
|
6
|
+
|
|
7
|
+
- New `utils/module-gate.util.ts`: the list of modules a client's list can
|
|
8
|
+
govern (generated from layer-common 5a96f95), the spelling groups, the
|
|
9
|
+
always-included set, and pure functions that work out which modules a
|
|
10
|
+
caller's apps must hide (`deniedModules`) and who would lose what if a list
|
|
11
|
+
changed (`moduleImpact`). Nothing calls them yet.
|
|
12
|
+
- The organisation and site module checks now treat every spelling of a module
|
|
13
|
+
as the same module (ticking `workOrder` also allows `work_orders`,
|
|
14
|
+
`work_order` and `work-orders`), and never refuse members, invitations, roles,
|
|
15
|
+
sites, customers, subscriptions, payment methods or site settings. This only
|
|
16
|
+
ever refuses less than before.
|
|
17
|
+
- A Site Settings save (`PATCH /api/sites/id/:id`) now always keeps the site's
|
|
18
|
+
stored module list. Before this, the save replaced `metadata` wholesale and
|
|
19
|
+
could wipe or overwrite that list. `PATCH /api/sites/:id/modules` is the only
|
|
20
|
+
way to change it.
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -11689,13 +11689,42 @@ function normaliseModules(modules) {
|
|
|
11689
11689
|
}
|
|
11690
11690
|
return out;
|
|
11691
11691
|
}
|
|
11692
|
+
var ALWAYS_ALLOWED = Object.freeze([
|
|
11693
|
+
"sites",
|
|
11694
|
+
"subscriptions",
|
|
11695
|
+
"customers",
|
|
11696
|
+
"payment-methods",
|
|
11697
|
+
"members",
|
|
11698
|
+
"invitations",
|
|
11699
|
+
"roles",
|
|
11700
|
+
"roles-and-permissions",
|
|
11701
|
+
"site-settings"
|
|
11702
|
+
]);
|
|
11703
|
+
var SPELLING_GROUPS = Object.freeze(
|
|
11704
|
+
[
|
|
11705
|
+
["work_orders", "workOrder", "work_order", "work-orders"],
|
|
11706
|
+
["visitor-mgmt", "visitorManagement"],
|
|
11707
|
+
["bulletin-board", "bulletin-board-mgmt"],
|
|
11708
|
+
["facility-booking-mgmt", "facility-booking"],
|
|
11709
|
+
["feedbacks", "feedback"],
|
|
11710
|
+
["building-mgmt", "buildingManagement"],
|
|
11711
|
+
["roles", "roles-and-permissions"],
|
|
11712
|
+
["service-provider-mgmt", "service-provider"],
|
|
11713
|
+
["online-form-configuration", "online-forms"]
|
|
11714
|
+
].map((group) => Object.freeze(group))
|
|
11715
|
+
);
|
|
11716
|
+
function moduleSpellings(key) {
|
|
11717
|
+
return SPELLING_GROUPS.find((group) => group.includes(key)) ?? [key];
|
|
11718
|
+
}
|
|
11692
11719
|
function orgAllowsModule(modules, resource) {
|
|
11693
11720
|
if (!Array.isArray(modules) || modules.length === 0)
|
|
11694
11721
|
return true;
|
|
11695
11722
|
const key = typeof resource === "string" ? resource.trim() : "";
|
|
11696
11723
|
if (!key)
|
|
11697
11724
|
return true;
|
|
11698
|
-
|
|
11725
|
+
if (ALWAYS_ALLOWED.includes(key))
|
|
11726
|
+
return true;
|
|
11727
|
+
return moduleSpellings(key).some((spelling) => modules.includes(spelling));
|
|
11699
11728
|
}
|
|
11700
11729
|
|
|
11701
11730
|
// src/models/site.model.ts
|
|
@@ -11722,7 +11751,15 @@ function rejectedSiteModules(orgModules, requested) {
|
|
|
11722
11751
|
if (!narrows(orgModules))
|
|
11723
11752
|
return [];
|
|
11724
11753
|
const org = normaliseModules(orgModules);
|
|
11725
|
-
return normaliseModules(requested).filter((key) => !org
|
|
11754
|
+
return normaliseModules(requested).filter((key) => !orgAllowsModule(org, key));
|
|
11755
|
+
}
|
|
11756
|
+
function keepStoredSiteModules(metadata, stored) {
|
|
11757
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
|
|
11758
|
+
return metadata;
|
|
11759
|
+
}
|
|
11760
|
+
const { modules: _sent, ...rest } = metadata;
|
|
11761
|
+
const kept = stored && typeof stored === "object" && !Array.isArray(stored) ? stored.modules : void 0;
|
|
11762
|
+
return kept === void 0 ? rest : { ...rest, modules: kept };
|
|
11726
11763
|
}
|
|
11727
11764
|
function rejectedSiteModulesMessage(rejected) {
|
|
11728
11765
|
return `This organisation has not been given ${rejected.join(", ")}, so a site cannot offer it. Ask Seven365 to add it to the organisation first.`;
|
|
@@ -38727,8 +38764,8 @@ function useSiteController() {
|
|
|
38727
38764
|
}
|
|
38728
38765
|
const { _id, ...rest } = value;
|
|
38729
38766
|
await requireSiteWrite(req, _id);
|
|
38767
|
+
const existing = rest?.metadata ? await _getSiteById(_id) : null;
|
|
38730
38768
|
if (rest?.metadata?.residentAppModules) {
|
|
38731
|
-
const existing = await _getSiteById(_id);
|
|
38732
38769
|
const org = existing?.orgId ? await _getOrgById(existing.orgId.toString()).catch(
|
|
38733
38770
|
() => null
|
|
38734
38771
|
) : null;
|
|
@@ -38743,6 +38780,12 @@ function useSiteController() {
|
|
|
38743
38780
|
return;
|
|
38744
38781
|
}
|
|
38745
38782
|
}
|
|
38783
|
+
if (rest?.metadata) {
|
|
38784
|
+
rest.metadata = keepStoredSiteModules(
|
|
38785
|
+
rest.metadata,
|
|
38786
|
+
existing?.metadata
|
|
38787
|
+
);
|
|
38788
|
+
}
|
|
38746
38789
|
await _updateById(_id, rest);
|
|
38747
38790
|
res.json({ message: "Successfully updated site." });
|
|
38748
38791
|
return;
|
|
@@ -56240,7 +56283,6 @@ function UseAccessManagementRepo() {
|
|
|
56240
56283
|
const type = params.type;
|
|
56241
56284
|
const search = params.search;
|
|
56242
56285
|
const typeFilter = type.toLowerCase() === "all" ? [] : [{ $eq: ["$type", type] }];
|
|
56243
|
-
const userIdFilter = params.userId ? [{ $eq: ["$userId", new import_mongodb90.ObjectId(params.userId)] }] : [];
|
|
56244
56286
|
const searchFilter = search ? [
|
|
56245
56287
|
{
|
|
56246
56288
|
$or: [
|
|
@@ -56315,7 +56357,9 @@ function UseAccessManagementRepo() {
|
|
|
56315
56357
|
{ $eq: ["$isActivated", true] },
|
|
56316
56358
|
{ $eq: ["$userType", userType] },
|
|
56317
56359
|
...typeFilter,
|
|
56318
|
-
|
|
56360
|
+
// Cards actually held by a user only - a card sitting
|
|
56361
|
+
// unassigned on the unit (`userId: null`) is left out.
|
|
56362
|
+
{ $ne: ["$userId", null] }
|
|
56319
56363
|
]
|
|
56320
56364
|
},
|
|
56321
56365
|
...searchFilter[0]
|
|
@@ -71374,24 +71418,21 @@ function useAccessManagementController() {
|
|
|
71374
71418
|
unitId,
|
|
71375
71419
|
userType,
|
|
71376
71420
|
type,
|
|
71377
|
-
search = ""
|
|
71378
|
-
userId = ""
|
|
71421
|
+
search = ""
|
|
71379
71422
|
} = req.query;
|
|
71380
71423
|
const schema2 = import_joi101.default.object({
|
|
71381
71424
|
site: import_joi101.default.string().hex().required(),
|
|
71382
71425
|
unitId: import_joi101.default.string().hex().required(),
|
|
71383
71426
|
userType: import_joi101.default.string().required(),
|
|
71384
71427
|
type: import_joi101.default.string().valid("all", ...Object.values(EAccessCardTypes)).required(),
|
|
71385
|
-
search: import_joi101.default.string().optional().allow("", null)
|
|
71386
|
-
userId: import_joi101.default.string().hex().optional().allow("", null)
|
|
71428
|
+
search: import_joi101.default.string().optional().allow("", null)
|
|
71387
71429
|
});
|
|
71388
71430
|
const { error } = schema2.validate({
|
|
71389
71431
|
site,
|
|
71390
71432
|
unitId,
|
|
71391
71433
|
userType,
|
|
71392
71434
|
type,
|
|
71393
|
-
search
|
|
71394
|
-
userId
|
|
71435
|
+
search
|
|
71395
71436
|
});
|
|
71396
71437
|
if (error) {
|
|
71397
71438
|
return res.status(400).json({ message: error.message });
|
|
@@ -71403,8 +71444,7 @@ function useAccessManagementController() {
|
|
|
71403
71444
|
unitId,
|
|
71404
71445
|
userType,
|
|
71405
71446
|
type,
|
|
71406
|
-
search
|
|
71407
|
-
userId
|
|
71447
|
+
search
|
|
71408
71448
|
});
|
|
71409
71449
|
return res.status(200).json({ message: "Success", data: result });
|
|
71410
71450
|
} catch (error) {
|