@7365admin1/core 2.72.0 → 2.74.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/dist/index.js CHANGED
@@ -4088,6 +4088,51 @@ function useMemberRepo() {
4088
4088
  throw error;
4089
4089
  }
4090
4090
  }
4091
+ async function getByUserIdTypeOrg(user, type, org) {
4092
+ try {
4093
+ user = new import_mongodb11.ObjectId(user);
4094
+ } catch {
4095
+ throw new import_node_server_utils12.BadRequestError("Invalid user ID format.");
4096
+ }
4097
+ try {
4098
+ org = new import_mongodb11.ObjectId(org);
4099
+ } catch {
4100
+ throw new import_node_server_utils12.BadRequestError("Invalid organization ID format.");
4101
+ }
4102
+ const cacheKey = (0, import_node_server_utils12.makeCacheKey)(namespace_collection, {
4103
+ user: user.toString(),
4104
+ type,
4105
+ org: org.toString()
4106
+ });
4107
+ const cachedData = await getCache(cacheKey);
4108
+ if (cachedData) {
4109
+ import_node_server_utils12.logger.info(`Cache hit for key: ${cacheKey}`);
4110
+ return cachedData;
4111
+ }
4112
+ try {
4113
+ const data = await collection.findOne({
4114
+ user,
4115
+ type,
4116
+ org
4117
+ });
4118
+ if (!data) {
4119
+ throw new import_node_server_utils12.NotFoundError("Member not found.");
4120
+ }
4121
+ setCache(cacheKey, data, 15 * 60).then(() => {
4122
+ import_node_server_utils12.logger.info(`Cache set for key: ${cacheKey}`);
4123
+ }).catch((err) => {
4124
+ import_node_server_utils12.logger.error(`Failed to set cache for key: ${cacheKey}`, err);
4125
+ });
4126
+ return data;
4127
+ } catch (error) {
4128
+ if (error instanceof import_node_server_utils12.AppError) {
4129
+ throw error;
4130
+ }
4131
+ throw new import_node_server_utils12.InternalServerError(
4132
+ "Internal server error, failed to retrieve member."
4133
+ );
4134
+ }
4135
+ }
4091
4136
  return {
4092
4137
  createIndex,
4093
4138
  createUniqueIndex,
@@ -4108,7 +4153,8 @@ function useMemberRepo() {
4108
4153
  countUserMembershipById,
4109
4154
  updateRoleById,
4110
4155
  getByRoles,
4111
- updateSiteById
4156
+ updateSiteById,
4157
+ getByUserIdTypeOrg
4112
4158
  };
4113
4159
  }
4114
4160
 
