@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.
@@ -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
- return modules.includes(key);
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.includes(key));
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;