@7365admin1/core 2.44.0 → 2.46.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
@@ -34,9 +34,12 @@ __export(src_exports, {
34
34
  AccessTypeProps: () => AccessTypeProps,
35
35
  AppServiceType: () => AppServiceType,
36
36
  BuildingStatus: () => BuildingStatus,
37
+ BulletinOrder: () => BulletinOrder,
37
38
  BulletinRecipient: () => BulletinRecipient,
38
39
  BulletinSort: () => BulletinSort,
39
40
  BulletinStatus: () => BulletinStatus,
41
+ BulletinVideoOrder: () => BulletinVideoOrder,
42
+ BulletinVideoSort: () => BulletinVideoSort,
40
43
  CameraType: () => CameraType,
41
44
  DEVICE_STATUS: () => DEVICE_STATUS,
42
45
  DOBStatus: () => DOBStatus,
@@ -3012,7 +3015,8 @@ function useUserRepo() {
3012
3015
  "dateOfBirth",
3013
3016
  "profile",
3014
3017
  "gender",
3015
- "defaultOrg"
3018
+ "defaultOrg",
3019
+ "status"
3016
3020
  ];
3017
3021
  if (!allowedFields.includes(field)) {
3018
3022
  throw new import_node_server_utils10.BadRequestError(
@@ -5894,6 +5898,13 @@ var MRole = class {
5894
5898
  throw new import_node_server_utils22.BadRequestError("Invalid org ID format.");
5895
5899
  }
5896
5900
  }
5901
+ if (typeof value.site === "string" && value.site.length === 24) {
5902
+ try {
5903
+ value.site = new import_mongodb19.ObjectId(value.site);
5904
+ } catch (error) {
5905
+ throw new import_node_server_utils22.BadRequestError("Invalid site ID format.");
5906
+ }
5907
+ }
5897
5908
  if (value.createdBy) {
5898
5909
  try {
5899
5910
  value.createdBy = new import_mongodb19.ObjectId(value.createdBy);
@@ -5907,6 +5918,8 @@ var MRole = class {
5907
5918
  this.permissions = value.permissions ?? [];
5908
5919
  this.type = value.type ? value.type : "account";
5909
5920
  this.org = value.org ?? "";
5921
+ this.site = value.site ?? "";
5922
+ this.platform = value.platform ?? "website";
5910
5923
  this.default = value.default ?? false;
5911
5924
  this.status = value.status ?? "active";
5912
5925
  this.createdBy = value.createdBy ?? "";
@@ -7190,7 +7203,9 @@ function useRoleController() {
7190
7203
  name: import_joi14.default.string().required(),
7191
7204
  permissions: import_joi14.default.array().items(import_joi14.default.string()).required(),
7192
7205
  type: import_joi14.default.string().optional().allow("", null),
7193
- org: import_joi14.default.string().hex().optional().allow("", null)
7206
+ org: import_joi14.default.string().hex().optional().allow("", null),
7207
+ site: import_joi14.default.string().hex().optional().allow("", null),
7208
+ platform: import_joi14.default.string().valid("website", "mobile").optional().default("website")
7194
7209
  });
7195
7210
  const payload = { ...req.body };
7196
7211
  const { error } = validation.validate(payload);
@@ -13119,7 +13134,7 @@ function useSiteCameraRepo() {
13119
13134
  key: { type: 1 }
13120
13135
  },
13121
13136
  {
13122
- key: { host: 1, type: 1, status: 1 },
13137
+ key: { host: 1, type: 1, status: 1, site: 1 },
13123
13138
  unique: true,
13124
13139
  partialFilterExpression: { status: "active" }
13125
13140
  }
@@ -15020,7 +15035,7 @@ function useVehicleRepo() {
15020
15035
  try {
15021
15036
  const updateValue = {
15022
15037
  ...value,
15023
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
15038
+ updatedAt: /* @__PURE__ */ new Date()
15024
15039
  };
15025
15040
  const res = await collection.updateOne(
15026
15041
  { _id },
@@ -16730,10 +16745,13 @@ function useVehicleService() {
16730
16745
  pullVehicleByRecNo: _pullVehicleByRecNo
16731
16746
  } = usePersonRepo();
16732
16747
  const { getUnitByBlockLevelUnitNumber: _getUnitByBlockLevelUnitNumber } = useBuildingUnitRepo();
16733
- async function add(value) {
16734
- const session = import_node_server_utils75.useAtlas.getClient()?.startSession();
16748
+ async function add(value, session) {
16749
+ const isExternalSession = !!session;
16735
16750
  if (!session) {
16736
- throw new Error("Unable to start session for vehicle service.");
16751
+ session = await import_node_server_utils75.useAtlas.getClient()?.startSession();
16752
+ if (!session) {
16753
+ throw new Error("Unable to start session for vehicle service.");
16754
+ }
16737
16755
  }
16738
16756
  const [_vehiclePlateNumber] = value.plateNumber;
16739
16757
  const [existingPlateNumber, org] = await Promise.all([
@@ -16790,7 +16808,9 @@ function useVehicleService() {
16790
16808
  const owner = value.name;
16791
16809
  const plateNumbers = value.plateNumber;
16792
16810
  try {
16793
- session.startTransaction();
16811
+ if (!isExternalSession) {
16812
+ session.startTransaction();
16813
+ }
16794
16814
  let message = "Vehicle plate number needs approval from property management.";
16795
16815
  let siteCameras = [];
16796
16816
  if (value.status && value.status !== "pending" /* PENDING */) {
@@ -16888,14 +16908,20 @@ function useVehicleService() {
16888
16908
  }
16889
16909
  await _add(vehicleValue, session);
16890
16910
  }
16891
- await session.commitTransaction();
16911
+ if (!isExternalSession) {
16912
+ await session.commitTransaction();
16913
+ }
16892
16914
  return message;
16893
16915
  } catch (error) {
16894
16916
  import_node_server_utils75.logger.error("Error in vehicle service add:", error);
16895
- await session.abortTransaction();
16917
+ if (!isExternalSession) {
16918
+ await session.abortTransaction();
16919
+ }
16896
16920
  throw error;
16897
16921
  } finally {
16898
- session.endSession();
16922
+ if (!isExternalSession) {
16923
+ session.endSession();
16924
+ }
16899
16925
  }
16900
16926
  }
16901
16927
  async function deleteVehicle(_id, recno, site, type, bypass = false) {
@@ -16986,11 +17012,14 @@ function useVehicleService() {
16986
17012
  endDate = new Date(startDate);
16987
17013
  endDate.setFullYear(endDate.getFullYear() + 10);
16988
17014
  } else {
16989
- startDate = hasStart ? new Date(vehicle.start) : null;
16990
- endDate = hasEnd ? new Date(vehicle.end) : null;
17015
+ startDate = hasStart ? new Date(vehicle.start) : /* @__PURE__ */ new Date();
17016
+ if (hasEnd) {
17017
+ endDate = new Date(vehicle.end);
17018
+ } else {
17019
+ endDate = new Date(startDate);
17020
+ endDate.setFullYear(endDate.getFullYear() + 10);
17021
+ }
16991
17022
  }
16992
- const startIso = startDate ? startDate.toISOString() : "";
16993
- const endIso = endDate ? endDate.toISOString() : "";
16994
17023
  const startDahua = startDate ? formatDahuaDate(startDate) : "";
16995
17024
  const endDahua = endDate ? formatDahuaDate(endDate) : "";
16996
17025
  try {
@@ -17047,8 +17076,8 @@ function useVehicleService() {
17047
17076
  }
17048
17077
  const formattedValue = {
17049
17078
  ...value,
17050
- start: startIso,
17051
- end: endIso
17079
+ start: startDate,
17080
+ end: endDate
17052
17081
  };
17053
17082
  await _updateVehicleById(id, formattedValue, session);
17054
17083
  await session.commitTransaction();
@@ -17428,6 +17457,40 @@ function useVehicleService() {
17428
17457
  };
17429
17458
  }
17430
17459
 
17460
+ // src/utils/logger-dahua.ts
17461
+ var winston = __toESM(require("winston"));
17462
+ var import_winston_daily_rotate_file = __toESM(require("winston-daily-rotate-file"));
17463
+ var loggerDahua = winston.createLogger({
17464
+ level: "info",
17465
+ format: winston.format.combine(
17466
+ winston.format.timestamp(),
17467
+ winston.format.json()
17468
+ ),
17469
+ transports: [
17470
+ // 1. Daily Error Logs - Using the class directly
17471
+ new import_winston_daily_rotate_file.default({
17472
+ filename: "logs/dahua/error-%DATE%.log",
17473
+ datePattern: "YYYY-MM-DD",
17474
+ level: "error",
17475
+ zippedArchive: true,
17476
+ maxSize: "20m",
17477
+ maxFiles: "14d"
17478
+ }),
17479
+ // 2. Daily Combined Logs - Using the class directly
17480
+ new import_winston_daily_rotate_file.default({
17481
+ filename: "logs/dahua/combined-%DATE%.log",
17482
+ datePattern: "YYYY-MM-DD",
17483
+ zippedArchive: true,
17484
+ maxSize: "20m",
17485
+ maxFiles: "14d"
17486
+ }),
17487
+ // 3. Console logging (Optional)
17488
+ new winston.transports.Console({
17489
+ format: winston.format.simple()
17490
+ })
17491
+ ]
17492
+ });
17493
+
17431
17494
  // src/services/dahua.service.ts
17432
17495
  function useDahuaDigest({
17433
17496
  host = "",
@@ -17485,14 +17548,14 @@ function useDahuaService() {
17485
17548
  function enqueue(buffer) {
17486
17549
  if (queue.length >= MAX_QUEUE_SIZE) {
17487
17550
  droppedChunks++;
17488
- import_node_server_utils76.logger.error(
17551
+ loggerDahua.error(
17489
17552
  `[${site}][${gate}] Queue overflow. Dropped: ${droppedChunks}`
17490
17553
  );
17491
17554
  return;
17492
17555
  }
17493
17556
  queue.push(buffer);
17494
17557
  if (queue.length >= BACKPRESSURE_THRESHOLD && streamRef && !streamRef.isPaused()) {
17495
- import_node_server_utils76.logger.warn(
17558
+ loggerDahua.warn(
17496
17559
  `[${site}][${gate}] Queue at ${queue.length}/${MAX_QUEUE_SIZE}, pausing stream`
17497
17560
  );
17498
17561
  streamRef.pause();
@@ -17509,7 +17572,7 @@ function useDahuaService() {
17509
17572
  if (streamRef && streamRef.isPaused()) {
17510
17573
  streamRef.resume();
17511
17574
  }
17512
- import_node_server_utils76.logger.info(
17575
+ loggerDahua.info(
17513
17576
  `[${site}][${gate}] BufferQueue destroyed. Processed=${processedChunks}, Dropped=${droppedChunks}`
17514
17577
  );
17515
17578
  }
@@ -17522,20 +17585,20 @@ function useDahuaService() {
17522
17585
  await handleBuffer(buffer);
17523
17586
  processedChunks++;
17524
17587
  if (queue.length <= RESUME_THRESHOLD && streamRef && streamRef.isPaused()) {
17525
- import_node_server_utils76.logger.info(
17588
+ loggerDahua.info(
17526
17589
  `[${site}][${gate}] Queue at ${queue.length}/${MAX_QUEUE_SIZE}, resuming stream`
17527
17590
  );
17528
17591
  streamRef.resume();
17529
17592
  }
17530
17593
  } catch (err) {
17531
- import_node_server_utils76.logger.error(`[${site}][${gate}] Error processing buffer:`, err);
17594
+ loggerDahua.error(`[${site}][${gate}] Error processing buffer:`, err);
17532
17595
  } finally {
17533
17596
  processing = false;
17534
17597
  processNext();
17535
17598
  }
17536
17599
  }
17537
17600
  async function processVehicleTransaction() {
17538
- import_node_server_utils76.logger.info(
17601
+ loggerDahua.info(
17539
17602
  `[${site}][${gate}] Vehicle transaction: Plate=${plateNumber}, UTC=${UTCData}, UTCMs=${UTCMs}`
17540
17603
  );
17541
17604
  let org = "";
@@ -17543,7 +17606,7 @@ function useDahuaService() {
17543
17606
  const theSite = await getSiteById(site);
17544
17607
  org = theSite?.orgId.toString() || "unknown";
17545
17608
  } catch (error) {
17546
- import_node_server_utils76.logger.error(
17609
+ loggerDahua.error(
17547
17610
  `[${site}][${gate}] Error fetching site for orgId:`,
17548
17611
  error
17549
17612
  );
@@ -17563,7 +17626,7 @@ function useDahuaService() {
17563
17626
  });
17564
17627
  }
17565
17628
  } catch (error) {
17566
- import_node_server_utils76.logger.error(
17629
+ loggerDahua.error(
17567
17630
  `[${site}][${gate}] Error closing existing open transaction:`,
17568
17631
  error
17569
17632
  );
@@ -17619,7 +17682,7 @@ function useDahuaService() {
17619
17682
  currentSnapshotField = "snapshotEntryImage";
17620
17683
  } catch (error) {
17621
17684
  console.log("failed to create visitor transaction", error);
17622
- import_node_server_utils76.logger.error(
17685
+ loggerDahua.error(
17623
17686
  `[${site}][${gate}] Error creating visitor transaction:`,
17624
17687
  error
17625
17688
  );
@@ -17703,7 +17766,7 @@ function useDahuaService() {
17703
17766
  try {
17704
17767
  await import_fs.promises.mkdir(dir, { recursive: true });
17705
17768
  await import_fs.promises.writeFile(snapFolder, accumulatedImageBuffer);
17706
- import_node_server_utils76.logger.debug(`[${site}][${gate}] Saved image locally: ${filename}`);
17769
+ loggerDahua.debug(`[${site}][${gate}] Saved image locally: ${filename}`);
17707
17770
  const fileId = await _createFile(
17708
17771
  {
17709
17772
  originalname: filename,
@@ -17712,7 +17775,7 @@ function useDahuaService() {
17712
17775
  },
17713
17776
  `anpr/${site}`
17714
17777
  );
17715
- import_node_server_utils76.logger.info(
17778
+ loggerDahua.info(
17716
17779
  `[${site}][${gate}] Created file record for image: ${fileId.toString()}`
17717
17780
  );
17718
17781
  if (currentTransactionId && currentSnapshotField) {
@@ -17720,23 +17783,23 @@ function useDahuaService() {
17720
17783
  [currentSnapshotField]: fileId.toString()
17721
17784
  });
17722
17785
  }
17723
- import_node_server_utils76.logger.info(
17786
+ loggerDahua.info(
17724
17787
  `[${site}][${gate}] Image stored with fileId: ${fileId.toString()}`
17725
17788
  );
17726
17789
  await import_fs.promises.unlink(snapFolder);
17727
- import_node_server_utils76.logger.debug(`[${site}][${gate}] Deleted local file: ${filename}`);
17790
+ loggerDahua.debug(`[${site}][${gate}] Deleted local file: ${filename}`);
17728
17791
  } catch (err) {
17729
- import_node_server_utils76.logger.error(
17792
+ loggerDahua.error(
17730
17793
  `[${site}][${gate}] Failed to process image ${filename}:`,
17731
17794
  err
17732
17795
  );
17733
17796
  try {
17734
17797
  await import_fs.promises.unlink(snapFolder);
17735
- import_node_server_utils76.logger.debug(
17798
+ loggerDahua.debug(
17736
17799
  `[${site}][${gate}] Cleaned up local file after error: ${filename}`
17737
17800
  );
17738
17801
  } catch (unlinkErr) {
17739
- import_node_server_utils76.logger.error(
17802
+ loggerDahua.error(
17740
17803
  `[${site}][${gate}] Failed to clean up local file: ${filename}`,
17741
17804
  unlinkErr
17742
17805
  );
@@ -17771,7 +17834,7 @@ function useDahuaService() {
17771
17834
  },
17772
17835
  "snapshots"
17773
17836
  );
17774
- import_node_server_utils76.logger.info(`Successfully saved snapshot fileId: ${fileId.toString()}`);
17837
+ loggerDahua.info(`Successfully saved snapshot fileId: ${fileId.toString()}`);
17775
17838
  return fileId;
17776
17839
  } catch (error) {
17777
17840
  throw error;
@@ -17790,7 +17853,7 @@ function useDahuaService() {
17790
17853
  const contentType = response.res.headers["content-type"];
17791
17854
  const boundaryMatch = contentType?.match(/boundary=(.*)$/i);
17792
17855
  const boundary = boundaryMatch ? `--${boundaryMatch[1]}` : "--myboundary";
17793
- import_node_server_utils76.logger.debug(`[${site}][${gate}] Using boundary: ${boundary}`);
17856
+ loggerDahua.debug(`[${site}][${gate}] Using boundary: ${boundary}`);
17794
17857
  const bufferQueue = useBufferQueue(
17795
17858
  boundary,
17796
17859
  site,
@@ -17802,7 +17865,7 @@ function useDahuaService() {
17802
17865
  );
17803
17866
  bufferQueue.setStream(response.res);
17804
17867
  if ([400, 401, 403, 500].includes(response.statusCode)) {
17805
- import_node_server_utils76.logger.error(
17868
+ loggerDahua.error(
17806
17869
  `[${site}][${gate}] Connection error:`,
17807
17870
  response.statusCode
17808
17871
  );
@@ -17811,14 +17874,14 @@ function useDahuaService() {
17811
17874
  );
17812
17875
  }
17813
17876
  if ([200, 201, 202].includes(response.statusCode)) {
17814
- import_node_server_utils76.logger.info(`[${site}][${gate}] Successfully connected to ANPR.`);
17877
+ loggerDahua.info(`[${site}][${gate}] Successfully connected to ANPR.`);
17815
17878
  console.log(`[${site}][${gate}] Successfully connected to ANPR.`);
17816
17879
  }
17817
17880
  response.res.on("data", (chunk) => {
17818
17881
  bufferQueue.enqueue(chunk);
17819
17882
  });
17820
17883
  const handleDisconnect = async (reason, err) => {
17821
- import_node_server_utils76.logger.error(
17884
+ loggerDahua.error(
17822
17885
  `[${site}][${gate}] ${reason}`,
17823
17886
  err ? err.code || err : ""
17824
17887
  );
@@ -17841,7 +17904,7 @@ function useDahuaService() {
17841
17904
  (err) => handleDisconnect("Connection error:", err)
17842
17905
  );
17843
17906
  } catch (error) {
17844
- import_node_server_utils76.logger.error(
17907
+ loggerDahua.error(
17845
17908
  `[${site}][${gate}] Initial connect error:`,
17846
17909
  error.code || error
17847
17910
  );
@@ -17878,7 +17941,7 @@ function useDahuaService() {
17878
17941
  });
17879
17942
  return response;
17880
17943
  } catch (error2) {
17881
- import_node_server_utils76.logger.error(`[${value.host}] Error adding plate number:`, error2);
17944
+ loggerDahua.error(`[${value.host}] Error adding plate number:`, error2);
17882
17945
  throw new import_node_server_utils76.BadRequestError(`Failed to add plate number: ${error2.message}`);
17883
17946
  }
17884
17947
  }
@@ -17915,7 +17978,7 @@ function useDahuaService() {
17915
17978
  });
17916
17979
  return response;
17917
17980
  } catch (error2) {
17918
- import_node_server_utils76.logger.error(`[${value.host}] Error updating plate number:`, error2);
17981
+ loggerDahua.error(`[${value.host}] Error updating plate number:`, error2);
17919
17982
  throw new import_node_server_utils76.BadRequestError(
17920
17983
  `Failed to update plate number: ${error2.message}`
17921
17984
  );
@@ -17942,7 +18005,7 @@ function useDahuaService() {
17942
18005
  });
17943
18006
  return response;
17944
18007
  } catch (error2) {
17945
- import_node_server_utils76.logger.error(`[${value.host}] Error removing plate number:`, error2);
18008
+ loggerDahua.error(`[${value.host}] Error removing plate number:`, error2);
17946
18009
  }
17947
18010
  }
17948
18011
  async function getPlateNumber(value) {
@@ -17967,7 +18030,7 @@ function useDahuaService() {
17967
18030
  const text = response?.data?.toString?.("utf-8");
17968
18031
  return text;
17969
18032
  } catch (error2) {
17970
- import_node_server_utils76.logger.error(`[${value.host}] Error finding plate number:`, error2);
18033
+ loggerDahua.error(`[${value.host}] Error finding plate number:`, error2);
17971
18034
  throw error2;
17972
18035
  }
17973
18036
  }
@@ -18004,7 +18067,7 @@ function useDahuaService() {
18004
18067
  });
18005
18068
  return response;
18006
18069
  } catch (error2) {
18007
- import_node_server_utils76.logger.error(`[${value.host}] Error bulk add plate number:`, error2);
18070
+ loggerDahua.error(`[${value.host}] Error bulk add plate number:`, error2);
18008
18071
  throw new import_node_server_utils76.BadRequestError(
18009
18072
  `Failed bulk adding plate number: ${error2.message}`
18010
18073
  );
@@ -19561,7 +19624,7 @@ function useVehicleController() {
19561
19624
  next(new import_node_server_utils87.BadRequestError("Spreadsheet file is required."));
19562
19625
  return;
19563
19626
  }
19564
- const { originalname, path: path4 } = req.file;
19627
+ const { originalname, path: path5 } = req.file;
19565
19628
  const lowerName = originalname.toLowerCase();
19566
19629
  const rowSchema = import_joi46.default.object({
19567
19630
  fullName: import_joi46.default.string().trim().required(),
@@ -19600,7 +19663,7 @@ function useVehicleController() {
19600
19663
  let rows = [];
19601
19664
  if (lowerName.endsWith(".xlsx") || lowerName.endsWith(".xls")) {
19602
19665
  const workbook = new import_exceljs.default.Workbook();
19603
- await workbook.xlsx.readFile(path4);
19666
+ await workbook.xlsx.readFile(path5);
19604
19667
  const worksheet = workbook.worksheets[0];
19605
19668
  if (!worksheet) {
19606
19669
  next(
@@ -19626,7 +19689,7 @@ function useVehicleController() {
19626
19689
  } else if (lowerName.endsWith(".csv")) {
19627
19690
  rows = await new Promise((resolve, reject) => {
19628
19691
  const parsed = [];
19629
- import_fs2.default.createReadStream(path4).pipe((0, import_csv_parser.default)()).on("data", (row) => parsed.push(row)).on("end", () => resolve(parsed)).on("error", reject);
19692
+ import_fs2.default.createReadStream(path5).pipe((0, import_csv_parser.default)()).on("data", (row) => parsed.push(row)).on("end", () => resolve(parsed)).on("error", reject);
19630
19693
  });
19631
19694
  } else {
19632
19695
  next(
@@ -19665,7 +19728,7 @@ function useVehicleController() {
19665
19728
  validationErrors: invalidRows,
19666
19729
  data
19667
19730
  });
19668
- import_fs2.default.unlink(path4, () => {
19731
+ import_fs2.default.unlink(path5, () => {
19669
19732
  });
19670
19733
  } catch (error) {
19671
19734
  import_node_server_utils87.logger.log({ level: "error", message: error.message });
@@ -19863,26 +19926,27 @@ function useVehicleController() {
19863
19926
  }
19864
19927
  }
19865
19928
  async function approveVehicleById(req, res, next) {
19866
- const validation = import_joi46.default.object({
19867
- _id: import_joi46.default.string().hex().length(24).required(),
19868
- org: import_joi46.default.string().hex().length(24).required(),
19869
- site: import_joi46.default.string().hex().length(24).required()
19870
- });
19871
- const _id = req.params.id;
19872
- const payload = { ...req.body };
19873
- const { error, value } = validation.validate({ _id, ...payload });
19874
- if (error) {
19875
- import_node_server_utils87.logger.log({ level: "error", message: error.message });
19876
- next(new import_node_server_utils87.BadRequestError(error.message));
19877
- return;
19878
- }
19879
19929
  try {
19880
- await _approveVehicleById(value._id, value.org, value.site);
19930
+ const schema2 = import_joi46.default.object({
19931
+ _id: import_joi46.default.string().hex().length(24).required(),
19932
+ org: import_joi46.default.string().hex().length(24).required(),
19933
+ site: import_joi46.default.string().hex().length(24).required()
19934
+ });
19935
+ const payload = { _id: req.params.id, ...req.body };
19936
+ const { error, value } = schema2.validate(payload, { abortEarly: false });
19937
+ if (error) {
19938
+ const messages = error.details.map((d) => d.message).join(", ");
19939
+ import_node_server_utils87.logger.log({ level: "error", message: messages });
19940
+ next(new import_node_server_utils87.BadRequestError(messages));
19941
+ return;
19942
+ }
19943
+ const { _id, org, site } = value;
19944
+ await _approveVehicleById(_id, org, site);
19881
19945
  res.json({ message: "Successfully approved and updated vehicle." });
19882
19946
  return;
19883
- } catch (error2) {
19884
- import_node_server_utils87.logger.log({ level: "error", message: error2.message });
19885
- next(error2);
19947
+ } catch (error) {
19948
+ import_node_server_utils87.logger.log({ level: "error", message: error.message });
19949
+ next(error);
19886
19950
  return;
19887
19951
  }
19888
19952
  }
@@ -24064,7 +24128,16 @@ var import_node_server_utils108 = require("@7365admin1/node-server-utils");
24064
24128
 
24065
24129
  // src/services/person.service.ts
24066
24130
  var import_node_server_utils107 = require("@7365admin1/node-server-utils");
24131
+ var import_path = __toESM(require("path"));
24067
24132
  function usePersonService() {
24133
+ const MailerConfig = {
24134
+ host: MAILER_TRANSPORT_HOST,
24135
+ port: MAILER_TRANSPORT_PORT,
24136
+ secure: MAILER_TRANSPORT_SECURE,
24137
+ email: MAILER_EMAIL,
24138
+ password: MAILER_PASSWORD
24139
+ };
24140
+ const mailer = new import_node_server_utils107.useMailer(MailerConfig);
24068
24141
  const {
24069
24142
  add: _add,
24070
24143
  getById: _getById,
@@ -24085,6 +24158,7 @@ function usePersonService() {
24085
24158
  const { updateStatusById } = useFileRepo();
24086
24159
  const { getById: getOrgById } = useOrgRepo();
24087
24160
  const { getSiteById } = useSiteRepo();
24161
+ const { add: addVehicle } = useVehicleService();
24088
24162
  async function add(value) {
24089
24163
  const session = import_node_server_utils107.useAtlas.getClient()?.startSession();
24090
24164
  if (!session) {
@@ -24118,7 +24192,7 @@ function usePersonService() {
24118
24192
  email: value.email,
24119
24193
  password: hashedPassword,
24120
24194
  name: value.name,
24121
- status: value.platform == "mobile" ? "deleted" : "active",
24195
+ status: value.platform == "mobile" ? "pending" : "active",
24122
24196
  defaultOrg: value.org?.toString() || ""
24123
24197
  };
24124
24198
  const userId = await addUser(user, session);
@@ -24239,6 +24313,9 @@ function usePersonService() {
24239
24313
  const session = import_node_server_utils107.useAtlas.getClient()?.startSession();
24240
24314
  session?.startTransaction();
24241
24315
  try {
24316
+ const person = await _getById(id.toString());
24317
+ if (!person)
24318
+ throw new import_node_server_utils107.BadRequestError("Person not found.");
24242
24319
  if (value.approvedBy) {
24243
24320
  const approvedBy = await getUserById(value.approvedBy.id);
24244
24321
  if (!approvedBy || !approvedBy.name)
@@ -24246,9 +24323,100 @@ function usePersonService() {
24246
24323
  value.approvedBy.name = approvedBy.name;
24247
24324
  value.approvedBy.id = approvedBy._id;
24248
24325
  }
24326
+ const vehicle = {
24327
+ plateNumber: person.plateNumber || "",
24328
+ type: "whitelist",
24329
+ category: person.type || "",
24330
+ name: person.name,
24331
+ phoneNumber: person.contact,
24332
+ org: person.org.toString(),
24333
+ site: person.site.toString(),
24334
+ block: person.block,
24335
+ level: person.level,
24336
+ unit: person.unit.toString(),
24337
+ nric: person.nric,
24338
+ status: "active",
24339
+ peopleId: person._id?.toString()
24340
+ };
24341
+ const reviewStatus = value.status;
24342
+ if (reviewStatus === "approved") {
24343
+ value.status = "active";
24344
+ }
24249
24345
  await _reviewResidentPerson(id, value, session);
24346
+ const logoPath = import_path.default.join(
24347
+ __dirname,
24348
+ "public",
24349
+ "images",
24350
+ "seven-365.svg"
24351
+ );
24352
+ const statusIconPath = import_path.default.join(__dirname, "public", "icons");
24353
+ let title = "";
24354
+ let message2 = "";
24355
+ let hideLogin = true;
24356
+ let logo = logoPath;
24357
+ let statusLogo = statusIconPath;
24358
+ if (person.user) {
24359
+ let userStatus = "";
24360
+ switch (reviewStatus) {
24361
+ case "approved":
24362
+ userStatus = "active";
24363
+ if (person.plateNumber && person.plateNumber.trim() !== "") {
24364
+ await addVehicle(vehicle, session);
24365
+ }
24366
+ title = "Your account has been approved";
24367
+ hideLogin = false;
24368
+ statusLogo = `${statusIconPath}/approved-icon.png`;
24369
+ message2 = `Welcome, ${person.name}! Thank you for signing up; we're excited to have you join us!`;
24370
+ break;
24371
+ case "resubmit":
24372
+ userStatus = "resubmit";
24373
+ title = "We request resubmission for your application";
24374
+ hideLogin = false;
24375
+ statusLogo = `${statusIconPath}/resubmission-icon.png`;
24376
+ message2 = `Hi ${person.name}, please resubmit your application with the required updates.`;
24377
+ break;
24378
+ case "rejected":
24379
+ userStatus = "rejected";
24380
+ title = "Your account request for deletion has been rejected.";
24381
+ statusLogo = `${statusIconPath}/deleted-icon.png`;
24382
+ message2 = `Hi ${person.name}, unfortunately your application has been rejected. Please contact support for more information.`;
24383
+ break;
24384
+ default:
24385
+ throw new Error("Invalid review status");
24386
+ }
24387
+ const dir = __dirname;
24388
+ const filePath = (0, import_node_server_utils107.getDirectory)(
24389
+ dir,
24390
+ "./public/handlebars/resident-remarks-email"
24391
+ );
24392
+ const emailContent = (0, import_node_server_utils107.compileHandlebar)({
24393
+ context: {
24394
+ title,
24395
+ message2,
24396
+ hideLogin,
24397
+ logo,
24398
+ statusLogo
24399
+ },
24400
+ filePath
24401
+ });
24402
+ await mailer.sendMail({
24403
+ to: person.email,
24404
+ subject: title,
24405
+ html: emailContent,
24406
+ sender: "iService365"
24407
+ }).catch((error) => {
24408
+ import_node_server_utils107.logger.log({
24409
+ level: "error",
24410
+ message: `Error sending user ${reviewStatus} email: ${error}`
24411
+ });
24412
+ });
24413
+ await _updateUserFieldById(
24414
+ { _id: person.user.toString(), field: "status", value: userStatus },
24415
+ session
24416
+ );
24417
+ }
24250
24418
  await session?.commitTransaction();
24251
- return `Successfully ${value.status} person`;
24419
+ return `Successfully ${reviewStatus} person`;
24252
24420
  } catch (error) {
24253
24421
  await session?.abortTransaction();
24254
24422
  throw error;
@@ -29303,6 +29471,11 @@ var BulletinSort = /* @__PURE__ */ ((BulletinSort2) => {
29303
29471
  BulletinSort2["ID"] = "_id";
29304
29472
  return BulletinSort2;
29305
29473
  })(BulletinSort || {});
29474
+ var BulletinOrder = /* @__PURE__ */ ((BulletinOrder2) => {
29475
+ BulletinOrder2["ASC"] = "asc";
29476
+ BulletinOrder2["DESC"] = "desc";
29477
+ return BulletinOrder2;
29478
+ })(BulletinOrder || {});
29306
29479
  var schemaBulletinBoard = import_joi75.default.object({
29307
29480
  _id: import_joi75.default.string().hex().optional().allow("", null),
29308
29481
  site: import_joi75.default.string().hex().optional().allow("", null),
@@ -29599,12 +29772,13 @@ function useBulletinBoardRepo() {
29599
29772
  }
29600
29773
  async function processExpiredBulletinBoards(session) {
29601
29774
  const today = (/* @__PURE__ */ new Date()).toISOString();
29775
+ const query = {
29776
+ noExpiration: false,
29777
+ endDate: { $lt: today }
29778
+ };
29602
29779
  try {
29603
29780
  const res = await collection.updateMany(
29604
- {
29605
- noExpiration: false,
29606
- endDate: { $lt: today }
29607
- },
29781
+ query,
29608
29782
  {
29609
29783
  $set: {
29610
29784
  status: "expired",
@@ -29762,9 +29936,9 @@ function useBulletinBoardController() {
29762
29936
  page: import_joi76.default.number().integer().min(1).allow("", null).default(1),
29763
29937
  limit: import_joi76.default.number().integer().min(1).max(100).allow("", null).default(10),
29764
29938
  sort: import_joi76.default.string().valid(...Object.values(BulletinSort)).default("_id" /* ID */),
29765
- order: import_joi76.default.string().valid(...Object.values(SortOrder)).default("desc" /* DESC */),
29939
+ order: import_joi76.default.string().valid(...Object.values(BulletinOrder)).default("desc" /* DESC */),
29766
29940
  site: import_joi76.default.string().hex().length(24).required(),
29767
- status: import_joi76.default.string().valid(...Object.values(BuildingStatus)).optional().default("active" /* ACTIVE */),
29941
+ status: import_joi76.default.string().valid(...Object.values(BulletinStatus)).optional().default("active" /* ACTIVE */),
29768
29942
  recipients: import_joi76.default.alternatives().try(
29769
29943
  import_joi76.default.array().items(
29770
29944
  import_joi76.default.string().valid(...Object.values(BulletinRecipient))
@@ -29824,21 +29998,23 @@ function useBulletinBoardController() {
29824
29998
  }
29825
29999
  }
29826
30000
  async function getBulletinBoardById(req, res, next) {
29827
- const validation = import_joi76.default.string().hex().required();
29828
- const _id = req.params.id;
29829
- const { error } = validation.validate(_id);
29830
- if (error) {
29831
- import_node_server_utils137.logger.log({ level: "error", message: error.message });
29832
- next(new import_node_server_utils137.BadRequestError(error.message));
29833
- return;
29834
- }
29835
30001
  try {
30002
+ const schema2 = import_joi76.default.object({
30003
+ _id: import_joi76.default.string().hex().length(24).required()
30004
+ });
30005
+ const { error, value } = schema2.validate({ _id: req.params.id });
30006
+ if (error) {
30007
+ import_node_server_utils137.logger.log({ level: "error", message: error.message });
30008
+ next(new import_node_server_utils137.BadRequestError(error.message));
30009
+ return;
30010
+ }
30011
+ const { _id } = value;
29836
30012
  const data = await _getBulletinBoardById(_id);
29837
30013
  res.status(200).json(data);
29838
30014
  return;
29839
- } catch (error2) {
29840
- import_node_server_utils137.logger.log({ level: "error", message: error2.message });
29841
- next(error2);
30015
+ } catch (error) {
30016
+ import_node_server_utils137.logger.log({ level: "error", message: error.message });
30017
+ next(error);
29842
30018
  return;
29843
30019
  }
29844
30020
  }
@@ -31146,7 +31322,7 @@ var schemaEventManagement = import_joi81.default.object({
31146
31322
  site: import_joi81.default.string().required(),
31147
31323
  title: import_joi81.default.string().required(),
31148
31324
  description: import_joi81.default.string().optional().allow(""),
31149
- dateTime: import_joi81.default.alternatives().try(import_joi81.default.string(), import_joi81.default.date()).required(),
31325
+ dateTime: import_joi81.default.date().iso().required(),
31150
31326
  status: import_joi81.default.string().optional().default("planned"),
31151
31327
  type: import_joi81.default.string().optional().default("TASK")
31152
31328
  });
@@ -31154,7 +31330,7 @@ var schemaUpdateEventManagement = import_joi81.default.object({
31154
31330
  _id: import_joi81.default.string().hex().required(),
31155
31331
  title: import_joi81.default.string().optional().allow(null, ""),
31156
31332
  description: import_joi81.default.string().optional().allow(null, ""),
31157
- dateTime: import_joi81.default.alternatives().try(import_joi81.default.string(), import_joi81.default.date()).optional().allow(null, ""),
31333
+ dateTime: import_joi81.default.date().iso().optional().allow(null, ""),
31158
31334
  status: import_joi81.default.string().optional().allow(null, ""),
31159
31335
  type: import_joi81.default.string().optional().allow(null, "")
31160
31336
  });
@@ -31178,10 +31354,10 @@ function MEventManagement(value) {
31178
31354
  site: value.site,
31179
31355
  title: value.title,
31180
31356
  description: value.description ?? "",
31181
- dateTime: value.dateTime,
31357
+ dateTime: new Date(value.dateTime),
31182
31358
  status: value.status ?? "planned",
31183
31359
  type: value.type ?? "TASK",
31184
- createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
31360
+ createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
31185
31361
  updatedAt: value.updatedAt,
31186
31362
  deletedAt: value.deletedAt
31187
31363
  };
@@ -31282,7 +31458,7 @@ function useEventManagementRepo() {
31282
31458
  ...type && { type }
31283
31459
  };
31284
31460
  if (search) {
31285
- query.$text = { $search: search };
31461
+ query.$or = [{ title: { $regex: search, $options: "i" } }];
31286
31462
  cacheOptions.search = search;
31287
31463
  }
31288
31464
  const cacheKey = (0, import_node_server_utils146.makeCacheKey)(events_namespace_collection, cacheOptions);
@@ -31359,7 +31535,7 @@ function useEventManagementRepo() {
31359
31535
  }
31360
31536
  }
31361
31537
  async function updateEventManagementById(_id, value, session) {
31362
- value.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
31538
+ value.updatedAt = /* @__PURE__ */ new Date();
31363
31539
  try {
31364
31540
  _id = new import_mongodb85.ObjectId(_id);
31365
31541
  } catch (error) {
@@ -31405,8 +31581,7 @@ function useEventManagementRepo() {
31405
31581
  try {
31406
31582
  const updateValue = {
31407
31583
  status: "deleted",
31408
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
31409
- deletedAt: (/* @__PURE__ */ new Date()).toISOString()
31584
+ deletedAt: /* @__PURE__ */ new Date()
31410
31585
  };
31411
31586
  const res = await collection.updateOne({ _id }, { $set: updateValue });
31412
31587
  if (res.modifiedCount === 0) {
@@ -31499,7 +31674,12 @@ function useEventManagementService() {
31499
31674
  const session = import_node_server_utils147.useAtlas.getClient()?.startSession();
31500
31675
  session?.startTransaction();
31501
31676
  try {
31502
- await _updateEventManagementById(id, value, session);
31677
+ const updatedValue = {
31678
+ ...value.dateTime && { dateTime: new Date(value.dateTime) },
31679
+ ...value.title && { title: value.title },
31680
+ ...value.description && { description: value.description }
31681
+ };
31682
+ await _updateEventManagementById(id, updatedValue, session);
31503
31683
  await session?.commitTransaction();
31504
31684
  return "Successfully updated event.";
31505
31685
  } catch (error) {
@@ -32981,7 +33161,7 @@ var import_mongodb90 = require("mongodb");
32981
33161
 
32982
33162
  // src/utils/access-management.ts
32983
33163
  var import_fs3 = __toESM(require("fs"));
32984
- var import_path = __toESM(require("path"));
33164
+ var import_path2 = __toESM(require("path"));
32985
33165
  var import_axios = __toESM(require("axios"));
32986
33166
  var import_xml2js = require("xml2js");
32987
33167
  var import_crypto = __toESM(require("crypto"));
@@ -33011,7 +33191,7 @@ var minifyXml = (xml) => {
33011
33191
  };
33012
33192
  var readTemplate = (name, params) => {
33013
33193
  const template = import_fs3.default.readFileSync(
33014
- import_path.default.join(__dirname, `../src/public/xml-templates/${name}.xml`),
33194
+ import_path2.default.join(__dirname, `../dist/public/xml-templates/${name}.xml`),
33015
33195
  "utf-8"
33016
33196
  );
33017
33197
  if (!params)
@@ -33123,9 +33303,9 @@ var import_xml2js2 = require("xml2js");
33123
33303
  // src/utils/rsa-encryption.ts
33124
33304
  var crypto2 = __toESM(require("crypto"));
33125
33305
  var import_fs4 = __toESM(require("fs"));
33126
- var import_path2 = __toESM(require("path"));
33127
- var pub = import_path2.default.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_pub.pem");
33128
- var priv = import_path2.default.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_priv.pem");
33306
+ var import_path3 = __toESM(require("path"));
33307
+ var pub = import_path3.default.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_pub.pem");
33308
+ var priv = import_path3.default.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_priv.pem");
33129
33309
  var EncryptionCredentials = class {
33130
33310
  };
33131
33311
  EncryptionCredentials.RAW_PUBLIC_KEY = import_fs4.default.readFileSync(pub, "utf8");
@@ -33242,6 +33422,19 @@ function UseAccessManagementRepo() {
33242
33422
  return Promise.reject("Failed to create Access cards indexes.");
33243
33423
  }
33244
33424
  }
33425
+ async function indexCombination() {
33426
+ try {
33427
+ await Promise.all([
33428
+ collection().createIndex({ isWinsland: 1 }),
33429
+ collection().createIndex({ doorName: 1 }),
33430
+ collection().createIndex({ liftName: 1 }),
33431
+ collection().createIndex({ liftName: 1, doorName: 1, isWinsland: 1 })
33432
+ ]);
33433
+ return Promise.resolve("Access cards indexes created.");
33434
+ } catch (error) {
33435
+ return Promise.reject("Failed to create Access cards indexes.");
33436
+ }
33437
+ }
33245
33438
  async function createIndexForEntrypass() {
33246
33439
  try {
33247
33440
  const entrypass = collectionName("entrypass-settings");
@@ -35119,7 +35312,8 @@ function UseAccessManagementRepo() {
35119
35312
  addVisitorAccessCardRepo,
35120
35313
  signQrCodeRepo,
35121
35314
  checkoutVisitorRepo,
35122
- getBlockLevelAndUnitListRepo
35315
+ getBlockLevelAndUnitListRepo,
35316
+ indexCombination
35123
35317
  };
35124
35318
  }
35125
35319
 
@@ -35192,8 +35386,8 @@ function useAccessManagementSvc() {
35192
35386
  const command = readTemplate("door-levels");
35193
35387
  const response = await sendCommand(command, params.acm_url);
35194
35388
  const res = await (0, import_xml2js3.parseStringPromise)(response, { explicitArray: false });
35195
- const format = await formatDoorAccessLevels(res);
35196
- return format;
35389
+ const format2 = await formatDoorAccessLevels(res);
35390
+ return format2;
35197
35391
  } catch (err) {
35198
35392
  throw new Error(err.message);
35199
35393
  }
@@ -35203,8 +35397,8 @@ function useAccessManagementSvc() {
35203
35397
  const command = readTemplate("lift-levels");
35204
35398
  const response = await sendCommand(command, params.acm_url);
35205
35399
  const res = await (0, import_xml2js3.parseStringPromise)(response, { explicitArray: false });
35206
- const format = await formatLiftAccessLevels(res);
35207
- return format;
35400
+ const format2 = await formatLiftAccessLevels(res);
35401
+ return format2;
35208
35402
  } catch (error) {
35209
35403
  throw new Error(error.message);
35210
35404
  }
@@ -35214,8 +35408,8 @@ function useAccessManagementSvc() {
35214
35408
  const command = readTemplate("access-group");
35215
35409
  const response = await sendCommand(command, params.acm_url);
35216
35410
  const res = await (0, import_xml2js3.parseStringPromise)(response, { explicitArray: false });
35217
- const format = await formatAccessGroup(res);
35218
- return format;
35411
+ const format2 = await formatAccessGroup(res);
35412
+ return format2;
35219
35413
  } catch (err) {
35220
35414
  throw new Error(err.message);
35221
35415
  }
@@ -37431,6 +37625,17 @@ function useOccurrenceBookController() {
37431
37625
  // src/models/bulletin-video.model.ts
37432
37626
  var import_mongodb95 = require("mongodb");
37433
37627
  var import_joi90 = __toESM(require("joi"));
37628
+ var BulletinVideoSort = /* @__PURE__ */ ((BulletinVideoSort2) => {
37629
+ BulletinVideoSort2["CREATED_AT"] = "createdAt";
37630
+ BulletinVideoSort2["NAME"] = "name";
37631
+ BulletinVideoSort2["ID"] = "_id";
37632
+ return BulletinVideoSort2;
37633
+ })(BulletinVideoSort || {});
37634
+ var BulletinVideoOrder = /* @__PURE__ */ ((BulletinVideoOrder2) => {
37635
+ BulletinVideoOrder2["ASC"] = "asc";
37636
+ BulletinVideoOrder2["DESC"] = "desc";
37637
+ return BulletinVideoOrder2;
37638
+ })(BulletinVideoOrder || {});
37434
37639
  var schemaBulletinVideo = import_joi90.default.object({
37435
37640
  site: import_joi90.default.string().hex().required(),
37436
37641
  title: import_joi90.default.string().optional().allow(null, ""),
@@ -37494,6 +37699,18 @@ function useBulletinVideoRepo() {
37494
37699
  );
37495
37700
  }
37496
37701
  }
37702
+ async function createTextIndex() {
37703
+ try {
37704
+ await collection.createIndex({
37705
+ title: "text",
37706
+ description: "text"
37707
+ });
37708
+ } catch (error) {
37709
+ throw new import_node_server_utils161.InternalServerError(
37710
+ "Failed to create text index on bulletin videos."
37711
+ );
37712
+ }
37713
+ }
37497
37714
  const namespace_collection = "bulletin-videos";
37498
37715
  const collection = db.collection(namespace_collection);
37499
37716
  const { delNamespace, getCache, setCache } = (0, import_node_server_utils161.useCache)(namespace_collection);
@@ -37533,7 +37750,8 @@ function useBulletinVideoRepo() {
37533
37750
  }
37534
37751
  const query = {
37535
37752
  site,
37536
- status: { $ne: "deleted" }
37753
+ status: { $ne: "deleted" },
37754
+ ...search && { $text: { $search: search } }
37537
37755
  };
37538
37756
  sort = Object.keys(sort).length > 0 ? sort : { _id: -1 };
37539
37757
  const cacheOptions = {
@@ -37541,10 +37759,14 @@ function useBulletinVideoRepo() {
37541
37759
  sort: JSON.stringify(sort),
37542
37760
  page,
37543
37761
  limit,
37544
- status: { $ne: "deleted" }
37762
+ status: { $ne: "deleted" },
37763
+ ...search && { search }
37545
37764
  };
37546
37765
  if (search) {
37547
- query.$text = { $search: search };
37766
+ query.$or = [
37767
+ { title: { $regex: search, $options: "i" } },
37768
+ { description: { $regex: search, $options: "i" } }
37769
+ ];
37548
37770
  cacheOptions.search = search;
37549
37771
  }
37550
37772
  const cacheKey = (0, import_node_server_utils161.makeCacheKey)(namespace_collection, cacheOptions);
@@ -37680,7 +37902,8 @@ function useBulletinVideoRepo() {
37680
37902
  getBulletinVideoById,
37681
37903
  updateBulletinVideoById,
37682
37904
  deleteBulletinVideoById,
37683
- createIndexes
37905
+ createIndexes,
37906
+ createTextIndex
37684
37907
  };
37685
37908
  }
37686
37909
 
@@ -37759,39 +37982,35 @@ function useBulletinVideoController() {
37759
37982
  deleteBulletinVideoById: _deleteBulletinVideoById
37760
37983
  } = useBulletinVideoRepo();
37761
37984
  async function add(req, res, next) {
37762
- const payload = { ...req.body };
37763
- const { error } = schemaBulletinVideo.validate(payload, {
37764
- abortEarly: false
37765
- });
37766
- if (error) {
37767
- const messages = error.details.map((d) => d.message).join(", ");
37768
- import_node_server_utils163.logger.log({ level: "error", message: messages });
37769
- next(new import_node_server_utils163.BadRequestError(messages));
37770
- return;
37771
- }
37772
37985
  try {
37773
- const data = await _add(payload);
37986
+ const { error, value } = schemaBulletinVideo.validate(req.body, {
37987
+ abortEarly: false
37988
+ });
37989
+ if (error) {
37990
+ const messages = error.details.map((d) => d.message).join(", ");
37991
+ import_node_server_utils163.logger.log({ level: "error", message: messages });
37992
+ next(new import_node_server_utils163.BadRequestError(messages));
37993
+ return;
37994
+ }
37995
+ const data = await _add(value);
37774
37996
  res.status(201).json(data);
37775
37997
  return;
37776
- } catch (error2) {
37777
- import_node_server_utils163.logger.log({ level: "error", message: error2.message });
37778
- next(error2);
37998
+ } catch (error) {
37999
+ import_node_server_utils163.logger.log({ level: "error", message: error.message });
38000
+ next(error);
37779
38001
  return;
37780
38002
  }
37781
38003
  }
37782
38004
  async function getAll(req, res, next) {
37783
- const allowedFields = ["createdAt", "name"];
37784
- const allowedOrder = ["asc", "desc"];
37785
38005
  const validation = import_joi91.default.object({
37786
38006
  search: import_joi91.default.string().optional().allow("", null),
37787
38007
  page: import_joi91.default.number().integer().min(1).allow("", null).default(1),
37788
38008
  limit: import_joi91.default.number().integer().min(1).max(100).allow("", null).default(10),
37789
- sort: import_joi91.default.string().pattern(/^([a-zA-Z0-9_]+)(,[a-zA-Z0-9_]+)*$/).optional().allow("", ...allowedFields),
37790
- order: import_joi91.default.string().pattern(/^(asc|desc)(,(asc|desc))*$/).optional().allow("", ...allowedOrder),
37791
- site: import_joi91.default.string().hex().required()
38009
+ sort: import_joi91.default.string().valid(...Object.values(BulletinVideoSort)).default("_id" /* ID */),
38010
+ order: import_joi91.default.string().valid(...Object.values(BulletinVideoOrder)).default("desc" /* DESC */),
38011
+ site: import_joi91.default.string().hex().length(24).required()
37792
38012
  });
37793
- const query = { ...req.query };
37794
- const { error } = validation.validate(query, {
38013
+ const { error, value } = validation.validate(req.query, {
37795
38014
  abortEarly: false
37796
38015
  });
37797
38016
  if (error) {
@@ -37800,19 +38019,10 @@ function useBulletinVideoController() {
37800
38019
  next(new import_node_server_utils163.BadRequestError(messages));
37801
38020
  return;
37802
38021
  }
37803
- const search = req.query.search ?? "";
37804
- const page = parseInt(req.query.page ?? "1");
37805
- const limit = parseInt(req.query.limit ?? "10");
37806
- const site = req.query.site ?? "";
37807
- const sortObj = {};
37808
- const sortFields = String(req.query.sort).split(",");
37809
- const sortOrders = String(req.query.order).split(",");
37810
- sortFields.forEach((field, index) => {
37811
- if (allowedFields.includes(field)) {
37812
- const order = sortOrders[index] === "asc" ? 1 : -1;
37813
- sortObj[field] = order;
37814
- }
37815
- });
38022
+ const { search, page, limit, site, sort, order } = value;
38023
+ const sortObj = {
38024
+ [sort ?? "_id" /* ID */]: order === "asc" /* ASC */ ? 1 : -1
38025
+ };
37816
38026
  try {
37817
38027
  const data = await _getAll({
37818
38028
  search,
@@ -37830,21 +38040,23 @@ function useBulletinVideoController() {
37830
38040
  }
37831
38041
  }
37832
38042
  async function getBulletinVideoById(req, res, next) {
37833
- const validation = import_joi91.default.string().hex().required();
37834
- const _id = req.params.id;
37835
- const { error } = validation.validate(_id);
37836
- if (error) {
37837
- import_node_server_utils163.logger.log({ level: "error", message: error.message });
37838
- next(new import_node_server_utils163.BadRequestError(error.message));
37839
- return;
37840
- }
37841
38043
  try {
38044
+ const schema2 = import_joi91.default.object({
38045
+ _id: import_joi91.default.string().hex().length(24).required()
38046
+ });
38047
+ const { error, value } = schema2.validate({ _id: req.params.id });
38048
+ if (error) {
38049
+ import_node_server_utils163.logger.log({ level: "error", message: error.message });
38050
+ next(new import_node_server_utils163.BadRequestError(error.message));
38051
+ return;
38052
+ }
38053
+ const { _id } = value;
37842
38054
  const data = await _getBulletinVideoById(_id);
37843
38055
  res.status(200).json(data);
37844
38056
  return;
37845
- } catch (error2) {
37846
- import_node_server_utils163.logger.log({ level: "error", message: error2.message });
37847
- next(error2);
38057
+ } catch (error) {
38058
+ import_node_server_utils163.logger.log({ level: "error", message: error.message });
38059
+ next(error);
37848
38060
  return;
37849
38061
  }
37850
38062
  }
@@ -37871,21 +38083,23 @@ function useBulletinVideoController() {
37871
38083
  }
37872
38084
  }
37873
38085
  async function deleteBulletinVideoById(req, res, next) {
37874
- const validation = import_joi91.default.string().hex().required();
37875
- const _id = req.params.id;
37876
- const { error } = validation.validate(_id);
37877
- if (error) {
37878
- import_node_server_utils163.logger.log({ level: "error", message: error.message });
37879
- next(new import_node_server_utils163.BadRequestError(error.message));
37880
- return;
37881
- }
37882
38086
  try {
38087
+ const schema2 = import_joi91.default.object({
38088
+ _id: import_joi91.default.string().hex().length(24).required()
38089
+ });
38090
+ const { error, value } = schema2.validate({ _id: req.params.id });
38091
+ if (error) {
38092
+ import_node_server_utils163.logger.log({ level: "error", message: error.message });
38093
+ next(new import_node_server_utils163.BadRequestError(error.message));
38094
+ return;
38095
+ }
38096
+ const { _id } = value;
37883
38097
  await _deleteBulletinVideoById(_id);
37884
38098
  res.status(200).json({ message: "Successfully deleted bulletin video." });
37885
38099
  return;
37886
- } catch (error2) {
37887
- import_node_server_utils163.logger.log({ level: "error", message: error2.message });
37888
- next(error2);
38100
+ } catch (error) {
38101
+ import_node_server_utils163.logger.log({ level: "error", message: error.message });
38102
+ next(error);
37889
38103
  return;
37890
38104
  }
37891
38105
  }
@@ -44060,11 +44274,11 @@ async function fetchAttendanceData({
44060
44274
  };
44061
44275
  }
44062
44276
  }
44063
- function filterByShiftTime(attendance, shiftData, timezone, format) {
44277
+ function filterByShiftTime(attendance, shiftData, timezone, format2) {
44064
44278
  return attendance.filter((item) => {
44065
44279
  if (!item.checkIn)
44066
44280
  return false;
44067
- const checkInLocal = (0, import_moment_timezone.default)(item.checkIn, format);
44281
+ const checkInLocal = (0, import_moment_timezone.default)(item.checkIn, format2);
44068
44282
  if (!checkInLocal.isValid())
44069
44283
  return false;
44070
44284
  const [startHour, startMinute] = shiftData.checkIn.split(":").map(Number);
@@ -44139,7 +44353,7 @@ function designationCount(attendance, designationConfig, shiftName) {
44139
44353
  }
44140
44354
  return result;
44141
44355
  }
44142
- function totalCountPerShift(attendance, shiftData, timezone, format) {
44356
+ function totalCountPerShift(attendance, shiftData, timezone, format2) {
44143
44357
  let totalCountPerShift3 = [];
44144
44358
  const seen = /* @__PURE__ */ new Set();
44145
44359
  const uniqueAttendanceData = [];
@@ -44162,7 +44376,7 @@ function totalCountPerShift(attendance, shiftData, timezone, format) {
44162
44376
  data = uniqueAttendanceData.filter((item) => {
44163
44377
  if (!item.checkIn)
44164
44378
  return false;
44165
- const checkInLocal = (0, import_moment_timezone.default)(item.checkIn, format);
44379
+ const checkInLocal = (0, import_moment_timezone.default)(item.checkIn, format2);
44166
44380
  if (!checkInLocal.isValid())
44167
44381
  return false;
44168
44382
  const [startHour, startMinute] = shift.checkIn.split(":").map(Number);
@@ -44199,11 +44413,11 @@ function totalCountPerShift(attendance, shiftData, timezone, format) {
44199
44413
  }
44200
44414
  return totalCountPerShift3;
44201
44415
  }
44202
- function filterByStatus(attendance, shiftData, timezone, format, status) {
44416
+ function filterByStatus(attendance, shiftData, timezone, format2, status) {
44203
44417
  return attendance.filter((item) => {
44204
44418
  if (!item.checkIn)
44205
44419
  return false;
44206
- const checkInLocal = (0, import_moment_timezone.default)(item.checkIn, format);
44420
+ const checkInLocal = (0, import_moment_timezone.default)(item.checkIn, format2);
44207
44421
  if (!checkInLocal.isValid())
44208
44422
  return false;
44209
44423
  const [lateHour, lateMinute] = shiftData.lateCheckInAlert.split(":").map(Number);
@@ -44253,7 +44467,7 @@ async function fetchSites({ siteUrl, token }) {
44253
44467
  } while (attempt < maxRetries);
44254
44468
  throw lastError;
44255
44469
  }
44256
- async function totalCountPerStatus(attendance, shiftName, shiftData, timezone, format, totalShifts) {
44470
+ async function totalCountPerStatus(attendance, shiftName, shiftData, timezone, format2, totalShifts) {
44257
44471
  const totalCountPerStatus3 = {
44258
44472
  onTime: 0,
44259
44473
  late: 0,
@@ -44270,7 +44484,7 @@ async function totalCountPerStatus(attendance, shiftName, shiftData, timezone, f
44270
44484
  const shiftStartTime = parseTime(shift.checkIn);
44271
44485
  const shiftEndTime = parseTime(shift.checkOut);
44272
44486
  const lateTime = parseTime(shift.lateCheckInAlert);
44273
- const uniqueAttendanceData = shiftName === "all" ? await filterByShiftTime(attendance, shift, timezone, format) : attendance;
44487
+ const uniqueAttendanceData = shiftName === "all" ? await filterByShiftTime(attendance, shift, timezone, format2) : attendance;
44274
44488
  for (const item of uniqueAttendanceData) {
44275
44489
  const {
44276
44490
  checkIn: checkInStr,
@@ -44279,9 +44493,9 @@ async function totalCountPerStatus(attendance, shiftName, shiftData, timezone, f
44279
44493
  } = item;
44280
44494
  if (!checkInStr || seenGlobal.has(identificationNumber))
44281
44495
  continue;
44282
- const checkIn = (0, import_moment_timezone.default)(checkInStr, format);
44283
- const checkOut = checkOutStr ? (0, import_moment_timezone.default)(checkOutStr, format) : null;
44284
- const checkOutChecker = checkOut ? (0, import_moment_timezone.default)(checkOutStr, format) : checkIn;
44496
+ const checkIn = (0, import_moment_timezone.default)(checkInStr, format2);
44497
+ const checkOut = checkOutStr ? (0, import_moment_timezone.default)(checkOutStr, format2) : null;
44498
+ const checkOutChecker = checkOut ? (0, import_moment_timezone.default)(checkOutStr, format2) : checkIn;
44285
44499
  if (!checkIn.isValid())
44286
44500
  continue;
44287
44501
  const shiftStart = (0, import_moment_timezone.default)(checkIn).set({ ...shiftStartTime, second: 59, millisecond: 59 }).subtract(default_early_checkIn, "hour");
@@ -44317,7 +44531,7 @@ async function totalCountPerStatus(attendance, shiftName, shiftData, timezone, f
44317
44531
  totalCountPerStatus3.totalCount = shiftMap[shiftName];
44318
44532
  return totalCountPerStatus3;
44319
44533
  }
44320
- async function chartCountData(attendance, shiftData, timezone, format, totalShifts, startDateStr, endDateStr, status = "all") {
44534
+ async function chartCountData(attendance, shiftData, timezone, format2, totalShifts, startDateStr, endDateStr, status = "all") {
44321
44535
  const categorizedData = [];
44322
44536
  const seenPerDay = /* @__PURE__ */ new Set();
44323
44537
  const parseTime = (timeStr) => {
@@ -44340,7 +44554,7 @@ async function chartCountData(attendance, shiftData, timezone, format, totalShif
44340
44554
  dailyAttendance,
44341
44555
  shiftData,
44342
44556
  timezone,
44343
- format
44557
+ format2
44344
44558
  );
44345
44559
  if (status === "all" || status === "under" || status === "over") {
44346
44560
  const shifts = [
@@ -44386,7 +44600,7 @@ async function chartCountData(attendance, shiftData, timezone, format, totalShif
44386
44600
  dailyAttendance,
44387
44601
  shift,
44388
44602
  timezone,
44389
- format
44603
+ format2
44390
44604
  );
44391
44605
  for (const item of uniqueAttendanceData) {
44392
44606
  const {
@@ -44396,7 +44610,7 @@ async function chartCountData(attendance, shiftData, timezone, format, totalShif
44396
44610
  } = item;
44397
44611
  if (!checkInStr)
44398
44612
  continue;
44399
- const checkIn = (0, import_moment_timezone.default)(checkInStr, format);
44613
+ const checkIn = (0, import_moment_timezone.default)(checkInStr, format2);
44400
44614
  if (!checkIn.isValid())
44401
44615
  continue;
44402
44616
  const dayKey = `${identificationNumber}-${checkIn.format(
@@ -44405,7 +44619,7 @@ async function chartCountData(attendance, shiftData, timezone, format, totalShif
44405
44619
  if (seenPerDay.has(dayKey))
44406
44620
  continue;
44407
44621
  seenPerDay.add(dayKey);
44408
- const checkOut = checkOutStr ? (0, import_moment_timezone.default)(checkOutStr, format) : checkIn;
44622
+ const checkOut = checkOutStr ? (0, import_moment_timezone.default)(checkOutStr, format2) : checkIn;
44409
44623
  const shiftStart = (0, import_moment_timezone.default)(checkIn).set({ ...shiftStartTime, second: 59, millisecond: 59 }).subtract(default_early_checkIn, "hour");
44410
44624
  const shiftEnd = (0, import_moment_timezone.default)(checkOut).set({ ...shiftEndTime, second: 0, millisecond: 0 }).subtract(default_early_checkIn, "hour");
44411
44625
  const lateCheckIn = (0, import_moment_timezone.default)(checkIn).set({
@@ -50099,9 +50313,12 @@ function useRoleControllerV2() {
50099
50313
  AccessTypeProps,
50100
50314
  AppServiceType,
50101
50315
  BuildingStatus,
50316
+ BulletinOrder,
50102
50317
  BulletinRecipient,
50103
50318
  BulletinSort,
50104
50319
  BulletinStatus,
50320
+ BulletinVideoOrder,
50321
+ BulletinVideoSort,
50105
50322
  CameraType,
50106
50323
  DEVICE_STATUS,
50107
50324
  DOBStatus,