@7365admin1/core 3.64.3-staging.288 → 3.64.3-staging.289
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.js +46 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -3
- 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.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;
|