@7365admin1/core 3.139.0 → 3.140.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @iservice365/core
2
2
 
3
+ ## 3.140.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ff48585: A person's memberships list (`GET /members/users/:id`) leaves out taken-away (inactive / deleted) memberships by default; `?include=removed` returns the history. One shared entitlement test (`isEntitledMembership`, `entitledMemberships`) now also drives the site/org membership lookup, notification categories and role permissions.
8
+
9
+ ## 3.139.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 45755c1: Security: a membership that was taken away ("inactive" after the service-provider Repair or Finish-setup Undo, or "deleted") no longer grants organisation, site or role reach (resolveInviteActor, camera site entitlement, role-holder check).
14
+
3
15
  ## 3.139.0
4
16
 
5
17
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -1095,7 +1095,9 @@ declare function useMemberService(): {
1095
1095
  updateSiteById: (id: string, siteId: string, siteName: string) => Promise<{
1096
1096
  message: string;
1097
1097
  }>;
1098
- getAllByUser: (user: string) => Promise<{
1098
+ getAllByUser: (user: string, { includeRemoved }?: {
1099
+ includeRemoved?: boolean | undefined;
1100
+ }) => Promise<{
1099
1101
  items: TMember[];
1100
1102
  total: number;
1101
1103
  }>;
package/dist/index.js CHANGED
@@ -4374,7 +4374,10 @@ function sameAppType(a, b) {
4374
4374
  // src/utils/member-lookup.util.ts
4375
4375
  var idOf = (v) => v == null ? "" : String(v?._id ?? v).toLowerCase();
4376
4376
  function isLiveMembership(m) {
4377
- return m.status !== "deleted" && !m.deletedAt;
4377
+ return !TAKEN_AWAY_MEMBER_STATUSES.includes(String(m?.status ?? "")) && !m?.deletedAt;
4378
+ }
4379
+ function entitledMemberships(rows) {
4380
+ return (Array.isArray(rows) ? rows : []).filter(isLiveMembership);
4378
4381
  }
4379
4382
  function pickSiteMembership(rows, type, site, org = "") {
4380
4383
  site = site.toLowerCase();
@@ -4402,6 +4405,7 @@ function pickLookupMembership(rows, type, site = "", org = "") {
4402
4405
  return preferWorkingMembership(list.filter((m) => sameAppType(m.type, type)));
4403
4406
  }
4404
4407
  var WORKING = /* @__PURE__ */ new Set(["active", "approved"]);
4408
+ var TAKEN_AWAY_MEMBER_STATUSES = ["deleted", "inactive"];
4405
4409
  function preferWorkingMembership(rows, defaultOrg = "") {
4406
4410
  const list = Array.isArray(rows) ? rows : [];
4407
4411
  const working = list.filter((m) => WORKING.has(String(m.status ?? "")) && !m.deletedAt);
@@ -5255,7 +5259,7 @@ function useMemberRepo() {
5255
5259
  // sets it inactive, removal deletes it) must not keep the organisation
5256
5260
  // on the person's list: latitude.sec@ still saw JLL Singapore beside its
5257
5261
  // own company after the repair (owner report 2026-09-30).
5258
- status: { $nin: ["inactive", "deleted"] }
5262
+ status: { $nin: TAKEN_AWAY_MEMBER_STATUSES }
5259
5263
  };
5260
5264
  const cacheOptions = {
5261
5265
  page: page2,
@@ -9905,7 +9909,7 @@ async function resolveInviteActor(userId) {
9905
9909
  const db2 = import_node_server_utils28.useAtlas.getDb();
9906
9910
  if (!db2)
9907
9911
  return { ...EMPTY, id };
9908
- const members = await db2.collection("members").find({ user: new import_mongodb26.ObjectId(id), status: { $ne: "deleted" } }).toArray();
9912
+ const members = await db2.collection("members").find({ user: new import_mongodb26.ObjectId(id), status: { $nin: TAKEN_AWAY_MEMBER_STATUSES } }).toArray();
9909
9913
  const adminMember = members.find((m) => m.type === "admin");
9910
9914
  let isSuperAdmin2 = false;
9911
9915
  let staffPermissions;
@@ -10212,7 +10216,7 @@ async function holdsRole(userId, roleId, orgId) {
10212
10216
  const member = await db2.collection("members").findOne({
10213
10217
  user: new import_mongodb26.ObjectId(id),
10214
10218
  role: new import_mongodb26.ObjectId(role),
10215
- status: { $ne: "deleted" },
10219
+ status: { $nin: TAKEN_AWAY_MEMBER_STATUSES },
10216
10220
  // both shapes, as `hasOrgInvitation` does for `metadata.org`
10217
10221
  ...org ? { org: { $in: [new import_mongodb26.ObjectId(org), org] } } : {}
10218
10222
  });
@@ -23153,7 +23157,8 @@ async function getUserPermissions(params) {
23153
23157
  if (!roleId || !import_mongodb51.ObjectId.isValid(roleId)) {
23154
23158
  const memberQuery = {
23155
23159
  user: new import_mongodb51.ObjectId(user),
23156
- status: { $ne: "deleted" }
23160
+ // A taken-away (inactive) row grants no permissions either.
23161
+ status: { $nin: TAKEN_AWAY_MEMBER_STATUSES }
23157
23162
  };
23158
23163
  if (org && import_mongodb51.ObjectId.isValid(org)) {
23159
23164
  memberQuery.org = new import_mongodb51.ObjectId(org);
@@ -23243,7 +23248,7 @@ function useCameraViewService() {
23243
23248
  }
23244
23249
  }
23245
23250
  async function resolveSiteAccess(params) {
23246
- const memberships = await params.db.collection("members").find({ user: new import_mongodb52.ObjectId(params.userId), status: { $ne: "deleted" } }).project({ siteId: 1, org: 1, role: 1, type: 1 }).toArray();
23251
+ const memberships = await params.db.collection("members").find({ user: new import_mongodb52.ObjectId(params.userId), status: { $nin: TAKEN_AWAY_MEMBER_STATUSES } }).project({ siteId: 1, org: 1, role: 1, type: 1 }).toArray();
23247
23252
  const memberOrgIds = [
23248
23253
  ...new Map(
23249
23254
  memberships.filter((membership) => membership.org).map((membership) => [String(membership.org), membership.org])
@@ -29441,9 +29446,10 @@ function useMemberService() {
29441
29446
  throw error;
29442
29447
  }
29443
29448
  }
29444
- async function getAllByUser(user) {
29449
+ async function getAllByUser(user, { includeRemoved = false } = {}) {
29445
29450
  try {
29446
- const members = await _getAllByUserId(user);
29451
+ const all = await _getAllByUserId(user);
29452
+ const members = includeRemoved ? all : entitledMemberships(all);
29447
29453
  return {
29448
29454
  items: members,
29449
29455
  total: members.length
@@ -30004,7 +30010,9 @@ function useMemberController() {
30004
30010
  return;
30005
30011
  }
30006
30012
  try {
30007
- const data = await _getAllByUser(userId);
30013
+ const data = await _getAllByUser(userId, {
30014
+ includeRemoved: req.query.include === "removed"
30015
+ });
30008
30016
  const whole = await requireSelfOrPlatformStaff(req, userId, {
30009
30017
  resource: "members",
30010
30018
  action: "view-members"
@@ -30045,7 +30053,7 @@ function useMemberController() {
30045
30053
  org
30046
30054
  ) : null;
30047
30055
  const inOrg = org && !atSite ? await _getByUserIdTypeOrg(user, type, org).catch(() => null) : null;
30048
- const liveInOrg = inOrg && inOrg.status !== "deleted" && !inOrg.deletedAt ? inOrg : null;
30056
+ const liveInOrg = inOrg && isLiveMembership(inOrg) ? inOrg : null;
30049
30057
  const data = atSite ?? liveInOrg ?? await _getByUserIdType(user, type);
30050
30058
  res.json(data);
30051
30059
  return;
@@ -108074,7 +108082,7 @@ function useNotificationPreferenceService() {
108074
108082
  const db2 = import_node_server_utils330.useAtlas.getDb();
108075
108083
  if (!db2)
108076
108084
  return [];
108077
- const members = await db2.collection("members").find({ user: new import_mongodb200.ObjectId(userId), status: { $ne: "deleted" } }).toArray();
108085
+ const members = await db2.collection("members").find({ user: new import_mongodb200.ObjectId(userId), status: { $nin: TAKEN_AWAY_MEMBER_STATUSES } }).toArray();
108078
108086
  if (!members.length)
108079
108087
  return [];
108080
108088
  const isResident = members.some((m) => m.type === "resident");