@7365admin1/core 3.79.1-staging.336 → 3.79.1-staging.338
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 +59 -0
- package/dist/index.js +47 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +47 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +68 -68
- package/.changeset/vehicle-one-plate-per-site.md +0 -58
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
# @iservice365/core
|
|
2
2
|
|
|
3
|
+
## 3.80.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- a267a47: Vehicle statuses say which list a vehicle is on, a site holds a plate once
|
|
8
|
+
whatever its status, and every vehicle keeps a history.
|
|
9
|
+
|
|
10
|
+
**Statuses.** A whitelist vehicle is `active`, a season pass `temporary`, a
|
|
11
|
+
blocked vehicle `blocked`. Blocking a resident or season pass puts its plate on
|
|
12
|
+
the blocklist of every active camera except Exit for ten years (whatever the
|
|
13
|
+
pass's own dates) and takes it OFF every camera's allowed list, so no camera
|
|
14
|
+
holds a plate on both lists; approving a pending blocklist vehicle uses the
|
|
15
|
+
same ten years, and a new camera is filled the same way. Unblocking sets `unblocked` and takes the plate off every active camera's
|
|
16
|
+
blocklist by plate number - and off the allowed list too, so an unblocked car
|
|
17
|
+
is on no list rather than quietly whitelisted again. A blocked, unblocked,
|
|
18
|
+
deleted or inactive vehicle can be blocked again in place. Everything that
|
|
19
|
+
writes, syncs, revokes or recognises a plate at the gate now treats `active`,
|
|
20
|
+
`temporary` and `blocked` as live; the gate still recognises a season pass as a
|
|
21
|
+
registered resident until its expiry, and an unblocked plate no longer counts
|
|
22
|
+
as blocked at visitor check-in.
|
|
23
|
+
|
|
24
|
+
**Categories and tabs.** A whitelist vehicle is filed `resident`, a season
|
|
25
|
+
pass `season_pass` (new), and a vehicle added to the blocklist `visitor` or
|
|
26
|
+
`contractor` (new in the vehicle enum; default `visitor`); blocked from a visitor transaction it keeps that type - `delivery`, `pick-up` or `drop-off` (new), a guest as `visitor`. A season pass seen at the gate is logged as a `resident` transaction. Blocking keeps the
|
|
27
|
+
category, so a blocked resident is still `resident`; editing a season pass type
|
|
28
|
+
on or off moves a whitelist vehicle between `resident` and `season_pass`. The
|
|
29
|
+
vehicle list takes `view` - `residents`, `season-passes` or `block-listed` -
|
|
30
|
+
for the three tabs; older season passes saved as `resident` show under Season
|
|
31
|
+
Passes. The gate counts `resident` and `season_pass` as registered.
|
|
32
|
+
|
|
33
|
+
**Update an existing plate from the add form.** `existingPlatesAtSite`
|
|
34
|
+
answers which of the plates being added the site already holds, with each
|
|
35
|
+
record's tab and status; `moveVehicle` saves the form's details on that record
|
|
36
|
+
and moves it to the form's tab (off every camera list, onto the list of its new
|
|
37
|
+
kind; pending for a security agency without the approve permission). Its
|
|
38
|
+
history records "moved".
|
|
39
|
+
|
|
40
|
+
**Sync.** `syncVehicleToCameras` puts a live vehicle's plate on every active
|
|
41
|
+
camera of its list that lacks it (a plate saved while its cameras were
|
|
42
|
+
inactive), camera by camera, and records the cameras that took it;
|
|
43
|
+
`activeCameraCounts` gives the active cameras per list so the screens can offer
|
|
44
|
+
it.
|
|
45
|
+
|
|
46
|
+
**One plate per site.** Adding a plate the site already has - deleted,
|
|
47
|
+
pending, temporary, blocked or unblocked included - is refused with its status
|
|
48
|
+
and "edit the existing vehicle instead" (restore, for a deleted one). The same
|
|
49
|
+
check guards approve, restore and plate edits. Matching ignores case and
|
|
50
|
+
spacing.
|
|
51
|
+
|
|
52
|
+
**History.** `history` holds the last 20 changes - created, updated,
|
|
53
|
+
approved, restored, blocked, unblocked, deleted - each with the user's id, the
|
|
54
|
+
time and the fields that changed. `getSpecificVehicleById` adds each user's
|
|
55
|
+
name.
|
|
56
|
+
|
|
57
|
+
**Also:** the vehicle list returns every status unless one is asked for; the
|
|
58
|
+
camera's record id (`recNo`) is no longer stored; `processDeletingExpiredVehicles`
|
|
59
|
+
is no longer needed (the camera enforces each pass's own expiry) and should be
|
|
60
|
+
unscheduled by the API.
|
|
61
|
+
|
|
3
62
|
## 3.79.0
|
|
4
63
|
|
|
5
64
|
### Minor Changes
|
package/dist/index.js
CHANGED
|
@@ -35163,25 +35163,44 @@ function useVehicleService() {
|
|
|
35163
35163
|
}
|
|
35164
35164
|
return failures;
|
|
35165
35165
|
}
|
|
35166
|
+
const CAMERA_WRITE_ROUNDS = 3;
|
|
35167
|
+
const CAMERA_WRITE_RETRY_DELAY_MS = 3e3;
|
|
35166
35168
|
async function writeToCameras(cameras, write, journal, options = {}) {
|
|
35167
35169
|
const failures = [];
|
|
35168
35170
|
let recNo = "";
|
|
35169
35171
|
for (const camera of cameras) {
|
|
35170
|
-
|
|
35171
|
-
|
|
35172
|
-
|
|
35173
|
-
|
|
35172
|
+
for (let round = 1; ; round++) {
|
|
35173
|
+
try {
|
|
35174
|
+
if (options.onlyIfMissing || round > 1) {
|
|
35175
|
+
const { inserted } = await ensurePlateOnCamera(camera, write);
|
|
35176
|
+
if (inserted)
|
|
35177
|
+
journal.inserted(camera, write.mode, write.plateNumber);
|
|
35178
|
+
} else {
|
|
35179
|
+
recNo = await insertPlateOnCamera(camera, write) || recNo;
|
|
35174
35180
|
journal.inserted(camera, write.mode, write.plateNumber);
|
|
35175
|
-
|
|
35176
|
-
|
|
35177
|
-
|
|
35181
|
+
}
|
|
35182
|
+
if (round > 1) {
|
|
35183
|
+
import_node_server_utils109.logger.info(
|
|
35184
|
+
`[${cameraLabel(camera)}] write ${write.mode} went through on round ${round}`
|
|
35185
|
+
);
|
|
35186
|
+
}
|
|
35187
|
+
break;
|
|
35188
|
+
} catch (error) {
|
|
35189
|
+
const transient = classifyDahuaFailure(error?.message ?? error) === "transient";
|
|
35190
|
+
if (transient && round < CAMERA_WRITE_ROUNDS) {
|
|
35191
|
+
logCameraFailure(`write ${write.mode} (round ${round}, retrying)`, camera, error);
|
|
35192
|
+
await new Promise(
|
|
35193
|
+
(resolve) => setTimeout(resolve, CAMERA_WRITE_RETRY_DELAY_MS * round)
|
|
35194
|
+
);
|
|
35195
|
+
continue;
|
|
35196
|
+
}
|
|
35197
|
+
logCameraFailure(`write ${write.mode}`, camera, error);
|
|
35198
|
+
failures.push({
|
|
35199
|
+
camera: cameraLabel(camera),
|
|
35200
|
+
reason: anprWriteReason(error)
|
|
35201
|
+
});
|
|
35202
|
+
break;
|
|
35178
35203
|
}
|
|
35179
|
-
} catch (error) {
|
|
35180
|
-
logCameraFailure(`write ${write.mode}`, camera, error);
|
|
35181
|
-
failures.push({
|
|
35182
|
-
camera: cameraLabel(camera),
|
|
35183
|
-
reason: anprWriteReason(error)
|
|
35184
|
-
});
|
|
35185
35204
|
}
|
|
35186
35205
|
}
|
|
35187
35206
|
return { failures, recNo };
|
|
@@ -35568,6 +35587,9 @@ function useVehicleService() {
|
|
|
35568
35587
|
}
|
|
35569
35588
|
const _plateNumber = String(vehicle.plateNumber ?? "");
|
|
35570
35589
|
const owner = vehicle.name;
|
|
35590
|
+
const approveOutcome = ["deleted", "inactive", "rejected"].includes(
|
|
35591
|
+
String(vehicle.status ?? "")
|
|
35592
|
+
) ? "restored" : "approved";
|
|
35571
35593
|
const isBlocklist = vehicle.type === "blocklist" /* BLOCKLIST */;
|
|
35572
35594
|
const mode = listMode(vehicle.type);
|
|
35573
35595
|
const hasStart = typeof vehicle.start === "string" ? vehicle.start.trim() !== "" : !!vehicle.start;
|
|
@@ -35596,7 +35618,7 @@ function useVehicleService() {
|
|
|
35596
35618
|
const cameraSite = vehicle.site ?? siteId;
|
|
35597
35619
|
const siteCameras = isBlocklist ? await blockCamerasAt(cameraSite) : await allowCamerasAt(cameraSite);
|
|
35598
35620
|
if (!siteCameras.length) {
|
|
35599
|
-
throw new import_node_server_utils109.BadRequestError(anprNoCameraRefusal(
|
|
35621
|
+
throw new import_node_server_utils109.BadRequestError(anprNoCameraRefusal(approveOutcome));
|
|
35600
35622
|
}
|
|
35601
35623
|
const { failures } = await writeToCameras(
|
|
35602
35624
|
siteCameras,
|
|
@@ -35614,7 +35636,7 @@ function useVehicleService() {
|
|
|
35614
35636
|
cameraFailureSentence({
|
|
35615
35637
|
failures,
|
|
35616
35638
|
operation: "added to",
|
|
35617
|
-
outcome:
|
|
35639
|
+
outcome: approveOutcome,
|
|
35618
35640
|
consequence: isBlocklist ? "it would still open the barrier" : "it would not open the barrier"
|
|
35619
35641
|
})
|
|
35620
35642
|
);
|
|
@@ -35725,7 +35747,11 @@ function useVehicleService() {
|
|
|
35725
35747
|
const ownEnd = validDate(vehicle.end);
|
|
35726
35748
|
let startDate;
|
|
35727
35749
|
let endDate;
|
|
35728
|
-
if (
|
|
35750
|
+
if (isBlocklist) {
|
|
35751
|
+
const block = blockWindow();
|
|
35752
|
+
startDate = new Date(block.start);
|
|
35753
|
+
endDate = new Date(block.end);
|
|
35754
|
+
} else if (ownEnd) {
|
|
35729
35755
|
if (ownEnd.getTime() <= Date.now()) {
|
|
35730
35756
|
throw new import_node_server_utils109.BadRequestError(
|
|
35731
35757
|
`This vehicle's expiry date (${dahuaWallClock(
|
|
@@ -40245,6 +40271,10 @@ function useVehicleController() {
|
|
|
40245
40271
|
message: "You do not have permission to view vehicles."
|
|
40246
40272
|
};
|
|
40247
40273
|
const VEHICLE_DETAILS = {
|
|
40274
|
+
permissions: ["vehicle-mgmt:see-vehicle-details"],
|
|
40275
|
+
message: "You do not have permission to view vehicle details."
|
|
40276
|
+
};
|
|
40277
|
+
const VEHICLE_EDIT_READ = {
|
|
40248
40278
|
permissions: [
|
|
40249
40279
|
"vehicle-mgmt:see-vehicle-details",
|
|
40250
40280
|
"vehicle-mgmt:update-vehicle"
|
|
@@ -40651,7 +40681,7 @@ function useVehicleController() {
|
|
|
40651
40681
|
}
|
|
40652
40682
|
const { _id } = value;
|
|
40653
40683
|
try {
|
|
40654
|
-
await requireVehicleReach(req, _id,
|
|
40684
|
+
await requireVehicleReach(req, _id, VEHICLE_EDIT_READ);
|
|
40655
40685
|
const site = await _getSpecificVehicleById(_id);
|
|
40656
40686
|
res.json(site);
|
|
40657
40687
|
return;
|