@7365admin1/core 2.9.0 → 2.11.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.mjs CHANGED
@@ -372,7 +372,8 @@ function useFeedbackRepo() {
372
372
  query.$or = [
373
373
  { subject: { $regex: search, $options: "i" } },
374
374
  { description: { $regex: search, $options: "i" } },
375
- { createdByName: { $regex: search, $options: "i" } }
375
+ { createdByName: { $regex: search, $options: "i" } },
376
+ { category: { $regex: search, $options: "i" } }
376
377
  ];
377
378
  cacheOptions.search = search;
378
379
  }
@@ -933,6 +934,7 @@ function useWorkOrderRepo() {
933
934
  }
934
935
  }
935
936
  const { delNamespace, setCache, getCache, delCache } = useCache3(namespace_collection);
937
+ const { delNamespace: _delDashboardNameSpace } = useCache3("dashboard");
936
938
  async function createWorkOrder(value, session) {
937
939
  try {
938
940
  value = MWorkOrder(value);
@@ -945,6 +947,11 @@ function useWorkOrderRepo() {
945
947
  err
946
948
  );
947
949
  });
950
+ _delDashboardNameSpace().then(() => {
951
+ logger5.info(`Cache cleared for namespace: dashboard`);
952
+ }).catch((err) => {
953
+ logger5.error(`Failed to clear cache for namespace: dashboard`, err);
954
+ });
948
955
  return res.insertedId;
