@7365admin1/core 3.64.3-staging.287 → 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,17 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ Use the organisation the app asks for when loading a user's membership.
6
+
7
+ Every mobile app loads its user's role through
8
+ `GET /api/members/user/:id/app/:type?org=<org>`, and `getByUserIdType` ignored
9
+ `org`, answering with the first membership of that app type it found. A person
10
+ in more than one organisation could therefore be handed another organisation's
11
+ membership in the app they were using.
12
+
13
+ It now prefers a LIVE membership in the requested organisation. When there is
14
+ none there (or only a removed one), or no valid `org` is sent, it answers exactly
15
+ as before, so no caller that received a membership now receives "not found", and
16
+ a removed membership never wins over a live one. Login and the other internal
17
+ uses of the repository lookup are unchanged.
@@ -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.`;
@@ -27949,9 +27986,12 @@ function useMemberController() {
27949
27986
  }
27950
27987
  const user = req.params.id;
27951
27988
  const type = req.params.type;
27989
+ const org = typeof req.query.org === "string" && /^[0-9a-fA-F]{24}$/.test(req.query.org) ? req.query.org : "";
27952
27990
  try {
27953
27991
  await requireSelfOrPlatformStaff(req, user, { resource: "members", action: "view-members" });
27954
- const data = await _getByUserIdType(user, type);
27992
+ const inOrg = org ? await _getByUserIdTypeOrg(user, type, org).catch(() => null) : null;
27993
+ const liveInOrg = inOrg && inOrg.status !== "deleted" && !inOrg.deletedAt ? inOrg : null;
27994
+ const data = liveInOrg ?? await _getByUserIdType(user, type);
27955
27995
  res.json(data);
27956
27996
  return;
27957
27997
  } catch (error2) {
@@ -38724,8 +38764,8 @@ function useSiteController() {
38724
38764
  }
38725
38765
  const { _id, ...rest } = value;
38726
38766
  await requireSiteWrite(req, _id);
38767
+ const existing = rest?.metadata ? await _getSiteById(_id) : null;
38727
38768
  if (rest?.metadata?.residentAppModules) {
38728
- const existing = await _getSiteById(_id);
38729
38769
  const org = existing?.orgId ? await _getOrgById(existing.orgId.toString()).catch(
38730
38770
  () => null
38731
38771
  ) : null;
@@ -38740,6 +38780,12 @@ function useSiteController() {
38740
38780
  return;
38741
38781
  }
38742
38782
  }
38783
+ if (rest?.metadata) {
38784
+ rest.metadata = keepStoredSiteModules(
38785
+ rest.metadata,
38786
+ existing?.metadata
38787
+ );
38788
+ }
38743
38789
  await _updateById(_id, rest);
38744
38790
  res.json({ message: "Successfully updated site." });
38745
38791
  return;