tabletcommand-backend-models 7.4.113 → 7.4.115
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/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/models/department.js +36 -1
- package/build/models/department.js.map +1 -1
- package/build/models/zonehaven-account.js +67 -0
- package/build/models/zonehaven-account.js.map +1 -0
- package/build/test/0index.js +1 -0
- package/build/test/0index.js.map +1 -1
- package/build/test/department.js +32 -0
- package/build/test/department.js.map +1 -1
- package/build/test/mock.js +16 -0
- package/build/test/mock.js.map +1 -1
- package/build/test/zonehaven-account.js +64 -0
- package/build/test/zonehaven-account.js.map +1 -0
- package/build/types/zonehaven-account.js +3 -0
- package/build/types/zonehaven-account.js.map +1 -0
- package/definitions/index.d.ts +8 -1
- package/definitions/index.d.ts.map +1 -1
- package/definitions/models/department.d.ts +3 -1
- package/definitions/models/department.d.ts.map +1 -1
- package/definitions/models/zonehaven-account.d.ts +13 -0
- package/definitions/models/zonehaven-account.d.ts.map +1 -0
- package/definitions/test/mock.d.ts +2 -0
- package/definitions/test/mock.d.ts.map +1 -1
- package/definitions/test/zonehaven-account.d.ts +2 -0
- package/definitions/test/zonehaven-account.d.ts.map +1 -0
- package/definitions/types/department.d.ts +9 -0
- package/definitions/types/department.d.ts.map +1 -1
- package/definitions/types/zonehaven-account.d.ts +15 -0
- package/definitions/types/zonehaven-account.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +8 -0
- package/src/models/department.ts +40 -0
- package/src/models/zonehaven-account.ts +78 -0
- package/src/test/0index.ts +1 -0
- package/src/test/department.ts +35 -0
- package/src/test/mock.ts +18 -0
- package/src/test/zonehaven-account.ts +70 -0
- package/src/types/department.ts +12 -0
- package/src/types/zonehaven-account.ts +15 -0
package/src/models/department.ts
CHANGED
|
@@ -80,6 +80,8 @@ import {
|
|
|
80
80
|
OneStepConfigurationType,
|
|
81
81
|
DroneSenseConfigurationType,
|
|
82
82
|
DronesConfigurationType,
|
|
83
|
+
DronesVideoType,
|
|
84
|
+
DronesVideoUrlsType,
|
|
83
85
|
USFTConfigurationType,
|
|
84
86
|
VehicleStatusWebhookConfigType,
|
|
85
87
|
VehicleStatusWebhookConnectionType,
|
|
@@ -548,8 +550,14 @@ export const DroneSenseConfigurationDefault = {
|
|
|
548
550
|
apiKey: "",
|
|
549
551
|
};
|
|
550
552
|
|
|
553
|
+
export const DronesVideoDefault: DronesVideoType = {
|
|
554
|
+
sources: [],
|
|
555
|
+
urls: { web: "" },
|
|
556
|
+
};
|
|
557
|
+
|
|
551
558
|
export const DronesConfigurationDefault = {
|
|
552
559
|
enabled: false,
|
|
560
|
+
video: DronesVideoDefault,
|
|
553
561
|
};
|
|
554
562
|
|
|
555
563
|
export const OrientationMarkerColorDefault: ColorSchemaType = {
|
|
@@ -1534,11 +1542,39 @@ export default async function DepartmentModule(mongoose: MongooseModule) {
|
|
|
1534
1542
|
id: false,
|
|
1535
1543
|
});
|
|
1536
1544
|
|
|
1545
|
+
const DronesVideoUrls = new Schema<DronesVideoUrlsType>({
|
|
1546
|
+
web: {
|
|
1547
|
+
type: String,
|
|
1548
|
+
default: "",
|
|
1549
|
+
},
|
|
1550
|
+
}, {
|
|
1551
|
+
_id: false,
|
|
1552
|
+
id: false,
|
|
1553
|
+
});
|
|
1554
|
+
|
|
1555
|
+
const DronesVideo = new Schema<DronesVideoType>({
|
|
1556
|
+
sources: {
|
|
1557
|
+
type: [String],
|
|
1558
|
+
default: [],
|
|
1559
|
+
},
|
|
1560
|
+
urls: {
|
|
1561
|
+
type: DronesVideoUrls,
|
|
1562
|
+
default: () => ({ web: "" }),
|
|
1563
|
+
},
|
|
1564
|
+
}, {
|
|
1565
|
+
_id: false,
|
|
1566
|
+
id: false,
|
|
1567
|
+
});
|
|
1568
|
+
|
|
1537
1569
|
const DronesConfiguration = new Schema<DronesConfigurationType>({
|
|
1538
1570
|
enabled: {
|
|
1539
1571
|
type: Boolean,
|
|
1540
1572
|
default: false,
|
|
1541
1573
|
},
|
|
1574
|
+
video: {
|
|
1575
|
+
type: DronesVideo,
|
|
1576
|
+
default: () => ({ sources: [], urls: { web: "" } }),
|
|
1577
|
+
},
|
|
1542
1578
|
}, {
|
|
1543
1579
|
_id: false,
|
|
1544
1580
|
id: false,
|
|
@@ -2393,6 +2429,10 @@ export default async function DepartmentModule(mongoose: MongooseModule) {
|
|
|
2393
2429
|
type: Number,
|
|
2394
2430
|
default: 45000,
|
|
2395
2431
|
},
|
|
2432
|
+
accountName: {
|
|
2433
|
+
type: String,
|
|
2434
|
+
default: "",
|
|
2435
|
+
},
|
|
2396
2436
|
},
|
|
2397
2437
|
|
|
2398
2438
|
watchDuty: {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MongooseModule,
|
|
3
|
+
} from "../helpers";
|
|
4
|
+
import { Model } from "mongoose";
|
|
5
|
+
import { ZonehavenAccountType } from "../types/zonehaven-account";
|
|
6
|
+
import { EncryptedDataType } from "../types/common";
|
|
7
|
+
|
|
8
|
+
export interface ZonehavenAccount extends ZonehavenAccountType { }
|
|
9
|
+
|
|
10
|
+
export default async function ZonehavenAccountModule(mongoose: MongooseModule) {
|
|
11
|
+
const { Schema } = mongoose;
|
|
12
|
+
|
|
13
|
+
const EncryptedData = new Schema<EncryptedDataType>({
|
|
14
|
+
iv: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: "",
|
|
17
|
+
},
|
|
18
|
+
encryptedData: {
|
|
19
|
+
type: String,
|
|
20
|
+
default: "",
|
|
21
|
+
},
|
|
22
|
+
}, {
|
|
23
|
+
_id: false,
|
|
24
|
+
id: false,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const modelSchema = new Schema<ZonehavenAccountType>({
|
|
28
|
+
_id: {
|
|
29
|
+
type: Schema.Types.ObjectId,
|
|
30
|
+
auto: true,
|
|
31
|
+
},
|
|
32
|
+
name: {
|
|
33
|
+
type: String,
|
|
34
|
+
required: true,
|
|
35
|
+
immutable: true,
|
|
36
|
+
},
|
|
37
|
+
url: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: "",
|
|
40
|
+
},
|
|
41
|
+
username: {
|
|
42
|
+
type: String,
|
|
43
|
+
default: "",
|
|
44
|
+
},
|
|
45
|
+
password: {
|
|
46
|
+
type: EncryptedData,
|
|
47
|
+
default: null,
|
|
48
|
+
},
|
|
49
|
+
token: {
|
|
50
|
+
type: String,
|
|
51
|
+
default: null,
|
|
52
|
+
},
|
|
53
|
+
expireAt: {
|
|
54
|
+
type: Date,
|
|
55
|
+
},
|
|
56
|
+
referer: {
|
|
57
|
+
type: String,
|
|
58
|
+
default: null,
|
|
59
|
+
},
|
|
60
|
+
}, {
|
|
61
|
+
autoIndex: false,
|
|
62
|
+
timestamps: true,
|
|
63
|
+
toJSON: {
|
|
64
|
+
versionKey: false,
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
modelSchema.index({
|
|
69
|
+
name: 1,
|
|
70
|
+
}, {
|
|
71
|
+
name: "name_1_unique",
|
|
72
|
+
unique: true,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return mongoose.model<ZonehavenAccount>("ZonehavenAccount", modelSchema, "massive_zonehaven_account", { overwriteModels: true });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface ZonehavenAccountModel extends Model<ZonehavenAccount> { }
|
package/src/test/0index.ts
CHANGED
|
@@ -79,5 +79,6 @@ describe(" Models", function() {
|
|
|
79
79
|
assert.isFunction(models.UserRegistration, "Missing UserRegistration");
|
|
80
80
|
assert.isFunction(models.ValidationReport, "Missing ValidationReport");
|
|
81
81
|
assert.isFunction(models.WatchDutyEvent, "Missing WatchDutyEvent");
|
|
82
|
+
assert.isFunction(models.ZonehavenAccount, "Missing ZonehavenAccount");
|
|
82
83
|
});
|
|
83
84
|
});
|
package/src/test/department.ts
CHANGED
|
@@ -145,6 +145,41 @@ describe("Department", function () {
|
|
|
145
145
|
assert.isFalse(sut.drones.enabled);
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
+
it("defaults drones.video to no sources and an empty web url", async function () {
|
|
149
|
+
const item = new models.Department(testItem);
|
|
150
|
+
const sut = await item.save();
|
|
151
|
+
assert.deepEqual(sut.drones.video.sources, []);
|
|
152
|
+
assert.equal(sut.drones.video.urls.web, "");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("saves drones.video sources and urls, with no subdocument _id", async function () {
|
|
156
|
+
const item = new models.Department({
|
|
157
|
+
...testItem,
|
|
158
|
+
drones: {
|
|
159
|
+
enabled: true,
|
|
160
|
+
video: {
|
|
161
|
+
sources: ["Skydio"],
|
|
162
|
+
urls: { web: "https://video.example.com/player/{uuid}?token={token}" },
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
const sut = await item.save();
|
|
167
|
+
assert.deepEqual(sut.drones.video.sources, ["Skydio"]);
|
|
168
|
+
assert.equal(sut.drones.video.urls.web, "https://video.example.com/player/{uuid}?token={token}");
|
|
169
|
+
assert.isUndefined((sut.drones.video as unknown as { _id?: unknown })._id);
|
|
170
|
+
assert.isUndefined((sut.drones.video.urls as unknown as { _id?: unknown })._id);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("loads drones.video with defaults for a document saved without drones", async function () {
|
|
174
|
+
const legacyItem = { ...testItem };
|
|
175
|
+
delete legacyItem.drones;
|
|
176
|
+
const item = new models.Department(legacyItem);
|
|
177
|
+
const sut = await item.save();
|
|
178
|
+
const loaded = await models.Department.findOne({ _id: sut._id });
|
|
179
|
+
assert.deepEqual(loaded?.drones.video.sources, []);
|
|
180
|
+
assert.equal(loaded?.drones.video.urls.web, "");
|
|
181
|
+
});
|
|
182
|
+
|
|
148
183
|
it("saves samsara.tagIds and defaults it to an empty array", async function () {
|
|
149
184
|
const item = new models.Department({
|
|
150
185
|
...testItem,
|
package/src/test/mock.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { IncidentNotified } from "../models/incident-notified";
|
|
|
18
18
|
import { Location } from "../models/location";
|
|
19
19
|
import { ManagedIncident } from "../models/managed-incident";
|
|
20
20
|
import { SAML } from "../models/saml";
|
|
21
|
+
import { ZonehavenAccountType } from "../types/zonehaven-account";
|
|
21
22
|
|
|
22
23
|
export default function mockModule(dependencies: { mongoose: Mongoose; }) {
|
|
23
24
|
function shouldRun() {
|
|
@@ -1031,6 +1032,22 @@ export default function mockModule(dependencies: { mongoose: Mongoose; }) {
|
|
|
1031
1032
|
watchDutyModifiedAt: new Date("2025-08-02T11:00:00.000Z"),
|
|
1032
1033
|
};
|
|
1033
1034
|
|
|
1035
|
+
const zonehavenAccount: ZonehavenAccountType = {
|
|
1036
|
+
_id: new mongoose.Types.ObjectId(),
|
|
1037
|
+
name: "default",
|
|
1038
|
+
url: "https://agservergenasys.zonehaven.com/arcgis/rest/services/tc_data/FeatureServer/0",
|
|
1039
|
+
username: "zonehaven-user",
|
|
1040
|
+
password: {
|
|
1041
|
+
iv: "18f17",
|
|
1042
|
+
encryptedData: "dee54",
|
|
1043
|
+
},
|
|
1044
|
+
token: "test-zonehaven-token",
|
|
1045
|
+
expireAt: new Date("2025-12-12T01:02:03.000Z"),
|
|
1046
|
+
referer: "tabletcommand.com",
|
|
1047
|
+
createdAt: new Date("2025-11-10T20:01:01.111+0000"),
|
|
1048
|
+
updatedAt: new Date("2025-11-20T20:02:02.222+0000"),
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1034
1051
|
const dataSharingAgreement = {
|
|
1035
1052
|
departmentId: "5195426cc4e016a988000965",
|
|
1036
1053
|
departmentName: "Test Department",
|
|
@@ -1739,5 +1756,6 @@ export default function mockModule(dependencies: { mongoose: Mongoose; }) {
|
|
|
1739
1756
|
userRegistration,
|
|
1740
1757
|
validationReport,
|
|
1741
1758
|
watchDutyEvent,
|
|
1759
|
+
zonehavenAccount,
|
|
1742
1760
|
};
|
|
1743
1761
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { assert } from "chai";
|
|
2
|
+
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
3
|
+
import { isDate } from "lodash";
|
|
4
|
+
|
|
5
|
+
import * as m from "../index";
|
|
6
|
+
import * as config from "./config";
|
|
7
|
+
import mockModule from "./mock";
|
|
8
|
+
|
|
9
|
+
describe("ZonehavenAccount", function() {
|
|
10
|
+
let models: m.BackendModels, mongoose: m.MongooseModule;
|
|
11
|
+
let testItem: Partial<m.ZonehavenAccount>;
|
|
12
|
+
beforeEach(async function() {
|
|
13
|
+
const c = await m.connect(config.url);
|
|
14
|
+
models = c.models;
|
|
15
|
+
mongoose = c.mongoose;
|
|
16
|
+
const mock = mockModule({
|
|
17
|
+
mongoose
|
|
18
|
+
});
|
|
19
|
+
testItem = mock.zonehavenAccount;
|
|
20
|
+
await mock.beforeEach();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(async function() {
|
|
24
|
+
await mongoose.disconnect();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("is saved", async function() {
|
|
28
|
+
assert.isObject(testItem);
|
|
29
|
+
const item = new models.ZonehavenAccount(testItem);
|
|
30
|
+
const sut = await item.save();
|
|
31
|
+
assert.isNotNull(sut._id);
|
|
32
|
+
assert.isNotNull(sut.id);
|
|
33
|
+
assert.equal(sut._id.toString(), testItem._id?.toString());
|
|
34
|
+
|
|
35
|
+
assert.equal(sut.name, "default");
|
|
36
|
+
assert.equal(sut.url, testItem.url);
|
|
37
|
+
assert.equal(sut.username, testItem.username);
|
|
38
|
+
|
|
39
|
+
assert.isObject(sut.password);
|
|
40
|
+
assert.equal(sut.password?.iv, testItem.password?.iv);
|
|
41
|
+
assert.equal(sut.password?.encryptedData, testItem.password?.encryptedData);
|
|
42
|
+
|
|
43
|
+
assert.equal(sut.token, testItem.token);
|
|
44
|
+
assert.isTrue(isDate(sut.expireAt));
|
|
45
|
+
assert.equal(sut.expireAt?.toISOString(), testItem.expireAt?.toISOString());
|
|
46
|
+
assert.equal(sut.referer, testItem.referer);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("enforces a unique name", async function() {
|
|
50
|
+
const item = new models.ZonehavenAccount(testItem);
|
|
51
|
+
await item.save();
|
|
52
|
+
|
|
53
|
+
const duplicate = new models.ZonehavenAccount({ ...testItem, _id: new mongoose.Types.ObjectId() });
|
|
54
|
+
try {
|
|
55
|
+
await duplicate.save();
|
|
56
|
+
assert.fail("Should have thrown duplicate key error");
|
|
57
|
+
} catch (error) {
|
|
58
|
+
assert.include(String((error as Error).message), "duplicate key");
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("does not allow changing name after creation", async function() {
|
|
63
|
+
const item = new models.ZonehavenAccount(testItem);
|
|
64
|
+
const sut = await item.save();
|
|
65
|
+
|
|
66
|
+
sut.name = "demo";
|
|
67
|
+
const saved = await sut.save();
|
|
68
|
+
assert.equal(saved.name, "default");
|
|
69
|
+
});
|
|
70
|
+
});
|
package/src/types/department.ts
CHANGED
|
@@ -359,8 +359,18 @@ export interface DroneSenseConfigurationType {
|
|
|
359
359
|
apiKey: string,
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
+
export interface DronesVideoUrlsType {
|
|
363
|
+
web: string,
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export interface DronesVideoType {
|
|
367
|
+
sources: string[],
|
|
368
|
+
urls: DronesVideoUrlsType,
|
|
369
|
+
}
|
|
370
|
+
|
|
362
371
|
export interface DronesConfigurationType {
|
|
363
372
|
enabled: boolean,
|
|
373
|
+
video: DronesVideoType,
|
|
364
374
|
}
|
|
365
375
|
|
|
366
376
|
export interface FireMapperConfigurationType {
|
|
@@ -567,6 +577,8 @@ export type AccountConfigurationZonehaven = {
|
|
|
567
577
|
visible: boolean,
|
|
568
578
|
layerUrl: string,
|
|
569
579
|
fadeZoomLevel: number,
|
|
580
|
+
// References ZonehavenAccount.name - empty string means unassigned/legacy fallback.
|
|
581
|
+
accountName: string,
|
|
570
582
|
};
|
|
571
583
|
|
|
572
584
|
export type AccountConfigurationWatchDuty = {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Types } from "mongoose";
|
|
2
|
+
import { EncryptedDataType } from "./common";
|
|
3
|
+
|
|
4
|
+
export interface ZonehavenAccountType {
|
|
5
|
+
_id: Types.ObjectId,
|
|
6
|
+
name: string, // "default", "demo" - unique, immutable once set
|
|
7
|
+
url: string,
|
|
8
|
+
username: string,
|
|
9
|
+
password: EncryptedDataType | null,
|
|
10
|
+
token: string | null,
|
|
11
|
+
expireAt: Date | null,
|
|
12
|
+
referer: string | null,
|
|
13
|
+
createdAt: Date,
|
|
14
|
+
updatedAt: Date,
|
|
15
|
+
}
|