@7365admin1/core 2.50.0 → 2.52.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 +8 -3
- package/dist/index.js +412 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +412 -53
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4333,6 +4333,9 @@ function useVerificationRepo() {
|
|
|
4333
4333
|
return Promise.reject(error);
|
|
4334
4334
|
}
|
|
4335
4335
|
}
|
|
4336
|
+
async function findOne(query) {
|
|
4337
|
+
return await collection.findOne(query);
|
|
4338
|
+
}
|
|
4336
4339
|
return {
|
|
4337
4340
|
createIndex,
|
|
4338
4341
|
createTextIndex,
|
|
@@ -4341,7 +4344,8 @@ function useVerificationRepo() {
|
|
|
4341
4344
|
getVerifications,
|
|
4342
4345
|
getByIdByType,
|
|
4343
4346
|
updateStatusById,
|
|
4344
|
-
getByStatus
|
|
4347
|
+
getByStatus,
|
|
4348
|
+
findOne
|
|
4345
4349
|
};
|
|
4346
4350
|
}
|
|
4347
4351
|
|
|
@@ -5645,29 +5649,28 @@ function useVerificationService() {
|
|
|
5645
5649
|
throw error;
|
|
5646
5650
|
}
|
|
5647
5651
|
}
|
|
5648
|
-
async function createSimpleUserInvite({
|
|
5649
|
-
email,
|
|
5650
|
-
metadata
|
|
5651
|
-
}) {
|
|
5652
|
+
async function createSimpleUserInvite({ email, metadata }) {
|
|
5652
5653
|
const type = "user-invite";
|
|
5654
|
+
if (metadata?.org)
|
|
5655
|
+
await getOrgById(metadata.org);
|
|
5656
|
+
if (metadata?.siteId)
|
|
5657
|
+
await getSiteById(metadata.siteId);
|
|
5658
|
+
const existing = await useVerificationRepo().findOne({
|
|
5659
|
+
type,
|
|
5660
|
+
email,
|
|
5661
|
+
"metadata.org": metadata?.org,
|
|
5662
|
+
"metadata.siteId": metadata?.siteId
|
|
5663
|
+
});
|
|
5664
|
+
if (existing)
|
|
5665
|
+
return existing._id;
|
|
5653
5666
|
const value = {
|
|
5654
5667
|
type,
|
|
5655
5668
|
email,
|
|
5656
5669
|
metadata,
|
|
5657
|
-
expireAt: new Date(
|
|
5658
|
-
(/* @__PURE__ */ new Date()).getTime() + 72 * 60 * 60 * 1e3
|
|
5659
|
-
).toISOString(),
|
|
5670
|
+
expireAt: new Date(Date.now() + 72 * 60 * 60 * 1e3).toISOString(),
|
|
5660
5671
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5661
5672
|
};
|
|
5662
|
-
if (value.metadata?.org) {
|
|
5663
|
-
await getOrgById(value.metadata?.org);
|
|
5664
|
-
}
|
|
5665
|
-
if (value.metadata?.siteId) {
|
|
5666
|
-
await getSiteById(value.metadata?.siteId);
|
|
5667
|
-
}
|
|
5668
5673
|
const res = await add(value);
|
|
5669
|
-
const dir = __dirname;
|
|
5670
|
-
const filePath = (0, import_node_server_utils21.getDirectory)(dir, "./public/handlebars/user-invite");
|
|
5671
5674
|
const link = `${APP_MAIN}/verify/invitation/${res}`;
|
|
5672
5675
|
const emailContent = (0, import_node_server_utils21.compileHandlebar)({
|
|
5673
5676
|
context: {
|
|
@@ -5675,9 +5678,9 @@ function useVerificationService() {
|
|
|
5675
5678
|
validity: VERIFICATION_USER_INVITE_DURATION,
|
|
5676
5679
|
link
|
|
5677
5680
|
},
|
|
5678
|
-
filePath
|
|
5681
|
+
filePath: (0, import_node_server_utils21.getDirectory)(__dirname, "./public/handlebars/user-invite")
|
|
5679
5682
|
});
|
|
5680
|
-
mailer.sendMail({
|
|
5683
|
+
await mailer.sendMail({
|
|
5681
5684
|
to: email,
|
|
5682
5685
|
subject: "User Invite",
|
|
5683
5686
|
html: emailContent,
|
|
@@ -7504,7 +7507,7 @@ function useMemberService() {
|
|
|
7504
7507
|
getByRoles
|
|
7505
7508
|
} = useMemberRepo();
|
|
7506
7509
|
const { getById: _getVerificationById, updateStatusById } = useVerificationRepo();
|
|
7507
|
-
const { getUserByEmail, updateDefaultOrgByEmail } = useUserRepo();
|
|
7510
|
+
const { getUserByEmail, updateDefaultOrgByEmail, getUserById } = useUserRepo();
|
|
7508
7511
|
const { getById: getOrgById } = useOrgRepo();
|
|
7509
7512
|
const { getSiteById } = useSiteRepo();
|
|
7510
7513
|
const { getOwnerRolesByTypeOrg } = useRoleRepo();
|
|
@@ -7566,6 +7569,52 @@ function useMemberService() {
|
|
|
7566
7569
|
session?.endSession();
|
|
7567
7570
|
}
|
|
7568
7571
|
}
|
|
7572
|
+
async function createMemberDirect({
|
|
7573
|
+
userId,
|
|
7574
|
+
orgId,
|
|
7575
|
+
roleId,
|
|
7576
|
+
app,
|
|
7577
|
+
siteId,
|
|
7578
|
+
siteName
|
|
7579
|
+
}) {
|
|
7580
|
+
const session = import_node_server_utils30.useAtlas.getClient()?.startSession();
|
|
7581
|
+
session?.startTransaction();
|
|
7582
|
+
try {
|
|
7583
|
+
const org = await getOrgById(orgId);
|
|
7584
|
+
if (!org)
|
|
7585
|
+
throw new import_node_server_utils30.BadRequestError("Organization not found.");
|
|
7586
|
+
const user = await getUserById(userId);
|
|
7587
|
+
if (!user)
|
|
7588
|
+
throw new import_node_server_utils30.BadRequestError("User not found.");
|
|
7589
|
+
const member = await addMember(
|
|
7590
|
+
{
|
|
7591
|
+
org: org._id?.toString() || "",
|
|
7592
|
+
orgName: org.name || "",
|
|
7593
|
+
user: user._id?.toString() || "",
|
|
7594
|
+
name: user?.email,
|
|
7595
|
+
role: roleId,
|
|
7596
|
+
type: app,
|
|
7597
|
+
siteId: siteId ?? "",
|
|
7598
|
+
siteName: siteName ?? ""
|
|
7599
|
+
},
|
|
7600
|
+
session
|
|
7601
|
+
);
|
|
7602
|
+
if (!user.defaultOrg) {
|
|
7603
|
+
await updateDefaultOrgByEmail(
|
|
7604
|
+
user.email,
|
|
7605
|
+
org._id?.toString() || "",
|
|
7606
|
+
session
|
|
7607
|
+
);
|
|
7608
|
+
}
|
|
7609
|
+
await session?.commitTransaction();
|
|
7610
|
+
return { member };
|
|
7611
|
+
} catch (error) {
|
|
7612
|
+
await session?.abortTransaction();
|
|
7613
|
+
throw error;
|
|
7614
|
+
} finally {
|
|
7615
|
+
session?.endSession();
|
|
7616
|
+
}
|
|
7617
|
+
}
|
|
7569
7618
|
async function updateRoleById(id, role, type, org) {
|
|
7570
7619
|
const owner = await getOwnerRolesByTypeOrg(type, org);
|
|
7571
7620
|
if (!owner.length) {
|
|
@@ -7593,6 +7642,7 @@ function useMemberService() {
|
|
|
7593
7642
|
}
|
|
7594
7643
|
return {
|
|
7595
7644
|
createMember,
|
|
7645
|
+
createMemberDirect,
|
|
7596
7646
|
updateRoleById
|
|
7597
7647
|
};
|
|
7598
7648
|
}
|
|
@@ -7607,7 +7657,7 @@ function useMemberController() {
|
|
|
7607
7657
|
updateMemberStatus: _updateMemberStatus,
|
|
7608
7658
|
updateStatusByUserId: _updateStatusByUserId
|
|
7609
7659
|
} = useMemberRepo();
|
|
7610
|
-
const { createMember: _createMember, updateRoleById: _updateRoleById } = useMemberService();
|
|
7660
|
+
const { createMember: _createMember, createMemberDirect: _createMemberDirect, updateRoleById: _updateRoleById } = useMemberService();
|
|
7611
7661
|
async function createMember(req, res, next) {
|
|
7612
7662
|
const validation = import_joi15.default.string().hex().required();
|
|
7613
7663
|
const _id = req.params.id;
|
|
@@ -7796,6 +7846,32 @@ function useMemberController() {
|
|
|
7796
7846
|
return;
|
|
7797
7847
|
}
|
|
7798
7848
|
}
|
|
7849
|
+
async function createMemberDirect(req, res, next) {
|
|
7850
|
+
const validation = import_joi15.default.object({
|
|
7851
|
+
userId: import_joi15.default.string().hex().required(),
|
|
7852
|
+
orgId: import_joi15.default.string().hex().required(),
|
|
7853
|
+
roleId: import_joi15.default.string().hex().required(),
|
|
7854
|
+
app: import_joi15.default.string().required(),
|
|
7855
|
+
siteId: import_joi15.default.string().hex().optional().allow("", null),
|
|
7856
|
+
siteName: import_joi15.default.string().optional().allow("", null)
|
|
7857
|
+
});
|
|
7858
|
+
const { error } = validation.validate(req.body);
|
|
7859
|
+
if (error) {
|
|
7860
|
+
import_node_server_utils31.logger.log({ level: "error", message: error.message });
|
|
7861
|
+
next(new import_node_server_utils31.BadRequestError(error.message));
|
|
7862
|
+
return;
|
|
7863
|
+
}
|
|
7864
|
+
const { userId, orgId, roleId, app, siteId, siteName } = req.body;
|
|
7865
|
+
try {
|
|
7866
|
+
const data = await _createMemberDirect({ userId, orgId, roleId, app, siteId, siteName });
|
|
7867
|
+
res.status(201).json(data);
|
|
7868
|
+
return;
|
|
7869
|
+
} catch (error2) {
|
|
7870
|
+
import_node_server_utils31.logger.log({ level: "error", message: error2.message });
|
|
7871
|
+
next(error2);
|
|
7872
|
+
return;
|
|
7873
|
+
}
|
|
7874
|
+
}
|
|
7799
7875
|
return {
|
|
7800
7876
|
createMember,
|
|
7801
7877
|
getByUserId,
|
|
@@ -7803,7 +7879,8 @@ function useMemberController() {
|
|
|
7803
7879
|
getAll,
|
|
7804
7880
|
getOrgsByMembership,
|
|
7805
7881
|
updateMemberStatus,
|
|
7806
|
-
updateRoleById
|
|
7882
|
+
updateRoleById,
|
|
7883
|
+
createMemberDirect
|
|
7807
7884
|
};
|
|
7808
7885
|
}
|
|
7809
7886
|
|
|
@@ -13236,23 +13313,42 @@ var CameraType = /* @__PURE__ */ ((CameraType2) => {
|
|
|
13236
13313
|
})(CameraType || {});
|
|
13237
13314
|
var schemaUpdateSiteCamera = import_joi34.default.object({
|
|
13238
13315
|
host: import_joi34.default.string().required(),
|
|
13239
|
-
username: import_joi34.default.string().
|
|
13240
|
-
|
|
13316
|
+
username: import_joi34.default.string().when("type", {
|
|
13317
|
+
is: "anpr",
|
|
13318
|
+
then: import_joi34.default.required(),
|
|
13319
|
+
otherwise: import_joi34.default.optional().allow(null, "")
|
|
13320
|
+
}),
|
|
13321
|
+
password: import_joi34.default.string().when("type", {
|
|
13322
|
+
is: "anpr",
|
|
13323
|
+
then: import_joi34.default.required(),
|
|
13324
|
+
otherwise: import_joi34.default.optional().allow(null, "")
|
|
13325
|
+
}),
|
|
13241
13326
|
category: import_joi34.default.string().allow("standard", "resident", "visitor").required(),
|
|
13242
13327
|
guardPost: import_joi34.default.number().integer().optional(),
|
|
13243
|
-
direction: import_joi34.default.string().optional().allow("entry", "exit", "both", "none")
|
|
13328
|
+
direction: import_joi34.default.string().optional().allow("entry", "exit", "both", "none"),
|
|
13329
|
+
status: import_joi34.default.string().optional().allow("active", "inactive", "deleted"),
|
|
13330
|
+
name: import_joi34.default.string().optional().allow(null, "")
|
|
13244
13331
|
});
|
|
13245
13332
|
var schemaSiteCamera = import_joi34.default.object({
|
|
13246
13333
|
_id: import_joi34.default.string().hex().optional(),
|
|
13247
13334
|
site: import_joi34.default.string().hex().required(),
|
|
13248
13335
|
host: import_joi34.default.string().required(),
|
|
13249
|
-
username: import_joi34.default.string().
|
|
13250
|
-
|
|
13336
|
+
username: import_joi34.default.string().when("type", {
|
|
13337
|
+
is: "anpr",
|
|
13338
|
+
then: import_joi34.default.required(),
|
|
13339
|
+
otherwise: import_joi34.default.optional().allow(null, "")
|
|
13340
|
+
}),
|
|
13341
|
+
password: import_joi34.default.string().when("type", {
|
|
13342
|
+
is: "anpr",
|
|
13343
|
+
then: import_joi34.default.required(),
|
|
13344
|
+
otherwise: import_joi34.default.optional().allow(null, "")
|
|
13345
|
+
}),
|
|
13251
13346
|
type: import_joi34.default.string().allow("ip", "anpr").required(),
|
|
13252
13347
|
category: import_joi34.default.string().allow("standard", "resident", "visitor").required(),
|
|
13253
13348
|
direction: import_joi34.default.string().required().allow("entry", "exit", "both", "none"),
|
|
13254
13349
|
guardPost: import_joi34.default.number().integer().optional(),
|
|
13255
13350
|
status: import_joi34.default.string().optional().allow("active", "inactive", "deleted"),
|
|
13351
|
+
name: import_joi34.default.string().optional().allow(null, ""),
|
|
13256
13352
|
createdAt: import_joi34.default.date().optional(),
|
|
13257
13353
|
updatedAt: import_joi34.default.date().optional(),
|
|
13258
13354
|
deletedAt: import_joi34.default.date().optional()
|
|
@@ -13281,6 +13377,7 @@ function MSiteCamera(value) {
|
|
|
13281
13377
|
guardPost: value.guardPost ?? 0,
|
|
13282
13378
|
status: value.status ?? "active",
|
|
13283
13379
|
direction: value.direction ?? "",
|
|
13380
|
+
name: value.name ?? "",
|
|
13284
13381
|
createdAt: value.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
13285
13382
|
updatedAt: value.updatedAt ?? "",
|
|
13286
13383
|
deletedAt: value.deletedAt ?? ""
|
|
@@ -13595,7 +13692,24 @@ var schemaUpdateVisTrans = import_joi36.default.object({
|
|
|
13595
13692
|
checkInRemarks: import_joi36.default.string().optional().allow("", null),
|
|
13596
13693
|
checkOutRemarks: import_joi36.default.string().optional().allow("", null),
|
|
13597
13694
|
expectedCheckIn: import_joi36.default.string().isoDate().optional(),
|
|
13598
|
-
purpose: import_joi36.default.string().optional().allow(null, "")
|
|
13695
|
+
purpose: import_joi36.default.string().optional().allow(null, ""),
|
|
13696
|
+
members: import_joi36.default.array().items(
|
|
13697
|
+
import_joi36.default.object({
|
|
13698
|
+
name: import_joi36.default.string().optional().allow(null, ""),
|
|
13699
|
+
nric: import_joi36.default.string().optional().allow(null, ""),
|
|
13700
|
+
visitorPass: import_joi36.default.array().items(
|
|
13701
|
+
import_joi36.default.object({
|
|
13702
|
+
keyId: import_joi36.default.string().hex().length(24).required()
|
|
13703
|
+
})
|
|
13704
|
+
).optional().allow(null),
|
|
13705
|
+
passKeys: import_joi36.default.array().items(
|
|
13706
|
+
import_joi36.default.object({
|
|
13707
|
+
keyId: import_joi36.default.string().hex().length(24).required()
|
|
13708
|
+
})
|
|
13709
|
+
).optional().allow(null),
|
|
13710
|
+
contact: import_joi36.default.string().optional().allow(null, "")
|
|
13711
|
+
})
|
|
13712
|
+
).optional().allow(null)
|
|
13599
13713
|
});
|
|
13600
13714
|
function MVisitorTransaction(value) {
|
|
13601
13715
|
const { error } = schemaVisitorTransaction.validate(value, {
|
|
@@ -14045,14 +14159,14 @@ function useVisitorTransactionRepo() {
|
|
|
14045
14159
|
);
|
|
14046
14160
|
}
|
|
14047
14161
|
}
|
|
14048
|
-
async function updateById(_id, value, session,
|
|
14162
|
+
async function updateById(_id, value, session, isManualCheckOut = true) {
|
|
14049
14163
|
try {
|
|
14050
14164
|
_id = new import_mongodb40.ObjectId(_id);
|
|
14051
14165
|
} catch (error) {
|
|
14052
14166
|
throw new import_node_server_utils68.BadRequestError("Invalid visitor transaction ID format.");
|
|
14053
14167
|
}
|
|
14054
14168
|
value.updatedAt = /* @__PURE__ */ new Date();
|
|
14055
|
-
if (value.checkOut &&
|
|
14169
|
+
if (value.checkOut && isManualCheckOut) {
|
|
14056
14170
|
value.manualCheckout = true;
|
|
14057
14171
|
}
|
|
14058
14172
|
try {
|
|
@@ -17475,7 +17589,7 @@ function useDahuaService() {
|
|
|
17475
17589
|
);
|
|
17476
17590
|
}
|
|
17477
17591
|
}
|
|
17478
|
-
if (["entry"
|
|
17592
|
+
if (["entry"].includes(designation) && plateNumber) {
|
|
17479
17593
|
await closeOpenTransaction(plateNumber);
|
|
17480
17594
|
const vehicle = await getVehicleByPlateNumber(plateNumber);
|
|
17481
17595
|
const visitorTransaction = {
|
|
@@ -17530,11 +17644,11 @@ function useDahuaService() {
|
|
|
17530
17644
|
} catch (error) {
|
|
17531
17645
|
console.log("failed to create visitor transaction", error);
|
|
17532
17646
|
loggerDahua.error(
|
|
17533
|
-
`[${site}][${
|
|
17647
|
+
`[${site}][${host}] Error creating visitor transaction:`,
|
|
17534
17648
|
error
|
|
17535
17649
|
);
|
|
17536
17650
|
}
|
|
17537
|
-
} else if (["exit"
|
|
17651
|
+
} else if (["exit"].includes(designation) && plateNumber) {
|
|
17538
17652
|
const vehicle = await getVehicleByPlateNumber(plateNumber);
|
|
17539
17653
|
const existingOpenTransaction = await getOpenByPlateNumber(
|
|
17540
17654
|
plateNumber,
|
|
@@ -17559,6 +17673,92 @@ function useDahuaService() {
|
|
|
17559
17673
|
if (onDetected2) {
|
|
17560
17674
|
onDetected2({ reload: true, site: existingOpenTransaction?.site?.toString(), host, direction });
|
|
17561
17675
|
}
|
|
17676
|
+
} else if (["both"].includes(designation) && plateNumber) {
|
|
17677
|
+
if (direction.toLowerCase() === "leave") {
|
|
17678
|
+
const vehicle = await getVehicleByPlateNumber(plateNumber);
|
|
17679
|
+
const existingOpenTransaction = await getOpenByPlateNumber(
|
|
17680
|
+
plateNumber,
|
|
17681
|
+
site
|
|
17682
|
+
);
|
|
17683
|
+
if (existingOpenTransaction?._id) {
|
|
17684
|
+
currentTransactionId = existingOpenTransaction._id.toString();
|
|
17685
|
+
currentSnapshotField = "snapshotExitImage";
|
|
17686
|
+
}
|
|
17687
|
+
if (vehicle?.recNo) {
|
|
17688
|
+
const dahuaPayload = {
|
|
17689
|
+
host,
|
|
17690
|
+
username,
|
|
17691
|
+
password,
|
|
17692
|
+
plateNumber,
|
|
17693
|
+
mode: "TrafficRedList" /* TRAFFIC_REDLIST */,
|
|
17694
|
+
recno: vehicle?.recNo
|
|
17695
|
+
};
|
|
17696
|
+
await removePlateNumber(dahuaPayload);
|
|
17697
|
+
}
|
|
17698
|
+
await closeOpenTransaction(plateNumber);
|
|
17699
|
+
if (onDetected2 && existingOpenTransaction?.site) {
|
|
17700
|
+
onDetected2({ reload: true, site: existingOpenTransaction?.site?.toString(), host, direction });
|
|
17701
|
+
}
|
|
17702
|
+
} else if (direction.toLowerCase() === "approach") {
|
|
17703
|
+
await closeOpenTransaction(plateNumber);
|
|
17704
|
+
const vehicle = await getVehicleByPlateNumber(plateNumber);
|
|
17705
|
+
const visitorTransaction = {
|
|
17706
|
+
site,
|
|
17707
|
+
plateNumber,
|
|
17708
|
+
org,
|
|
17709
|
+
status: "unregistered" /* UNREGISTERED */
|
|
17710
|
+
};
|
|
17711
|
+
const typesForAutoRegister = Object.values(PersonTypes);
|
|
17712
|
+
let startDate = vehicle?.start ? new Date(vehicle?.start) : /* @__PURE__ */ new Date();
|
|
17713
|
+
let endDate = vehicle?.end ? new Date(vehicle?.end) : new Date(startDate.getTime() + 60 * 60 * 1e3);
|
|
17714
|
+
if (vehicle && typeof vehicle.category === "string" && typesForAutoRegister.includes(vehicle.category)) {
|
|
17715
|
+
visitorTransaction.name = vehicle.name;
|
|
17716
|
+
visitorTransaction.nric = vehicle.nric;
|
|
17717
|
+
visitorTransaction.contact = vehicle.phoneNumber;
|
|
17718
|
+
visitorTransaction.block = Number(vehicle.block);
|
|
17719
|
+
visitorTransaction.level = vehicle.level;
|
|
17720
|
+
visitorTransaction.unit = vehicle.unit?.toString();
|
|
17721
|
+
visitorTransaction.unitName = vehicle.unitName;
|
|
17722
|
+
visitorTransaction.type = vehicle.category;
|
|
17723
|
+
visitorTransaction.status = "registered" /* REGISTERED */;
|
|
17724
|
+
visitorTransaction.recNo = vehicle.recNo;
|
|
17725
|
+
visitorTransaction.expiredAt = vehicle.end;
|
|
17726
|
+
}
|
|
17727
|
+
const dahuaPayload = {
|
|
17728
|
+
host,
|
|
17729
|
+
username,
|
|
17730
|
+
password,
|
|
17731
|
+
plateNumber,
|
|
17732
|
+
mode: "TrafficRedList" /* TRAFFIC_REDLIST */,
|
|
17733
|
+
owner: vehicle?.name ?? ""
|
|
17734
|
+
};
|
|
17735
|
+
dahuaPayload.start = formatDahuaDate(startDate);
|
|
17736
|
+
dahuaPayload.end = formatDahuaDate(endDate);
|
|
17737
|
+
const shouldHaveTimeLimit = visitorTransaction.type === "guest" /* GUEST */ || visitorTransaction.status === "unregistered" /* UNREGISTERED */;
|
|
17738
|
+
if (shouldHaveTimeLimit) {
|
|
17739
|
+
const startDate2 = /* @__PURE__ */ new Date();
|
|
17740
|
+
const endDate2 = new Date(startDate2.getTime() + 60 * 60 * 1e3);
|
|
17741
|
+
dahuaPayload.start = formatDahuaDate(startDate2);
|
|
17742
|
+
dahuaPayload.end = formatDahuaDate(endDate2);
|
|
17743
|
+
visitorTransaction.expiredAt = endDate2.toISOString();
|
|
17744
|
+
}
|
|
17745
|
+
try {
|
|
17746
|
+
await addPlateNumber(dahuaPayload);
|
|
17747
|
+
const result = await add(visitorTransaction, void 0, true);
|
|
17748
|
+
const transactionId = result?._id;
|
|
17749
|
+
currentTransactionId = transactionId?.toString();
|
|
17750
|
+
currentSnapshotField = "snapshotEntryImage";
|
|
17751
|
+
if (onDetected2) {
|
|
17752
|
+
onDetected2({ _id: transactionId, site: result?.site?.toString(), plateNumber: result.plateNumber, host, direction });
|
|
17753
|
+
}
|
|
17754
|
+
} catch (error) {
|
|
17755
|
+
console.log("failed to create visitor transaction", error);
|
|
17756
|
+
loggerDahua.error(
|
|
17757
|
+
`[${site}][${host}] Error creating visitor transaction:`,
|
|
17758
|
+
error
|
|
17759
|
+
);
|
|
17760
|
+
}
|
|
17761
|
+
}
|
|
17562
17762
|
}
|
|
17563
17763
|
}
|
|
17564
17764
|
}
|
|
@@ -17690,6 +17890,9 @@ function useDahuaService() {
|
|
|
17690
17890
|
}
|
|
17691
17891
|
}
|
|
17692
17892
|
async function listenToCamera(camera, onDetected) {
|
|
17893
|
+
if (camera?.type != "anpr" && camera?.status != "deleted") {
|
|
17894
|
+
return;
|
|
17895
|
+
}
|
|
17693
17896
|
if (onDetected) {
|
|
17694
17897
|
_savedOnDetected = onDetected;
|
|
17695
17898
|
}
|
|
@@ -17698,6 +17901,14 @@ function useDahuaService() {
|
|
|
17698
17901
|
return;
|
|
17699
17902
|
}
|
|
17700
17903
|
const cameraId = camera._id.toString();
|
|
17904
|
+
if (camera.status !== "active") {
|
|
17905
|
+
if (cameraRegistry.has(cameraId)) {
|
|
17906
|
+
loggerDahua.info(`[${camera?.host ?? camera?._id}] Camera is ${camera.status}. Stopping connection.`);
|
|
17907
|
+
cameraRegistry.get(cameraId)?.abort();
|
|
17908
|
+
cameraRegistry.delete(cameraId);
|
|
17909
|
+
}
|
|
17910
|
+
return;
|
|
17911
|
+
}
|
|
17701
17912
|
if (cameraRegistry.has(cameraId)) {
|
|
17702
17913
|
loggerDahua.info(`[${camera.host}] Stopping existing connection for update.`);
|
|
17703
17914
|
cameraRegistry.get(cameraId)?.abort();
|
|
@@ -17845,6 +18056,9 @@ function useDahuaService() {
|
|
|
17845
18056
|
continue;
|
|
17846
18057
|
} else if ([400, 401, 403, 500].includes(response.statusCode)) {
|
|
17847
18058
|
loggerDahua.error(`[${host}] Connection error: ${response.statusCode}`);
|
|
18059
|
+
if (onDetected) {
|
|
18060
|
+
onDetected({ site, messagePermanent: `Camera with last 3 characters ${host?.slice(-3)} Connection Error. Check username and password.` });
|
|
18061
|
+
}
|
|
17848
18062
|
return;
|
|
17849
18063
|
}
|
|
17850
18064
|
loggerDahua.info(`[${host}] Successfully connected to ANPR.`);
|
|
@@ -17897,8 +18111,15 @@ function useDahuaService() {
|
|
|
17897
18111
|
break;
|
|
17898
18112
|
}
|
|
17899
18113
|
loggerDahua.error(
|
|
17900
|
-
`[${host}] Connection lost or error: ${error.message || error}. Retrying in
|
|
18114
|
+
`[${host}] Connection lost or error: ${error.message || error}. Retrying in 10 seconds...`
|
|
17901
18115
|
);
|
|
18116
|
+
if (onDetected) {
|
|
18117
|
+
onDetected({
|
|
18118
|
+
site,
|
|
18119
|
+
host,
|
|
18120
|
+
message: `Camera in ${gate} Connection Lost. Retrying in 10 seconds. Check the camera if this issue persists, Or set the camera to Inactive to stop this notification.`
|
|
18121
|
+
});
|
|
18122
|
+
}
|
|
17902
18123
|
} finally {
|
|
17903
18124
|
if (bufferQueue?.destroy) {
|
|
17904
18125
|
try {
|
|
@@ -17919,7 +18140,7 @@ function useDahuaService() {
|
|
|
17919
18140
|
}
|
|
17920
18141
|
}
|
|
17921
18142
|
if (!signal.aborted) {
|
|
17922
|
-
await new Promise((res) => setTimeout(res,
|
|
18143
|
+
await new Promise((res) => setTimeout(res, 1e4));
|
|
17923
18144
|
}
|
|
17924
18145
|
}
|
|
17925
18146
|
loggerDahua.info(`[${host}] ANPR Listener stopped.`);
|
|
@@ -18421,6 +18642,8 @@ function useSiteCameraRepo() {
|
|
|
18421
18642
|
}
|
|
18422
18643
|
try {
|
|
18423
18644
|
await collection.deleteOne({ _id }, { session });
|
|
18645
|
+
const { listenToCamera } = useDahuaService();
|
|
18646
|
+
await listenToCamera({ _id, status: "deleted" });
|
|
18424
18647
|
delCachedData();
|
|
18425
18648
|
return "Successfully deleted site camera.";
|
|
18426
18649
|
} catch (error) {
|
|
@@ -19258,7 +19481,7 @@ function useBuildingRepo() {
|
|
|
19258
19481
|
}
|
|
19259
19482
|
}
|
|
19260
19483
|
}
|
|
19261
|
-
async function getBuildingLevel(site, block) {
|
|
19484
|
+
async function getBuildingLevel(site, block, isVMS) {
|
|
19262
19485
|
try {
|
|
19263
19486
|
site = new import_mongodb49.ObjectId(site);
|
|
19264
19487
|
} catch (error) {
|
|
@@ -19268,8 +19491,7 @@ function useBuildingRepo() {
|
|
|
19268
19491
|
site,
|
|
19269
19492
|
block
|
|
19270
19493
|
};
|
|
19271
|
-
const
|
|
19272
|
-
const cacheKey = (0, import_node_server_utils82.makeCacheKey)(buildings_namespace_collection, cacheOptions);
|
|
19494
|
+
const cacheKey = (0, import_node_server_utils82.makeCacheKey)(buildings_namespace_collection, { ...query, isVMS });
|
|
19273
19495
|
try {
|
|
19274
19496
|
const cached = await getCache(cacheKey);
|
|
19275
19497
|
if (cached) {
|
|
@@ -19279,7 +19501,24 @@ function useBuildingRepo() {
|
|
|
19279
19501
|
});
|
|
19280
19502
|
return cached;
|
|
19281
19503
|
}
|
|
19282
|
-
const
|
|
19504
|
+
const pipeline = [{ $match: { ...query } }];
|
|
19505
|
+
if (isVMS) {
|
|
19506
|
+
pipeline.push({
|
|
19507
|
+
$lookup: {
|
|
19508
|
+
from: "building-levels",
|
|
19509
|
+
let: { id: "$_id" },
|
|
19510
|
+
pipeline: [
|
|
19511
|
+
{
|
|
19512
|
+
$match: {
|
|
19513
|
+
$expr: { $eq: ["$block", "$$id"] }
|
|
19514
|
+
}
|
|
19515
|
+
}
|
|
19516
|
+
],
|
|
19517
|
+
as: "building_levels"
|
|
19518
|
+
}
|
|
19519
|
+
});
|
|
19520
|
+
}
|
|
19521
|
+
const result = await collection.aggregate(pipeline).toArray();
|
|
19283
19522
|
setCache(cacheKey, result, 300).then(() => {
|
|
19284
19523
|
import_node_server_utils82.logger.log({
|
|
19285
19524
|
level: "info",
|
|
@@ -19467,6 +19706,9 @@ function useBuildingService() {
|
|
|
19467
19706
|
// src/controllers/building.controller.ts
|
|
19468
19707
|
var import_node_server_utils84 = require("@7365admin1/node-server-utils");
|
|
19469
19708
|
var import_joi44 = __toESM(require("joi"));
|
|
19709
|
+
var import_exceljs = __toESM(require("exceljs"));
|
|
19710
|
+
var import_csv_parser = __toESM(require("csv-parser"));
|
|
19711
|
+
var import_fs2 = __toESM(require("fs"));
|
|
19470
19712
|
function useBuildingController() {
|
|
19471
19713
|
const {
|
|
19472
19714
|
getAll: _getAll,
|
|
@@ -19488,7 +19730,10 @@ function useBuildingController() {
|
|
|
19488
19730
|
serial: import_joi44.default.string().optional().allow("", null),
|
|
19489
19731
|
status: import_joi44.default.string().optional().allow("", null),
|
|
19490
19732
|
// buildingFloorPlan: Joi.array().items(Joi.string()).optional(),
|
|
19491
|
-
buildingFiles: import_joi44.default.array().items({
|
|
19733
|
+
buildingFiles: import_joi44.default.array().items({
|
|
19734
|
+
id: import_joi44.default.string().hex().optional().allow("", null),
|
|
19735
|
+
name: import_joi44.default.string().optional().allow("", null)
|
|
19736
|
+
}).optional().allow("", null)
|
|
19492
19737
|
});
|
|
19493
19738
|
const { error } = validation.validate(value);
|
|
19494
19739
|
if (error) {
|
|
@@ -19608,6 +19853,7 @@ function useBuildingController() {
|
|
|
19608
19853
|
async function getBuildingLevel(req, res, next) {
|
|
19609
19854
|
const site = req.params.site ?? "";
|
|
19610
19855
|
let block = req.query.block;
|
|
19856
|
+
const isVMS = req.query.isVMS;
|
|
19611
19857
|
const validation = import_joi44.default.object({
|
|
19612
19858
|
site: import_joi44.default.string().hex().required(),
|
|
19613
19859
|
block: import_joi44.default.number().required()
|
|
@@ -19619,20 +19865,132 @@ function useBuildingController() {
|
|
|
19619
19865
|
}
|
|
19620
19866
|
block = parseInt(block) ?? 0;
|
|
19621
19867
|
try {
|
|
19622
|
-
const siteBlock = await _getBuildingLevel(site, block);
|
|
19868
|
+
const siteBlock = await _getBuildingLevel(site, block, isVMS);
|
|
19623
19869
|
res.json(siteBlock);
|
|
19624
19870
|
return;
|
|
19625
19871
|
} catch (error2) {
|
|
19626
19872
|
next(error2);
|
|
19627
19873
|
}
|
|
19628
19874
|
}
|
|
19875
|
+
async function uploadSpreadsheetBuilding(req, res, next) {
|
|
19876
|
+
try {
|
|
19877
|
+
if (!req.file) {
|
|
19878
|
+
next(new import_node_server_utils84.BadRequestError("Spreadsheet file is required."));
|
|
19879
|
+
return;
|
|
19880
|
+
}
|
|
19881
|
+
const { originalname, path: path4 } = req.file;
|
|
19882
|
+
const lowerName = originalname.toLowerCase();
|
|
19883
|
+
const rowSchema = import_joi44.default.object({
|
|
19884
|
+
block: import_joi44.default.number().integer().min(0).required(),
|
|
19885
|
+
level: import_joi44.default.string().optional().allow(null, ""),
|
|
19886
|
+
unit: import_joi44.default.string().optional().allow(null, ""),
|
|
19887
|
+
category: import_joi44.default.string().trim().required(),
|
|
19888
|
+
name: import_joi44.default.string().trim().optional().allow(null, ""),
|
|
19889
|
+
email: import_joi44.default.string().email().lowercase().optional().allow(null, ""),
|
|
19890
|
+
phoneNumber: import_joi44.default.string().trim().optional().allow(null, "")
|
|
19891
|
+
});
|
|
19892
|
+
const querySchema = import_joi44.default.object({
|
|
19893
|
+
site: import_joi44.default.string().hex().length(24).required(),
|
|
19894
|
+
org: import_joi44.default.string().hex().length(24).optional().allow(null, "")
|
|
19895
|
+
});
|
|
19896
|
+
const { error: queryError, value: queryValue } = querySchema.validate(
|
|
19897
|
+
req.query,
|
|
19898
|
+
{ abortEarly: false, convert: true }
|
|
19899
|
+
);
|
|
19900
|
+
if (queryError) {
|
|
19901
|
+
next(
|
|
19902
|
+
new import_node_server_utils84.BadRequestError(
|
|
19903
|
+
queryError.details.map((d) => d.message).join(", ")
|
|
19904
|
+
)
|
|
19905
|
+
);
|
|
19906
|
+
return;
|
|
19907
|
+
}
|
|
19908
|
+
const { site, org } = queryValue;
|
|
19909
|
+
let rows = [];
|
|
19910
|
+
if (lowerName.endsWith(".xlsx") || lowerName.endsWith(".xls")) {
|
|
19911
|
+
const workbook = new import_exceljs.default.Workbook();
|
|
19912
|
+
await workbook.xlsx.readFile(path4);
|
|
19913
|
+
const worksheet = workbook.worksheets[0];
|
|
19914
|
+
if (!worksheet) {
|
|
19915
|
+
next(
|
|
19916
|
+
new import_node_server_utils84.BadRequestError("No worksheet found in uploaded Excel file.")
|
|
19917
|
+
);
|
|
19918
|
+
return;
|
|
19919
|
+
}
|
|
19920
|
+
const headerRow = worksheet.getRow(1);
|
|
19921
|
+
const headers = (headerRow.values || []).slice(1).map(
|
|
19922
|
+
(header) => String(header ?? "").trim().replace(/\(.*\)/, "").trim()
|
|
19923
|
+
);
|
|
19924
|
+
worksheet.eachRow((row, rowNumber) => {
|
|
19925
|
+
if (rowNumber === 1)
|
|
19926
|
+
return;
|
|
19927
|
+
const rowData = {};
|
|
19928
|
+
headers.forEach((header, index) => {
|
|
19929
|
+
rowData[header] = row.getCell(index + 1).value ?? "";
|
|
19930
|
+
});
|
|
19931
|
+
if (Object.values(rowData).some(
|
|
19932
|
+
(v) => v !== "" && v !== null && v !== void 0
|
|
19933
|
+
)) {
|
|
19934
|
+
rows.push(rowData);
|
|
19935
|
+
}
|
|
19936
|
+
});
|
|
19937
|
+
} else if (lowerName.endsWith(".csv")) {
|
|
19938
|
+
rows = await new Promise((resolve, reject) => {
|
|
19939
|
+
const parsed = [];
|
|
19940
|
+
import_fs2.default.createReadStream(path4).pipe((0, import_csv_parser.default)()).on("headers", (headers) => {
|
|
19941
|
+
headers = headers.map(
|
|
19942
|
+
(h) => h.trim().replace(/\(.*\)/, "").trim()
|
|
19943
|
+
);
|
|
19944
|
+
}).on("data", (row) => parsed.push(row)).on("end", () => resolve(parsed)).on("error", reject);
|
|
19945
|
+
});
|
|
19946
|
+
} else {
|
|
19947
|
+
next(
|
|
19948
|
+
new import_node_server_utils84.BadRequestError("Only .xlsx, .xls, or .csv files are allowed.")
|
|
19949
|
+
);
|
|
19950
|
+
return;
|
|
19951
|
+
}
|
|
19952
|
+
const validRows = [];
|
|
19953
|
+
const invalidRows = [];
|
|
19954
|
+
rows.forEach((row, index) => {
|
|
19955
|
+
const { error, value } = rowSchema.validate(row, {
|
|
19956
|
+
abortEarly: false,
|
|
19957
|
+
stripUnknown: true
|
|
19958
|
+
});
|
|
19959
|
+
if (error) {
|
|
19960
|
+
invalidRows.push({
|
|
19961
|
+
row: index + 2,
|
|
19962
|
+
data: row,
|
|
19963
|
+
errors: error.details.map((d) => d.message)
|
|
19964
|
+
});
|
|
19965
|
+
} else {
|
|
19966
|
+
validRows.push(value);
|
|
19967
|
+
}
|
|
19968
|
+
});
|
|
19969
|
+
res.status(200).json({
|
|
19970
|
+
message: "Spreadsheet import completed (buildings).",
|
|
19971
|
+
fileName: originalname,
|
|
19972
|
+
totalRows: rows.length,
|
|
19973
|
+
validRows: validRows.length,
|
|
19974
|
+
invalidRows: invalidRows.length,
|
|
19975
|
+
validationErrors: invalidRows,
|
|
19976
|
+
data: validRows
|
|
19977
|
+
// testing: return the validated building rows directly
|
|
19978
|
+
});
|
|
19979
|
+
import_fs2.default.unlink(path4, () => {
|
|
19980
|
+
});
|
|
19981
|
+
} catch (error) {
|
|
19982
|
+
import_node_server_utils84.logger.log({ level: "error", message: error.message });
|
|
19983
|
+
next(error);
|
|
19984
|
+
}
|
|
19985
|
+
}
|
|
19629
19986
|
return {
|
|
19630
19987
|
createBuilding,
|
|
19631
19988
|
getAll,
|
|
19632
19989
|
getById,
|
|
19633
19990
|
updateById,
|
|
19634
19991
|
deleteById,
|
|
19635
|
-
getBuildingLevel
|
|
19992
|
+
getBuildingLevel,
|
|
19993
|
+
uploadSpreadsheetBuilding
|
|
19636
19994
|
};
|
|
19637
19995
|
}
|
|
19638
19996
|
|
|
@@ -19948,9 +20306,9 @@ function useBuildingUnitController() {
|
|
|
19948
20306
|
// src/controllers/vehicle.controller.ts
|
|
19949
20307
|
var import_node_server_utils87 = require("@7365admin1/node-server-utils");
|
|
19950
20308
|
var import_joi46 = __toESM(require("joi"));
|
|
19951
|
-
var
|
|
19952
|
-
var
|
|
19953
|
-
var
|
|
20309
|
+
var import_exceljs2 = __toESM(require("exceljs"));
|
|
20310
|
+
var import_csv_parser2 = __toESM(require("csv-parser"));
|
|
20311
|
+
var import_fs3 = __toESM(require("fs"));
|
|
19954
20312
|
function useVehicleController() {
|
|
19955
20313
|
const {
|
|
19956
20314
|
add: _add,
|
|
@@ -20070,7 +20428,7 @@ function useVehicleController() {
|
|
|
20070
20428
|
const { site, org } = queryValue;
|
|
20071
20429
|
let rows = [];
|
|
20072
20430
|
if (lowerName.endsWith(".xlsx") || lowerName.endsWith(".xls")) {
|
|
20073
|
-
const workbook = new
|
|
20431
|
+
const workbook = new import_exceljs2.default.Workbook();
|
|
20074
20432
|
await workbook.xlsx.readFile(path4);
|
|
20075
20433
|
const worksheet = workbook.worksheets[0];
|
|
20076
20434
|
if (!worksheet) {
|
|
@@ -20099,7 +20457,7 @@ function useVehicleController() {
|
|
|
20099
20457
|
} else if (lowerName.endsWith(".csv")) {
|
|
20100
20458
|
rows = await new Promise((resolve, reject) => {
|
|
20101
20459
|
const parsed = [];
|
|
20102
|
-
|
|
20460
|
+
import_fs3.default.createReadStream(path4).pipe((0, import_csv_parser2.default)()).on("headers", (headers) => {
|
|
20103
20461
|
headers = headers.map(
|
|
20104
20462
|
(h) => h.trim().replace(/\(.*\)/, "").trim()
|
|
20105
20463
|
);
|
|
@@ -20142,7 +20500,7 @@ function useVehicleController() {
|
|
|
20142
20500
|
validationErrors: invalidRows,
|
|
20143
20501
|
data
|
|
20144
20502
|
});
|
|
20145
|
-
|
|
20503
|
+
import_fs3.default.unlink(path4, () => {
|
|
20146
20504
|
});
|
|
20147
20505
|
} catch (error) {
|
|
20148
20506
|
import_node_server_utils87.logger.log({ level: "error", message: error.message });
|
|
@@ -20536,8 +20894,9 @@ function useSiteCameraService() {
|
|
|
20536
20894
|
try {
|
|
20537
20895
|
session.startTransaction();
|
|
20538
20896
|
await _add(value, session);
|
|
20897
|
+
const message = value.type === "ip" ? "CCTV(s) added successfully." : "ANPR(s) added successfully.";
|
|
20539
20898
|
await session.commitTransaction();
|
|
20540
|
-
return
|
|
20899
|
+
return message;
|
|
20541
20900
|
} catch (error2) {
|
|
20542
20901
|
await session.abortTransaction();
|
|
20543
20902
|
throw error2;
|
|
@@ -33671,7 +34030,7 @@ var import_node_server_utils153 = require("@7365admin1/node-server-utils");
|
|
|
33671
34030
|
var import_mongodb90 = require("mongodb");
|
|
33672
34031
|
|
|
33673
34032
|
// src/utils/access-management.ts
|
|
33674
|
-
var
|
|
34033
|
+
var import_fs4 = __toESM(require("fs"));
|
|
33675
34034
|
var import_path = __toESM(require("path"));
|
|
33676
34035
|
var import_axios = __toESM(require("axios"));
|
|
33677
34036
|
var import_xml2js = require("xml2js");
|
|
@@ -33701,7 +34060,7 @@ var minifyXml = (xml) => {
|
|
|
33701
34060
|
return xml.replace(/>\s+</g, "><").replace(/\n/g, "").replace(/\r/g, "").replace(/\t/g, "").trim();
|
|
33702
34061
|
};
|
|
33703
34062
|
var readTemplate = (name, params) => {
|
|
33704
|
-
const template =
|
|
34063
|
+
const template = import_fs4.default.readFileSync(
|
|
33705
34064
|
import_path.default.join(__dirname, `../dist/public/xml-templates/${name}.xml`),
|
|
33706
34065
|
"utf-8"
|
|
33707
34066
|
);
|
|
@@ -33832,14 +34191,14 @@ var import_xml2js2 = require("xml2js");
|
|
|
33832
34191
|
|
|
33833
34192
|
// src/utils/rsa-encryption.ts
|
|
33834
34193
|
var crypto2 = __toESM(require("crypto"));
|
|
33835
|
-
var
|
|
34194
|
+
var import_fs5 = __toESM(require("fs"));
|
|
33836
34195
|
var import_path2 = __toESM(require("path"));
|
|
33837
34196
|
var pub = import_path2.default.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_pub.pem");
|
|
33838
34197
|
var priv = import_path2.default.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_priv.pem");
|
|
33839
34198
|
var EncryptionCredentials = class {
|
|
33840
34199
|
};
|
|
33841
|
-
EncryptionCredentials.RAW_PUBLIC_KEY =
|
|
33842
|
-
EncryptionCredentials.RAW_PRIVATE_KEY =
|
|
34200
|
+
EncryptionCredentials.RAW_PUBLIC_KEY = import_fs5.default.readFileSync(pub, "utf8");
|
|
34201
|
+
EncryptionCredentials.RAW_PRIVATE_KEY = import_fs5.default.readFileSync(priv, "utf8");
|
|
33843
34202
|
var EntrypassRSAEncryption = class extends EncryptionCredentials {
|
|
33844
34203
|
static hexToCardNumber(hex) {
|
|
33845
34204
|
if (!/^[0-9A-Fa-f]{8}$/.test(hex)) {
|