949
956
  } catch (error) {
950
957
  throw error;
@@ -993,7 +1000,9 @@ function useWorkOrderRepo() {
993
1000
  if (search) {
994
1001
  query.$or = [
995
1002
  { subject: { $regex: search, $options: "i" } },
996
- { createdByName: { $regex: search, $options: "i" } }
1003
+ { createdByName: { $regex: search, $options: "i" } },
1004
+ { description: { $regex: search, $options: "i" } },
1005
+ { category: { $regex: search, $options: "i" } }
997
1006
  ];
998
1007
  cacheOptions.search = search;
999
1008
  }
@@ -1179,11 +1188,18 @@ function useWorkOrderRepo() {
1179
1188
  if (res.modifiedCount === 0) {
1180
1189
  throw new InternalServerError3("Unable to update work order.");
1181
1190
  }
1182
- const cacheKey = makeCacheKey3(namespace_collection, { _id });
1183
- delCache(cacheKey).then(() => {
1184
- logger5.info(`Cache deleted for key: ${cacheKey}`);
1191
+ delNamespace().then(() => {
1192
+ logger5.info(`Cache cleared for namespace: ${namespace_collection}`);
1193
+ }).catch((err) => {
1194
+ logger5.error(
1195
+ `Failed to clear cache for namespace: ${namespace_collection}`,
1196
+ err
1197
+ );
1198
+ });
1199
+ _delDashboardNameSpace().then(() => {
1200
+ logger5.info(`Cache cleared for namespace: dashboard`);
1185
1201
  }).catch((err) => {
1186
- logger5.error(`Failed to delete cache for key: ${cacheKey}`, err);
1202
+ logger5.error(`Failed to clear cache for namespace: dashboard`, err);
1187
1203
  });
1188
1204
  return res.modifiedCount;
1189
1205
  } catch (error) {
@@ -1206,11 +1222,18 @@ function useWorkOrderRepo() {
1206
1222
  if (res.modifiedCount === 0) {
1207
1223
  throw new InternalServerError3("Unable to update work order status.");
1208
1224
  }
1209
- const cacheKey = makeCacheKey3(namespace_collection, { _id });
1210
- delCache(cacheKey).then(() => {
1211
- logger5.info(`Cache deleted for key: ${cacheKey}`);
1225
+ delNamespace().then(() => {
1226
+ logger5.info(`Cache cleared for namespace: ${namespace_collection}`);
1227
+ }).catch((err) => {
1228
+ logger5.error(
1229
+ `Failed to clear cache for namespace: ${namespace_collection}`,
1230
+ err
1231
+ );
1232
+ });
1233
+ _delDashboardNameSpace().then(() => {
1234
+ logger5.info(`Cache cleared for namespace: dashboard`);
1212
1235
  }).catch((err) => {
1213
- logger5.error(`Failed to delete cache for key: ${cacheKey}`, err);
1236
+ logger5.error(`Failed to clear cache for namespace: dashboard`, err);
1214
1237
  });
1215
1238
  return res.modifiedCount;
1216
1239
  } catch (error) {
@@ -1228,11 +1251,18 @@ function useWorkOrderRepo() {
1228
1251
  { $set: updateValue },
1229
1252
  session
1230
1253
  );
1231
- const cacheKey = makeCacheKey3(namespace_collection, { createdBy: _id });
1232
- delCache(cacheKey).then(() => {
1233
- logger5.info(`Cache deleted for key: ${cacheKey}`);
1254
+ delNamespace().then(() => {
1255
+ logger5.info(`Cache cleared for namespace: ${namespace_collection}`);
1234
1256
  }).catch((err) => {
1235
- logger5.error(`Failed to delete cache for key: ${cacheKey}`, err);
1257
+ logger5.error(
1258
+ `Failed to clear cache for namespace: ${namespace_collection}`,
1259
+ err
1260
+ );
1261
+ });
1262
+ _delDashboardNameSpace().then(() => {
1263
+ logger5.info(`Cache cleared for namespace: dashboard`);
1264
+ }).catch((err) => {
1265
+ logger5.error(`Failed to clear cache for namespace: dashboard`, err);
1236
1266
  });
1237
1267
  return res.modifiedCount;
1238
1268
  } catch (error) {
@@ -1262,11 +1292,18 @@ function useWorkOrderRepo() {
1262
1292
  "Unable to mark work order as completed."
1263
1293
  );
1264
1294
  }
1265
- const cacheKey = makeCacheKey3(namespace_collection, { _id });
1266
- delCache(cacheKey).then(() => {
1267
- logger5.info(`Cache deleted for key: ${cacheKey}`);
1295
+ delNamespace().then(() => {
1296
+ logger5.info(`Cache cleared for namespace: ${namespace_collection}`);
1297
+ }).catch((err) => {
1298
+ logger5.error(
1299
+ `Failed to clear cache for namespace: ${namespace_collection}`,
1300
+ err
1301
+ );
1302
+ });
1303
+ _delDashboardNameSpace().then(() => {
1304
+ logger5.info(`Cache cleared for namespace: dashboard`);
1268
1305
  }).catch((err) => {
1269
- logger5.error(`Failed to delete cache for key: ${cacheKey}`, err);
1306
+ logger5.error(`Failed to clear cache for namespace: dashboard`, err);
1270
1307
  });
1271
1308
  return res.modifiedCount;
1272
1309
  } catch (error) {
@@ -1293,11 +1330,18 @@ function useWorkOrderRepo() {
1293
1330
  if (res.modifiedCount === 0) {
1294
1331
  throw new InternalServerError3("Unable to delete work order.");
1295
1332
  }
1296
- const cacheKey = makeCacheKey3(namespace_collection, { _id });
1297
- delCache(cacheKey).then(() => {
1298
- logger5.info(`Cache deleted for key: ${cacheKey}`);
1333
+ delNamespace().then(() => {
1334
+ logger5.info(`Cache cleared for namespace: ${namespace_collection}`);
1299
1335
  }).catch((err) => {
1300
- logger5.error(`Failed to delete cache for key: ${cacheKey}`, err);
1336
+ logger5.error(
1337
+ `Failed to clear cache for namespace: ${namespace_collection}`,
1338
+ err
1339
+ );
1340
+ });
1341
+ _delDashboardNameSpace().then(() => {
1342
+ logger5.info(`Cache cleared for namespace: dashboard`);
1343
+ }).catch((err) => {
1344
+ logger5.error(`Failed to clear cache for namespace: dashboard`, err);
1301
1345
  });
1302
1346
  return res.modifiedCount;
1303
1347
  } catch (error) {
@@ -2855,6 +2899,14 @@ function useVerificationRepo() {
2855
2899
  throw new InternalServerError7("Error updating verification status.");
2856
2900
  }
2857
2901
  }
2902
+ async function getByStatus(status) {
2903
+ try {
2904
+ const data = await collection.find({ status }).toArray();
2905
+ return data;
2906
+ } catch (error) {
2907
+ return Promise.reject(error);
2908
+ }
2909
+ }
2858
2910
  return {
2859
2911
  createIndex,
2860
2912
  createTextIndex,
@@ -2862,7 +2914,8 @@ function useVerificationRepo() {
2862
2914
  getById,
2863
2915
  getVerifications,
2864
2916
  getByIdByType,
2865
- updateStatusById
2917
+ updateStatusById,
2918
+ getByStatus
2866
2919
  };
2867
2920
  }
2868
2921
 
@@ -3226,7 +3279,8 @@ var allowedFieldsSite = [
3226
3279
  "metadata.block",
3227
3280
  "metadata.guardPosts",
3228
3281
  "metadata.gracePeriod",
3229
- "metadata.incidentCounter"
3282
+ "metadata.incidentCounter",
3283
+ "metadata.incidentLogo"
3230
3284
  ];
3231
3285
  var siteSchema = Joi8.object({
3232
3286
  name: Joi8.string().required(),
@@ -4115,7 +4169,8 @@ function useVerificationService() {
4115
4169
  const {
4116
4170
  add,
4117
4171
  getById: _getById,
4118
- updateStatusById: _updateStatusById
4172
+ updateStatusById: _updateStatusById,
4173
+ getByStatus: _getByStatus
4119
4174
  } = useVerificationRepo();
4120
4175
  const { getUserByEmail } = useUserRepo();
4121
4176
  const { getById: getOrgById, getByEmail: getOrgByEmail } = useOrgRepo();
@@ -4361,7 +4416,6 @@ function useVerificationService() {
4361
4416
  }
4362
4417
  async function cancelUserInvitation(id) {
4363
4418
  try {
4364
- await verify(id);
4365
4419
  await updateStatusById(id, "cancelled");
4366
4420
  } catch (error) {
4367
4421
  throw new InternalServerError11(
@@ -4423,6 +4477,30 @@ function useVerificationService() {
4423
4477
  throw error;
4424
4478
  }
4425
4479
  }
4480
+ async function checkExpiredInvitation() {
4481
+ const session = useAtlas10.getClient()?.startSession();
4482
+ session?.startTransaction();
4483
+ try {
4484
+ const verifications = await _getByStatus("pending");
4485
+ for (const verification of verifications) {
4486
+ const expiration = new Date(verification.expireAt).getTime();
4487
+ const now = (/* @__PURE__ */ new Date()).getTime();
4488
+ if (now > expiration) {
4489
+ await _updateStatusById(verification._id.toString(), "expired");
4490
+ }
4491
+ }
4492
+ return "Successfully checked for expired invitations.";
4493
+ } catch (error) {
4494
+ await session?.abortTransaction();
4495
+ logger14.log({
4496
+ level: "info",
4497
+ message: `Error checking expired user invitation: ${error}`
4498
+ });
4499
+ throw error;
4500
+ } finally {
4501
+ session?.endSession();
4502
+ }
4503
+ }
4426
4504
  return {
4427
4505
  createUserInvite,
4428
4506
  createForgetPassword,
@@ -4431,7 +4509,8 @@ function useVerificationService() {
4431
4509
  verify,
4432
4510
  cancelUserInvitation,
4433
4511
  updateStatusById,
4434
- signUp
4512
+ signUp,
4513
+ checkExpiredInvitation
4435
4514
  };
4436
4515
  }
4437
4516
 
@@ -5641,6 +5720,16 @@ function useFileRepo() {
5641
5720
  const namespace_collection = "files";
5642
5721
  const collection = db.collection(namespace_collection);
5643
5722
  const { delNamespace, getCache, setCache } = useCache13(namespace_collection);
5723
+ async function createIndex() {
5724
+ try {
5725
+ await collection.createIndexes([
5726
+ { key: { createdAt: 1 } },
5727
+ { key: { status: 1 } }
5728
+ ]);
5729
+ } catch (error) {
5730
+ throw new InternalServerError14("Failed to create index on feedback.");
5731
+ }
5732
+ }
5644
5733
  async function createFile(value, session) {
5645
5734
  try {
5646
5735
  value = new MFile(value);
@@ -5769,7 +5858,8 @@ function useFileRepo() {
5769
5858
  deleteFileById,
5770
5859
  getAllDraftedFiles,
5771
5860
  updateStatusById,
5772
- getFileById
5861
+ getFileById,
5862
+ createIndex
5773
5863
  };
5774
5864
  }
5775
5865
 
@@ -10802,7 +10892,8 @@ function useFeedbackController() {
10802
10892
  }
10803
10893
  async function deleteFeedback(req, res, next) {
10804
10894
  const validation = Joi28.string().hex().required();
10805
- const _id = req.params.id;
10895
+ const _id = req.query.id;
10896
+ console.log(_id);
10806
10897
  const { error } = validation.validate(_id);
10807
10898
  if (error) {
10808
10899
  logger39.log({ level: "error", message: error.message });
@@ -11166,7 +11257,8 @@ function useWorkOrderController() {
11166
11257
  }
11167
11258
  async function deleteWorkOrder(req, res, next) {
11168
11259
  const validation = Joi29.string().hex().required();
11169
- const _id = req.params.id;
11260
+ const _id = req.query.id;
11261
+ console.log(_id);
11170
11262
  const { error } = validation.validate(_id);
11171
11263
  if (error) {
11172
11264
  logger40.log({ level: "error", message: error.message });
@@ -12706,7 +12798,7 @@ function useSiteController() {
12706
12798
  const validation = Joi36.object({
12707
12799
  _id: Joi36.string().hex().required(),
12708
12800
  field: Joi36.string().valid(...allowedFieldsSite).required(),
12709
- value: Joi36.number().integer().min(0).required()
12801
+ value: Joi36.alternatives().try(Joi36.number().integer().min(0), Joi36.string().hex().length(24)).required()
12710
12802
  });
12711
12803
  const _id = req.params.id ?? "";
12712
12804
  const field = req.body.field ?? "";
@@ -27207,11 +27299,11 @@ var EAccessCardTypes = /* @__PURE__ */ ((EAccessCardTypes2) => {
27207
27299
  EAccessCardTypes2["QR"] = "QRCODE";
27208
27300
  return EAccessCardTypes2;
27209
27301
  })(EAccessCardTypes || {});
27210
- var EAccessCardUserTypes = /* @__PURE__ */ ((EAccessCardUserTypes2) => {
27211
- EAccessCardUserTypes2["RESIDENT"] = "Resident/Tenant";
27212
- EAccessCardUserTypes2["CONTRACTOR"] = "Contractor";
27213
- EAccessCardUserTypes2["VISITOR"] = "Visitor";
27214
- return EAccessCardUserTypes2;
27302
+ var EAccessCardUserTypes = /* @__PURE__ */ ((EAccessCardUserTypes4) => {
27303
+ EAccessCardUserTypes4["RESIDENT"] = "Resident/Tenant";
27304
+ EAccessCardUserTypes4["CONTRACTOR"] = "Contractor";
27305
+ EAccessCardUserTypes4["VISITOR"] = "Visitor";
27306
+ return EAccessCardUserTypes4;
27215
27307
  })(EAccessCardUserTypes || {});
27216
27308
  var AccessTypeProps = /* @__PURE__ */ ((AccessTypeProps2) => {
27217
27309
  AccessTypeProps2["NORMAL"] = "Normal";
@@ -27273,7 +27365,8 @@ var MAccessCard = class {
27273
27365
  doorName,
27274
27366
  liftName,
27275
27367
  replacementStatus,
27276
- vmsRemarks
27368
+ vmsRemarks,
27369
+ isWinsland = false
27277
27370
  } = {}) {
27278
27371
  this._id = _id;
27279
27372
  this.userId = userId;
@@ -27300,12 +27393,14 @@ var MAccessCard = class {
27300
27393
  this.liftName = liftName;
27301
27394
  this.replacementStatus = replacementStatus;
27302
27395
  this.vmsRemarks = vmsRemarks;
27396
+ this.isWinsland = isWinsland;
27303
27397
  }
27304
27398
  };
27305
27399
 
27306
27400
  // src/repositories/access-management.repo.ts
27307
27401
  import {
27308
27402
  InternalServerError as InternalServerError47,
27403
+ paginate as paginate38,
27309
27404
  useAtlas as useAtlas74
27310
27405
  } from "@7365admin1/node-server-utils";
27311
27406
  import { ObjectId as ObjectId83 } from "mongodb";
@@ -27352,6 +27447,15 @@ function UseAccessManagementRepo() {
27352
27447
  return Promise.reject("Failed to create Access cards indexes.");
27353
27448
  }
27354
27449
  }
27450
+ async function createIndexForEntrypass() {
27451
+ try {
27452
+ const entrypass = collectionName("entrypass-settings");
27453
+ await Promise.all([entrypass.createIndex({ site: 1 })]);
27454
+ return Promise.resolve("Access cards indexes created.");
27455
+ } catch (error) {
27456
+ return Promise.reject("Failed to create Access cards indexes.");
27457
+ }
27458
+ }
27355
27459
  async function addPhysicalCardRepo({
27356
27460
  payload
27357
27461
  }) {
@@ -27442,7 +27546,8 @@ function UseAccessManagementRepo() {
27442
27546
  liftName: params.liftName,
27443
27547
  assignedUnit: new ObjectId83(units[i]),
27444
27548
  createdAt: new Date(params.createdAt),
27445
- updatedAt: new Date(params.updatedAt)
27549
+ updatedAt: new Date(params.updatedAt),
27550
+ isWinsland: params.isWinsland
27446
27551
  });
27447
27552
  try {
27448
27553
  const result = await collection().insertOne(newCard);
@@ -27494,7 +27599,8 @@ function UseAccessManagementRepo() {
27494
27599
  liftName: params.liftName,
27495
27600
  assignedUnit: null,
27496
27601
  createdAt: new Date(params.createdAt),
27497
- updatedAt: new Date(params.updatedAt)
27602
+ updatedAt: new Date(params.updatedAt),
27603
+ isWinsland: params.isWinsland
27498
27604
  });
27499
27605
  try {
27500
27606
  const result = await collection().insertOne(newCard);
@@ -27526,10 +27632,538 @@ function UseAccessManagementRepo() {
27526
27632
  throw new Error(error.message);
27527
27633
  }
27528
27634
  }
27635
+ async function accessManagementSettingsRepo(params) {
27636
+ try {
27637
+ params.site = new ObjectId83(params.site);
27638
+ const result = collectionName("entrypass-settings").updateOne(
27639
+ { site: params.site },
27640
+ {
27641
+ $set: {
27642
+ ...params,
27643
+ updatedAt: /* @__PURE__ */ new Date()
27644
+ },
27645
+ $setOnInsert: {
27646
+ createdAt: /* @__PURE__ */ new Date()
27647
+ }
27648
+ },
27649
+ { upsert: true }
27650
+ );
27651
+ await createIndexForEntrypass();
27652
+ return result;
27653
+ } catch (error) {
27654
+ throw new Error(error.message);
27655
+ }
27656
+ }
27657
+ async function allAccessCardsCountsRepo(params) {
27658
+ try {
27659
+ const site = new ObjectId83(params.site);
27660
+ const userType = params.userType;
27661
+ const result = await collection().aggregate([
27662
+ {
27663
+ $match: { site, userType }
27664
+ },
27665
+ {
27666
+ $facet: {
27667
+ available_physical: [{ $match: { assignedUnit: { $eq: null }, type: "NFC" /* NFC */ } }, { $count: "count" }],
27668
+ available_non_physical: [{ $match: { assignedUnit: { $eq: null }, type: "QRCODE" /* QR */ } }, { $count: "count" }],
27669
+ assigned_physical: [{ $match: { assignedUnit: { $ne: null }, type: "NFC" /* NFC */ } }, { $count: "count" }],
27670
+ assigned_non_physical: [{ $match: { assignedUnit: { $ne: null }, type: "QRCODE" /* QR */ } }, { $count: "count" }]
27671
+ }
27672
+ }
27673
+ ]).toArray();
27674
+ const totalCardCount = {
27675
+ available_physical: result[0].available_physical[0] ? result[0].available_physical[0].count : 0,
27676
+ available_non_physical: result[0].available_non_physical[0] ? result[0].available_non_physical[0].count : 0,
27677
+ assigned_physical: result[0].assigned_physical[0] ? result[0].assigned_physical[0].count : 0,
27678
+ assigned_non_physical: result[0].assigned_non_physical[0] ? result[0].assigned_non_physical[0].count : 0
27679
+ };
27680
+ return totalCardCount;
27681
+ } catch (error) {
27682
+ throw new Error(error.message);
27683
+ }
27684
+ }
27685
+ async function availableAccessCardsRepo(params) {
27686
+ try {
27687
+ const site = new ObjectId83(params.site);
27688
+ const userType = params.userType;
27689
+ const type = params.type;
27690
+ const query = {
27691
+ site: { $in: [site] },
27692
+ userType,
27693
+ assignedUnit: null,
27694
+ type,
27695
+ isActivated: true
27696
+ };
27697
+ const result = await collection().aggregate([
27698
+ {
27699
+ $match: { ...query }
27700
+ },
27701
+ {
27702
+ $project: {
27703
+ accessLevel: 1,
27704
+ liftAccessLevel: 1,
27705
+ doorName: 1,
27706
+ liftName: 1
27707
+ }
27708
+ },
27709
+ {
27710
+ $group: {
27711
+ _id: {
27712
+ accessLevel: "$accessLevel",
27713
+ liftAccessLevel: "$liftAccessLevel",
27714
+ doorName: "$doorName",
27715
+ liftName: "$liftName"
27716
+ },
27717
+ count: { $sum: 1 }
27718
+ }
27719
+ },
27720
+ {
27721
+ $project: {
27722
+ _id: 0,
27723
+ accessLevel: "$_id.accessLevel",
27724
+ liftAccessLevel: "$_id.liftAccessLevel",
27725
+ doorName: "$_id.doorName",
27726
+ liftName: "$_id.liftName",
27727
+ count: 1
27728
+ }
27729
+ }
27730
+ ]).toArray();
27731
+ return result;
27732
+ } catch (error) {
27733
+ throw new Error(error.message);
27734
+ }
27735
+ }
27736
+ function getAfterSecondSlash(term) {
27737
+ const first = term.indexOf("/");
27738
+ if (first === -1)
27739
+ return "";
27740
+ const second = term.indexOf("/", first + 1);
27741
+ if (second === -1)
27742
+ return "";
27743
+ return term.substring(second + 1).toLowerCase();
27744
+ }
27745
+ function buildSearchQuery(search) {
27746
+ if (!search) {
27747
+ return {};
27748
+ }
27749
+ const terms = search.split("/").map((s) => s.trim()).filter(Boolean);
27750
+ if (search.includes("/")) {
27751
+ switch (true) {
27752
+ case terms.length >= 3:
27753
+ return {
27754
+ $and: [
27755
+ { $expr: { $eq: [{ $toLower: "$name" }, terms[0].toLowerCase()] } },
27756
+ { $expr: { $eq: [{ $toLower: "$level.level" }, terms[1].toLowerCase()] } },
27757
+ { $expr: { $eq: [{ $toLower: "$level.units.name" }, getAfterSecondSlash(search)] } }
27758
+ ]
27759
+ };
27760
+ case terms.length === 2:
27761
+ return {
27762
+ $and: [
27763
+ { $expr: { $eq: [{ $toLower: "$name" }, terms[0].toLowerCase()] } },
27764
+ { $expr: { $eq: [{ $toLower: "$level.level" }, terms[1].toLowerCase()] } }
27765
+ ]
27766
+ };
27767
+ default:
27768
+ return {
27769
+ $expr: { $eq: [{ $toLower: "$name" }, terms[0].toLowerCase()] }
27770
+ };
27771
+ }
27772
+ }
27773
+ return {
27774
+ $or: [
27775
+ { name: { $regex: search.trim(), $options: "i" } },
27776
+ { "level.level": { $regex: search.trim(), $options: "i" } },
27777
+ { "level.units.name": { $regex: search.trim(), $options: "i" } }
27778
+ ]
27779
+ };
27780
+ }
27781
+ async function userTypeAccessCardsRepo(params) {
27782
+ try {
27783
+ const site = new ObjectId83(params.site);
27784
+ const userType = params.userType;
27785
+ const page = params.page ? Number(params.page) - 1 : 0;
27786
+ const limit = Number(params.limit) || 10;
27787
+ const search = params.search;
27788
+ const defaultQuery = {
27789
+ site
27790
+ };
27791
+ const searchQuery = buildSearchQuery(search);
27792
+ const result = await collectionName("buildings").aggregate([
27793
+ // ✅ Match early with index-friendly query
27794
+ {
27795
+ $match: {
27796
+ ...defaultQuery,
27797
+ status: { $ne: "deleted" }
27798
+ }
27799
+ },
27800
+ // ✅ Only project needed fields before heavy lookups
27801
+ {
27802
+ $project: {
27803
+ _id: 1,
27804
+ name: 1,
27805
+ site: 1
27806
+ }
27807
+ },
27808
+ // ✅ Use localField/foreignField for better index usage
27809
+ {
27810
+ $lookup: {
27811
+ from: "building-levels",
27812
+ localField: "_id",
27813
+ foreignField: "block",
27814
+ pipeline: [
27815
+ { $match: { status: { $ne: "deleted" } } },
27816
+ {
27817
+ $lookup: {
27818
+ from: "building-units",
27819
+ localField: "_id",
27820
+ foreignField: "level",
27821
+ pipeline: [
27822
+ { $match: { status: { $ne: "deleted" } } },
27823
+ { $project: { _id: 1, name: 1 } }
27824
+ ],
27825
+ as: "units"
27826
+ }
27827
+ },
27828
+ {
27829
+ $match: { "units.0": { $exists: true } }
27830
+ },
27831
+ {
27832
+ $project: {
27833
+ _id: 1,
27834
+ level: 1,
27835
+ units: 1
27836
+ }
27837
+ }
27838
+ ],
27839
+ as: "level"
27840
+ }
27841
+ },
27842
+ // ✅ Filter out buildings with no levels early
27843
+ {
27844
+ $match: { "level.0": { $exists: true } }
27845
+ },
27846
+ // ✅ Unwind to flatten the hierarchy
27847
+ {
27848
+ $unwind: {
27849
+ path: "$level",
27850
+ preserveNullAndEmptyArrays: false
27851
+ }
27852
+ },
27853
+ {
27854
+ $unwind: {
27855
+ path: "$level.units",
27856
+ preserveNullAndEmptyArrays: false
27857
+ }
27858
+ },
27859
+ // Groups by unit _id and keeps only the first occurrence
27860
+ {
27861
+ $group: {
27862
+ _id: "$level.units._id",
27863
+ doc: { $first: "$$ROOT" }
27864
+ }
27865
+ },
27866
+ {
27867
+ $replaceRoot: { newRoot: "$doc" }
27868
+ },
27869
+ // ✅ Apply search filter
27870
+ {
27871
+ $match: {
27872
+ ...searchQuery
27873
+ }
27874
+ },
27875
+ {
27876
+ $facet: {
27877
+ totalCount: [{ $count: "count" }],
27878
+ items: [
27879
+ // ✅ Sort BEFORE skip/limit for correct pagination
27880
+ { $sort: { _id: -1 } },
27881
+ { $skip: page * limit },
27882
+ { $limit: limit },
27883
+ // ✅ Users lookup - optimized with index hint
27884
+ {
27885
+ $lookup: {
27886
+ from: "users",
27887
+ let: { unit: "$level.units._id" },
27888
+ pipeline: [
27889
+ {
27890
+ $match: {
27891
+ $expr: { $eq: ["$unitNumber", "$$unit"] },
27892
+ residentType: "House/Unit Owner"
27893
+ }
27894
+ },
27895
+ { $limit: 1 },
27896
+ { $project: { _id: 1, givenName: 1, surname: 1 } }
27897
+ ],
27898
+ as: "unitOwner"
27899
+ }
27900
+ },
27901
+ // ✅ Access card lookup - optimized query
27902
+ {
27903
+ $lookup: {
27904
+ from: "access-cards",
27905
+ let: { unit: "$level.units._id" },
27906
+ pipeline: [
27907
+ {
27908
+ $match: {
27909
+ $expr: {
27910
+ $in: [
27911
+ "$$unit",
27912
+ { $cond: [{ $isArray: "$assignedUnit" }, "$assignedUnit", ["$assignedUnit"]] }
27913
+ ]
27914
+ },
27915
+ userType
27916
+ }
27917
+ },
27918
+ { $project: { _id: 1, userId: 1, type: 1, cardNo: 1, isActivated: 1 } }
27919
+ ],
27920
+ as: "accessCards"
27921
+ }
27922
+ },
27923
+ // ✅ Compute all card categorization and counts in ONE stage
27924
+ {
27925
+ $addFields: {
27926
+ f_Available: {
27927
+ $filter: {
27928
+ input: "$accessCards",
27929
+ as: "card",
27930
+ cond: { $and: [{ $eq: ["$$card.userId", null] }, { $eq: ["$$card.isActivated", true] }] }
27931
+ }
27932
+ },
27933
+ f_Assigned: {
27934
+ $filter: {
27935
+ input: "$accessCards",
27936
+ as: "card",
27937
+ cond: { $ne: ["$$card.userId", null] }
27938
+ }
27939
+ }
27940
+ }
27941
+ },
27942
+ // ✅ Final projection with all computed fields
27943
+ {
27944
+ $project: {
27945
+ _id: "$level.units._id",
27946
+ name: "$level.units.name",
27947
+ level: { _id: "$level._id", level: "$level.level" },
27948
+ block: { _id: "$_id", name: "$name" },
27949
+ site: "$site",
27950
+ unit_owner: { $arrayElemAt: ["$unitOwner", 0] },
27951
+ available: {
27952
+ physical: { $filter: { input: "$f_Available", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
27953
+ non_physical: { $filter: { input: "$f_Available", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
27954
+ },
27955
+ assigned: {
27956
+ physical: { $filter: { input: "$f_Assigned", as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } },
27957
+ non_physical: { $filter: { input: "$f_Assigned", as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } }
27958
+ },
27959
+ cardCounts: {
27960
+ available: {
27961
+ physical: { $size: { $filter: { input: { $ifNull: ["$f_Available", []] }, as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } } },
27962
+ non_physical: { $size: { $filter: { input: { $ifNull: ["$f_Available", []] }, as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } } }
27963
+ },
27964
+ assigned: {
27965
+ physical: { $size: { $filter: { input: { $ifNull: ["$f_Assigned", []] }, as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } } },
27966
+ non_physical: { $size: { $filter: { input: { $ifNull: ["$f_Assigned", []] }, as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } } }
27967
+ }
27968
+ },
27969
+ totalCardCount: {
27970
+ $add: [
27971
+ { $size: { $filter: { input: { $ifNull: ["$f_Available", []] }, as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } } },
27972
+ { $size: { $filter: { input: { $ifNull: ["$f_Available", []] }, as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } } },
27973
+ { $size: { $filter: { input: { $ifNull: ["$f_Assigned", []] }, as: "c", cond: { $eq: ["$$c.type", "NFC" /* NFC */] } } } },
27974
+ { $size: { $filter: { input: { $ifNull: ["$f_Assigned", []] }, as: "c", cond: { $eq: ["$$c.type", "QRCODE" /* QR */] } } } }
27975
+ ]
27976
+ }
27977
+ }
27978
+ }
27979
+ ]
27980
+ }
27981
+ }
27982
+ ], { allowDiskUse: true }).toArray();
27983
+ const totalCount = result[0]?.totalCount?.[0]?.count ?? 0;
27984
+ const items = result[0]?.items ?? [];
27985
+ const paginatedResult = paginate38(items, page, limit, totalCount);
27986
+ return paginatedResult;
27987
+ } catch (error) {
27988
+ throw new Error(error.message);
27989
+ }
27990
+ }
27991
+ async function assignedAccessCardsRepo(params) {
27992
+ try {
27993
+ const site = new ObjectId83(params.site);
27994
+ const userType = params.userType;
27995
+ const type = params.type;
27996
+ const search = params.search;
27997
+ const query = {
27998
+ site: { $in: [site] }
27999
+ };
28000
+ const searchQuery = buildSearchQuery(search);
28001
+ const result = await collectionName("buildings").aggregate([
28002
+ // ✅ Match early with index-friendly query
28003
+ {
28004
+ $match: {
28005
+ ...query,
28006
+ status: { $ne: "deleted" }
28007
+ }
28008
+ },
28009
+ // ✅ Only project needed fields before heavy lookups
28010
+ {
28011
+ $project: {
28012
+ _id: 1,
28013
+ name: 1,
28014
+ site: 1
28015
+ }
28016
+ },
28017
+ // ✅ Use localField/foreignField for better index usage
28018
+ {
28019
+ $lookup: {
28020
+ from: "building-levels",
28021
+ localField: "_id",
28022
+ foreignField: "block",
28023
+ pipeline: [
28024
+ { $match: { status: { $ne: "deleted" } } },
28025
+ {
28026
+ $lookup: {
28027
+ from: "building-units",
28028
+ localField: "_id",
28029
+ foreignField: "level",
28030
+ pipeline: [
28031
+ { $match: { status: { $ne: "deleted" } } },
28032
+ { $project: { _id: 1, name: 1 } },
28033
+ {
28034
+ $lookup: {
28035
+ from: "access-cards",
28036
+ localField: "_id",
28037
+ foreignField: "assignedUnit",
28038
+ pipeline: [
28039
+ {
28040
+ $match: {
28041
+ isActivated: true,
28042
+ userType,
28043
+ type
28044
+ }
28045
+ },
28046
+ {
28047
+ $group: {
28048
+ _id: null,
28049
+ accessLevels: { $addToSet: "$accessLevel" },
28050
+ liftAccessLevels: { $addToSet: "$liftAccessLevel" },
28051
+ doorNames: { $addToSet: "$doorName" },
28052
+ liftNames: { $addToSet: "$liftName" },
28053
+ cards: {
28054
+ $push: {
28055
+ _id: "$_id",
28056
+ cardNo: "$cardNo",
28057
+ accessLevel: "$accessLevel",
28058
+ liftAccessLevel: "$liftAccessLevel",
28059
+ doorName: "$doorName",
28060
+ liftName: "$liftName"
28061
+ }
28062
+ }
28063
+ }
28064
+ },
28065
+ {
28066
+ $project: {
28067
+ _id: 0,
28068
+ accessCardCount: {
28069
+ $size: "$cards"
28070
+ },
28071
+ accessLevels: 1,
28072
+ liftAccessLevels: 1,
28073
+ doorNames: 1,
28074
+ liftNames: 1
28075
+ }
28076
+ }
28077
+ ],
28078
+ as: "fAccessCards"
28079
+ }
28080
+ },
28081
+ {
28082
+ $match: {
28083
+ "fAccessCards.0": { $exists: true }
28084
+ }
28085
+ }
28086
+ ],
28087
+ as: "units"
28088
+ }
28089
+ },
28090
+ {
28091
+ $match: { "units.0": { $exists: true } }
28092
+ },
28093
+ {
28094
+ $project: {
28095
+ _id: 1,
28096
+ level: 1,
28097
+ units: 1
28098
+ }
28099
+ }
28100
+ ],
28101
+ as: "level"
28102
+ }
28103
+ },
28104
+ // ✅ Filter out buildings with no levels early
28105
+ {
28106
+ $match: { "level.0": { $exists: true } }
28107
+ },
28108
+ // ✅ Unwind to flatten the hierarchy
28109
+ {
28110
+ $unwind: {
28111
+ path: "$level",
28112
+ preserveNullAndEmptyArrays: false
28113
+ }
28114
+ },
28115
+ {
28116
+ $unwind: {
28117
+ path: "$level.units",
28118
+ preserveNullAndEmptyArrays: false
28119
+ }
28120
+ },
28121
+ {
28122
+ $unwind: {
28123
+ path: "$level.units.fAccessCards",
28124
+ preserveNullAndEmptyArrays: false
28125
+ }
28126
+ },
28127
+ // // Groups by unit _id and keeps only the first occurrence
28128
+ {
28129
+ $group: {
28130
+ _id: "$level.units._id",
28131
+ doc: { $first: "$$ROOT" }
28132
+ }
28133
+ },
28134
+ {
28135
+ $replaceRoot: { newRoot: "$doc" }
28136
+ },
28137
+ // ✅ Apply search filter
28138
+ {
28139
+ $match: {
28140
+ ...searchQuery
28141
+ }
28142
+ },
28143
+ {
28144
+ $project: {
28145
+ name: 1,
28146
+ "level.level": 1,
28147
+ "level.units.name": 1,
28148
+ "level.units.fAccessCards": 1
28149
+ }
28150
+ }
28151
+ ], { allowDiskUse: true }).toArray();
28152
+ return result;
28153
+ } catch (error) {
28154
+ throw new Error(error.message);
28155
+ }
28156
+ }
27529
28157
  return {
27530
28158
  createIndexes,
28159
+ createIndexForEntrypass,
27531
28160
  addPhysicalCardRepo,
27532
- addNonPhysicalCardRepo
28161
+ addNonPhysicalCardRepo,
28162
+ accessManagementSettingsRepo,
28163
+ allAccessCardsCountsRepo,
28164
+ availableAccessCardsRepo,
28165
+ userTypeAccessCardsRepo,
28166
+ assignedAccessCardsRepo
27533
28167
  };
27534
28168
  }
27535
28169
 
@@ -27634,8 +28268,18 @@ var formatAccessGroup = (data, search) => {
27634
28268
 
27635
28269
  // src/services/access-management.service.ts
27636
28270
  import { parseStringPromise } from "xml2js";
28271
+ import { useCache as useCache47 } from "@7365admin1/node-server-utils";
28272
+ var namespace = "cache:acm";
27637
28273
  function useAccessManagementSvc() {
27638
- const { addPhysicalCardRepo, addNonPhysicalCardRepo } = UseAccessManagementRepo();
28274
+ const {
28275
+ addPhysicalCardRepo,
28276
+ addNonPhysicalCardRepo,
28277
+ accessManagementSettingsRepo,
28278
+ allAccessCardsCountsRepo,
28279
+ availableAccessCardsRepo,
28280
+ userTypeAccessCardsRepo,
28281
+ assignedAccessCardsRepo
28282
+ } = UseAccessManagementRepo();
27639
28283
  const addPhysicalCardSvc = async (payload) => {
27640
28284
  try {
27641
28285
  const response = await addPhysicalCardRepo({ payload });
@@ -27652,12 +28296,34 @@ function useAccessManagementSvc() {
27652
28296
  throw new Error(err.message);
27653
28297
  }
27654
28298
  };
28299
+ const setCache = async (params) => {
28300
+ const { key, data, ttlSeconds = 60, redis } = params;
28301
+ const jsonData = JSON.stringify(data);
28302
+ await redis.set(key, jsonData, "EX", ttlSeconds);
28303
+ };
28304
+ const getCache = async (params) => {
28305
+ const { key, redis } = params;
28306
+ const result = await redis.get(key);
28307
+ return result ? JSON.parse(result) : null;
28308
+ };
27655
28309
  const doorAccessLevelsSvc = async (params) => {
27656
28310
  try {
28311
+ const key = `${namespace}:${params.user}:door-levels`;
28312
+ const listKey = `${namespace}:${params.user}:list`;
28313
+ const { redis } = useCache47(key);
28314
+ const cachedData = await getCache({ key, redis });
28315
+ if (cachedData) {
28316
+ console.log("\u26A1 Cache hit:", key);
28317
+ redis.expire(key, 60).catch(console.error);
28318
+ redis.lrem(listKey, 0, key).then(() => redis.lpush(listKey, key)).then(() => redis.ltrim(listKey, 0, 9)).catch(console.error);
28319
+ return cachedData;
28320
+ }
27657
28321
  const command = readTemplate("door-levels");
27658
28322
  const response = await sendCommand(command, params.acm_url);
27659
28323
  const res = await parseStringPromise(response, { explicitArray: false });
27660
28324
  const format = await formatDoorAccessLevels(res);
28325
+ await setCache({ key, data: format, ttlSeconds: 60, redis });
28326
+ redis.lrem(listKey, 0, key).then(() => redis.lpush(listKey, key)).then(() => redis.ltrim(listKey, 0, 9)).catch(console.error);
27661
28327
  return format;
27662
28328
  } catch (err) {
27663
28329
  throw new Error(err.message);
@@ -27665,10 +28331,22 @@ function useAccessManagementSvc() {
27665
28331
  };
27666
28332
  const liftAccessLevelsSvc = async (params) => {
27667
28333
  try {
28334
+ const key = `${namespace}:${params.user}:lift-levels`;
28335
+ const listKey = `${namespace}:${params.user}:list`;
28336
+ const { redis } = useCache47(key);
28337
+ const cachedData = await getCache({ key, redis });
28338
+ if (cachedData) {
28339
+ console.log("\u26A1 Cache hit:", key);
28340
+ redis.expire(key, 60).catch(console.error);
28341
+ redis.lrem(listKey, 0, key).then(() => redis.lpush(listKey, key)).then(() => redis.ltrim(listKey, 0, 9)).catch(console.error);
28342
+ return cachedData;
28343
+ }
27668
28344
  const command = readTemplate("lift-levels");
27669
28345
  const response = await sendCommand(command, params.acm_url);
27670
28346
  const res = await parseStringPromise(response, { explicitArray: false });
27671
28347
  const format = await formatLiftAccessLevels(res);
28348
+ await setCache({ key, data: format, ttlSeconds: 60, redis });
28349
+ redis.lrem(listKey, 0, key).then(() => redis.lpush(listKey, key)).then(() => redis.ltrim(listKey, 0, 9)).catch(console.error);
27672
28350
  return format;
27673
28351
  } catch (error) {
27674
28352
  throw new Error(error.message);
@@ -27682,7 +28360,47 @@ function useAccessManagementSvc() {
27682
28360
  const format = await formatAccessGroup(res);
27683
28361
  return format;
27684
28362
  } catch (err) {
27685
- console.error("Failed to connect:", err);
28363
+ throw new Error(err.message);
28364
+ }
28365
+ };
28366
+ const accessManagementSettingsSvc = async (settings) => {
28367
+ try {
28368
+ const response = await accessManagementSettingsRepo({ ...settings });
28369
+ return response;
28370
+ } catch (err) {
28371
+ throw new Error(err.message);
28372
+ }
28373
+ };
28374
+ const allAccessCardsCountsSvc = async (params) => {
28375
+ try {
28376
+ const response = await allAccessCardsCountsRepo({ ...params });
28377
+ return response;
28378
+ } catch (err) {
28379
+ throw new Error(err.message);
28380
+ }
28381
+ };
28382
+ const availableAccessCardsSvc = async (params) => {
28383
+ try {
28384
+ const response = await availableAccessCardsRepo({ ...params });
28385
+ return response;
28386
+ } catch (err) {
28387
+ throw new Error(err.message);
28388
+ }
28389
+ };
28390
+ const userTypeAccessCardsSvc = async (params) => {
28391
+ try {
28392
+ const response = await userTypeAccessCardsRepo({ ...params });
28393
+ return response;
28394
+ } catch (err) {
28395
+ throw new Error(err.message);
28396
+ }
28397
+ };
28398
+ const assignedAccessCardsSvc = async (params) => {
28399
+ try {
28400
+ const response = await assignedAccessCardsRepo({ ...params });
28401
+ return response;
28402
+ } catch (err) {
28403
+ throw new Error(err.message);
27686
28404
  }
27687
28405
  };
27688
28406
  return {
@@ -27690,7 +28408,12 @@ function useAccessManagementSvc() {
27690
28408
  addNonPhysicalCardSvc,
27691
28409
  doorAccessLevelsSvc,
27692
28410
  liftAccessLevelsSvc,
27693
- accessGroupsSvc
28411
+ accessGroupsSvc,
28412
+ accessManagementSettingsSvc,
28413
+ allAccessCardsCountsSvc,
28414
+ availableAccessCardsSvc,
28415
+ userTypeAccessCardsSvc,
28416
+ assignedAccessCardsSvc
27694
28417
  };
27695
28418
  }
27696
28419
 
@@ -27701,7 +28424,12 @@ function useAccessManagementController() {
27701
28424
  addNonPhysicalCardSvc,
27702
28425
  doorAccessLevelsSvc,
27703
28426
  liftAccessLevelsSvc,
27704
- accessGroupsSvc
28427
+ accessGroupsSvc,
28428
+ accessManagementSettingsSvc,
28429
+ allAccessCardsCountsSvc,
28430
+ availableAccessCardsSvc,
28431
+ userTypeAccessCardsSvc,
28432
+ assignedAccessCardsSvc
27705
28433
  } = useAccessManagementSvc();
27706
28434
  const addPhysicalCard = async (req, res) => {
27707
28435
  try {
@@ -27761,7 +28489,8 @@ function useAccessManagementController() {
27761
28489
  createdAt,
27762
28490
  updatedAt,
27763
28491
  startDate,
27764
- endDate
28492
+ endDate,
28493
+ isWinsland
27765
28494
  } = req.body;
27766
28495
  const schema2 = Joi85.object({
27767
28496
  site: Joi85.string().hex().required(),
@@ -27777,7 +28506,8 @@ function useAccessManagementController() {
27777
28506
  startDate: Joi85.date().required(),
27778
28507
  endDate: Joi85.date().required(),
27779
28508
  createdAt: Joi85.date().required(),
27780
- updatedAt: Joi85.date().required()
28509
+ updatedAt: Joi85.date().required(),
28510
+ isWinsland: Joi85.boolean().optional().allow(null)
27781
28511
  });
27782
28512
  const { error } = schema2.validate({
27783
28513
  site,
@@ -27793,7 +28523,8 @@ function useAccessManagementController() {
27793
28523
  startDate,
27794
28524
  endDate,
27795
28525
  createdAt,
27796
- updatedAt
28526
+ updatedAt,
28527
+ isWinsland
27797
28528
  });
27798
28529
  if (error) {
27799
28530
  throw new Error(`${error.message}`);
@@ -27812,7 +28543,8 @@ function useAccessManagementController() {
27812
28543
  startDate,
27813
28544
  endDate,
27814
28545
  createdAt,
27815
- updatedAt
28546
+ updatedAt,
28547
+ isWinsland
27816
28548
  });
27817
28549
  return res.status(201).json({
27818
28550
  data: result,
@@ -27828,10 +28560,11 @@ function useAccessManagementController() {
27828
28560
  const doorAccessLevels = async (req, res) => {
27829
28561
  try {
27830
28562
  const { acm_url } = req.query;
28563
+ const user = req.cookies?.sid;
27831
28564
  if (!acm_url || typeof acm_url !== "string") {
27832
28565
  throw new Error("Access Control URL is required");
27833
28566
  }
27834
- const result = await doorAccessLevelsSvc({ acm_url });
28567
+ const result = await doorAccessLevelsSvc({ acm_url, user });
27835
28568
  return res.status(200).json({ message: "Success", data: result });
27836
28569
  } catch (error) {
27837
28570
  return res.status(400).json({
@@ -27843,10 +28576,11 @@ function useAccessManagementController() {
27843
28576
  const liftAccessLevels = async (req, res) => {
27844
28577
  try {
27845
28578
  const { acm_url } = req.query;
28579
+ const user = req.cookies?.sid;
27846
28580
  if (!acm_url || typeof acm_url !== "string") {
27847
28581
  throw new Error("Access Control URL is required");
27848
28582
  }
27849
- const result = await liftAccessLevelsSvc({ acm_url });
28583
+ const result = await liftAccessLevelsSvc({ acm_url, user });
27850
28584
  return res.status(200).json({ message: "Success", data: result });
27851
28585
  } catch (error) {
27852
28586
  return res.status(400).json({
@@ -27870,12 +28604,123 @@ function useAccessManagementController() {
27870
28604
  });
27871
28605
  }
27872
28606
  };
28607
+ const accessManagementSettings = async (req, res) => {
28608
+ try {
28609
+ const settings = req.body;
28610
+ const result = await accessManagementSettingsSvc(settings);
28611
+ return res.status(201).json({ message: "Success", data: result });
28612
+ } catch (error) {
28613
+ return res.status(400).json({
28614
+ data: null,
28615
+ message: error.message
28616
+ });
28617
+ }
28618
+ };
28619
+ const allAccessCardsCounts = async (req, res) => {
28620
+ try {
28621
+ const { site, userType } = req.query;
28622
+ const schema2 = Joi85.object({
28623
+ site: Joi85.string().hex().required(),
28624
+ userType: Joi85.string().required()
28625
+ });
28626
+ const { error } = schema2.validate({ site, userType });
28627
+ if (error) {
28628
+ throw new Error(`${error.message}`);
28629
+ }
28630
+ const result = await allAccessCardsCountsSvc({ site, userType });
28631
+ return res.status(200).json({ message: "Success", data: result });
28632
+ } catch (error) {
28633
+ return res.status(400).json({
28634
+ data: null,
28635
+ message: error.message
28636
+ });
28637
+ }
28638
+ };
28639
+ const availableAccessCards = async (req, res) => {
28640
+ try {
28641
+ const { site, userType, type } = req.query;
28642
+ const schema2 = Joi85.object({
28643
+ site: Joi85.string().hex().required(),
28644
+ userType: Joi85.string().optional().allow("", null),
28645
+ type: Joi85.string().optional().allow("", null)
28646
+ });
28647
+ const { error } = schema2.validate({ site, userType, type });
28648
+ if (error) {
28649
+ return res.status(400).json({ message: error.message });
28650
+ }
28651
+ const result = await availableAccessCardsSvc({ site, userType, type });
28652
+ return res.status(200).json({ message: "Success", data: result });
28653
+ } catch (error) {
28654
+ return res.status(400).json({
28655
+ data: null,
28656
+ message: error.message
28657
+ });
28658
+ }
28659
+ };
28660
+ const userTypeAccessCards = async (req, res) => {
28661
+ try {
28662
+ const {
28663
+ page = 1,
28664
+ limit = 10,
28665
+ search = "",
28666
+ site,
28667
+ organization,
28668
+ userType
28669
+ } = req.query;
28670
+ const schema2 = Joi85.object({
28671
+ page: Joi85.number().required(),
28672
+ limit: Joi85.number().optional().default(10),
28673
+ site: Joi85.string().hex().required(),
28674
+ organization: Joi85.string().hex().optional().allow("", null),
28675
+ search: Joi85.string().optional().allow("", null),
28676
+ userType: Joi85.string().required()
28677
+ });
28678
+ const { error } = schema2.validate({ page, limit, site, organization, search, userType });
28679
+ if (error) {
28680
+ return res.status(400).json({ message: error.message });
28681
+ }
28682
+ const result = await userTypeAccessCardsSvc({ page, limit, search, site, organization, userType });
28683
+ return res.status(200).json({ message: "Success", data: result });
28684
+ } catch (error) {
28685
+ return res.status(500).json({
28686
+ data: null,
28687
+ message: error.message
28688
+ });
28689
+ }
28690
+ };
28691
+ const assignedAccessCards = async (req, res) => {
28692
+ try {
28693
+ const { site, userType, type, search = "" } = req.query;
28694
+ const schema2 = Joi85.object({
28695
+ site: Joi85.string().hex().required(),
28696
+ userType: Joi85.string().required(),
28697
+ type: Joi85.string().required(),
28698
+ search: Joi85.string().optional().allow("", null)
28699
+ });
28700
+ const { error } = schema2.validate({ site, userType, type, search });
28701
+ if (error) {
28702
+ return res.status(400).json({ message: error.message });
28703
+ }
28704
+ const result = await assignedAccessCardsSvc({ site, userType, type, search });
28705
+ return res.status(200).json({ message: "Success", data: result });
28706
+ } catch (error) {
28707
+ return res.status(500).json({
28708
+ data: null,
28709
+ message: error.message
28710
+ });
28711
+ }
28712
+ };
27873
28713
  return {
27874
28714
  addPhysicalCard,
27875
28715
  addNonPhysicalCard,
27876
28716
  doorAccessLevels,
27877
28717
  liftAccessLevels,
27878
- accessGroups
28718
+ accessGroups,
28719
+ accessManagementSettings,
28720
+ allAccessCardsCounts,
28721
+ availableAccessCards,
28722
+ userTypeAccessCards,
28723
+ assignedAccessCards
27879
28724
  };
27880
28725
  }
27881
28726
 
@@ -27945,7 +28790,7 @@ import {
27945
28790
  makeCacheKey as makeCacheKey45,
27946
28791
  paginate as paginate39,
27947
28792
  useAtlas as useAtlas75,
27948
- useCache as useCache47
28793
+ useCache as useCache48
27949
28794
  } from "@7365admin1/node-server-utils";
27950
28795
  import { ObjectId as ObjectId85 } from "mongodb";
27951
28796
  function useNfcPatrolTagRepo() {
@@ -27956,8 +28801,8 @@ function useNfcPatrolTagRepo() {
27956
28801
  const namespace_collection = "nfc-patrol-tags";
27957
28802
  const namespace_collection_nfc_patrol_routes = "nfc-patrol-routes";
27958
28803
  const collection = db.collection(namespace_collection);
27959
- const { delNamespace, getCache, setCache } = useCache47(namespace_collection);
27960
- const { delNamespace: delNamespaceNfcPatrolRoutes } = useCache47(
28804
+ const { delNamespace, getCache, setCache } = useCache48(namespace_collection);
28805
+ const { delNamespace: delNamespaceNfcPatrolRoutes } = useCache48(
27961
28806
  namespace_collection_nfc_patrol_routes
27962
28807
  );
27963
28808
  async function createIndexes() {
@@ -28404,7 +29249,7 @@ import {
28404
29249
  NotFoundError as NotFoundError37,
28405
29250
  paginate as paginate40,
28406
29251
  useAtlas as useAtlas77,
28407
- useCache as useCache48
29252
+ useCache as useCache49
28408
29253
  } from "@7365admin1/node-server-utils";
28409
29254
  import { ObjectId as ObjectId87 } from "mongodb";
28410
29255
  function useOccurrenceBookRepo() {
@@ -28436,7 +29281,7 @@ function useOccurrenceBookRepo() {
28436
29281
  }
28437
29282
  const namespace_collection = "occurrence-books";
28438
29283
  const collection = db.collection(namespace_collection);
28439
- const { delNamespace, getCache, setCache } = useCache48(namespace_collection);
29284
+ const { delNamespace, getCache, setCache } = useCache49(namespace_collection);
28440
29285
  async function add(value, session) {
28441
29286
  try {
28442
29287
  value = MOccurrenceBook(value);
@@ -29014,7 +29859,7 @@ import {
29014
29859
  NotFoundError as NotFoundError38,
29015
29860
  paginate as paginate41,
29016
29861
  useAtlas as useAtlas79,
29017
- useCache as useCache49
29862
+ useCache as useCache50
29018
29863
  } from "@7365admin1/node-server-utils";
29019
29864
  import { ObjectId as ObjectId89 } from "mongodb";
29020
29865
  function useBulletinVideoRepo() {
@@ -29033,7 +29878,7 @@ function useBulletinVideoRepo() {
29033
29878
  }
29034
29879
  const namespace_collection = "bulletin-videos";
29035
29880
  const collection = db.collection(namespace_collection);
29036
- const { delNamespace, getCache, setCache } = useCache49(namespace_collection);
29881
+ const { delNamespace, getCache, setCache } = useCache50(namespace_collection);
29037
29882
  async function add(value, session) {
29038
29883
  try {
29039
29884
  value = MBulletinVideo(value);
@@ -29565,7 +30410,7 @@ import {
29565
30410
  InternalServerError as InternalServerError51,
29566
30411
  logger as logger127,
29567
30412
  useAtlas as useAtlas81,
29568
- useCache as useCache50,
30413
+ useCache as useCache51,
29569
30414
  paginate as paginate42,
29570
30415
  makeCacheKey as makeCacheKey48
29571
30416
  } from "@7365admin1/node-server-utils";
@@ -29577,7 +30422,7 @@ function useStatementOfAccountRepo() {
29577
30422
  }
29578
30423
  const namespace_collection = "site.statement-of-accounts";
29579
30424
  const collection = db.collection(namespace_collection);
29580
- const { delNamespace, getCache, setCache } = useCache50(namespace_collection);
30425
+ const { delNamespace, getCache, setCache } = useCache51(namespace_collection);
29581
30426
  async function createTextIndex() {
29582
30427
  try {
29583
30428
  await collection.createIndex({
@@ -30340,7 +31185,7 @@ import {
30340
31185
  NotFoundError as NotFoundError40,
30341
31186
  paginate as paginate43,
30342
31187
  useAtlas as useAtlas83,
30343
- useCache as useCache51
31188
+ useCache as useCache52
30344
31189
  } from "@7365admin1/node-server-utils";
30345
31190
  import { ObjectId as ObjectId93 } from "mongodb";
30346
31191
  function useEntryPassSettingsRepo() {
@@ -30350,7 +31195,7 @@ function useEntryPassSettingsRepo() {
30350
31195
  }
30351
31196
  const namespace_collection = "site.entrypass-settings";
30352
31197
  const collection = db.collection(namespace_collection);
30353
- const { delNamespace, getCache, setCache } = useCache51(namespace_collection);
31198
+ const { delNamespace, getCache, setCache } = useCache52(namespace_collection);
30354
31199
  async function createTextIndex() {
30355
31200
  try {
30356
31201
  await collection.createIndex({
@@ -30912,7 +31757,7 @@ import {
30912
31757
  logger as logger133,
30913
31758
  makeCacheKey as makeCacheKey50,
30914
31759
  useAtlas as useAtlas84,
30915
- useCache as useCache52
31760
+ useCache as useCache53
30916
31761
  } from "@7365admin1/node-server-utils";
30917
31762
  function useDashboardRepo() {
30918
31763
  const db = useAtlas84.getDb();
@@ -30923,7 +31768,7 @@ function useDashboardRepo() {
30923
31768
  const work_order_collection = db.collection("work-orders");
30924
31769
  const visitor_collection = db.collection("visitor.transactions");
30925
31770
  const namespace_collection = "dashboard";
30926
- const { delNamespace, getCache, setCache } = useCache52(namespace_collection);
31771
+ const { delNamespace, getCache, setCache } = useCache53(namespace_collection);
30927
31772
  async function getAll({
30928
31773
  site = ""
30929
31774
  }, session) {
@@ -31087,7 +31932,7 @@ import {
31087
31932
  makeCacheKey as makeCacheKey51,
31088
31933
  paginate as paginate44,
31089
31934
  useAtlas as useAtlas85,
31090
- useCache as useCache53
31935
+ useCache as useCache54
31091
31936
  } from "@7365admin1/node-server-utils";
31092
31937
  import { ObjectId as ObjectId95 } from "mongodb";
31093
31938
  function useNfcPatrolRouteRepo() {
@@ -31097,7 +31942,7 @@ function useNfcPatrolRouteRepo() {
31097
31942
  }
31098
31943
  const namespace_collection = "nfc-patrol-routes";
31099
31944
  const collection = db.collection(namespace_collection);
31100
- const { delNamespace, getCache, setCache } = useCache53(namespace_collection);
31945
+ const { delNamespace, getCache, setCache } = useCache54(namespace_collection);
31101
31946
  async function createIndexes() {
31102
31947
  try {
31103
31948
  await collection.createIndexes([
@@ -31819,7 +32664,11 @@ function MIncidentReport(value) {
31819
32664
  }
31820
32665
 
31821
32666
  // src/services/incident-report.service.ts
31822
- import { useAtlas as useAtlas88, BadRequestError as BadRequestError160 } from "@7365admin1/node-server-utils";
32667
+ import {
32668
+ useAtlas as useAtlas88,
32669
+ BadRequestError as BadRequestError160,
32670
+ NotFoundError as NotFoundError44
32671
+ } from "@7365admin1/node-server-utils";
31823
32672
 
31824
32673
  // src/repositories/incident-report.repo.ts
31825
32674
  import {
@@ -31830,7 +32679,7 @@ import {
31830
32679
  NotFoundError as NotFoundError43,
31831
32680
  paginate as paginate45,
31832
32681
  useAtlas as useAtlas87,
31833
- useCache as useCache54
32682
+ useCache as useCache55
31834
32683
  } from "@7365admin1/node-server-utils";
31835
32684
  import { ObjectId as ObjectId97 } from "mongodb";
31836
32685
  function useIncidentReportRepo() {
@@ -31861,7 +32710,7 @@ function useIncidentReportRepo() {
31861
32710
  }
31862
32711
  const namespace_collection = "incident-reports";
31863
32712
  const collection = db.collection(namespace_collection);
31864
- const { delNamespace, getCache, setCache } = useCache54(namespace_collection);
32713
+ const { delNamespace, getCache, setCache } = useCache55(namespace_collection);
31865
32714
  async function add(value, session) {
31866
32715
  try {
31867
32716
  value = MIncidentReport(value);
@@ -32151,15 +33000,18 @@ function useIncidentReportService() {
32151
33000
  const {
32152
33001
  add: _add,
32153
33002
  updateIncidentReportById: _updateIncidentReportById,
32154
- reviewIncidentReport: _reviewIncidentReport
33003
+ reviewIncidentReport: _reviewIncidentReport,
33004
+ getIncidentReportById: _getIncidentReportById
32155
33005
  } = useIncidentReportRepo();
32156
33006
  const {
32157
33007
  updateSiteIncidentCounter: _updateSiteIncidentCounter,
32158
33008
  getSiteById: _getSiteById
32159
33009
  } = useSiteRepo();
33010
+ const { updateStatusById } = useFileRepo();
32160
33011
  const { getUserById } = useUserRepo();
32161
33012
  const { getById: _getUnitById } = useBuildingUnitRepo();
32162
33013
  const { getById: _getOrganizationById } = useOrgRepo();
33014
+ const { deleteFile } = useFileService();
32163
33015
  async function add(value) {
32164
33016
  const session = useAtlas88.getClient()?.startSession();
32165
33017
  session?.startTransaction();
@@ -32177,6 +33029,19 @@ function useIncidentReportService() {
32177
33029
  );
32178
33030
  }
32179
33031
  }
33032
+ const incidentAttachments = value?.photos ?? [];
33033
+ if (incidentAttachments.length > 0) {
33034
+ for (const attachment of incidentAttachments) {
33035
+ const file = await updateStatusById(
33036
+ attachment,
33037
+ { status: "active" },
33038
+ session
33039
+ );
33040
+ if (!file) {
33041
+ throw new NotFoundError44("File not found.");
33042
+ }
33043
+ }
33044
+ }
32180
33045
  const result = await _add(value, session);
32181
33046
  await session?.commitTransaction();
32182
33047
  return result;
@@ -32191,6 +33056,26 @@ function useIncidentReportService() {
32191
33056
  const session = useAtlas88.getClient()?.startSession();
32192
33057
  session?.startTransaction();
32193
33058
  try {
33059
+ const incidentReport = await _getIncidentReportById(id);
33060
+ const dataAttchments = value?.photos || [];
33061
+ const incidentAttachments = incidentReport?.photos || [];
33062
+ const deletedFiles = [];
33063
+ incidentAttachments.forEach((id2) => {
33064
+ if (!dataAttchments.includes(id2)) {
33065
+ deletedFiles.push(id2);
33066
+ }
33067
+ });
33068
+ if (deletedFiles.length > 0) {
33069
+ await Promise.all(
33070
+ deletedFiles.map(async (id2) => {
33071
+ try {
33072
+ await deleteFile(id2);
33073
+ } catch (error) {
33074
+ throw error;
33075
+ }
33076
+ })
33077
+ );
33078
+ }
32194
33079
  await _updateIncidentReportById(id, value, session);
32195
33080
  await session?.commitTransaction();
32196
33081
  return "Successfully updated incident report.";
@@ -32564,9 +33449,9 @@ import {
32564
33449
  InternalServerError as InternalServerError56,
32565
33450
  logger as logger142,
32566
33451
  makeCacheKey as makeCacheKey53,
32567
- NotFoundError as NotFoundError44,
33452
+ NotFoundError as NotFoundError45,
32568
33453
  useAtlas as useAtlas89,
32569
- useCache as useCache55
33454
+ useCache as useCache56
32570
33455
  } from "@7365admin1/node-server-utils";
32571
33456
  import { ObjectId as ObjectId99 } from "mongodb";
32572
33457
  function useNfcPatrolSettingsRepository() {
@@ -32576,7 +33461,7 @@ function useNfcPatrolSettingsRepository() {
32576
33461
  }
32577
33462
  const namespace_collection = "site.nfc-patrol-settings";
32578
33463
  const collection = db.collection(namespace_collection);
32579
- const { delNamespace, setCache, getCache } = useCache55(namespace_collection);
33464
+ const { delNamespace, setCache, getCache } = useCache56(namespace_collection);
32580
33465
  async function createIndexes() {
32581
33466
  try {
32582
33467
  await collection.createIndexes([{ key: { site: 1 }, unique: true }]);
@@ -32654,7 +33539,7 @@ function useNfcPatrolSettingsRepository() {
32654
33539
  { session }
32655
33540
  );
32656
33541
  if (res.matchedCount === 0) {
32657
- throw new NotFoundError44("NFC patrol settings not found for this site.");
33542
+ throw new NotFoundError45("NFC patrol settings not found for this site.");
32658
33543
  }
32659
33544
  delNamespace().then(() => {
32660
33545
  logger142.info(`Cache cleared for namespace: ${namespace_collection}`);
@@ -32818,10 +33703,10 @@ import {
32818
33703
  InternalServerError as InternalServerError57,
32819
33704
  logger as logger145,
32820
33705
  makeCacheKey as makeCacheKey54,
32821
- NotFoundError as NotFoundError45,
33706
+ NotFoundError as NotFoundError46,
32822
33707
  paginate as paginate46,
32823
33708
  useAtlas as useAtlas91,
32824
- useCache as useCache56
33709
+ useCache as useCache57
32825
33710
  } from "@7365admin1/node-server-utils";
32826
33711
 
32827
33712
  // src/models/occurrence-subject.model.ts
@@ -32898,7 +33783,7 @@ function useOccurrenceSubjectRepo() {
32898
33783
  }
32899
33784
  const namespace_collection = "occurrence-subjects";
32900
33785
  const collection = db.collection(namespace_collection);
32901
- const { delNamespace, getCache, setCache } = useCache56(namespace_collection);
33786
+ const { delNamespace, getCache, setCache } = useCache57(namespace_collection);
32902
33787
  async function add(value, session) {
32903
33788
  try {
32904
33789
  value = MOccurrenceSubject(value);
@@ -33037,7 +33922,7 @@ function useOccurrenceSubjectRepo() {
33037
33922
  try {
33038
33923
  const data = await collection.findOne({ _id }, { session });
33039
33924
  if (!data) {
33040
- throw new NotFoundError45("Occurrence subject not found.");
33925
+ throw new NotFoundError46("Occurrence subject not found.");
33041
33926
  }
33042
33927
  setCache(cacheKey, data, 15 * 60).then(() => {
33043
33928
  logger145.info(`Cache set for key: ${cacheKey}`);
@@ -33463,10 +34348,10 @@ import {
33463
34348
  InternalServerError as InternalServerError58,
33464
34349
  logger as logger147,
33465
34350
  makeCacheKey as makeCacheKey55,
33466
- NotFoundError as NotFoundError46,
34351
+ NotFoundError as NotFoundError47,
33467
34352
  paginate as paginate47,
33468
34353
  useAtlas as useAtlas93,
33469
- useCache as useCache57
34354
+ useCache as useCache58
33470
34355
  } from "@7365admin1/node-server-utils";
33471
34356
  import { ObjectId as ObjectId103 } from "mongodb";
33472
34357
  function useOnlineFormRepo() {
@@ -33476,7 +34361,7 @@ function useOnlineFormRepo() {
33476
34361
  }
33477
34362
  const namespace_collection = "online-forms";
33478
34363
  const collection = db.collection(namespace_collection);
33479
- const { delNamespace, getCache, setCache } = useCache57(namespace_collection);
34364
+ const { delNamespace, getCache, setCache } = useCache58(namespace_collection);
33480
34365
  async function createTextIndex() {
33481
34366
  try {
33482
34367
  await collection.createIndex({
@@ -33599,7 +34484,7 @@ function useOnlineFormRepo() {
33599
34484
  }
33600
34485
  ]).toArray();
33601
34486
  if (!data || !data.length) {
33602
- throw new NotFoundError46("Document not found.");
34487
+ throw new NotFoundError47("Document not found.");
33603
34488
  }
33604
34489
  setCache(cacheKey, data[0], 15 * 60).then(() => {
33605
34490
  logger147.info(`Cache set for key: ${cacheKey}`);
@@ -34212,7 +35097,7 @@ import {
34212
35097
  makeCacheKey as makeCacheKey56,
34213
35098
  paginate as paginate48,
34214
35099
  useAtlas as useAtlas95,
34215
- useCache as useCache58
35100
+ useCache as useCache59
34216
35101
  } from "@7365admin1/node-server-utils";
34217
35102
  import { ObjectId as ObjectId105 } from "mongodb";
34218
35103
  function useNfcPatrolLogRepo() {
@@ -34222,7 +35107,7 @@ function useNfcPatrolLogRepo() {
34222
35107
  }
34223
35108
  const namespace_collection = "nfc-patrol-logs";
34224
35109
  const collection = db.collection(namespace_collection);
34225
- const { delNamespace, getCache, setCache } = useCache58(namespace_collection);
35110
+ const { delNamespace, getCache, setCache } = useCache59(namespace_collection);
34226
35111
  async function createIndexes() {
34227
35112
  try {
34228
35113
  await collection.createIndexes([