@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.
@@ -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
@@ -7576,7 +7576,6 @@ declare function UseAccessManagementRepo(): {
7576
7576
  userType: string;
7577
7577
  type: string;
7578
7578
  search: string;
7579
- userId?: string | null;
7580
7579
  }) => Promise<bson.Document>;
7581
7580
  acknowlegdeCardRepo: (params: {
7582
7581
  userId: string[];
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;
@@ -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
- ...userIdFilter
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) {