@7365admin1/core 3.64.3-staging.283 → 3.64.3-staging.285

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/dist/index.d.ts CHANGED
@@ -4851,7 +4851,6 @@ declare function MPerson(value: TPerson): {
4851
4851
  end: string | Date | undefined;
4852
4852
  type: "resident" | "walk-in" | "drop-off" | "contractor" | "delivery" | "pick-up" | "guest" | "tenant" | undefined;
4853
4853
  email: string | undefined;
4854
- password: string;
4855
4854
  status: string;
4856
4855
  nric: string | undefined;
4857
4856
  remarks: string | undefined;
@@ -7577,6 +7576,7 @@ declare function UseAccessManagementRepo(): {
7577
7576
  userType: string;
7578
7577
  type: string;
7579
7578
  search: string;
7579
+ userId?: string | null;
7580
7580
  }) => Promise<bson.Document>;
7581
7581
  acknowlegdeCardRepo: (params: {
7582
7582
  userId: string[];
package/dist/index.js CHANGED
@@ -9035,6 +9035,14 @@ var MVerificationV2 = class {
9035
9035
  }
9036
9036
  };
9037
9037
 
9038
+ // src/utils/email-match.util.ts
9039
+ function escapeRegex(value) {
9040
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9041
+ }
9042
+ function emailFilter(email) {
9043
+ return { $regex: `^${escapeRegex(email)}$`, $options: "i" };
9044
+ }
9045
+
9038
9046
  // src/repositories/user.repo.ts
9039
9047
  function useUserRepo() {
9040
9048
  const { updateFeedbackCreatedByName } = useFeedbackRepo();
@@ -9099,7 +9107,7 @@ function useUserRepo() {
9099
9107
  async function getUserByEmail(email) {
9100
9108
  try {
9101
9109
  const data = await collection.findOne({
9102
- email: { $regex: `^${email}$`, $options: "i" }
9110
+ email: emailFilter(email)
9103
9111
  });
9104
9112
  return data;
9105
9113
  } catch (error) {
@@ -9109,7 +9117,7 @@ function useUserRepo() {
9109
9117
  async function userExistsByEmail(email) {
9110
9118
  try {
9111
9119
  const data = await collection.findOne(
9112
- { email: { $regex: `^${email}$`, $options: "i" } },
9120
+ { email: emailFilter(email) },
9113
9121
  { projection: { _id: 1 } }
9114
9122
  );
9115
9123
  return Boolean(data);
@@ -9130,7 +9138,7 @@ function useUserRepo() {
9130
9138
  return cachedData;
9131
9139
  }
9132
9140
  const query2 = {
9133
- email: { $regex: `^${email}$`, $options: "i" },
9141
+ email: emailFilter(email),
9134
9142
  status: "complete" /* COMPLETE */
9135
9143
  };
9136
9144
  const data = await collection.findOne(query2);
@@ -18301,7 +18309,12 @@ function MPerson(value) {
18301
18309
  end: value.end,
18302
18310
  type: value.type,
18303
18311
  email: value.email,
18304
- password: value.password ?? "",
18312
+ // No `password` here, deliberately. This return is the whitelist that
18313
+ // decides what reaches the `people` collection, and it used to carry the
18314
+ // admin-typed password in clear text — into a document that
18315
+ // `GET /api/people` hands back to the console. The only copy that should
18316
+ // exist is the hash `person.service` writes to the `users` row before the
18317
+ // insert, and nothing anywhere reads it back off the person.
18305
18318
  status: value.status ?? "active",
18306
18319
  nric: value.nric,
18307
18320
  remarks: value.remarks,
@@ -22720,7 +22733,7 @@ function useVehicleRepo() {
22720
22733
  let query2 = { ...baseQuery };
22721
22734
  if (search)
22722
22735
  query2.$text = { $search: search };
22723
- const escapeRegex = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22736
+ const escapeRegex2 = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22724
22737
  const buildGroupedPipeline = (matchQuery) => [
22725
22738
  { $match: matchQuery },
22726
22739
  {
@@ -22892,7 +22905,7 @@ function useVehicleRepo() {
22892
22905
  const countResult = await collection.aggregate(buildGroupedCountPipeline(query2)).toArray();
22893
22906
  length = countResult[0]?.total || 0;
22894
22907
  if ((!items || items.length === 0) && search) {
22895
- const escaped = escapeRegex(search);
22908
+ const escaped = escapeRegex2(search);
22896
22909
  const regexQuery = {
22897
22910
  ...baseQuery,
22898
22911
  $or: [
@@ -23498,7 +23511,7 @@ function useVehicleRepo() {
23498
23511
  ...baseQuery,
23499
23512
  ...search && { $text: { $search: search } }
23500
23513
  };
23501
- const escapeRegex = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
23514
+ const escapeRegex2 = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
23502
23515
  const buildPipeline = (matchQuery) => [
23503
23516
  { $match: matchQuery },
23504
23517
  {
@@ -23526,7 +23539,7 @@ function useVehicleRepo() {
23526
23539
  const countResult = await collection.aggregate(buildCountPipeline(query2)).toArray();
23527
23540
  length = countResult[0]?.total || 0;
23528
23541
  if ((!items || items.length === 0) && search) {
23529
- const escaped = escapeRegex(search);
23542
+ const escaped = escapeRegex2(search);
23530
23543
  const regexQuery = {
23531
23544
  ...baseQuery,
23532
23545
  $or: [
@@ -36675,9 +36688,10 @@ function useBuildingUnitRepo() {
36675
36688
  building_units_namespace_collection,
36676
36689
  cacheOptions
36677
36690
  );
36678
- const buildingCollection = await db2?.collection("buildings").findOne({ _id: (0, import_node_server_utils102.toObjectId)(block) });
36691
+ const blockObjectId = (0, import_node_server_utils102.toObjectId)(block);
36692
+ const buildingCollection = await db2?.collection("buildings").findOne({ _id: blockObjectId });
36679
36693
  const blockNumber = buildingCollection?.block;
36680
- query2.block = blockNumber !== void 0 ? blockNumber : block;
36694
+ query2.block = blockNumber !== void 0 ? { $in: [blockNumber, blockObjectId] } : blockObjectId;
36681
36695
  try {
36682
36696
  const data = await collection.aggregate([{ $match: query2 }, { $project: { name: 1 } }]).toArray();
36683
36697
  setCache(cacheKey, data, 15 * 60).then(() => {
@@ -44768,6 +44782,24 @@ var import_mongodb88 = require("mongodb");
44768
44782
  var import_node_server_utils134 = require("@7365admin1/node-server-utils");
44769
44783
  var import_mongodb83 = require("mongodb");
44770
44784
 
44785
+ // src/utils/resident-account.util.ts
44786
+ function residentAccountGaps(value) {
44787
+ const gaps = [];
44788
+ if (!value.name)
44789
+ gaps.push("a name");
44790
+ if (!value.email)
44791
+ gaps.push("an email address");
44792
+ if (!value.password)
44793
+ gaps.push("a password");
44794
+ return gaps;
44795
+ }
44796
+ function residentAccountGapMessage(value) {
44797
+ const gaps = residentAccountGaps(value);
44798
+ if (gaps.length === 0)
44799
+ return "";
44800
+ return `A ${value.type} needs ${gaps.join(", ")} to be able to sign in. Please complete the form and try again.`;
44801
+ }
44802
+
44771
44803
  // src/services/platform-terms.service.ts
44772
44804
  var import_node_server_utils133 = require("@7365admin1/node-server-utils");
44773
44805
 
@@ -45115,6 +45147,69 @@ function usePersonService() {
45115
45147
  acceptByUserId: _acceptTermsByUserId,
45116
45148
  assertLatestTerms: _assertLatestTerms
45117
45149
  } = usePlatformTermsService();
45150
+ async function ensureResidentAccount(value, session) {
45151
+ const gap = residentAccountGapMessage(value);
45152
+ if (gap) {
45153
+ throw new import_node_server_utils134.BadRequestError(gap);
45154
+ }
45155
+ const _user = await getUserByEmail(value.email);
45156
+ if (_user) {
45157
+ throw new import_node_server_utils134.BadRequestError(`User already exists: ${value.email}.`);
45158
+ }
45159
+ const hashedPassword = await (0, import_node_server_utils134.hashPassword)(value.password);
45160
+ const user = {
45161
+ email: value.email,
45162
+ password: hashedPassword,
45163
+ name: value.name,
45164
+ status: value.platform == "mobile" ? "pending" : "active",
45165
+ defaultOrg: value.org?.toString() || "",
45166
+ block: value.block,
45167
+ level: value.level,
45168
+ type: value.type,
45169
+ unitName: value.unitName,
45170
+ contact: value.contact,
45171
+ site: value.site?.toString() || "",
45172
+ unitId: value.unit?.toString() || ""
45173
+ };
45174
+ const userId = await addUser(user, session);
45175
+ if (!userId) {
45176
+ throw new import_node_server_utils134.BadRequestError(
45177
+ `Could not create the sign-in account for ${value.email}.`
45178
+ );
45179
+ }
45180
+ let org = null;
45181
+ if (value?.org) {
45182
+ org = await getOrgById(value.org);
45183
+ if (!org) {
45184
+ value.org = "";
45185
+ }
45186
+ }
45187
+ let site;
45188
+ if (value.site) {
45189
+ site = await getSiteById(value.site);
45190
+ }
45191
+ await addMember(
45192
+ {
45193
+ org: value.org?.toString() || "",
45194
+ orgName: org?.name || "",
45195
+ user: userId.toString(),
45196
+ name: value.name,
45197
+ role: "",
45198
+ type: "resident",
45199
+ siteId: value.site?.toString() || "",
45200
+ siteName: site?.name || ""
45201
+ },
45202
+ session
45203
+ );
45204
+ if (value.acceptedTerms) {
45205
+ await _acceptTermsByUserId(
45206
+ userId.toString(),
45207
+ value.acceptedTerms,
45208
+ session
45209
+ );
45210
+ }
45211
+ return userId.toString();
45212
+ }
45118
45213
  async function add(value) {
45119
45214
  const session = import_node_server_utils134.useAtlas.getClient()?.startSession();
45120
45215
  if (!session) {
@@ -45138,61 +45233,8 @@ function usePersonService() {
45138
45233
  const isValidType = ["resident" /* RESIDENT */, "tenant" /* TENANT */].includes(
45139
45234
  value?.type
45140
45235
  );
45141
- if (value.email && value.password && value.name && isValidType) {
45142
- const _user = await getUserByEmail(value.email);
45143
- if (_user) {
45144
- throw new import_node_server_utils134.BadRequestError(`User already exists: ${value.email}.`);
45145
- }
45146
- const hashedPassword = await (0, import_node_server_utils134.hashPassword)(value.password);
45147
- const user = {
45148
- email: value.email,
45149
- password: hashedPassword,
45150
- name: value.name,
45151
- status: value.platform == "mobile" ? "pending" : "active",
45152
- defaultOrg: value.org?.toString() || "",
45153
- block: value.block,
45154
- level: value.level,
45155
- type: value.type,
45156
- unitName: value.unitName,
45157
- contact: value.contact,
45158
- site: value.site?.toString() || "",
45159
- unitId: value.unit?.toString() || ""
45160
- };
45161
- const userId = await addUser(user, session);
45162
- value.user = userId.toString();
45163
- let org = null;
45164
- if (userId) {
45165
- if (value?.org) {
45166
- org = await getOrgById(value.org);
45167
- if (!org) {
45168
- value.org = "";
45169
- }
45170
- }
45171
- let site;
45172
- if (value.site) {
45173
- site = await getSiteById(value.site);
45174
- }
45175
- await addMember(
45176
- {
45177
- org: value.org?.toString() || "",
45178
- orgName: org?.name || "",
45179
- user: userId.toString(),
45180
- name: value.name,
45181
- role: "",
45182
- type: "resident",
45183
- siteId: value.site?.toString() || "",
45184
- siteName: site?.name || ""
45185
- },
45186
- session
45187
- );
45188
- if (value.acceptedTerms) {
45189
- await _acceptTermsByUserId(
45190
- userId.toString(),
45191
- value.acceptedTerms,
45192
- session
45193
- );
45194
- }
45195
- }
45236
+ if (isValidType) {
45237
+ value.user = await ensureResidentAccount(value, session);
45196
45238
  }
45197
45239
  if (value.isOwner && value.unit) {
45198
45240
  const unit = await _getUnitById(value.unit.toString());
@@ -45263,6 +45305,18 @@ function usePersonService() {
45263
45305
  const isBlockChanged = "block" in value && toKey(value.block) !== toKey(person.block);
45264
45306
  const isLevelChanged = "level" in value && toKey(value.level) !== toKey(person.level);
45265
45307
  const isUnitChanged = "unit" in value && toKey(value.unit) !== toKey(person.unit);
45308
+ const personType = value.type ?? person.type;
45309
+ const carriesLogin = [
45310
+ "resident" /* RESIDENT */,
45311
+ "tenant" /* TENANT */
45312
+ ].includes(personType);
45313
+ if (carriesLogin && !person.user && value.password) {
45314
+ value.user = await ensureResidentAccount(
45315
+ { ...person, ...value, type: personType },
45316
+ session
45317
+ );
45318
+ }
45319
+ delete value.password;
45266
45320
  await _updateById(_id, value, session);
45267
45321
  if (isOrgChanged && person.user) {
45268
45322
  await _updateUserOrgById(
@@ -45509,7 +45563,7 @@ function usePersonService() {
45509
45563
  let set = {};
45510
45564
  const cleanInput = (str) => str.replace(/\s+/g, "");
45511
45565
  const cleanPhone = (str) => str.replace(/\D/g, "");
45512
- const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45566
+ const escapeRegex2 = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45513
45567
  const nric = value.nric ? cleanInput(value.nric) : "";
45514
45568
  const name = value.name?.trim();
45515
45569
  const contact = value.contact?.trim();
@@ -45517,8 +45571,8 @@ function usePersonService() {
45517
45571
  const email = value.email?.trim();
45518
45572
  const type = value.type?.trim();
45519
45573
  const company = value.company?.trim();
45520
- const nricQuery = nric ? { nric: { $regex: `^${escapeRegex(nric)}$`, $options: "i" } } : null;
45521
- const nameQuery = name ? { name: { $regex: `^${escapeRegex(name)}$`, $options: "i" } } : null;
45574
+ const nricQuery = nric ? { nric: { $regex: `^${escapeRegex2(nric)}$`, $options: "i" } } : null;
45575
+ const nameQuery = name ? { name: { $regex: `^${escapeRegex2(name)}$`, $options: "i" } } : null;
45522
45576
  let nricCondition = null;
45523
45577
  if (nric) {
45524
45578
  if (nric.length < 9) {
@@ -45531,8 +45585,8 @@ function usePersonService() {
45531
45585
  }
45532
45586
  const orConditions = [
45533
45587
  ...nricCondition ? [nricCondition] : [],
45534
- ...contact ? [{ contacts: { $regex: `^\\+?${cleanPhone(escapeRegex(contact))}$`, $options: "i" } }] : [],
45535
- ...plateNumber ? [{ plateNumbers: { $regex: `^${escapeRegex(plateNumber)}$`, $options: "i" } }] : []
45588
+ ...contact ? [{ contacts: { $regex: `^\\+?${cleanPhone(escapeRegex2(contact))}$`, $options: "i" } }] : [],
45589
+ ...plateNumber ? [{ plateNumbers: { $regex: `^${escapeRegex2(plateNumber)}$`, $options: "i" } }] : []
45536
45590
  ];
45537
45591
  const existingPerson2 = await findFirstTen(
45538
45592
  {
@@ -47441,7 +47495,7 @@ function useHidAmicoRepo() {
47441
47495
  passwordSet: Boolean(password)
47442
47496
  };
47443
47497
  }
47444
- function escapeRegex(value) {
47498
+ function escapeRegex2(value) {
47445
47499
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
47446
47500
  }
47447
47501
  function buildIdentityKeyQuery(value) {
@@ -47650,7 +47704,7 @@ function useHidAmicoRepo() {
47650
47704
  { serviceProvider: { $in: subjectIds } },
47651
47705
  { user: { $in: subjectIds } }
47652
47706
  ] : null;
47653
- const search = value.search ? escapeRegex(value.search) : "";
47707
+ const search = value.search ? escapeRegex2(value.search) : "";
47654
47708
  const searchOr = search ? [
47655
47709
  { hidUserId: { $regex: search, $options: "i" } },
47656
47710
  { registration: { $regex: search, $options: "i" } },
@@ -47914,7 +47968,7 @@ function useHidAmicoRepo() {
47914
47968
  const text2 = search.trim();
47915
47969
  if (!text2)
47916
47970
  return {};
47917
- const pattern = { $regex: escapeRegex(text2), $options: "i" };
47971
+ const pattern = { $regex: escapeRegex2(text2), $options: "i" };
47918
47972
  return {
47919
47973
  $or: [
47920
47974
  { name: pattern },
@@ -55965,6 +56019,7 @@ function UseAccessManagementRepo() {
55965
56019
  const type = params.type;
55966
56020
  const search = params.search;
55967
56021
  const typeFilter = type.toLowerCase() === "all" ? [] : [{ $eq: ["$type", type] }];
56022
+ const userIdFilter = params.userId ? [{ $eq: ["$userId", new import_mongodb90.ObjectId(params.userId)] }] : [];
55968
56023
  const searchFilter = search ? [
55969
56024
  {
55970
56025
  $or: [
@@ -56038,7 +56093,8 @@ function UseAccessManagementRepo() {
56038
56093
  { $eq: ["$site", site] },
56039
56094
  { $eq: ["$isActivated", true] },
56040
56095
  { $eq: ["$userType", userType] },
56041
- ...typeFilter
56096
+ ...typeFilter,
56097
+ ...userIdFilter
56042
56098
  ]
56043
56099
  },
56044
56100
  ...searchFilter[0]
@@ -62786,7 +62842,7 @@ function usePatrolEmailRepo() {
62786
62842
  throw new import_node_server_utils163.BadRequestError(`Invalid ${label} format.`);
62787
62843
  }
62788
62844
  }
62789
- function escapeRegex(value) {
62845
+ function escapeRegex2(value) {
62790
62846
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
62791
62847
  }
62792
62848
  async function createIndexes() {
@@ -62923,8 +62979,8 @@ function usePatrolEmailRepo() {
62923
62979
  ...status ? { status } : { status: { $ne: "deleted" } },
62924
62980
  ...search && {
62925
62981
  $or: [
62926
- { subject: { $regex: escapeRegex(search), $options: "i" } },
62927
- { recipients: { $regex: escapeRegex(search), $options: "i" } }
62982
+ { subject: { $regex: escapeRegex2(search), $options: "i" } },
62983
+ { recipients: { $regex: escapeRegex2(search), $options: "i" } }
62928
62984
  ]
62929
62985
  }
62930
62986
  };
@@ -71097,21 +71153,24 @@ function useAccessManagementController() {
71097
71153
  unitId,
71098
71154
  userType,
71099
71155
  type,
71100
- search = ""
71156
+ search = "",
71157
+ userId = ""
71101
71158
  } = req.query;
71102
71159
  const schema2 = import_joi101.default.object({
71103
71160
  site: import_joi101.default.string().hex().required(),
71104
71161
  unitId: import_joi101.default.string().hex().required(),
71105
71162
  userType: import_joi101.default.string().required(),
71106
71163
  type: import_joi101.default.string().valid("all", ...Object.values(EAccessCardTypes)).required(),
71107
- search: import_joi101.default.string().optional().allow("", null)
71164
+ search: import_joi101.default.string().optional().allow("", null),
71165
+ userId: import_joi101.default.string().hex().optional().allow("", null)
71108
71166
  });
71109
71167
  const { error } = schema2.validate({
71110
71168
  site,
71111
71169
  unitId,
71112
71170
  userType,
71113
71171
  type,
71114
- search
71172
+ search,
71173
+ userId
71115
71174
  });
71116
71175
  if (error) {
71117
71176
  return res.status(400).json({ message: error.message });
@@ -71123,7 +71182,8 @@ function useAccessManagementController() {
71123
71182
  unitId,
71124
71183
  userType,
71125
71184
  type,
71126
- search
71185
+ search,
71186
+ userId
71127
71187
  });
71128
71188
  return res.status(200).json({ message: "Success", data: result });
71129
71189
  } catch (error) {