@7365admin1/core 3.38.0 → 3.40.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 +9 -4
- package/dist/index.js +247 -105
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +247 -105
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -23061,6 +23061,7 @@ function useVehicleRepo() {
|
|
|
23061
23061
|
if (error) {
|
|
23062
23062
|
throw new BadRequestError69(error.details[0].message);
|
|
23063
23063
|
}
|
|
23064
|
+
console.log("getVehicleByPlateNumber plateNumber", plateNumber);
|
|
23064
23065
|
try {
|
|
23065
23066
|
const data = await collection.findOne(
|
|
23066
23067
|
{ plateNumber, status: "active" },
|
|
@@ -23073,6 +23074,14 @@ function useVehicleRepo() {
|
|
|
23073
23074
|
);
|
|
23074
23075
|
}
|
|
23075
23076
|
}
|
|
23077
|
+
async function findOne(query) {
|
|
23078
|
+
try {
|
|
23079
|
+
const data = await collection.findOne(query);
|
|
23080
|
+
return data;
|
|
23081
|
+
} catch (error) {
|
|
23082
|
+
throw new InternalServerError25("Failed to fetch findOne vehicle." + error);
|
|
23083
|
+
}
|
|
23084
|
+
}
|
|
23076
23085
|
async function getVehicleBySiteAndPlateNumber(plateNumber, site, category, status) {
|
|
23077
23086
|
const { error } = Joi39.string().required().validate(plateNumber);
|
|
23078
23087
|
if (error) {
|
|
@@ -23381,7 +23390,8 @@ function useVehicleRepo() {
|
|
|
23381
23390
|
getSpecificVehicleById,
|
|
23382
23391
|
getBlocklistedVehicles,
|
|
23383
23392
|
getVehicleBySiteAndPlateNumber,
|
|
23384
|
-
getBlocklistedVehicleByPlateNumber
|
|
23393
|
+
getBlocklistedVehicleByPlateNumber,
|
|
23394
|
+
findOne
|
|
23385
23395
|
};
|
|
23386
23396
|
}
|
|
23387
23397
|
|
|
@@ -23460,12 +23470,13 @@ async function useDahuaDigestWithRetry({
|
|
|
23460
23470
|
headers = {},
|
|
23461
23471
|
timeout = 1e4,
|
|
23462
23472
|
streaming = false,
|
|
23463
|
-
retries =
|
|
23473
|
+
retries = 10,
|
|
23464
23474
|
retryDelayMs = 0
|
|
23465
23475
|
}) {
|
|
23466
23476
|
let lastError;
|
|
23467
23477
|
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
23468
23478
|
try {
|
|
23479
|
+
const effectiveTimeout = streaming ? 0 : timeout;
|
|
23469
23480
|
const response = await useDahuaDigest({
|
|
23470
23481
|
host,
|
|
23471
23482
|
username,
|
|
@@ -23473,16 +23484,23 @@ async function useDahuaDigestWithRetry({
|
|
|
23473
23484
|
endpoint,
|
|
23474
23485
|
method,
|
|
23475
23486
|
headers,
|
|
23476
|
-
timeout,
|
|
23487
|
+
timeout: effectiveTimeout,
|
|
23477
23488
|
streaming
|
|
23478
23489
|
});
|
|
23479
|
-
const text = getDahuaResponseText(response);
|
|
23480
23490
|
const statusCode = getDahuaStatusCode(response);
|
|
23481
|
-
|
|
23482
|
-
|
|
23483
|
-
|
|
23491
|
+
if (streaming) {
|
|
23492
|
+
if (statusCode === 200) {
|
|
23493
|
+
return response;
|
|
23494
|
+
}
|
|
23495
|
+
} else {
|
|
23496
|
+
const text = getDahuaResponseText(response);
|
|
23497
|
+
const isOk = statusCode === 200 && text.includes("OK");
|
|
23498
|
+
if (isOk) {
|
|
23499
|
+
return response;
|
|
23500
|
+
}
|
|
23484
23501
|
}
|
|
23485
|
-
const
|
|
23502
|
+
const errorText = streaming ? `HTTP ${statusCode}` : getDahuaResponseText(response);
|
|
23503
|
+
const shouldRetry = isDahuaInvalidAuthority(errorText);
|
|
23486
23504
|
if (shouldRetry && attempt < retries) {
|
|
23487
23505
|
loggerDahua.warn(
|
|
23488
23506
|
`[${host}] Dahua Invalid Authority. Retrying ${attempt}/${retries}`
|
|
@@ -23492,7 +23510,7 @@ async function useDahuaDigestWithRetry({
|
|
|
23492
23510
|
}
|
|
23493
23511
|
continue;
|
|
23494
23512
|
}
|
|
23495
|
-
throw new Error(`Dahua response: ${
|
|
23513
|
+
throw new Error(`Dahua response: ${errorText || `HTTP ${statusCode}`}`);
|
|
23496
23514
|
} catch (error) {
|
|
23497
23515
|
lastError = error;
|
|
23498
23516
|
const message = error?.message || String(error);
|
|
@@ -23875,6 +23893,7 @@ function useDahuaService() {
|
|
|
23875
23893
|
if (camera.status !== "active") {
|
|
23876
23894
|
if (cameraRegistry.has(cameraId)) {
|
|
23877
23895
|
loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] Camera is ${camera.status}. Stopping connection.`);
|
|
23896
|
+
console.log(`[${camera?.siteName}-${camera?.direction}] Camera is ${camera.status}. Stopping connection.`);
|
|
23878
23897
|
cameraRegistry.get(cameraId)?.abort();
|
|
23879
23898
|
cameraRegistry.delete(cameraId);
|
|
23880
23899
|
}
|
|
@@ -23882,6 +23901,7 @@ function useDahuaService() {
|
|
|
23882
23901
|
}
|
|
23883
23902
|
if (cameraRegistry.has(cameraId)) {
|
|
23884
23903
|
loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] Stopping existing connection for update.`);
|
|
23904
|
+
console.log(`[${camera?.siteName}-${camera?.direction}] Stopping existing connection for update.`);
|
|
23885
23905
|
cameraRegistry.get(cameraId)?.abort();
|
|
23886
23906
|
cameraRegistry.delete(cameraId);
|
|
23887
23907
|
}
|
|
@@ -23901,11 +23921,14 @@ function useDahuaService() {
|
|
|
23901
23921
|
}
|
|
23902
23922
|
async function getTrafficJunction(camera, signal, onDetected) {
|
|
23903
23923
|
console.log(`getTrafficJunction camera object`, camera);
|
|
23924
|
+
let authFailureCount = 0;
|
|
23925
|
+
const MAX_AUTH_RETRIES = 10;
|
|
23904
23926
|
while (!signal.aborted) {
|
|
23905
23927
|
let bufferQueue = null;
|
|
23906
23928
|
let response = null;
|
|
23929
|
+
let isAuthFailure = false;
|
|
23907
23930
|
try {
|
|
23908
|
-
response = await
|
|
23931
|
+
response = await useDahuaDigestWithRetry({
|
|
23909
23932
|
host: camera?.host,
|
|
23910
23933
|
username: camera?.username,
|
|
23911
23934
|
password: camera?.password,
|
|
@@ -23913,16 +23936,32 @@ function useDahuaService() {
|
|
|
23913
23936
|
timeout: 2e4,
|
|
23914
23937
|
streaming: true
|
|
23915
23938
|
});
|
|
23916
|
-
|
|
23917
|
-
|
|
23918
|
-
|
|
23919
|
-
|
|
23920
|
-
|
|
23939
|
+
const statusCode = getDahuaStatusCode(response);
|
|
23940
|
+
if (statusCode === 401) {
|
|
23941
|
+
loggerDahua.error(`[${camera?.siteName}-${camera?.direction}] 401 Unauthorized - Handshake or Wrong Credentials`);
|
|
23942
|
+
console.log(`[${camera?.siteName}-${camera?.direction}] 401 Unauthorized - Handshake or Wrong Credentials`);
|
|
23943
|
+
throw new Error("401 Unauthorized - Handshake or Wrong Credentials");
|
|
23944
|
+
} else if (statusCode === 403) {
|
|
23945
|
+
loggerDahua.error(
|
|
23946
|
+
`[${camera?.siteName}-${camera?.direction}] 403 Forbidden. Account locked or invalid permissions.`
|
|
23947
|
+
);
|
|
23921
23948
|
if (onDetected) {
|
|
23922
|
-
onDetected({
|
|
23949
|
+
onDetected({
|
|
23950
|
+
site: camera?.site,
|
|
23951
|
+
direction: camera?.direction,
|
|
23952
|
+
messagePermanent: `Camera [${camera?.siteName}-${camera?.direction}]. Connection Error. Check username and password and try after 10 minutes.`
|
|
23953
|
+
});
|
|
23954
|
+
}
|
|
23955
|
+
return;
|
|
23956
|
+
} else if ([400, 500].includes(statusCode)) {
|
|
23957
|
+
loggerDahua.error(`[${camera?.siteName}-${camera?.direction}] Connection error: ${statusCode}`);
|
|
23958
|
+
if (onDetected) {
|
|
23959
|
+
onDetected({ site: camera?.site, messagePermanent: `Camera [${camera?.siteName}-${camera?.direction}]. Connection Error. Possible Not Authorized.` });
|
|
23923
23960
|
}
|
|
23924
23961
|
return;
|
|
23925
23962
|
}
|
|
23963
|
+
authFailureCount = 0;
|
|
23964
|
+
isAuthFailure = false;
|
|
23926
23965
|
loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] Successfully connected to ANPR.`);
|
|
23927
23966
|
const contentType = response.res.headers["content-type"];
|
|
23928
23967
|
const boundaryMatch = contentType?.match(/boundary=(.*)$/i);
|
|
@@ -23967,15 +24006,53 @@ function useDahuaService() {
|
|
|
23967
24006
|
loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] Connection closed by system (Abort).`);
|
|
23968
24007
|
break;
|
|
23969
24008
|
}
|
|
23970
|
-
|
|
23971
|
-
|
|
23972
|
-
|
|
23973
|
-
|
|
23974
|
-
|
|
23975
|
-
|
|
23976
|
-
|
|
23977
|
-
|
|
23978
|
-
|
|
24009
|
+
const errMsg = String(error?.message || error);
|
|
24010
|
+
if (errMsg.includes("403") || errMsg.includes("Forbidden")) {
|
|
24011
|
+
loggerDahua.error(
|
|
24012
|
+
`[${camera?.siteName}-${camera?.direction}] 403 Forbidden thrown by Dahua client. Account locked or invalid credentials.`
|
|
24013
|
+
);
|
|
24014
|
+
if (onDetected) {
|
|
24015
|
+
onDetected({
|
|
24016
|
+
site: camera?.site,
|
|
24017
|
+
direction: camera?.direction,
|
|
24018
|
+
messagePermanent: `Camera [${camera?.siteName}-${camera?.direction}]. Connection Error. Check username and password and try after 10 minutes.`
|
|
24019
|
+
});
|
|
24020
|
+
}
|
|
24021
|
+
return;
|
|
24022
|
+
}
|
|
24023
|
+
const isAuthError = errMsg.includes("401") || errMsg.includes("Unauthorized") || errMsg.includes("Invalid Authority");
|
|
24024
|
+
if (isAuthError) {
|
|
24025
|
+
authFailureCount++;
|
|
24026
|
+
isAuthFailure = true;
|
|
24027
|
+
loggerDahua.warn(
|
|
24028
|
+
`[${camera?.siteName}-${camera?.direction}] Auth attempt ${authFailureCount}/${MAX_AUTH_RETRIES}`
|
|
24029
|
+
);
|
|
24030
|
+
if (authFailureCount >= MAX_AUTH_RETRIES) {
|
|
24031
|
+
loggerDahua.error(
|
|
24032
|
+
`[${camera?.siteName}-${camera?.direction}] Max auth failures reached (${MAX_AUTH_RETRIES}). Wrong credentials.`
|
|
24033
|
+
);
|
|
24034
|
+
if (onDetected) {
|
|
24035
|
+
onDetected({
|
|
24036
|
+
site: camera?.site,
|
|
24037
|
+
direction: camera?.direction,
|
|
24038
|
+
messagePermanent: `Camera [${camera?.siteName}-${camera?.direction}]. Connection Error. Check username and password.`
|
|
24039
|
+
});
|
|
24040
|
+
}
|
|
24041
|
+
return;
|
|
24042
|
+
}
|
|
24043
|
+
} else {
|
|
24044
|
+
authFailureCount = 0;
|
|
24045
|
+
isAuthFailure = false;
|
|
24046
|
+
loggerDahua.error(
|
|
24047
|
+
`[${camera?.siteName}-${camera?.direction}] Connection lost or error: ${error.message || error}. Retrying in 10 seconds...`
|
|
24048
|
+
);
|
|
24049
|
+
if (onDetected) {
|
|
24050
|
+
onDetected({
|
|
24051
|
+
site: camera?.site,
|
|
24052
|
+
direction: camera?.direction,
|
|
24053
|
+
message: `Camera in [${camera?.siteName}-${camera?.direction}] Connection Lost. Retrying in 10 seconds. Check the camera if this issue persists, Or set the camera to Inactive to stop this notification.`
|
|
24054
|
+
});
|
|
24055
|
+
}
|
|
23979
24056
|
}
|
|
23980
24057
|
} finally {
|
|
23981
24058
|
if (bufferQueue?.destroy) {
|
|
@@ -23997,7 +24074,8 @@ function useDahuaService() {
|
|
|
23997
24074
|
}
|
|
23998
24075
|
}
|
|
23999
24076
|
if (!signal.aborted) {
|
|
24000
|
-
|
|
24077
|
+
const waitMs = isAuthFailure ? 1e3 : 1e4;
|
|
24078
|
+
await new Promise((res) => setTimeout(res, waitMs));
|
|
24001
24079
|
}
|
|
24002
24080
|
}
|
|
24003
24081
|
loggerDahua.info(`[${camera?.siteName}-${camera?.direction}] ANPR Listener stopped.`);
|
|
@@ -24668,7 +24746,8 @@ function useSiteCameraRepo() {
|
|
|
24668
24746
|
throw new BadRequestError71("Site camera not found.");
|
|
24669
24747
|
}
|
|
24670
24748
|
if (result?._id) {
|
|
24671
|
-
const result2 = await findOne({ _id: new ObjectId44(result._id) });
|
|
24749
|
+
const result2 = await findOne({ _id: new ObjectId44(result._id) }, void 0, { session });
|
|
24750
|
+
console.log("updateById result2", result2);
|
|
24672
24751
|
if (result2?._id) {
|
|
24673
24752
|
const { listenToCamera } = useDahuaService();
|
|
24674
24753
|
await listenToCamera(result2);
|
|
@@ -24733,6 +24812,9 @@ function useSiteCameraRepo() {
|
|
|
24733
24812
|
throw new BadRequestError71("Invalid site ID format");
|
|
24734
24813
|
}
|
|
24735
24814
|
}
|
|
24815
|
+
if (value.status) {
|
|
24816
|
+
query.status = value.status;
|
|
24817
|
+
}
|
|
24736
24818
|
try {
|
|
24737
24819
|
const items = await collection.aggregate([
|
|
24738
24820
|
{
|
|
@@ -24803,7 +24885,7 @@ function useSiteCameraRepo() {
|
|
|
24803
24885
|
throw new BadRequestError71("Failed to retrieve site cameras.");
|
|
24804
24886
|
}
|
|
24805
24887
|
}
|
|
24806
|
-
async function findOne(query, project = {}) {
|
|
24888
|
+
async function findOne(query, project = {}, options = {}) {
|
|
24807
24889
|
try {
|
|
24808
24890
|
const pipeline = [
|
|
24809
24891
|
{ $match: query },
|
|
@@ -24852,14 +24934,14 @@ function useSiteCameraRepo() {
|
|
|
24852
24934
|
if (Object.keys(project).length > 0) {
|
|
24853
24935
|
pipeline.push({ $project: project });
|
|
24854
24936
|
}
|
|
24855
|
-
const result = await collection.aggregate(pipeline).toArray();
|
|
24937
|
+
const result = await collection.aggregate(pipeline, options).toArray();
|
|
24856
24938
|
return result.length > 0 ? result[0] : null;
|
|
24857
24939
|
} catch (error) {
|
|
24858
24940
|
console.error("Error in findOne aggregation:", error);
|
|
24859
24941
|
throw error;
|
|
24860
24942
|
}
|
|
24861
24943
|
}
|
|
24862
|
-
async function findMany(query, project = {}) {
|
|
24944
|
+
async function findMany(query, project = {}, options = {}) {
|
|
24863
24945
|
try {
|
|
24864
24946
|
const pipeline = [
|
|
24865
24947
|
{ $match: query },
|
|
@@ -24908,10 +24990,10 @@ function useSiteCameraRepo() {
|
|
|
24908
24990
|
if (Object.keys(project).length > 0) {
|
|
24909
24991
|
pipeline.push({ $project: project });
|
|
24910
24992
|
}
|
|
24911
|
-
const result = await collection.aggregate(pipeline).toArray();
|
|
24993
|
+
const result = await collection.aggregate(pipeline, options).toArray();
|
|
24912
24994
|
return result.length > 0 ? result : [];
|
|
24913
24995
|
} catch (error) {
|
|
24914
|
-
console.error("Error in
|
|
24996
|
+
console.error("Error in findMany aggregation:", error);
|
|
24915
24997
|
throw error;
|
|
24916
24998
|
}
|
|
24917
24999
|
}
|
|
@@ -24928,7 +25010,9 @@ function useSiteCameraRepo() {
|
|
|
24928
25010
|
getBySiteGuardPost,
|
|
24929
25011
|
updateById,
|
|
24930
25012
|
deleteById,
|
|
24931
|
-
getAllCameraWithPassword
|
|
25013
|
+
getAllCameraWithPassword,
|
|
25014
|
+
findMany,
|
|
25015
|
+
findOne
|
|
24932
25016
|
};
|
|
24933
25017
|
}
|
|
24934
25018
|
|
|
@@ -25060,9 +25144,9 @@ function usePersonRepo() {
|
|
|
25060
25144
|
{ email: { $regex: search, $options: "i" } },
|
|
25061
25145
|
{ nric: { $regex: search, $options: "i" } },
|
|
25062
25146
|
{ "plates.plateNumber": { $regex: search, $options: "i" } },
|
|
25063
|
-
{ contact: { $regex: makeContainsRegex(
|
|
25064
|
-
{ contacts: { $regex: makeContainsRegex(
|
|
25065
|
-
{ plateNumbers: { $regex: makeContainsRegex(
|
|
25147
|
+
{ contact: { $regex: makeContainsRegex(search) } },
|
|
25148
|
+
{ contacts: { $regex: makeContainsRegex(search) } },
|
|
25149
|
+
{ plateNumbers: { $regex: makeContainsRegex(search) } }
|
|
25066
25150
|
]
|
|
25067
25151
|
},
|
|
25068
25152
|
...ObjectId45.isValid(org) && { org: new ObjectId45(org) },
|
|
@@ -26865,7 +26949,8 @@ function useVehicleService() {
|
|
|
26865
26949
|
deleteExpiredVehicles: _deleteExpiredVehicles,
|
|
26866
26950
|
getVehicleByPlateNumber: _getVehicleByPlateNumber,
|
|
26867
26951
|
getAllExpiredVehicles: _getAllExpiredVehicles,
|
|
26868
|
-
bulkUpsertVehicles: _bulkUpsertVehicles
|
|
26952
|
+
bulkUpsertVehicles: _bulkUpsertVehicles,
|
|
26953
|
+
findOne
|
|
26869
26954
|
} = useVehicleRepo();
|
|
26870
26955
|
const {
|
|
26871
26956
|
addPlateNumber: _addPlateNumber,
|
|
@@ -26889,15 +26974,18 @@ function useVehicleService() {
|
|
|
26889
26974
|
throw new Error("Unable to start session for vehicle service.");
|
|
26890
26975
|
}
|
|
26891
26976
|
}
|
|
26977
|
+
console.log("add vehicle service value.plateNumber", value.plateNumber);
|
|
26892
26978
|
const [_vehiclePlateNumber] = value.plateNumber;
|
|
26893
|
-
|
|
26894
|
-
|
|
26979
|
+
console.log("add vehicle service plateNumber", _vehiclePlateNumber);
|
|
26980
|
+
const [
|
|
26981
|
+
// existingPlateNumber,
|
|
26982
|
+
org
|
|
26983
|
+
] = await Promise.all([
|
|
26984
|
+
// _getVehicleByPlateNumber(_vehiclePlateNumber),
|
|
26895
26985
|
_getById(value.org)
|
|
26896
26986
|
]);
|
|
26897
26987
|
if (!org)
|
|
26898
26988
|
throw new BadRequestError75("Org not found");
|
|
26899
|
-
if (existingPlateNumber)
|
|
26900
|
-
throw new BadRequestError75("Vehicle plate number already exists");
|
|
26901
26989
|
if (!Object.values(OrgNature).includes(org.nature)) {
|
|
26902
26990
|
throw new BadRequestError75(
|
|
26903
26991
|
"This organization is not allowed to add vehicles."
|
|
@@ -26910,7 +26998,6 @@ function useVehicleService() {
|
|
|
26910
26998
|
user,
|
|
26911
26999
|
org: value.org
|
|
26912
27000
|
});
|
|
26913
|
-
console.log("userPermissions vehicle.service.ts", userPermissions);
|
|
26914
27001
|
const hasSecurityBypass = addedBySecurity && Array.isArray(userPermissions) && (userPermissions.includes("*") || userPermissions.includes("vehicleManagement:approve-vehicle"));
|
|
26915
27002
|
if (hasSecurityBypass) {
|
|
26916
27003
|
addedByPM = true;
|
|
@@ -26969,17 +27056,16 @@ function useVehicleService() {
|
|
|
26969
27056
|
const siteCameraReq = await _getAllSiteCameras({
|
|
26970
27057
|
site: value.site,
|
|
26971
27058
|
type: "anpr",
|
|
26972
|
-
direction: ["both", "entry"],
|
|
27059
|
+
direction: ["both", "entry", "residents"],
|
|
26973
27060
|
page,
|
|
26974
|
-
limit
|
|
27061
|
+
limit,
|
|
27062
|
+
status: "active"
|
|
26975
27063
|
});
|
|
26976
27064
|
pages = siteCameraReq.pages || 1;
|
|
26977
27065
|
siteCameras.push(...siteCameraReq.items);
|
|
26978
27066
|
page++;
|
|
26979
27067
|
} while (page <= pages);
|
|
26980
|
-
|
|
26981
|
-
throw new BadRequestError75("No site cameras found.");
|
|
26982
|
-
}
|
|
27068
|
+
console.log("add vehicle service siteCameras", siteCameras);
|
|
26983
27069
|
}
|
|
26984
27070
|
for (const plateNumber of plateNumbers) {
|
|
26985
27071
|
const vehicleValue = {
|
|
@@ -31633,6 +31719,7 @@ function useSiteCameraService() {
|
|
|
31633
31719
|
const { add: _add, getAllCameraWithPassword: _getAllCameraWithPassword } = useSiteCameraRepo();
|
|
31634
31720
|
const { updateById: _updateById } = useSiteRepo();
|
|
31635
31721
|
const dahuaService = useDahuaService();
|
|
31722
|
+
const { updateById: _siteCameraUpdateById } = useSiteCameraRepo();
|
|
31636
31723
|
let cleanupTask = null;
|
|
31637
31724
|
async function add(value) {
|
|
31638
31725
|
const { error } = schemaSiteCamera.validate(value);
|
|
@@ -31666,6 +31753,7 @@ function useSiteCameraService() {
|
|
|
31666
31753
|
type: "anpr",
|
|
31667
31754
|
page,
|
|
31668
31755
|
limit
|
|
31756
|
+
// site: "6923d6664150ca6a69b9f2b2"
|
|
31669
31757
|
});
|
|
31670
31758
|
pages = siteCameraReq.pages || 1;
|
|
31671
31759
|
siteCameras.push(...siteCameraReq.items);
|
|
@@ -31681,9 +31769,27 @@ function useSiteCameraService() {
|
|
|
31681
31769
|
}
|
|
31682
31770
|
}
|
|
31683
31771
|
}
|
|
31772
|
+
async function updateById(id, value) {
|
|
31773
|
+
const session = useAtlas43.getClient()?.startSession();
|
|
31774
|
+
if (!session) {
|
|
31775
|
+
throw new Error("Unable to start session for site camera service.");
|
|
31776
|
+
}
|
|
31777
|
+
try {
|
|
31778
|
+
session.startTransaction();
|
|
31779
|
+
const result = await _siteCameraUpdateById(id, value, session);
|
|
31780
|
+
await session.commitTransaction();
|
|
31781
|
+
return result;
|
|
31782
|
+
} catch (error) {
|
|
31783
|
+
await session.abortTransaction();
|
|
31784
|
+
throw error;
|
|
31785
|
+
} finally {
|
|
31786
|
+
session.endSession();
|
|
31787
|
+
}
|
|
31788
|
+
}
|
|
31684
31789
|
return {
|
|
31685
31790
|
add,
|
|
31686
|
-
listenToCapturedPlateNumber
|
|
31791
|
+
listenToCapturedPlateNumber,
|
|
31792
|
+
updateById
|
|
31687
31793
|
};
|
|
31688
31794
|
}
|
|
31689
31795
|
|
|
@@ -31691,10 +31797,9 @@ function useSiteCameraService() {
|
|
|
31691
31797
|
import { BadRequestError as BadRequestError89 } from "@7365admin1/node-server-utils";
|
|
31692
31798
|
import Joi49 from "joi";
|
|
31693
31799
|
function useSiteCameraController() {
|
|
31694
|
-
const { add: _add } = useSiteCameraService();
|
|
31800
|
+
const { add: _add, updateById: _updateById } = useSiteCameraService();
|
|
31695
31801
|
const {
|
|
31696
31802
|
getAll: _getAll,
|
|
31697
|
-
updateById: _updateById,
|
|
31698
31803
|
deleteById: _deleteById
|
|
31699
31804
|
} = useSiteCameraRepo();
|
|
31700
31805
|
async function add(req, res, next) {
|
|
@@ -32983,7 +33088,7 @@ function useAttendanceRepository() {
|
|
|
32983
33088
|
localField: "user",
|
|
32984
33089
|
foreignField: "_id",
|
|
32985
33090
|
as: "user",
|
|
32986
|
-
pipeline: [{ $project: { name: 1 } }]
|
|
33091
|
+
pipeline: [{ $project: { name: 1, profile: 1 } }]
|
|
32987
33092
|
}
|
|
32988
33093
|
},
|
|
32989
33094
|
{ $unwind: { path: "$user", preserveNullAndEmptyArrays: true } }
|
|
@@ -32997,6 +33102,7 @@ function useAttendanceRepository() {
|
|
|
32997
33102
|
{
|
|
32998
33103
|
$project: {
|
|
32999
33104
|
userName: "$user.name",
|
|
33105
|
+
userProfile: "$user.profile",
|
|
33000
33106
|
checkInTimestamp: "$checkIn.timestamp",
|
|
33001
33107
|
checkOutTimestamp: "$checkOut.timestamp",
|
|
33002
33108
|
createdAt: 1
|
|
@@ -35487,7 +35593,7 @@ function useVisitorTransactionService() {
|
|
|
35487
35593
|
value.unitName = unit?.name;
|
|
35488
35594
|
}
|
|
35489
35595
|
const { nric = "", name = "", contact = "", plateNumber = "", email = "", site = "", type = "guest", company, createdBy } = value;
|
|
35490
|
-
if (/^(guest|walk-in|contractor|delivery)$/.test(type)) {
|
|
35596
|
+
if (/^(guest|walk-in|contractor|delivery)$/.test(type) && site) {
|
|
35491
35597
|
await addUpdateFromVisitor({
|
|
35492
35598
|
nric,
|
|
35493
35599
|
name,
|
|
@@ -35718,7 +35824,7 @@ function useVisitorTransactionService() {
|
|
|
35718
35824
|
value.checkIn = isNaN(parsed.getTime()) ? null : parsed;
|
|
35719
35825
|
}
|
|
35720
35826
|
const { nric = "", name = "", contact = "", plateNumber = "", email = "", site = "", type = "guest", company, createdBy } = value;
|
|
35721
|
-
if (/^(guest|walk-in|contractor|delivery)$/.test(type) &&
|
|
35827
|
+
if (/^(guest|walk-in|contractor|delivery)$/.test(type) && site) {
|
|
35722
35828
|
await addUpdateFromVisitor({
|
|
35723
35829
|
nric,
|
|
35724
35830
|
name,
|
|
@@ -35902,7 +36008,9 @@ function useVisitorTransactionService() {
|
|
|
35902
36008
|
value.site,
|
|
35903
36009
|
session,
|
|
35904
36010
|
void 0,
|
|
35905
|
-
id
|
|
36011
|
+
id,
|
|
36012
|
+
void 0,
|
|
36013
|
+
true
|
|
35906
36014
|
);
|
|
35907
36015
|
item.receivedDate = /* @__PURE__ */ new Date();
|
|
35908
36016
|
item.status = "Not Returned" /* NOT_RETURNED */;
|
|
@@ -35951,7 +36059,9 @@ function useVisitorTransactionService() {
|
|
|
35951
36059
|
value.site,
|
|
35952
36060
|
session,
|
|
35953
36061
|
void 0,
|
|
35954
|
-
id
|
|
36062
|
+
id,
|
|
36063
|
+
void 0,
|
|
36064
|
+
true
|
|
35955
36065
|
);
|
|
35956
36066
|
item.receivedDate = /* @__PURE__ */ new Date();
|
|
35957
36067
|
item.status = "Not Returned" /* NOT_RETURNED */;
|
|
@@ -55352,8 +55462,11 @@ function useNfcPatrolRouteRepo() {
|
|
|
55352
55462
|
const query = {
|
|
55353
55463
|
site
|
|
55354
55464
|
};
|
|
55355
|
-
if (search) {
|
|
55356
|
-
query
|
|
55465
|
+
if (search?.trim()) {
|
|
55466
|
+
query.name = {
|
|
55467
|
+
$regex: search.trim(),
|
|
55468
|
+
$options: "i"
|
|
55469
|
+
};
|
|
55357
55470
|
}
|
|
55358
55471
|
if (filter === "today" || filter === "notToday") {
|
|
55359
55472
|
const singaporeDateString = (/* @__PURE__ */ new Date()).toLocaleString("en-US", {
|
|
@@ -58775,13 +58888,9 @@ function useNfcPatrolLogRepo() {
|
|
|
58775
58888
|
};
|
|
58776
58889
|
if (date) {
|
|
58777
58890
|
if (type === "month") {
|
|
58778
|
-
const [year, month] = date.split("-").map(Number);
|
|
58779
|
-
const endDay = new Date(year, month, 0).getDate();
|
|
58780
58891
|
query.date = {
|
|
58781
|
-
$gte: `${
|
|
58782
|
-
$lte: `${
|
|
58783
|
-
endDay
|
|
58784
|
-
).padStart(2, "0")}`
|
|
58892
|
+
$gte: `${date}-01-01`,
|
|
58893
|
+
$lte: `${date}-12-31`
|
|
58785
58894
|
};
|
|
58786
58895
|
} else {
|
|
58787
58896
|
query.date = date;
|
|
@@ -59109,47 +59218,52 @@ function useNfcPatrolLogController() {
|
|
|
59109
59218
|
page: Joi111.number().integer().min(1).default(1),
|
|
59110
59219
|
limit: Joi111.number().integer().min(1).max(100).default(10),
|
|
59111
59220
|
site: Joi111.string().length(24).hex().required(),
|
|
59112
|
-
date: Joi111.string().pattern(/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])
|
|
59113
|
-
"string.pattern.base": "Date must be
|
|
59221
|
+
date: Joi111.string().pattern(/^\d{4}(-(0[1-9]|1[0-2])(-(0[1-9]|[12][0-9]|3[01]))?)?$/).optional().messages({
|
|
59222
|
+
"string.pattern.base": "Date must be YYYY or YYYY-MM or YYYY-MM-DD"
|
|
59114
59223
|
}),
|
|
59115
59224
|
type: Joi111.string().valid("month").optional(),
|
|
59116
59225
|
route: Joi111.object({
|
|
59117
|
-
_id: Joi111.string().length(24).hex().
|
|
59118
|
-
startTime: Joi111.string().pattern(/^([01]\d|2[0-3]):([0-5]\d)$/).
|
|
59119
|
-
|
|
59226
|
+
_id: Joi111.string().length(24).hex().optional(),
|
|
59227
|
+
startTime: Joi111.string().pattern(/^([01]\d|2[0-3]):([0-5]\d)$/).optional().messages({
|
|
59228
|
+
"string.pattern.base": "startTime must be in HH:mm 24-hour format"
|
|
59229
|
+
})
|
|
59230
|
+
}).min(1).optional()
|
|
59120
59231
|
});
|
|
59121
59232
|
const query = {
|
|
59233
|
+
page: req.query.page,
|
|
59234
|
+
limit: req.query.limit,
|
|
59122
59235
|
site: req.query.site,
|
|
59123
59236
|
date: req.query.date,
|
|
59124
|
-
|
|
59125
|
-
|
|
59126
|
-
|
|
59127
|
-
|
|
59237
|
+
type: req.query.type,
|
|
59238
|
+
route: req.query["route._id"] || req.query["route.startTime"] ? {
|
|
59239
|
+
...req.query["route._id"] ? { _id: req.query["route._id"] } : {},
|
|
59240
|
+
...req.query["route.startTime"] ? { startTime: req.query["route.startTime"] } : {}
|
|
59241
|
+
} : void 0
|
|
59128
59242
|
};
|
|
59129
59243
|
const { error, value } = validation.validate(query, {
|
|
59130
|
-
abortEarly: false
|
|
59244
|
+
abortEarly: false,
|
|
59245
|
+
allowUnknown: true,
|
|
59246
|
+
stripUnknown: true
|
|
59131
59247
|
});
|
|
59132
59248
|
if (error) {
|
|
59133
|
-
|
|
59134
|
-
|
|
59135
|
-
|
|
59136
|
-
|
|
59249
|
+
return next(
|
|
59250
|
+
new BadRequestError181(
|
|
59251
|
+
error.details.map((d) => d.message).join(", ")
|
|
59252
|
+
)
|
|
59253
|
+
);
|
|
59137
59254
|
}
|
|
59138
|
-
const { page, limit, site, date, route } = value;
|
|
59139
59255
|
try {
|
|
59140
59256
|
const data = await _getAllBySite({
|
|
59141
|
-
page,
|
|
59142
|
-
limit,
|
|
59143
|
-
site,
|
|
59144
|
-
date,
|
|
59145
|
-
|
|
59257
|
+
page: value.page,
|
|
59258
|
+
limit: value.limit,
|
|
59259
|
+
site: value.site,
|
|
59260
|
+
date: value.date,
|
|
59261
|
+
type: value.type,
|
|
59262
|
+
route: value.route
|
|
59146
59263
|
});
|
|
59147
|
-
res.status(200).json(data);
|
|
59148
|
-
return;
|
|
59264
|
+
return res.status(200).json(data);
|
|
59149
59265
|
} catch (error2) {
|
|
59150
|
-
|
|
59151
|
-
next(error2);
|
|
59152
|
-
return;
|
|
59266
|
+
return next(error2);
|
|
59153
59267
|
}
|
|
59154
59268
|
}
|
|
59155
59269
|
async function completeCheckpoint(req, res, next) {
|
|
@@ -64737,34 +64851,62 @@ import axios3 from "axios";
|
|
|
64737
64851
|
|
|
64738
64852
|
// src/utils/payment-signature.util.ts
|
|
64739
64853
|
import * as crypto3 from "crypto";
|
|
64854
|
+
function hasOwn(obj, key) {
|
|
64855
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
64856
|
+
}
|
|
64857
|
+
function sha512(input) {
|
|
64858
|
+
return crypto3.createHash("sha512").update(input).digest("hex");
|
|
64859
|
+
}
|
|
64860
|
+
function assertSecret(secretKey) {
|
|
64861
|
+
if (!secretKey) {
|
|
64862
|
+
throw new Error("Payment signature: missing secret key.");
|
|
64863
|
+
}
|
|
64864
|
+
}
|
|
64740
64865
|
function paymentSignature(params, secretKey) {
|
|
64741
|
-
|
|
64866
|
+
assertSecret(secretKey);
|
|
64867
|
+
const fieldOrder = [
|
|
64868
|
+
"mid",
|
|
64869
|
+
"order_id",
|
|
64870
|
+
"payment_type",
|
|
64871
|
+
"amount",
|
|
64872
|
+
"ccy",
|
|
64873
|
+
"card_no",
|
|
64874
|
+
"exp_date",
|
|
64875
|
+
"cvv2"
|
|
64876
|
+
];
|
|
64742
64877
|
let concatenated = "";
|
|
64743
64878
|
fieldOrder.forEach((v) => {
|
|
64744
|
-
if (!params
|
|
64879
|
+
if (!hasOwn(params, v)) {
|
|
64745
64880
|
return;
|
|
64746
|
-
}
|
|
64747
|
-
|
|
64881
|
+
}
|
|
64882
|
+
const raw = String(params[v] ?? "");
|
|
64883
|
+
if (v === "cvv2") {
|
|
64884
|
+
concatenated += raw.slice(-1);
|
|
64748
64885
|
} else if (v === "card_no") {
|
|
64749
|
-
concatenated +=
|
|
64886
|
+
concatenated += raw.substring(0, 6) + raw.slice(-4);
|
|
64750
64887
|
} else {
|
|
64751
|
-
concatenated +=
|
|
64888
|
+
concatenated += raw;
|
|
64752
64889
|
}
|
|
64753
64890
|
});
|
|
64754
64891
|
concatenated += secretKey;
|
|
64755
|
-
|
|
64756
|
-
return signature;
|
|
64892
|
+
return sha512(concatenated);
|
|
64757
64893
|
}
|
|
64758
64894
|
function genericSignature(params, secretKey) {
|
|
64759
|
-
|
|
64895
|
+
assertSecret(secretKey);
|
|
64896
|
+
const paramsCopy = {
|
|
64897
|
+
...params
|
|
64898
|
+
};
|
|
64760
64899
|
delete paramsCopy["signature"];
|
|
64761
|
-
const
|
|
64762
|
-
|
|
64763
|
-
|
|
64764
|
-
|
|
64765
|
-
|
|
64766
|
-
|
|
64767
|
-
|
|
64900
|
+
const concatenated = Object.keys(paramsCopy).sort().map((key) => {
|
|
64901
|
+
const value = paramsCopy[key];
|
|
64902
|
+
if (value !== null && typeof value === "object") {
|
|
64903
|
+
throw new Error(
|
|
64904
|
+
`Payment signature: non-primitive value for field "${key}".`
|
|
64905
|
+
);
|
|
64906
|
+
}
|
|
64907
|
+
return String(value ?? "");
|
|
64908
|
+
}).join("") + secretKey;
|
|
64909
|
+
return sha512(concatenated);
|
|
64768
64910
|
}
|
|
64769
64911
|
|
|
64770
64912
|
// src/repositories/reddot-payment.repository.ts
|
|
@@ -65193,7 +65335,7 @@ var useRedDotPaymentSvc = () => {
|
|
|
65193
65335
|
};
|
|
65194
65336
|
if (!process.env.MERCHANT_ENQUIRY) {
|
|
65195
65337
|
throw new Error(
|
|
65196
|
-
"
|
|
65338
|
+
"MERCHANT_ENQUIRY environment variable is not defined."
|
|
65197
65339
|
);
|
|
65198
65340
|
}
|
|
65199
65341
|
const url = process.env.MERCHANT_ENQUIRY;
|