@7365admin1/core 2.49.0 → 2.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.js +230 -52
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +230 -52
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3952,6 +3952,9 @@ function useVerificationRepo() {
|
|
|
3952
3952
|
return Promise.reject(error);
|
|
3953
3953
|
}
|
|
3954
3954
|
}
|
|
3955
|
+
async function findOne(query) {
|
|
3956
|
+
return await collection.findOne(query);
|
|
3957
|
+
}
|
|
3955
3958
|
return {
|
|
3956
3959
|
createIndex,
|
|
3957
3960
|
createTextIndex,
|
|
@@ -3960,7 +3963,8 @@ function useVerificationRepo() {
|
|
|
3960
3963
|
getVerifications,
|
|
3961
3964
|
getByIdByType,
|
|
3962
3965
|
updateStatusById,
|
|
3963
|
-
getByStatus
|
|
3966
|
+
getByStatus,
|
|
3967
|
+
findOne
|
|
3964
3968
|
};
|
|
3965
3969
|
}
|
|
3966
3970
|
|
|
@@ -5297,29 +5301,28 @@ function useVerificationService() {
|
|
|
5297
5301
|
throw error;
|
|
5298
5302
|
}
|
|
5299
5303
|
}
|
|
5300
|
-
async function createSimpleUserInvite({
|
|
5301
|
-
email,
|
|
5302
|
-
metadata
|
|
5303
|
-
}) {
|
|
5304
|
+
async function createSimpleUserInvite({ email, metadata }) {
|
|
5304
5305
|
const type = "user-invite";
|
|
5306
|
+
if (metadata?.org)
|
|
5307
|
+
await getOrgById(metadata.org);
|
|
5308
|
+
if (metadata?.siteId)
|
|
5309
|
+
await getSiteById(metadata.siteId);
|
|
5310
|
+
const existing = await useVerificationRepo().findOne({
|
|
5311
|
+
type,
|
|
5312
|
+
email,
|
|
5313
|
+
"metadata.org": metadata?.org,
|
|
5314
|
+
"metadata.siteId": metadata?.siteId
|
|
5315
|
+
});
|
|
5316
|
+
if (existing)
|
|
5317
|
+
return existing._id;
|
|
5305
5318
|
const value = {
|
|
5306
5319
|
type,
|
|
5307
5320
|
email,
|
|
5308
5321
|
metadata,
|
|
5309
|
-
expireAt: new Date(
|
|
5310
|
-
(/* @__PURE__ */ new Date()).getTime() + 72 * 60 * 60 * 1e3
|
|
5311
|
-
).toISOString(),
|
|
5322
|
+
expireAt: new Date(Date.now() + 72 * 60 * 60 * 1e3).toISOString(),
|
|
5312
5323
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5313
5324
|
};
|
|
5314
|
-
if (value.metadata?.org) {
|
|
5315
|
-
await getOrgById(value.metadata?.org);
|
|
5316
|
-
}
|
|
5317
|
-
if (value.metadata?.siteId) {
|
|
5318
|
-
await getSiteById(value.metadata?.siteId);
|
|
5319
|
-
}
|
|
5320
5325
|
const res = await add(value);
|
|
5321
|
-
const dir = __dirname;
|
|
5322
|
-
const filePath = getDirectory(dir, "./public/handlebars/user-invite");
|
|
5323
5326
|
const link = `${APP_MAIN}/verify/invitation/${res}`;
|
|
5324
5327
|
const emailContent = compileHandlebar({
|
|
5325
5328
|
context: {
|
|
@@ -5327,9 +5330,9 @@ function useVerificationService() {
|
|
|
5327
5330
|
validity: VERIFICATION_USER_INVITE_DURATION,
|
|
5328
5331
|
link
|
|
5329
5332
|
},
|
|
5330
|
-
filePath
|
|
5333
|
+
filePath: getDirectory(__dirname, "./public/handlebars/user-invite")
|
|
5331
5334
|
});
|
|
5332
|
-
mailer.sendMail({
|
|
5335
|
+
await mailer.sendMail({
|
|
5333
5336
|
to: email,
|
|
5334
5337
|
subject: "User Invite",
|
|
5335
5338
|
html: emailContent,
|
|
@@ -7181,7 +7184,7 @@ function useMemberService() {
|
|
|
7181
7184
|
getByRoles
|
|
7182
7185
|
} = useMemberRepo();
|
|
7183
7186
|
const { getById: _getVerificationById, updateStatusById } = useVerificationRepo();
|
|
7184
|
-
const { getUserByEmail, updateDefaultOrgByEmail } = useUserRepo();
|
|
7187
|
+
const { getUserByEmail, updateDefaultOrgByEmail, getUserById } = useUserRepo();
|
|
7185
7188
|
const { getById: getOrgById } = useOrgRepo();
|
|
7186
7189
|
const { getSiteById } = useSiteRepo();
|
|
7187
7190
|
const { getOwnerRolesByTypeOrg } = useRoleRepo();
|
|
@@ -7243,6 +7246,52 @@ function useMemberService() {
|
|
|
7243
7246
|
session?.endSession();
|
|
7244
7247
|
}
|
|
7245
7248
|
}
|
|
7249
|
+
async function createMemberDirect({
|
|
7250
|
+
userId,
|
|
7251
|
+
orgId,
|
|
7252
|
+
roleId,
|
|
7253
|
+
app,
|
|
7254
|
+
siteId,
|
|
7255
|
+
siteName
|
|
7256
|
+
}) {
|
|
7257
|
+
const session = useAtlas15.getClient()?.startSession();
|
|
7258
|
+
session?.startTransaction();
|
|
7259
|
+
try {
|
|
7260
|
+
const org = await getOrgById(orgId);
|
|
7261
|
+
if (!org)
|
|
7262
|
+
throw new BadRequestError29("Organization not found.");
|
|
7263
|
+
const user = await getUserById(userId);
|
|
7264
|
+
if (!user)
|
|
7265
|
+
throw new BadRequestError29("User not found.");
|
|
7266
|
+
const member = await addMember(
|
|
7267
|
+
{
|
|
7268
|
+
org: org._id?.toString() || "",
|
|
7269
|
+
orgName: org.name || "",
|
|
7270
|
+
user: user._id?.toString() || "",
|
|
7271
|
+
name: user?.email,
|
|
7272
|
+
role: roleId,
|
|
7273
|
+
type: app,
|
|
7274
|
+
siteId: siteId ?? "",
|
|
7275
|
+
siteName: siteName ?? ""
|
|
7276
|
+
},
|
|
7277
|
+
session
|
|
7278
|
+
);
|
|
7279
|
+
if (!user.defaultOrg) {
|
|
7280
|
+
await updateDefaultOrgByEmail(
|
|
7281
|
+
user.email,
|
|
7282
|
+
org._id?.toString() || "",
|
|
7283
|
+
session
|
|
7284
|
+
);
|
|
7285
|
+
}
|
|
7286
|
+
await session?.commitTransaction();
|
|
7287
|
+
return { member };
|
|
7288
|
+
} catch (error) {
|
|
7289
|
+
await session?.abortTransaction();
|
|
7290
|
+
throw error;
|
|
7291
|
+
} finally {
|
|
7292
|
+
session?.endSession();
|
|
7293
|
+
}
|
|
7294
|
+
}
|
|
7246
7295
|
async function updateRoleById(id, role, type, org) {
|
|
7247
7296
|
const owner = await getOwnerRolesByTypeOrg(type, org);
|
|
7248
7297
|
if (!owner.length) {
|
|
@@ -7270,6 +7319,7 @@ function useMemberService() {
|
|
|
7270
7319
|
}
|
|
7271
7320
|
return {
|
|
7272
7321
|
createMember,
|
|
7322
|
+
createMemberDirect,
|
|
7273
7323
|
updateRoleById
|
|
7274
7324
|
};
|
|
7275
7325
|
}
|
|
@@ -7284,7 +7334,7 @@ function useMemberController() {
|
|
|
7284
7334
|
updateMemberStatus: _updateMemberStatus,
|
|
7285
7335
|
updateStatusByUserId: _updateStatusByUserId
|
|
7286
7336
|
} = useMemberRepo();
|
|
7287
|
-
const { createMember: _createMember, updateRoleById: _updateRoleById } = useMemberService();
|
|
7337
|
+
const { createMember: _createMember, createMemberDirect: _createMemberDirect, updateRoleById: _updateRoleById } = useMemberService();
|
|
7288
7338
|
async function createMember(req, res, next) {
|
|
7289
7339
|
const validation = Joi15.string().hex().required();
|
|
7290
7340
|
const _id = req.params.id;
|
|
@@ -7473,6 +7523,32 @@ function useMemberController() {
|
|
|
7473
7523
|
return;
|
|
7474
7524
|
}
|
|
7475
7525
|
}
|
|
7526
|
+
async function createMemberDirect(req, res, next) {
|
|
7527
|
+
const validation = Joi15.object({
|
|
7528
|
+
userId: Joi15.string().hex().required(),
|
|
7529
|
+
orgId: Joi15.string().hex().required(),
|
|
7530
|
+
roleId: Joi15.string().hex().required(),
|
|
7531
|
+
app: Joi15.string().required(),
|
|
7532
|
+
siteId: Joi15.string().hex().optional().allow("", null),
|
|
7533
|
+
siteName: Joi15.string().optional().allow("", null)
|
|
7534
|
+
});
|
|
7535
|
+
const { error } = validation.validate(req.body);
|
|
7536
|
+
if (error) {
|
|
7537
|
+
logger21.log({ level: "error", message: error.message });
|
|
7538
|
+
next(new BadRequestError30(error.message));
|
|
7539
|
+
return;
|
|
7540
|
+
}
|
|
7541
|
+
const { userId, orgId, roleId, app, siteId, siteName } = req.body;
|
|
7542
|
+
try {
|
|
7543
|
+
const data = await _createMemberDirect({ userId, orgId, roleId, app, siteId, siteName });
|
|
7544
|
+
res.status(201).json(data);
|
|
7545
|
+
return;
|
|
7546
|
+
} catch (error2) {
|
|
7547
|
+
logger21.log({ level: "error", message: error2.message });
|
|
7548
|
+
next(error2);
|
|
7549
|
+
return;
|
|
7550
|
+
}
|
|
7551
|
+
}
|
|
7476
7552
|
return {
|
|
7477
7553
|
createMember,
|
|
7478
7554
|
getByUserId,
|
|
@@ -7480,7 +7556,8 @@ function useMemberController() {
|
|
|
7480
7556
|
getAll,
|
|
7481
7557
|
getOrgsByMembership,
|
|
7482
7558
|
updateMemberStatus,
|
|
7483
|
-
updateRoleById
|
|
7559
|
+
updateRoleById,
|
|
7560
|
+
createMemberDirect
|
|
7484
7561
|
};
|
|
7485
7562
|
}
|
|
7486
7563
|
|
|
@@ -13831,14 +13908,14 @@ function useVisitorTransactionRepo() {
|
|
|
13831
13908
|
);
|
|
13832
13909
|
}
|
|
13833
13910
|
}
|
|
13834
|
-
async function updateById(_id, value, session) {
|
|
13911
|
+
async function updateById(_id, value, session, isNotManualCheckOut = true) {
|
|
13835
13912
|
try {
|
|
13836
13913
|
_id = new ObjectId40(_id);
|
|
13837
13914
|
} catch (error) {
|
|
13838
13915
|
throw new BadRequestError66("Invalid visitor transaction ID format.");
|
|
13839
13916
|
}
|
|
13840
13917
|
value.updatedAt = /* @__PURE__ */ new Date();
|
|
13841
|
-
if (value.checkOut) {
|
|
13918
|
+
if (value.checkOut && isNotManualCheckOut) {
|
|
13842
13919
|
value.manualCheckout = true;
|
|
13843
13920
|
}
|
|
13844
13921
|
try {
|
|
@@ -14598,6 +14675,22 @@ function useVehicleRepo() {
|
|
|
14598
14675
|
throw error;
|
|
14599
14676
|
}
|
|
14600
14677
|
}
|
|
14678
|
+
async function getSpecificVehicleById(_id) {
|
|
14679
|
+
try {
|
|
14680
|
+
_id = new ObjectId42(_id);
|
|
14681
|
+
} catch (error) {
|
|
14682
|
+
throw new BadRequestError68("Invalid vehicle ID format.");
|
|
14683
|
+
}
|
|
14684
|
+
try {
|
|
14685
|
+
const result = await collection.findOne({ _id });
|
|
14686
|
+
if (!result) {
|
|
14687
|
+
throw new NotFoundError17("Vehicle not found.");
|
|
14688
|
+
}
|
|
14689
|
+
return result;
|
|
14690
|
+
} catch (error) {
|
|
14691
|
+
throw error;
|
|
14692
|
+
}
|
|
14693
|
+
}
|
|
14601
14694
|
async function getByPlaceNumber(value) {
|
|
14602
14695
|
const { error } = Joi38.string().required().validate(value);
|
|
14603
14696
|
if (error) {
|
|
@@ -14856,7 +14949,8 @@ function useVehicleRepo() {
|
|
|
14856
14949
|
deleteExpiredVehicles,
|
|
14857
14950
|
getAllVehiclesByUnitId,
|
|
14858
14951
|
getAllExpiredVehicles,
|
|
14859
|
-
bulkUpsertVehicles
|
|
14952
|
+
bulkUpsertVehicles,
|
|
14953
|
+
getSpecificVehicleById
|
|
14860
14954
|
};
|
|
14861
14955
|
}
|
|
14862
14956
|
|
|
@@ -17136,6 +17230,7 @@ var loggerDahua = winston.createLogger({
|
|
|
17136
17230
|
|
|
17137
17231
|
// src/services/dahua.service.ts
|
|
17138
17232
|
var cameraRegistry = /* @__PURE__ */ new Map();
|
|
17233
|
+
var _savedOnDetected;
|
|
17139
17234
|
function useDahuaDigest({
|
|
17140
17235
|
host = "",
|
|
17141
17236
|
username = "",
|
|
@@ -17200,7 +17295,7 @@ function useDahuaService() {
|
|
|
17200
17295
|
queue.push(buffer);
|
|
17201
17296
|
if (queue.length >= BACKPRESSURE_THRESHOLD && streamRef && !streamRef.isPaused()) {
|
|
17202
17297
|
loggerDahua.warn(
|
|
17203
|
-
`[${site}][${
|
|
17298
|
+
`[${site}][${host}] Queue at ${queue.length}/${MAX_QUEUE_SIZE}, pausing stream`
|
|
17204
17299
|
);
|
|
17205
17300
|
streamRef.pause();
|
|
17206
17301
|
}
|
|
@@ -17217,7 +17312,7 @@ function useDahuaService() {
|
|
|
17217
17312
|
streamRef.resume();
|
|
17218
17313
|
}
|
|
17219
17314
|
loggerDahua.info(
|
|
17220
|
-
`[${site}][${
|
|
17315
|
+
`[${site}][${host}] BufferQueue destroyed. Processed=${processedChunks}, Dropped=${droppedChunks}`
|
|
17221
17316
|
);
|
|
17222
17317
|
}
|
|
17223
17318
|
async function processNext(onDetected2) {
|
|
@@ -17265,9 +17360,9 @@ function useDahuaService() {
|
|
|
17265
17360
|
const transactionId = existingOpenTransaction?._id?.toString() || "";
|
|
17266
17361
|
if (existingOpenTransaction && !existingOpenTransaction.checkOut && transactionId) {
|
|
17267
17362
|
await updateById(transactionId, {
|
|
17268
|
-
checkOut:
|
|
17269
|
-
updatedAt:
|
|
17270
|
-
});
|
|
17363
|
+
checkOut: /* @__PURE__ */ new Date(),
|
|
17364
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
17365
|
+
}, void 0, false);
|
|
17271
17366
|
}
|
|
17272
17367
|
} catch (error) {
|
|
17273
17368
|
loggerDahua.error(
|
|
@@ -17326,7 +17421,7 @@ function useDahuaService() {
|
|
|
17326
17421
|
currentTransactionId = transactionId?.toString();
|
|
17327
17422
|
currentSnapshotField = "snapshotEntryImage";
|
|
17328
17423
|
if (onDetected2) {
|
|
17329
|
-
onDetected2({ _id: transactionId, site: result?.site?.toString(), plateNumber: result.plateNumber });
|
|
17424
|
+
onDetected2({ _id: transactionId, site: result?.site?.toString(), plateNumber: result.plateNumber, host, direction });
|
|
17330
17425
|
}
|
|
17331
17426
|
} catch (error) {
|
|
17332
17427
|
console.log("failed to create visitor transaction", error);
|
|
@@ -17335,8 +17430,7 @@ function useDahuaService() {
|
|
|
17335
17430
|
error
|
|
17336
17431
|
);
|
|
17337
17432
|
}
|
|
17338
|
-
}
|
|
17339
|
-
if (["exit", "both"].includes(designation) && direction.toLowerCase() === "leave" && plateNumber) {
|
|
17433
|
+
} else if (["exit", "both"].includes(designation) && direction.toLowerCase() === "leave" && plateNumber) {
|
|
17340
17434
|
const vehicle = await getVehicleByPlateNumber(plateNumber);
|
|
17341
17435
|
const existingOpenTransaction = await getOpenByPlateNumber(
|
|
17342
17436
|
plateNumber,
|
|
@@ -17358,6 +17452,9 @@ function useDahuaService() {
|
|
|
17358
17452
|
await removePlateNumber(dahuaPayload);
|
|
17359
17453
|
}
|
|
17360
17454
|
await closeOpenTransaction(plateNumber);
|
|
17455
|
+
if (onDetected2) {
|
|
17456
|
+
onDetected2({ reload: true, site: existingOpenTransaction?.site?.toString(), host, direction });
|
|
17457
|
+
}
|
|
17361
17458
|
}
|
|
17362
17459
|
}
|
|
17363
17460
|
}
|
|
@@ -17414,7 +17511,7 @@ function useDahuaService() {
|
|
|
17414
17511
|
try {
|
|
17415
17512
|
await fsAsync.mkdir(dir, { recursive: true });
|
|
17416
17513
|
await fsAsync.writeFile(snapFolder, accumulatedImageBuffer);
|
|
17417
|
-
loggerDahua.
|
|
17514
|
+
loggerDahua.info(`[${host}] Saved image locally: ${filename}`);
|
|
17418
17515
|
const fileId = await _createFile(
|
|
17419
17516
|
{
|
|
17420
17517
|
originalname: filename,
|
|
@@ -17489,9 +17586,12 @@ function useDahuaService() {
|
|
|
17489
17586
|
}
|
|
17490
17587
|
}
|
|
17491
17588
|
async function listenToCamera(camera, onDetected) {
|
|
17589
|
+
if (onDetected) {
|
|
17590
|
+
_savedOnDetected = onDetected;
|
|
17591
|
+
}
|
|
17492
17592
|
if (!camera?._id) {
|
|
17493
17593
|
loggerDahua.error(`Camera _id is required to listen to camera.`);
|
|
17494
|
-
|
|
17594
|
+
return;
|
|
17495
17595
|
}
|
|
17496
17596
|
const cameraId = camera._id.toString();
|
|
17497
17597
|
if (cameraRegistry.has(cameraId)) {
|
|
@@ -17501,6 +17601,11 @@ function useDahuaService() {
|
|
|
17501
17601
|
}
|
|
17502
17602
|
const controller = new AbortController();
|
|
17503
17603
|
cameraRegistry.set(cameraId, controller);
|
|
17604
|
+
const onDetectedHandler = onDetected || _savedOnDetected;
|
|
17605
|
+
if (!onDetectedHandler) {
|
|
17606
|
+
loggerDahua.error(`No plate detection handler registered for camera ${cameraId}`);
|
|
17607
|
+
return;
|
|
17608
|
+
}
|
|
17504
17609
|
getTrafficJunction(
|
|
17505
17610
|
camera.host,
|
|
17506
17611
|
camera.username,
|
|
@@ -17510,7 +17615,7 @@ function useDahuaService() {
|
|
|
17510
17615
|
camera.direction,
|
|
17511
17616
|
cameraId,
|
|
17512
17617
|
controller.signal,
|
|
17513
|
-
|
|
17618
|
+
onDetectedHandler
|
|
17514
17619
|
);
|
|
17515
17620
|
}
|
|
17516
17621
|
async function getTrafficJunctionOld(host = "", username = "", password = "", site = "", gate = "", designation = "", cameraId, signal, onDetected) {
|
|
@@ -17631,9 +17736,12 @@ function useDahuaService() {
|
|
|
17631
17736
|
timeout: 2e4,
|
|
17632
17737
|
streaming: true
|
|
17633
17738
|
});
|
|
17634
|
-
if (
|
|
17739
|
+
if (response.statusCode === 401) {
|
|
17740
|
+
loggerDahua.error(`[${host}] 401 Unauthorized. Potential handshake or wrong credentials.`);
|
|
17741
|
+
continue;
|
|
17742
|
+
} else if ([400, 401, 403, 500].includes(response.statusCode)) {
|
|
17635
17743
|
loggerDahua.error(`[${host}] Connection error: ${response.statusCode}`);
|
|
17636
|
-
|
|
17744
|
+
return;
|
|
17637
17745
|
}
|
|
17638
17746
|
loggerDahua.info(`[${host}] Successfully connected to ANPR.`);
|
|
17639
17747
|
const contentType = response.res.headers["content-type"];
|
|
@@ -17680,16 +17788,31 @@ function useDahuaService() {
|
|
|
17680
17788
|
});
|
|
17681
17789
|
});
|
|
17682
17790
|
} catch (error) {
|
|
17683
|
-
if (signal.aborted)
|
|
17791
|
+
if (signal.aborted || error.name === "AbortError" || error.code === "UND_ERR_ABORTED") {
|
|
17792
|
+
loggerDahua.info(`[${host}] Connection closed by system (Abort).`);
|
|
17684
17793
|
break;
|
|
17794
|
+
}
|
|
17685
17795
|
loggerDahua.error(
|
|
17686
17796
|
`[${host}] Connection lost or error: ${error.message || error}. Retrying in 5s...`
|
|
17687
17797
|
);
|
|
17688
17798
|
} finally {
|
|
17689
|
-
if (bufferQueue?.destroy)
|
|
17690
|
-
|
|
17691
|
-
|
|
17692
|
-
|
|
17799
|
+
if (bufferQueue?.destroy) {
|
|
17800
|
+
try {
|
|
17801
|
+
bufferQueue.destroy();
|
|
17802
|
+
} catch (e) {
|
|
17803
|
+
loggerDahua.error(`[${host}] Error destroying buffer queue:`, e);
|
|
17804
|
+
}
|
|
17805
|
+
}
|
|
17806
|
+
if (response?.res && typeof response.res.destroy === "function" && !response.res.destroyed) {
|
|
17807
|
+
try {
|
|
17808
|
+
response.res.on("error", () => {
|
|
17809
|
+
loggerDahua.error(`[${host}] Stream error during cleanup, likely already closed.`);
|
|
17810
|
+
});
|
|
17811
|
+
response.res.destroy();
|
|
17812
|
+
} catch (err) {
|
|
17813
|
+
loggerDahua.debug(`Cleanup: stream already closing: ${err?.message}`);
|
|
17814
|
+
}
|
|
17815
|
+
}
|
|
17693
17816
|
}
|
|
17694
17817
|
if (!signal.aborted) {
|
|
17695
17818
|
await new Promise((res) => setTimeout(res, 5e3));
|
|
@@ -17905,6 +18028,8 @@ function useSiteCameraRepo() {
|
|
|
17905
18028
|
try {
|
|
17906
18029
|
value = MSiteCamera(value);
|
|
17907
18030
|
const res = await collection.insertOne(value, { session });
|
|
18031
|
+
const { listenToCamera } = useDahuaService();
|
|
18032
|
+
await listenToCamera({ ...value, _id: res.insertedId });
|
|
17908
18033
|
delCachedData();
|
|
17909
18034
|
return res.insertedId;
|
|
17910
18035
|
} catch (error) {
|
|
@@ -19760,7 +19885,8 @@ function useVehicleController() {
|
|
|
19760
19885
|
getVehicles: _getVehicles,
|
|
19761
19886
|
getVehicleById: _getVehicleById,
|
|
19762
19887
|
getVehiclesByNRIC: _getVehiclesByNRIC,
|
|
19763
|
-
getAllVehiclesByUnitId: _getAllVehiclesByUnitId
|
|
19888
|
+
getAllVehiclesByUnitId: _getAllVehiclesByUnitId,
|
|
19889
|
+
getSpecificVehicleById: _getSpecificVehicleById
|
|
19764
19890
|
} = useVehicleRepo();
|
|
19765
19891
|
function normalizeRow(row) {
|
|
19766
19892
|
return Object.fromEntries(
|
|
@@ -19874,7 +20000,9 @@ function useVehicleController() {
|
|
|
19874
20000
|
return;
|
|
19875
20001
|
}
|
|
19876
20002
|
const headerRow = worksheet.getRow(1);
|
|
19877
|
-
const headers = (headerRow.values || []).slice(1).map(
|
|
20003
|
+
const headers = (headerRow.values || []).slice(1).map(
|
|
20004
|
+
(header) => String(header ?? "").trim().replace(/\(.*\)/, "").trim()
|
|
20005
|
+
);
|
|
19878
20006
|
worksheet.eachRow((row, rowNumber) => {
|
|
19879
20007
|
if (rowNumber === 1)
|
|
19880
20008
|
return;
|
|
@@ -19891,7 +20019,11 @@ function useVehicleController() {
|
|
|
19891
20019
|
} else if (lowerName.endsWith(".csv")) {
|
|
19892
20020
|
rows = await new Promise((resolve, reject) => {
|
|
19893
20021
|
const parsed = [];
|
|
19894
|
-
fs.createReadStream(path4).pipe(csv()).on("
|
|
20022
|
+
fs.createReadStream(path4).pipe(csv()).on("headers", (headers) => {
|
|
20023
|
+
headers = headers.map(
|
|
20024
|
+
(h) => h.trim().replace(/\(.*\)/, "").trim()
|
|
20025
|
+
);
|
|
20026
|
+
}).on("data", (row) => parsed.push(row)).on("end", () => resolve(parsed)).on("error", reject);
|
|
19895
20027
|
});
|
|
19896
20028
|
} else {
|
|
19897
20029
|
next(
|
|
@@ -20056,6 +20188,31 @@ function useVehicleController() {
|
|
|
20056
20188
|
return;
|
|
20057
20189
|
}
|
|
20058
20190
|
}
|
|
20191
|
+
async function getSpecificVehicleById(req, res, next) {
|
|
20192
|
+
const schema2 = Joi46.object({
|
|
20193
|
+
_id: Joi46.string().hex().length(24).required()
|
|
20194
|
+
});
|
|
20195
|
+
const { error, value } = schema2.validate(
|
|
20196
|
+
{ _id: req.params.id },
|
|
20197
|
+
{ abortEarly: false }
|
|
20198
|
+
);
|
|
20199
|
+
if (error) {
|
|
20200
|
+
const messages = error.details.map((d) => d.message).join(", ");
|
|
20201
|
+
logger65.log({ level: "error", message: messages });
|
|
20202
|
+
next(new BadRequestError84(messages));
|
|
20203
|
+
return;
|
|
20204
|
+
}
|
|
20205
|
+
const { _id } = value;
|
|
20206
|
+
try {
|
|
20207
|
+
const site = await _getSpecificVehicleById(_id);
|
|
20208
|
+
res.json(site);
|
|
20209
|
+
return;
|
|
20210
|
+
} catch (error2) {
|
|
20211
|
+
logger65.log({ level: "error", message: error2.message });
|
|
20212
|
+
next(error2);
|
|
20213
|
+
return;
|
|
20214
|
+
}
|
|
20215
|
+
}
|
|
20059
20216
|
async function updateVehicleById(req, res, next) {
|
|
20060
20217
|
try {
|
|
20061
20218
|
const schema2 = Joi46.object({
|
|
@@ -20275,7 +20432,8 @@ function useVehicleController() {
|
|
|
20275
20432
|
getVehiclesByNRIC,
|
|
20276
20433
|
reactivateVehicleById,
|
|
20277
20434
|
getAllVehiclesByUnitId,
|
|
20278
|
-
uploadSpreadsheetVehicles
|
|
20435
|
+
uploadSpreadsheetVehicles,
|
|
20436
|
+
getSpecificVehicleById
|
|
20279
20437
|
};
|
|
20280
20438
|
}
|
|
20281
20439
|
|
|
@@ -23421,6 +23579,12 @@ function useVisitorTransactionService() {
|
|
|
23421
23579
|
const parsed = new Date(value.checkOut);
|
|
23422
23580
|
value.checkOut = isNaN(parsed.getTime()) ? null : parsed;
|
|
23423
23581
|
}
|
|
23582
|
+
if (value.site) {
|
|
23583
|
+
value.site = typeof value.site === "string" ? new ObjectId59(value.site) : value.site;
|
|
23584
|
+
}
|
|
23585
|
+
if (value.unit) {
|
|
23586
|
+
value.unit = typeof value.unit === "string" ? new ObjectId59(value.unit) : value.unit;
|
|
23587
|
+
}
|
|
23424
23588
|
await _updateVisitorTansactionById(id, value, session);
|
|
23425
23589
|
await session?.commitTransaction();
|
|
23426
23590
|
return "Successfully updated visitor transaction.";
|
|
@@ -26260,7 +26424,7 @@ function usePatrolRouteRepo() {
|
|
|
26260
26424
|
id: "$_id",
|
|
26261
26425
|
start: startOfDay,
|
|
26262
26426
|
end: endOfDay,
|
|
26263
|
-
site: new ObjectId67(site)
|
|
26427
|
+
site: ObjectId67.isValid(site) ? new ObjectId67(site) : null
|
|
26264
26428
|
},
|
|
26265
26429
|
pipeline: [
|
|
26266
26430
|
{
|
|
@@ -26291,10 +26455,8 @@ function usePatrolRouteRepo() {
|
|
|
26291
26455
|
{ $skip: page * limit },
|
|
26292
26456
|
{ $limit: limit }
|
|
26293
26457
|
];
|
|
26294
|
-
const
|
|
26295
|
-
|
|
26296
|
-
collection.aggregate([{ $match: query }, { $count: "total" }], { session }).toArray()
|
|
26297
|
-
]);
|
|
26458
|
+
const items = await collection.aggregate(basePipeline, { session }).toArray();
|
|
26459
|
+
const countResult = await collection.aggregate([{ $match: query }, { $count: "total" }], { session }).toArray();
|
|
26298
26460
|
const totalCount = countResult[0]?.total || 0;
|
|
26299
26461
|
const data = paginate28(items, page, limit, totalCount);
|
|
26300
26462
|
setCache(cacheKey, data, 15 * 60).then(() => logger90.info(`Cache set for key: ${cacheKey}`)).catch(
|
|
@@ -26302,6 +26464,7 @@ function usePatrolRouteRepo() {
|
|
|
26302
26464
|
);
|
|
26303
26465
|
return data;
|
|
26304
26466
|
} catch (error) {
|
|
26467
|
+
console.error("[getScheduledRoute] ERROR:", error?.message, error?.stack);
|
|
26305
26468
|
throw error;
|
|
26306
26469
|
}
|
|
26307
26470
|
}
|
|
@@ -26588,6 +26751,7 @@ var schemaPatrolLog = Joi65.object({
|
|
|
26588
26751
|
cameras: Joi65.array().items(schemeLogCamera).required(),
|
|
26589
26752
|
status: Joi65.array().items(Joi65.string().valid("complete", "late", "incomplete")).required(),
|
|
26590
26753
|
incidentReport: incidentReportLog,
|
|
26754
|
+
platform: Joi65.string().valid("web", "mobile").optional().allow(null, ""),
|
|
26591
26755
|
createdAt: Joi65.date().optional(),
|
|
26592
26756
|
updatedAt: Joi65.date().optional(),
|
|
26593
26757
|
deletedAt: Joi65.date().optional()
|
|
@@ -26601,7 +26765,8 @@ var schemaUpdatePatrolLog = Joi65.object({
|
|
|
26601
26765
|
end: Joi65.string().optional().allow(null, ""),
|
|
26602
26766
|
cameras: Joi65.array().items(schemeLogCamera).optional().allow(null, ""),
|
|
26603
26767
|
status: Joi65.array().items(Joi65.string().valid("complete", "late", "incomplete")).optional().allow(null, ""),
|
|
26604
|
-
incidentReport: incidentReportLog
|
|
26768
|
+
incidentReport: incidentReportLog,
|
|
26769
|
+
platform: Joi65.string().valid("web", "mobile").optional().allow(null, "")
|
|
26605
26770
|
});
|
|
26606
26771
|
function MPatrolLog(value) {
|
|
26607
26772
|
const { error } = schemaPatrolLog.validate(value);
|
|
@@ -26655,6 +26820,7 @@ function MPatrolLog(value) {
|
|
|
26655
26820
|
status: value.status ?? [],
|
|
26656
26821
|
route: value.route,
|
|
26657
26822
|
incidentReport: value.incidentReport,
|
|
26823
|
+
platForm: value.platform ?? "",
|
|
26658
26824
|
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
26659
26825
|
updatedAt: value.updatedAt ?? "",
|
|
26660
26826
|
deletedAt: value.deletedAt ?? ""
|
|
@@ -27021,6 +27187,7 @@ function usePatrolLogService() {
|
|
|
27021
27187
|
}
|
|
27022
27188
|
}
|
|
27023
27189
|
}
|
|
27190
|
+
value.platform = value.platform === "web" ? "web" : "mobile";
|
|
27024
27191
|
const result = await _add(value, session);
|
|
27025
27192
|
await session.commitTransaction();
|
|
27026
27193
|
return result;
|
|
@@ -41257,6 +41424,7 @@ var schemaIncidentReport = Joi99.object({
|
|
|
41257
41424
|
approvedBy: Joi99.string().hex().allow(null, "").optional(),
|
|
41258
41425
|
approvedByName: Joi99.string().optional().allow("", null),
|
|
41259
41426
|
remarks: Joi99.string().optional().allow("", null),
|
|
41427
|
+
platform: Joi99.string().valid("web", "mobile").optional().allow(null, ""),
|
|
41260
41428
|
status: Joi99.string().valid("pending", "approved", "rejected").default("pending")
|
|
41261
41429
|
});
|
|
41262
41430
|
var schemaUpdateIncidentReport = Joi99.object({
|
|
@@ -41337,6 +41505,7 @@ var schemaUpdateIncidentReport = Joi99.object({
|
|
|
41337
41505
|
approvedBy: Joi99.string().hex().allow(null, "").optional(),
|
|
41338
41506
|
approvedByName: Joi99.string().optional().allow("", null),
|
|
41339
41507
|
remarks: Joi99.string().optional().allow("", null),
|
|
41508
|
+
platform: Joi99.string().valid("web", "mobile").optional().allow(null, ""),
|
|
41340
41509
|
status: Joi99.string().valid("pending", "approved", "rejected").default("pending")
|
|
41341
41510
|
});
|
|
41342
41511
|
function MIncidentReport(value) {
|
|
@@ -41398,6 +41567,7 @@ function MIncidentReport(value) {
|
|
|
41398
41567
|
approvedByName: value.approvedByName ?? "",
|
|
41399
41568
|
remarks: value.remarks ?? null,
|
|
41400
41569
|
status: value.status ?? "pending",
|
|
41570
|
+
platForm: value.platform ?? "",
|
|
41401
41571
|
createdAt: value.createdAt ?? /* @__PURE__ */ new Date(),
|
|
41402
41572
|
updatedAt: value.updatedAt,
|
|
41403
41573
|
deletedAt: value.deletedAt
|
|
@@ -41876,6 +42046,7 @@ function useIncidentReportService() {
|
|
|
41876
42046
|
}
|
|
41877
42047
|
}
|
|
41878
42048
|
}
|
|
42049
|
+
value.platform = value.platform === "web" ? "web" : "mobile";
|
|
41879
42050
|
const result = await _add(value, session);
|
|
41880
42051
|
await session?.commitTransaction();
|
|
41881
42052
|
return result;
|
|
@@ -42969,6 +43140,11 @@ function useOccurrenceEntryService() {
|
|
|
42969
43140
|
if (!occurrenceEntry) {
|
|
42970
43141
|
throw new Error("Occurrence entry not found.");
|
|
42971
43142
|
}
|
|
43143
|
+
if (value.incidentReportId) {
|
|
43144
|
+
await _updateOccurrenceEntryById(id, value, session);
|
|
43145
|
+
await session?.commitTransaction();
|
|
43146
|
+
return "Successfully updated occurrence entry (incident report).";
|
|
43147
|
+
}
|
|
42972
43148
|
const entryCount = await _getLatestSerialNumberInGroup(
|
|
42973
43149
|
occurrenceEntry.dailyOccurrenceBookId,
|
|
42974
43150
|
Number(occurrenceEntry.serialNumber)
|
|
@@ -43001,6 +43177,8 @@ function useOccurrenceEntryService() {
|
|
|
43001
43177
|
value.date = value.date ? value.date : occurrenceEntry.date;
|
|
43002
43178
|
value.userName = value.userName ? value.userName : occurrenceEntry.signature.name;
|
|
43003
43179
|
value.createdByName = value.createdByName ? value.createdByName : occurrenceEntry.createdByName;
|
|
43180
|
+
if (occurrenceEntry.incidentReportId)
|
|
43181
|
+
value.incidentReportId = occurrenceEntry.incidentReportId;
|
|
43004
43182
|
await _updateOccurrenceBookById(dobId, {
|
|
43005
43183
|
totalInput: book.totalInput + 1
|
|
43006
43184
|
});
|