@@ -4559,6 +4605,8 @@ var orgSchema = import_joi8.default.object({
4559
4605
  busInst: import_joi8.default.string().optional().allow("", null),
4560
4606
  status: import_joi8.default.string().optional().allow("", null),
4561
4607
  defaultSite: import_joi8.default.string().hex().optional().allow("", null),
4608
+ terms: import_joi8.default.string().optional().allow("", null),
4609
+ policies: import_joi8.default.string().optional().allow("", null),
4562
4610
  createdAt: import_joi8.default.string().optional().allow("", null),
4563
4611
  updatedAt: import_joi8.default.string().optional().allow("", null),
4564
4612
  deletedAt: import_joi8.default.string().optional().allow("", null)
@@ -4586,6 +4634,8 @@ function MOrg(value) {
4586
4634
  busInst: value.busInst,
4587
4635
  status: value.status || "active",
4588
4636
  defaultSite: value.defaultSite,
4637
+ terms: value.terms ?? "",
4638
+ policies: value.policies ?? "",
4589
4639
  createdAt: value.createdAt || /* @__PURE__ */ new Date(),
4590
4640
  updatedAt: "",
4591
4641
  deletedAt: ""
@@ -4601,6 +4651,7 @@ function useOrgRepo() {
4601
4651
  }
4602
4652
  const namespace_collection = "organizations";
4603
4653
  const collection = db.collection(namespace_collection);
4654
+ const rolesCollection = db.collection("roles");
4604
4655
  const { delNamespace, getCache, setCache } = (0, import_node_server_utils17.useCache)(namespace_collection);
4605
4656
  async function createIndex() {
4606
4657
  try {
@@ -5080,6 +5131,26 @@ function useOrgRepo() {
5080
5131
  throw error;
5081
5132
  }
5082
5133
  }
5134
+ async function getAdminOrgForResident() {
5135
+ const role = await rolesCollection.findOne({ type: "admin" });
5136
+ if (!role)
5137
+ throw new import_node_server_utils17.NotFoundError("Admin role not found.");
5138
+ let orgId;
5139
+ try {
5140
+ orgId = new import_mongodb15.ObjectId(role.org);
5141
+ } catch {
5142
+ throw new import_node_server_utils17.InternalServerError(
5143
+ "Invalid organization reference in admin role."
5144
+ );
5145
+ }
5146
+ const org = await collection.findOne(
5147
+ { _id: orgId },
5148
+ { projection: { terms: 1, policies: 1, _id: 0 } }
5149
+ );
5150
+ if (!org)
5151
+ throw new import_node_server_utils17.NotFoundError("Organization not found.");
5152
+ return org;
5153
+ }
5083
5154
  return {
5084
5155
  createIndex,
5085
5156
  createTextIndex,
@@ -5094,7 +5165,8 @@ function useOrgRepo() {
5094
5165
  updateStatusById,
5095
5166
  deleteById,
5096
5167
  getOrgsByEmail,
5097
- getOrganizationsWithSubscription
5168
+ getOrganizationsWithSubscription,
5169
+ getAdminOrgForResident
5098
5170
  };
5099
5171
  }
5100
5172
 
@@ -5699,7 +5771,7 @@ function useSiteRepo() {
5699
5771
  try {
5700
5772
  const items = await collection.aggregate([
5701
5773
  ...basePipeline,
5702
- { $project: { _id: 1, name: 1, orgId: 1 } },
5774
+ { $project: { _id: 1, name: 1, orgId: 1, category: 1 } },
5703
5775
  { $skip: page * limit },
5704
5776
  { $limit: limit }
5705
5777
  ]).toArray();
@@ -8297,6 +8369,7 @@ function useMemberController() {
8297
8369
  getAll: _getAll,
8298
8370
  getOrgsByMembership: _getOrgsByMembership,
8299
8371
  getByUserIdType: _getByUserIdType,
8372
+ getByUserIdTypeOrg: _getByUserIdTypeOrg,
8300
8373
  updateMemberStatus: _updateMemberStatus,
8301
8374
  updateStatusByUserId: _updateStatusByUserId,
8302
8375
  updateSiteById: _updateSiteById
@@ -8567,17 +8640,57 @@ function useMemberController() {
8567
8640
  next(error2);
8568
8641
  }
8569
8642
  }
8643
+ async function getByUserIdTypeOrg(req, res, next) {
8644
+ const validation = import_joi15.default.object({
8645
+ id: import_joi15.default.string().hex().required(),
8646
+ type: import_joi15.default.string().required(),
8647
+ org: import_joi15.default.string().hex().required()
8648
+ });
8649
+ const params = {
8650
+ ...req.params,
8651
+ ...req.query
8652
+ };
8653
+ const { error } = validation.validate(params);
8654
+ if (error) {
8655
+ import_node_server_utils31.logger.log({
8656
+ level: "error",
8657
+ message: error.message
8658
+ });
8659
+ next(new import_node_server_utils31.BadRequestError(error.message));
8660
+ return;
8661
+ }
8662
+ const user = req.params.id;
8663
+ const type = req.params.type;
8664
+ const org = req.query.org;
8665
+ try {
8666
+ const data = await _getByUserIdTypeOrg(
8667
+ user,
8668
+ type,
8669
+ org
8670
+ );
8671
+ res.json(data);
8672
+ return;
8673
+ } catch (error2) {
8674
+ import_node_server_utils31.logger.log({
8675
+ level: "error",
8676
+ message: error2.message
8677
+ });
8678
+ next(error2);
8679
+ return;
8680
+ }
8681
+ }
8570
8682
  return {
8571
8683
  createMember,
8572
8684
  getByUserId,
8573
8685
  getByUserIdType,
8574
8686
  getAll,
8687
+ getAllByUser,
8575
8688
  getOrgsByMembership,
8576
8689
  updateMemberStatus,
8577
8690
  updateRoleById,
8578
8691
  createMemberDirect,
8579
8692
  updateSiteById,
8580
- getAllByUser
8693
+ getByUserIdTypeOrg
8581
8694
  };
8582
8695
  }
8583
8696
 
@@ -9143,7 +9256,8 @@ function useOrgController() {
9143
9256
  getAll: _getAll,
9144
9257
  add: _add,
9145
9258
  update: _update,
9146
- getOrgsByEmail: _getOrgsByEmail
9259
+ getOrgsByEmail: _getOrgsByEmail,
9260
+ getAdminOrgForResident: _getAdminOrgForResident
9147
9261
  } = useOrgRepo();
9148
9262
  async function add(req, res, next) {
9149
9263
  const validation = import_joi18.default.object({
@@ -9151,7 +9265,9 @@ function useOrgController() {
9151
9265
  type: import_joi18.default.string().required(),
9152
9266
  nature: import_joi18.default.string().valid(...allowedNatures).required(),
9153
9267
  email: import_joi18.default.string().email().optional().allow("", null),
9154
- contact: import_joi18.default.string().optional().allow("", null)
9268
+ contact: import_joi18.default.string().optional().allow("", null),
9269
+ terms: import_joi18.default.string().optional().allow("", null),
9270
+ policies: import_joi18.default.string().optional().allow("", null)
9155
9271
  });
9156
9272
  const { error } = validation.validate(req.body);
9157
9273
  if (error) {
@@ -9357,7 +9473,9 @@ function useOrgController() {
9357
9473
  type: import_joi18.default.string().optional(),
9358
9474
  nature: import_joi18.default.string().valid(...allowedNatures).optional(),
9359
9475
  email: import_joi18.default.string().email().allow("", null).optional(),
9360
- contact: import_joi18.default.string().allow("", null).optional()
9476
+ contact: import_joi18.default.string().allow("", null).optional(),
9477
+ terms: import_joi18.default.string().optional().allow("", null),
9478
+ policies: import_joi18.default.string().optional().allow("", null)
9361
9479
  });
9362
9480
  const { error } = validation.validate(req.body);
9363
9481
  if (error) {
@@ -9376,6 +9494,15 @@ function useOrgController() {
9376
9494
  next(err);
9377
9495
  }
9378
9496
  }
9497
+ async function getAdminOrgForResident(_req, res, next) {
9498
+ try {
9499
+ const data = await _getAdminOrgForResident();
9500
+ res.status(200).json(data);
9501
+ } catch (error) {
9502
+ import_node_server_utils35.logger.log({ level: "error", message: error.message });
9503
+ next(error);
9504
+ }
9505
+ }
9379
9506
  return {
9380
9507
  add,
9381
9508
  addOnboardingOrg,
@@ -9385,7 +9512,8 @@ function useOrgController() {
9385
9512
  getById,
9386
9513
  getByEmail,
9387
9514
  update,
9388
- getOrgsByEmail
9515
+ getOrgsByEmail,
9516
+ getAdminOrgForResident
9389
9517
  };
9390
9518
  }
9391
9519
 
@@ -14540,7 +14668,8 @@ function MSiteCamera(value) {
14540
14668
  name: value.name ?? "",
14541
14669
  createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
14542
14670
  updatedAt: value.updatedAt ?? "",
14543
- deletedAt: value.deletedAt ?? ""
14671
+ deletedAt: value.deletedAt ?? "",
14672
+ ANPRSwitches: value.ANPRSwitches ?? void 0
14544
14673
  };
14545
14674
  }
14546
14675
 
@@ -14630,7 +14759,8 @@ var schemaPerson = import_joi36.default.object({
14630
14759
  plateNumber: import_joi36.default.string().optional().allow(null, ""),
14631
14760
  platform: import_joi36.default.string().valid("web", "mobile").optional().allow(null, ""),
14632
14761
  approvedBy: schemaApprover.optional().allow(null, ""),
14633
- countryCode: import_joi36.default.string().optional().allow(null, "")
14762
+ countryCode: import_joi36.default.string().optional().allow(null, ""),
14763
+ callingCode: import_joi36.default.string().optional().allow(null, "")
14634
14764
  });
14635
14765
  var schemaUpdatePerson = import_joi36.default.object({
14636
14766
  _id: import_joi36.default.string().hex().required(),
@@ -14654,7 +14784,8 @@ var schemaUpdatePerson = import_joi36.default.object({
14654
14784
  plateNumber: import_joi36.default.string().optional().allow(null, ""),
14655
14785
  platform: import_joi36.default.string().valid("web", "mobile").optional().allow(null, ""),
14656
14786
  approvedBy: schemaApprover.optional().allow(null, ""),
14657
- countryCode: import_joi36.default.string().optional().allow(null, "")
14787
+ countryCode: import_joi36.default.string().optional().allow(null, ""),
14788
+ callingCode: import_joi36.default.string().optional().allow(null, "")
14658
14789
  });
14659
14790
  function MPerson(value) {
14660
14791
  const { error } = schemaPerson.validate(value);
@@ -14728,6 +14859,7 @@ function MPerson(value) {
14728
14859
  platForm: value.platform ?? "",
14729
14860
  approvedBy: value.approvedBy ?? { id: "", name: "" },
14730
14861
  countryCode: value.countryCode ?? "",
14862
+ callingCode: value.callingCode ?? "",
14731
14863
  createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
14732
14864
  updatedAt: value.updatedAt,
14733
14865
  deletedAt: value.deletedAt
@@ -15522,6 +15654,7 @@ var VehicleSort = /* @__PURE__ */ ((VehicleSort2) => {
15522
15654
  var OrgNature = /* @__PURE__ */ ((OrgNature2) => {
15523
15655
  OrgNature2["PROPERTY_MANAGEMENT_AGENCY"] = "property_management_agency";
15524
15656
  OrgNature2["SECURITY_AGENCY"] = "security_agency";
15657
+ OrgNature2["REAL_ESTATE_DEVELOPER"] = "real_estate_developer";
15525
15658
  return OrgNature2;
15526
15659
  })(OrgNature || {});
15527
15660
  var ANPRMode = /* @__PURE__ */ ((ANPRMode2) => {
@@ -16650,39 +16783,70 @@ function useDahuaService() {
16650
16783
  loggerDahua.error("checkOutBySiteAndPlate catch error: ", error);
16651
16784
  }
16652
16785
  }
16653
- async function addTransaction(plateNumber2, site, cameraType, onDetected2) {
16786
+ async function addTransaction(plateNumber2, site, cameraType, ANPRSwitches, onDetected2) {
16654
16787
  if (!plateNumber2 || !site)
16655
- return;
16656
- const resident = await getVehicleBySiteAndPlateNumber(plateNumber2, camera?.site, "resident", "active");
16788
+ return null;
16657
16789
  let insert = null;
16658
- if (resident?._id && (cameraType == "entry" || cameraType == "residents")) {
16790
+ if (cameraType == "entry") {
16659
16791
  await checkOutBySiteAndPlate(camera.site, plateNumber2);
16660
- insert = await add({
16661
- site,
16662
- plateNumber: plateNumber2,
16663
- name: resident?.name,
16664
- nric: resident?.nric,
16665
- contact: resident?.phoneNumber,
16666
- block: Number(resident?.block),
16667
- level: resident?.level,
16668
- unit: resident?.unit?.toString(),
16669
- unitName: resident?.unitName,
16670
- type: resident?.category,
16671
- status: "registered" /* REGISTERED */
16672
- // expiredAt: resident?.end,
16673
- }, void 0, true);
16674
- loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Resident with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16675
- } else if (!resident?._id && (cameraType == "entry" || cameraType == "visitors")) {
16676
- if (!plateNumber2 || !site)
16677
- return;
16792
+ const resident = await getVehicleBySiteAndPlateNumber(plateNumber2, camera?.site, "resident", "active");
16793
+ if (resident?._id) {
16794
+ insert = await add({
16795
+ site,
16796
+ plateNumber: plateNumber2,
16797
+ name: resident?.name,
16798
+ nric: resident?.nric,
16799
+ contact: resident?.phoneNumber,
16800
+ block: Number(resident?.block),
16801
+ level: resident?.level,
16802
+ unit: resident?.unit?.toString(),
16803
+ unitName: resident?.unitName,
16804
+ type: resident?.category,
16805
+ status: "registered" /* REGISTERED */
16806
+ // expiredAt: resident?.end,
16807
+ }, void 0, true);
16808
+ loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Resident with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16809
+ } else if (ANPRSwitches?.enableUnregistered) {
16810
+ insert = await add({
16811
+ site,
16812
+ plateNumber: plateNumber2,
16813
+ status: "unregistered" /* UNREGISTERED */
16814
+ // expiredAt: resident?.end,
16815
+ }, void 0, true);
16816
+ loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Unregistered vehicle with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16817
+ }
16818
+ } else if (cameraType == "residents") {
16678
16819
  await checkOutBySiteAndPlate(camera.site, plateNumber2);
16679
- insert = await add({
16680
- site,
16681
- plateNumber: plateNumber2,
16682
- status: "unregistered" /* UNREGISTERED */
16683
- // expiredAt: resident?.end,
16684
- }, void 0, true);
16685
- loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Unregistered vehicle with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16820
+ const resident = await getVehicleBySiteAndPlateNumber(plateNumber2, camera?.site, "resident", "active");
16821
+ if (resident?._id) {
16822
+ insert = await add({
16823
+ site,
16824
+ plateNumber: plateNumber2,
16825
+ name: resident?.name,
16826
+ nric: resident?.nric,
16827
+ contact: resident?.phoneNumber,
16828
+ block: Number(resident?.block),
16829
+ level: resident?.level,
16830
+ unit: resident?.unit?.toString(),
16831
+ unitName: resident?.unitName,
16832
+ type: resident?.category,
16833
+ status: "registered" /* REGISTERED */
16834
+ // expiredAt: resident?.end,
16835
+ }, void 0, true);
16836
+ loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Resident with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16837
+ }
16838
+ } else if (cameraType == "visitors" && ANPRSwitches?.enableUnregistered) {
16839
+ await checkOutBySiteAndPlate(camera.site, plateNumber2);
16840
+ const resident = await getVehicleBySiteAndPlateNumber(plateNumber2, camera?.site, "resident", "active");
16841
+ if (!resident?._id) {
16842
+ insert = await add({
16843
+ site,
16844
+ plateNumber: plateNumber2,
16845
+ status: "unregistered" /* UNREGISTERED */
16846
+ // expiredAt: resident?.end,
16847
+ }, void 0, true);
16848
+ loggerDahua.info(`${camera?.siteName}-${camera?.direction}] Unregistered vehicle with plate ${plateNumber2} and transaction ID ${insert?._id}`);
16849
+ }
16686
16850
  }
16687
16851
  if (insert?._id && insert?.site && onDetected2) {
16688
16852
  onDetected2({ _id: insert?._id, site: insert?.site?.toString(), plateNumber: insert?.plateNumber, cameraDirection: camera?.direction, direction });
@@ -16695,10 +16859,12 @@ function useDahuaService() {
16695
16859
  );
16696
16860
  if ((camera?.direction == "entry" || camera?.direction == "visitors" || camera?.direction == "residents") && plateNumber) {
16697
16861
  try {
16698
- const result = await addTransaction(plateNumber, camera?.site, camera?.direction, onDetected2);
16699
- const transactionId = result?._id;
16700
- currentTransactionId = transactionId?.toString();
16701
- currentSnapshotField = "snapshotEntryImage";
16862
+ const result = await addTransaction(plateNumber, camera?.site, camera?.direction, camera?.ANPRSwitches, onDetected2);
16863
+ if (camera?.ANPRSwitches?.vehicleSnapshot && result?._id) {
16864
+ const transactionId = result?._id;
16865
+ currentTransactionId = transactionId?.toString();
16866
+ currentSnapshotField = "snapshotEntryImage";
16867
+ }
16702
16868
  } catch (error) {
16703
16869
  console.log("failed to create visitor transaction", error);
16704
16870
  loggerDahua.error(
@@ -16708,23 +16874,25 @@ function useDahuaService() {
16708
16874
  }
16709
16875
  } else if (camera?.direction == "exit" && plateNumber) {
16710
16876
  const existingOpenTransaction = await checkOutBySiteAndPlate(camera?.site, plateNumber, onDetected2);
16711
- if (existingOpenTransaction?._id) {
16877
+ if (existingOpenTransaction?._id && camera?.ANPRSwitches?.vehicleSnapshot) {
16712
16878
  currentTransactionId = existingOpenTransaction._id.toString();
16713
16879
  currentSnapshotField = "snapshotExitImage";
16714
16880
  }
16715
16881
  } else if (camera?.direction == "both" && plateNumber) {
16716
16882
  if (direction.toLowerCase() === "leave") {
16717
16883
  const existingOpenTransaction = await checkOutBySiteAndPlate(camera?.site, plateNumber, onDetected2);
16718
- if (existingOpenTransaction?._id) {
16884
+ if (existingOpenTransaction?._id && camera?.ANPRSwitches?.vehicleSnapshot) {
16719
16885
  currentTransactionId = existingOpenTransaction._id.toString();
16720
16886
  currentSnapshotField = "snapshotExitImage";
16721
16887
  }
16722
16888
  } else if (direction.toLowerCase() === "approach") {
16723
16889
  try {
16724
- const result = await addTransaction(plateNumber, camera?.site, "entry", onDetected2);
16725
- const transactionId = result?._id;
16726
- currentTransactionId = transactionId?.toString();
16727
- currentSnapshotField = "snapshotEntryImage";
16890
+ const result = await addTransaction(plateNumber, camera?.site, "entry", camera?.ANPRSwitches, onDetected2);
16891
+ if (camera?.ANPRSwitches?.vehicleSnapshot && result?._id) {
16892
+ const transactionId = result?._id;
16893
+ currentTransactionId = transactionId?.toString();
16894
+ currentSnapshotField = "snapshotEntryImage";
16895
+ }
16728
16896
  } catch (error) {
16729
16897
  console.log("failed to create visitor transaction", error);
16730
16898
  loggerDahua.error(
@@ -16763,7 +16931,7 @@ function useDahuaService() {
16763
16931
  if (plateNumber && UTCData) {
16764
16932
  await processVehicleTransaction(onDetected2);
16765
16933
  }
16766
- } else if (part.includes("Content-Type: image/jpeg")) {
16934
+ } else if (part.includes("Content-Type: image/jpeg") && camera?.ANPRSwitches?.vehicleSnapshot) {
16767
16935
  const [headers, ...imageParts] = part.split("\r\n\r\n");
16768
16936
  const imageChunk = Buffer.from(imageParts.join("\r\n\r\n"), "binary");
16769
16937
  const lengthMatch = headers.match(/Content-Length:\s*(\d+)/i);
@@ -17578,6 +17746,30 @@ function useSiteCameraRepo() {
17578
17746
  $project: {
17579
17747
  siteDetails: 0
17580
17748
  }
17749
+ },
17750
+ {
17751
+ $lookup: {
17752
+ from: "anpr-settings",
17753
+ localField: "site",
17754
+ foreignField: "site",
17755
+ as: "anprSettingsDetails"
17756
+ }
17757
+ },
17758
+ {
17759
+ $unwind: {
17760
+ path: "$anprSettingsDetails",
17761
+ preserveNullAndEmptyArrays: true
17762
+ }
17763
+ },
17764
+ {
17765
+ $addFields: {
17766
+ ANPRSwitches: "$anprSettingsDetails.ANPRSwitches"
17767
+ }
17768
+ },
17769
+ {
17770
+ $project: {
17771
+ anprSettingsDetails: 0
17772
+ }
17581
17773
  }
17582
17774
  ]).toArray();
17583
17775
  const length = await collection.countDocuments(query);
@@ -17613,9 +17805,29 @@ function useSiteCameraRepo() {
17613
17805
  $addFields: {
17614
17806
  siteName: "$siteDetails.name"
17615
17807
  }
17808
+ },
17809
+ {
17810
+ $lookup: {
17811
+ from: "anpr-settings",
17812
+ localField: "site",
17813
+ foreignField: "site",
17814
+ as: "anprSettingsDetails"
17815
+ }
17816
+ },
17817
+ {
17818
+ $unwind: {
17819
+ path: "$anprSettingsDetails",
17820
+ preserveNullAndEmptyArrays: true
17821
+ }
17822
+ },
17823
+ {
17824
+ $addFields: {
17825
+ ANPRSwitches: "$anprSettingsDetails.ANPRSwitches"
17826
+ }
17616
17827
  }
17617
17828
  ];
17618
17829
  pipeline.push({ $project: { siteDetails: 0 } });
17830
+ pipeline.push({ $project: { anprSettingsDetails: 0 } });
17619
17831
  if (Object.keys(project).length > 0) {
17620
17832
  pipeline.push({ $project: project });
17621
17833
  }
@@ -17626,6 +17838,62 @@ function useSiteCameraRepo() {
17626
17838
  throw error;
17627
17839
  }
17628
17840
  }
17841
+ async function findMany(query, project = {}) {
17842
+ try {
17843
+ const pipeline = [
17844
+ { $match: query },
17845
+ { $limit: 1 },
17846
+ {
17847
+ $lookup: {
17848
+ from: "sites",
17849
+ localField: "site",
17850
+ foreignField: "_id",
17851
+ as: "siteDetails"
17852
+ }
17853
+ },
17854
+ {
17855
+ $unwind: {
17856
+ path: "$siteDetails",
17857
+ preserveNullAndEmptyArrays: true
17858
+ }
17859
+ },
17860
+ {
17861
+ $addFields: {
17862
+ siteName: "$siteDetails.name"
17863
+ }
17864
+ },
17865
+ {
17866
+ $lookup: {
17867
+ from: "anpr-settings",
17868
+ localField: "site",
17869
+ foreignField: "site",
17870
+ as: "anprSettingsDetails"
17871
+ }
17872
+ },
17873
+ {
17874
+ $unwind: {
17875
+ path: "$anprSettingsDetails",
17876
+ preserveNullAndEmptyArrays: true
17877
+ }
17878
+ },
17879
+ {
17880
+ $addFields: {
17881
+ ANPRSwitches: "$anprSettingsDetails.ANPRSwitches"
17882
+ }
17883
+ }
17884
+ ];
17885
+ pipeline.push({ $project: { siteDetails: 0 } });
17886
+ pipeline.push({ $project: { anprSettingsDetails: 0 } });
17887
+ if (Object.keys(project).length > 0) {
17888
+ pipeline.push({ $project: project });
17889
+ }
17890
+ const result = await collection.aggregate(pipeline).toArray();
17891
+ return result.length > 0 ? result : [];
17892
+ } catch (error) {
17893
+ console.error("Error in findOne aggregation:", error);
17894
+ throw error;
17895
+ }
17896
+ }
17629
17897
  return {
17630
17898
  createIndexes,
17631
17899
  add,
@@ -39366,6 +39634,32 @@ function UseAccessManagementRepo() {
39366
39634
  throw new Error(error.message);
39367
39635
  }
39368
39636
  }
39637
+ async function qrCodeListRepo({ type, search, site, page, limit, isLift, userId }) {
39638
+ try {
39639
+ page = page ? page - 1 : 0;
39640
+ let defaultQuery = {};
39641
+ let searchQuery = {};
39642
+ site = new import_mongodb92.ObjectId(site);
39643
+ userId = new import_mongodb92.ObjectId(userId);
39644
+ if (search) {
39645
+ searchQuery = {
39646
+ $or: [{ fullName: { $regex: search, $options: "i" } }, { cardNo: { $regex: search, $options: "i" } }]
39647
+ };
39648
+ }
39649
+ defaultQuery = { site, isLiftCard: isLift, userId, userType: { $in: ["Visitor/Resident", "Resident/Tenant"] } };
39650
+ const result = collection().aggregate([
39651
+ {
39652
+ $match: { ...defaultQuery, ...searchQuery }
39653
+ },
39654
+ { $sort: { _id: -1 } },
39655
+ { $skip: page * limit },
39656
+ { $limit: limit }
39657
+ ]).toArray();
39658
+ return result;
39659
+ } catch (error) {
39660
+ throw new Error(error.message);
39661
+ }
39662
+ }
39369
39663
  return {
39370
39664
  createIndexes,
39371
39665
  createIndexForEntrypass,
@@ -39404,7 +39698,8 @@ function UseAccessManagementRepo() {
39404
39698
  uploadTemplateRepo,
39405
39699
  getResidentsRepo,
39406
39700
  userAccessCardsRepo,
39407
- removeTemplateRepo
39701
+ removeTemplateRepo,
39702
+ qrCodeListRepo
39408
39703
  };
39409
39704
  }
39410
39705
 
@@ -39451,7 +39746,8 @@ function useAccessManagementSvc() {
39451
39746
  uploadTemplateRepo,
39452
39747
  getResidentsRepo,
39453
39748
  userAccessCardsRepo,
39454
- removeTemplateRepo
39749
+ removeTemplateRepo,
39750
+ qrCodeListRepo
39455
39751
  } = UseAccessManagementRepo();
39456
39752
  const addPhysicalCardSvc = async (payload) => {
39457
39753
  try {
@@ -39837,6 +40133,14 @@ function useAccessManagementSvc() {
39837
40133
  throw new Error(err.message);
39838
40134
  }
39839
40135
  };
40136
+ const qrCodeListSvc = async ({ type, search, site, page, limit, isLift, userId }) => {
40137
+ try {
40138
+ const response = await qrCodeListRepo({ type, search, site, page, limit, isLift, userId });
40139
+ return response;
40140
+ } catch (err) {
40141
+ throw new Error(err.message);
40142
+ }
40143
+ };
39840
40144
  return {
39841
40145
  addPhysicalCardSvc,
39842
40146
  addNonPhysicalCardSvc,
@@ -39878,7 +40182,8 @@ function useAccessManagementSvc() {
39878
40182
  uploadTemplateSvc,
39879
40183
  getResidentsSvc,
39880
40184
  userAccessCardsSvc,
39881
- removeTemplateSvc
40185
+ removeTemplateSvc,
40186
+ qrCodeListSvc
39882
40187
  };
39883
40188
  }
39884
40189
 
@@ -39925,7 +40230,8 @@ function useAccessManagementController() {
39925
40230
  uploadTemplateSvc,
39926
40231
  getResidentsSvc,
39927
40232
  userAccessCardsSvc,
39928
- removeTemplateSvc
40233
+ removeTemplateSvc,
40234
+ qrCodeListSvc
39929
40235
  } = useAccessManagementSvc();
39930
40236
  const addPhysicalCard = async (req, res) => {
39931
40237
  try {
@@ -40994,6 +41300,47 @@ function useAccessManagementController() {
40994
41300
  });
40995
41301
  }
40996
41302
  };
41303
+ const qrCodeList = async (req, res) => {
41304
+ try {
41305
+ const {
41306
+ type,
41307
+ site,
41308
+ page,
41309
+ limit = 10,
41310
+ search = "",
41311
+ isLift,
41312
+ userId
41313
+ } = req.query;
41314
+ const schema2 = import_joi87.default.object({
41315
+ type: import_joi87.default.string().required(),
41316
+ site: import_joi87.default.string().hex().required(),
41317
+ page: import_joi87.default.number().optional().default(1),
41318
+ limit: import_joi87.default.number().optional().default(10),
41319
+ search: import_joi87.default.string().optional().allow("", null),
41320
+ isLift: import_joi87.default.boolean().optional().default(false),
41321
+ userId: import_joi87.default.string().required()
41322
+ });
41323
+ const { error } = schema2.validate({ type, site, page, limit, search, isLift, userId });
41324
+ if (error) {
41325
+ return res.status(400).json({ message: error.message });
41326
+ }
41327
+ const result = await qrCodeListSvc({
41328
+ type,
41329
+ site,
41330
+ page: Number(page),
41331
+ limit: Number(limit),
41332
+ search,
41333
+ isLift: Boolean(isLift),
41334
+ userId
41335
+ });
41336
+ return res.status(200).json({ data: result });
41337
+ } catch (error) {
41338
+ return res.status(400).json({
41339
+ data: null,
41340
+ message: error.message
41341
+ });
41342
+ }
41343
+ };
40997
41344
  return {
40998
41345
  addPhysicalCard,
40999
41346
  addNonPhysicalCard,
@@ -41033,7 +41380,8 @@ function useAccessManagementController() {
41033
41380
  uploadTemplate,
41034
41381
  getResidents,
41035
41382
  userAccessCards,
41036
- removeTemplate
41383
+ removeTemplate,
41384
+ qrCodeList
41037
41385
  };
41038
41386
  }
41039
41387
 
@@ -55284,7 +55632,8 @@ function usePostPrelovedRepo() {
55284
55632
  site,
55285
55633
  status,
55286
55634
  category,
55287
- subcategory
55635
+ subcategory,
55636
+ userId
55288
55637
  }, session) {
55289
55638
  page = page > 0 ? page - 1 : 0;
55290
55639
  if (site) {
@@ -55327,7 +55676,34 @@ function usePostPrelovedRepo() {
55327
55676
  ...categoryId && { category: categoryId },
55328
55677
  ...subcategoryIds && { subcategory: { $in: subcategoryIds } }
55329
55678
  };
55679
+ let userObjectId = null;
55680
+ if (userId) {
55681
+ try {
55682
+ userObjectId = new import_mongodb132.ObjectId(userId);
55683
+ } catch {
55684
+ throw new import_node_server_utils235.BadRequestError("Invalid user ID format.");
55685
+ }
55686
+ }
55330
55687
  const sortObj = buildSortObj(filter);
55688
+ const FAVORITE_COUNT_LOOKUP = {
55689
+ $lookup: {
55690
+ from: "post-favorites",
55691
+ localField: "_id",
55692
+ foreignField: "postId",
55693
+ pipeline: [{ $project: { userIds: 1 } }],
55694
+ as: "favoriteData"
55695
+ }
55696
+ };
55697
+ const favoriteUserIds = {
55698
+ $ifNull: [{ $arrayElemAt: ["$favoriteData.userIds", 0] }, []]
55699
+ };
55700
+ const FAVORITE_COUNT_ADD_FIELD = {
55701
+ $addFields: {
55702
+ favoriteCount: { $size: favoriteUserIds },
55703
+ isFavorited: userObjectId ? { $in: [userObjectId, favoriteUserIds] } : false
55704
+ }
55705
+ };
55706
+ const FAVORITE_COUNT_UNSET = { $unset: "favoriteData" };
55331
55707
  try {
55332
55708
  const items = await collection.aggregate(
55333
55709
  [
@@ -55335,6 +55711,9 @@ function usePostPrelovedRepo() {
55335
55711
  USER_LOOKUP,
55336
55712
  USER_UNWIND,
55337
55713
  CATEGORY_LOOKUP,
55714
+ FAVORITE_COUNT_LOOKUP,
55715
+ FAVORITE_COUNT_ADD_FIELD,
55716
+ FAVORITE_COUNT_UNSET,
55338
55717
  { $sort: sortObj },
55339
55718
  { $skip: page * limit },
55340
55719
  { $limit: limit }
@@ -55487,7 +55866,8 @@ function usePostPrelovedController() {
55487
55866
  import_joi134.default.string().valid(...Object.values(PostStatus))
55488
55867
  ).optional().allow(null),
55489
55868
  category: import_joi134.default.string().hex().length(24).optional().allow("", null),
55490
- subcategory: import_joi134.default.alternatives().try(import_joi134.default.array().items(import_joi134.default.string())).optional().allow(null, "")
55869
+ subcategory: import_joi134.default.alternatives().try(import_joi134.default.array().items(import_joi134.default.string())).optional().allow(null, ""),
55870
+ userId: import_joi134.default.string().optional().allow("", null)
55491
55871
  });
55492
55872
  const { error, value } = validation.validate(req.query, {
55493
55873
  abortEarly: false
@@ -55498,7 +55878,17 @@ function usePostPrelovedController() {
55498
55878
  next(new import_node_server_utils236.BadRequestError(messages));
55499
55879
  return;
55500
55880
  }
55501
- const { page, limit, search, filter, site, status, category, subcategory } = value;
55881
+ const {
55882
+ page,
55883
+ limit,
55884
+ search,
55885
+ filter,
55886
+ site,
55887
+ status,
55888
+ category,
55889
+ subcategory,
55890
+ userId
55891
+ } = value;
55502
55892
  try {
55503
55893
  const data = await _getAll({
55504
55894
  page,
@@ -55508,7 +55898,8 @@ function usePostPrelovedController() {
55508
55898
  site,
55509
55899
  status: status ? Array.isArray(status) ? status : [status] : void 0,
55510
55900
  category: category ?? void 0,
55511
- subcategory: subcategory ? Array.isArray(subcategory) ? subcategory : [subcategory] : void 0
55901
+ subcategory: subcategory ? Array.isArray(subcategory) ? subcategory : [subcategory] : void 0,
55902
+ userId
55512
55903
  });
55513
55904
  res.status(200).json(data);
55514
55905
  return;
@@ -55861,7 +56252,7 @@ function MCategoryPreloved(value) {
55861
56252
  name: value.name ?? "",
55862
56253
  createdBy: value.createdBy ?? "",
55863
56254
  site: value.site ?? null,
55864
- createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
56255
+ createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
55865
56256
  updatedAt: value.updatedAt ?? null
55866
56257
  };
55867
56258
  }
@@ -55916,14 +56307,26 @@ function useCategoryPrelovedRepo() {
55916
56307
  throw error;
55917
56308
  }
55918
56309
  }
55919
- return { getAll, getById };
56310
+ async function addCategory(item, session) {
56311
+ const doc = MCategoryPreloved(item);
56312
+ try {
56313
+ const res = await collection.insertOne(doc, { session });
56314
+ return res.insertedId;
56315
+ } catch (error) {
56316
+ const isDuplicated = error.message?.includes("duplicate");
56317
+ if (isDuplicated)
56318
+ throw new import_node_server_utils240.BadRequestError("Category already exists.");
56319
+ throw error;
56320
+ }
56321
+ }
56322
+ return { getAll, getById, addCategory };
55920
56323
  }
55921
56324
 
55922
56325
  // src/controllers/category-preloved.controller.ts
55923
56326
  var import_node_server_utils241 = require("@7365admin1/node-server-utils");
55924
56327
  var import_joi138 = __toESM(require("joi"));
55925
56328
  function useCategoryPrelovedController() {
55926
- const { getAll: _getAll, getById: _getById } = useCategoryPrelovedRepo();
56329
+ const { getAll: _getAll, getById: _getById, addCategory: _addCategory } = useCategoryPrelovedRepo();
55927
56330
  async function getAll(req, res, next) {
55928
56331
  const schema2 = import_joi138.default.object({
55929
56332
  search: import_joi138.default.string().optional().allow("", null),
@@ -55966,7 +56369,25 @@ function useCategoryPrelovedController() {
55966
56369
  return;
55967
56370
  }
55968
56371
  }
55969
- return { getAll, getById };
56372
+ async function addCategory(req, res, next) {
56373
+ const { error, value } = schemaCategoryPreloved.validate(req.body, {
56374
+ abortEarly: false
56375
+ });
56376
+ if (error) {
56377
+ const messages = error.details.map((d) => d.message).join(", ");
56378
+ import_node_server_utils241.logger.log({ level: "error", message: messages });
56379
+ next(new import_node_server_utils241.BadRequestError(messages));
56380
+ return;
56381
+ }
56382
+ try {
56383
+ const data = await _addCategory(value);
56384
+ res.status(201).json(data);
56385
+ } catch (error2) {
56386
+ import_node_server_utils241.logger.log({ level: "error", message: error2.message });
56387
+ next(error2);
56388
+ }
56389
+ }
56390
+ return { getAll, getById, addCategory };
55970
56391
  }
55971
56392
 
55972
56393
  // src/models/subcategory-preloved.model.ts
@@ -56142,6 +56563,11 @@ var FormEntryStatus = /* @__PURE__ */ ((FormEntryStatus2) => {
56142
56563
  var schemaFormEntry = import_joi141.default.object({
56143
56564
  _id: import_joi141.default.string().hex().optional().allow("", null),
56144
56565
  formType: import_joi141.default.string().required(),
56566
+ block: import_joi141.default.string().optional().allow(null, ""),
56567
+ level: import_joi141.default.string().optional().allow(null, ""),
56568
+ unit: import_joi141.default.string().optional().allow(null, ""),
56569
+ name: import_joi141.default.string().optional().allow(null, ""),
56570
+ phoneNumber: import_joi141.default.string().optional().allow(null, ""),
56145
56571
  fields: import_joi141.default.object().pattern(
56146
56572
  import_joi141.default.string(),
56147
56573
  import_joi141.default.alternatives().try(
@@ -56297,15 +56723,22 @@ function useFormEntryController() {
56297
56723
  }
56298
56724
  const headerRow = worksheet.getRow(1);
56299
56725
  const headers = headerRow.values.slice(1).map((h) => String(h ?? "").trim());
56726
+ const knownKeys = ["block", "level", "unit", "name", "phoneNumber"];
56727
+ const topLevel = {};
56300
56728
  const fields = {};
56301
56729
  headers.forEach((header) => {
56302
- fields[header] = null;
56730
+ const normalized = toCamelCase(header);
56731
+ if (knownKeys.includes(normalized)) {
56732
+ topLevel[normalized] = null;
56733
+ } else {
56734
+ fields[normalized] = null;
56735
+ }
56303
56736
  });
56304
56737
  const formType = req.file.originalname.replace(/\.[^/.]+$/, "");
56305
- const normalizedFields = normalizeKeys(fields);
56306
56738
  const payload = {
56307
56739
  formType,
56308
- fields: normalizedFields,
56740
+ ...topLevel,
56741
+ fields,
56309
56742
  status: "active" /* ACTIVE */
56310
56743
  };
56311
56744
  const { error, value } = schemaFormEntry.validate(payload, {