tabletcommand-backend-models 7.4.111 → 7.4.112
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/constants.js +6 -1
- package/build/constants.js.map +1 -1
- package/build/index.js +3 -1
- package/build/index.js.map +1 -1
- package/build/models/department.js +17 -1
- package/build/models/department.js.map +1 -1
- package/build/models/drone-connection.js +101 -0
- package/build/models/drone-connection.js.map +1 -0
- package/build/models/user.js +4 -0
- package/build/models/user.js.map +1 -1
- package/build/test/department.js +5 -0
- package/build/test/department.js.map +1 -1
- package/build/test/drone-connection.js +152 -0
- package/build/test/drone-connection.js.map +1 -0
- package/build/test/user.js +10 -0
- package/build/test/user.js.map +1 -1
- package/build/types/drone-connection.js +3 -0
- package/build/types/drone-connection.js.map +1 -0
- package/cspell.json +1 -0
- package/definitions/constants.d.ts +4 -0
- package/definitions/constants.d.ts.map +1 -1
- package/definitions/index.d.ts +9 -2
- package/definitions/index.d.ts.map +1 -1
- package/definitions/models/department.d.ts +3 -0
- package/definitions/models/department.d.ts.map +1 -1
- package/definitions/models/drone-connection.d.ts +22 -0
- package/definitions/models/drone-connection.d.ts.map +1 -0
- package/definitions/models/user.d.ts.map +1 -1
- package/definitions/test/drone-connection.d.ts +2 -0
- package/definitions/test/drone-connection.d.ts.map +1 -0
- package/definitions/types/department.d.ts +4 -0
- package/definitions/types/department.d.ts.map +1 -1
- package/definitions/types/drone-connection.d.ts +19 -0
- package/definitions/types/drone-connection.d.ts.map +1 -0
- package/definitions/types/user.d.ts +1 -0
- package/definitions/types/user.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +5 -0
- package/src/index.ts +8 -0
- package/src/models/department.ts +19 -0
- package/src/models/drone-connection.ts +121 -0
- package/src/models/user.ts +4 -0
- package/src/test/department.ts +6 -0
- package/src/test/drone-connection.ts +164 -0
- package/src/test/user.ts +11 -0
- package/src/types/department.ts +5 -0
- package/src/types/drone-connection.ts +21 -0
- package/src/types/user.ts +1 -0
package/src/models/department.ts
CHANGED
|
@@ -79,6 +79,7 @@ import {
|
|
|
79
79
|
UnitStatusCodesConfigType,
|
|
80
80
|
OneStepConfigurationType,
|
|
81
81
|
DroneSenseConfigurationType,
|
|
82
|
+
DronesConfigurationType,
|
|
82
83
|
USFTConfigurationType,
|
|
83
84
|
VehicleStatusWebhookConfigType,
|
|
84
85
|
VehicleStatusWebhookConnectionType,
|
|
@@ -547,6 +548,10 @@ export const DroneSenseConfigurationDefault = {
|
|
|
547
548
|
apiKey: "",
|
|
548
549
|
};
|
|
549
550
|
|
|
551
|
+
export const DronesConfigurationDefault = {
|
|
552
|
+
enabled: false,
|
|
553
|
+
};
|
|
554
|
+
|
|
550
555
|
export const OrientationMarkerColorDefault: ColorSchemaType = {
|
|
551
556
|
background: "#FC2125",
|
|
552
557
|
text: "#FFFFFF",
|
|
@@ -1529,6 +1534,16 @@ export default async function DepartmentModule(mongoose: MongooseModule) {
|
|
|
1529
1534
|
id: false,
|
|
1530
1535
|
});
|
|
1531
1536
|
|
|
1537
|
+
const DronesConfiguration = new Schema<DronesConfigurationType>({
|
|
1538
|
+
enabled: {
|
|
1539
|
+
type: Boolean,
|
|
1540
|
+
default: false,
|
|
1541
|
+
},
|
|
1542
|
+
}, {
|
|
1543
|
+
_id: false,
|
|
1544
|
+
id: false,
|
|
1545
|
+
});
|
|
1546
|
+
|
|
1532
1547
|
const FireMapperConfiguration = new Schema<FireMapperConfigurationType>({
|
|
1533
1548
|
enabled: {
|
|
1534
1549
|
type: Boolean,
|
|
@@ -2410,6 +2425,10 @@ export default async function DepartmentModule(mongoose: MongooseModule) {
|
|
|
2410
2425
|
type: DroneSenseConfiguration,
|
|
2411
2426
|
default: DroneSenseConfigurationDefault,
|
|
2412
2427
|
},
|
|
2428
|
+
drones: {
|
|
2429
|
+
type: DronesConfiguration,
|
|
2430
|
+
default: DronesConfigurationDefault,
|
|
2431
|
+
},
|
|
2413
2432
|
mark43: {
|
|
2414
2433
|
type: Mark43Config,
|
|
2415
2434
|
default: Mark43ConfigDefault
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Model } from "mongoose";
|
|
2
|
+
|
|
3
|
+
import { DroneProvider } from "../constants";
|
|
4
|
+
import {
|
|
5
|
+
currentDate,
|
|
6
|
+
MongooseModule,
|
|
7
|
+
} from "../helpers";
|
|
8
|
+
import { EncryptedDataType } from "../types/common";
|
|
9
|
+
import {
|
|
10
|
+
DroneConnectionOptionsType,
|
|
11
|
+
DroneConnectionType,
|
|
12
|
+
} from "../types/drone-connection";
|
|
13
|
+
|
|
14
|
+
export interface DroneConnection extends DroneConnectionType, Record<string, unknown> {
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const EncryptedDataDefault: EncryptedDataType = {
|
|
18
|
+
iv: "",
|
|
19
|
+
encryptedData: "",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function DroneConnectionSchema(mongoose: MongooseModule) {
|
|
23
|
+
const { Schema } = mongoose;
|
|
24
|
+
|
|
25
|
+
const EncryptedData = new Schema<EncryptedDataType>({
|
|
26
|
+
iv: {
|
|
27
|
+
type: String,
|
|
28
|
+
default: "",
|
|
29
|
+
},
|
|
30
|
+
encryptedData: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: "",
|
|
33
|
+
},
|
|
34
|
+
}, {
|
|
35
|
+
_id: false,
|
|
36
|
+
id: false,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const DroneConnectionOptions = new Schema<DroneConnectionOptionsType>({
|
|
40
|
+
drones: {
|
|
41
|
+
type: String,
|
|
42
|
+
enum: ["all", "listed"],
|
|
43
|
+
default: "all",
|
|
44
|
+
},
|
|
45
|
+
serials: {
|
|
46
|
+
type: [String],
|
|
47
|
+
default: [],
|
|
48
|
+
},
|
|
49
|
+
}, {
|
|
50
|
+
_id: false,
|
|
51
|
+
id: false,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const modelSchema = new Schema<DroneConnectionType>({
|
|
55
|
+
departmentId: {
|
|
56
|
+
type: Schema.Types.ObjectId,
|
|
57
|
+
ref: "Department",
|
|
58
|
+
required: true,
|
|
59
|
+
},
|
|
60
|
+
provider: {
|
|
61
|
+
type: String,
|
|
62
|
+
enum: Object.values(DroneProvider),
|
|
63
|
+
required: true,
|
|
64
|
+
},
|
|
65
|
+
active: {
|
|
66
|
+
type: Boolean,
|
|
67
|
+
default: false,
|
|
68
|
+
},
|
|
69
|
+
label: {
|
|
70
|
+
type: String,
|
|
71
|
+
default: "",
|
|
72
|
+
},
|
|
73
|
+
authToken: {
|
|
74
|
+
type: EncryptedData,
|
|
75
|
+
default: EncryptedDataDefault,
|
|
76
|
+
},
|
|
77
|
+
authSecret: {
|
|
78
|
+
type: EncryptedData,
|
|
79
|
+
default: EncryptedDataDefault,
|
|
80
|
+
},
|
|
81
|
+
options: {
|
|
82
|
+
type: DroneConnectionOptions,
|
|
83
|
+
required: false,
|
|
84
|
+
},
|
|
85
|
+
modified: {
|
|
86
|
+
type: Date,
|
|
87
|
+
default: currentDate,
|
|
88
|
+
},
|
|
89
|
+
}, {
|
|
90
|
+
autoIndex: false,
|
|
91
|
+
timestamps: {
|
|
92
|
+
createdAt: false,
|
|
93
|
+
updatedAt: "modified",
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
modelSchema.index({
|
|
98
|
+
departmentId: 1,
|
|
99
|
+
}, {
|
|
100
|
+
name: "departmentId_1",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
modelSchema.index({
|
|
104
|
+
departmentId: 1,
|
|
105
|
+
provider: 1,
|
|
106
|
+
label: 1,
|
|
107
|
+
}, {
|
|
108
|
+
name: "departmentId_1_provider_1_label_1_unique",
|
|
109
|
+
unique: true,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return modelSchema;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export default async function DroneConnectionModule(mongoose: MongooseModule) {
|
|
116
|
+
const modelSchema = DroneConnectionSchema(mongoose);
|
|
117
|
+
return mongoose.model<DroneConnection>("DroneConnection", modelSchema, "massive_drone_connection", { overwriteModels: true });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface DroneConnectionModel extends Model<DroneConnection> {
|
|
121
|
+
}
|
package/src/models/user.ts
CHANGED
package/src/test/department.ts
CHANGED
|
@@ -139,6 +139,12 @@ describe("Department", function () {
|
|
|
139
139
|
assert.isFalse(sut.watchDuty.visible);
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
+
it("defaults drones to disabled", async function () {
|
|
143
|
+
const item = new models.Department(testItem);
|
|
144
|
+
const sut = await item.save();
|
|
145
|
+
assert.isFalse(sut.drones.enabled);
|
|
146
|
+
});
|
|
147
|
+
|
|
142
148
|
it("saves samsara.tagIds and defaults it to an empty array", async function () {
|
|
143
149
|
const item = new models.Department({
|
|
144
150
|
...testItem,
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { assert } from "chai";
|
|
2
|
+
import { Types } from "mongoose";
|
|
3
|
+
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
4
|
+
import * as m from "../index";
|
|
5
|
+
import * as config from "./config";
|
|
6
|
+
|
|
7
|
+
describe("DroneConnection", function() {
|
|
8
|
+
let models: m.BackendModels, mongoose: m.MongooseModule;
|
|
9
|
+
let departmentId: Types.ObjectId;
|
|
10
|
+
|
|
11
|
+
beforeEach(async function() {
|
|
12
|
+
const c = await m.connect(config.url);
|
|
13
|
+
models = c.models;
|
|
14
|
+
mongoose = c.mongoose;
|
|
15
|
+
departmentId = new mongoose.Types.ObjectId();
|
|
16
|
+
await models.DroneConnection.syncIndexes();
|
|
17
|
+
});
|
|
18
|
+
afterEach(async function() {
|
|
19
|
+
await models.DroneConnection.deleteMany({});
|
|
20
|
+
await mongoose.disconnect();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("is saved and reads back every field", async function() {
|
|
24
|
+
const sut = await new models.DroneConnection({
|
|
25
|
+
departmentId,
|
|
26
|
+
provider: "skydio",
|
|
27
|
+
active: true,
|
|
28
|
+
label: "Skydio HQ",
|
|
29
|
+
authToken: { iv: "iv-token", encryptedData: "enc-token" },
|
|
30
|
+
authSecret: { iv: "iv-secret", encryptedData: "enc-secret" },
|
|
31
|
+
options: {
|
|
32
|
+
drones: "listed",
|
|
33
|
+
serials: ["SN-1", "SN-2"],
|
|
34
|
+
},
|
|
35
|
+
}).save();
|
|
36
|
+
|
|
37
|
+
assert.isNotNull(sut._id);
|
|
38
|
+
assert.equal(sut.departmentId.toString(), departmentId.toString());
|
|
39
|
+
assert.equal(sut.provider, "skydio");
|
|
40
|
+
assert.isTrue(sut.active);
|
|
41
|
+
assert.equal(sut.label, "Skydio HQ");
|
|
42
|
+
assert.equal(sut.authToken.iv, "iv-token");
|
|
43
|
+
assert.equal(sut.authToken.encryptedData, "enc-token");
|
|
44
|
+
assert.equal(sut.authSecret.iv, "iv-secret");
|
|
45
|
+
assert.equal(sut.authSecret.encryptedData, "enc-secret");
|
|
46
|
+
assert.equal(sut.options?.drones, "listed");
|
|
47
|
+
assert.deepEqual(sut.options?.serials, ["SN-1", "SN-2"]);
|
|
48
|
+
assert.instanceOf(sut.modified, Date);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("leaves options undefined when none are given", async function() {
|
|
52
|
+
const sut = await new models.DroneConnection({
|
|
53
|
+
departmentId,
|
|
54
|
+
provider: "skydio",
|
|
55
|
+
label: "No options",
|
|
56
|
+
authToken: { iv: "iv", encryptedData: "t" },
|
|
57
|
+
authSecret: { iv: "iv", encryptedData: "s" },
|
|
58
|
+
}).save();
|
|
59
|
+
|
|
60
|
+
assert.isUndefined(sut.options);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("rejects an unknown provider", async function() {
|
|
64
|
+
let thrownError: unknown = null;
|
|
65
|
+
try {
|
|
66
|
+
await new models.DroneConnection({
|
|
67
|
+
departmentId,
|
|
68
|
+
provider: "bogus",
|
|
69
|
+
label: "Bad provider",
|
|
70
|
+
}).save();
|
|
71
|
+
} catch (e) {
|
|
72
|
+
thrownError = e;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
assert.isNotNull(thrownError, "expected an unknown provider to be rejected");
|
|
76
|
+
assert.include(String((thrownError as Error).message), "provider");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("rejects an unknown options.drones value", async function() {
|
|
80
|
+
let thrownError: unknown = null;
|
|
81
|
+
try {
|
|
82
|
+
await new models.DroneConnection({
|
|
83
|
+
departmentId,
|
|
84
|
+
provider: "skydio",
|
|
85
|
+
label: "Bad options",
|
|
86
|
+
options: {
|
|
87
|
+
drones: "list",
|
|
88
|
+
serials: [],
|
|
89
|
+
},
|
|
90
|
+
}).save();
|
|
91
|
+
} catch (e) {
|
|
92
|
+
thrownError = e;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
assert.isNotNull(thrownError, "expected an unknown options.drones value to be rejected");
|
|
96
|
+
assert.include(String((thrownError as Error).message), "options.drones");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("stores no timestamp field outside the schema", async function() {
|
|
100
|
+
await new models.DroneConnection({
|
|
101
|
+
departmentId,
|
|
102
|
+
provider: "skydio",
|
|
103
|
+
label: "Raw read",
|
|
104
|
+
}).save();
|
|
105
|
+
|
|
106
|
+
const raw = await models.DroneConnection.collection.findOne({ departmentId });
|
|
107
|
+
assert.isNotNull(raw);
|
|
108
|
+
assert.notProperty(raw, "createdAt");
|
|
109
|
+
assert.notProperty(raw, "updatedAt");
|
|
110
|
+
assert.property(raw, "modified");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("advances modified on findOneAndUpdate", async function() {
|
|
114
|
+
const staleDate = new Date("2020-01-02T03:04:05.000Z");
|
|
115
|
+
await new models.DroneConnection({
|
|
116
|
+
departmentId,
|
|
117
|
+
provider: "skydio",
|
|
118
|
+
label: "Stale",
|
|
119
|
+
}).save();
|
|
120
|
+
await models.DroneConnection.collection.updateOne({
|
|
121
|
+
departmentId,
|
|
122
|
+
}, {
|
|
123
|
+
$set: {
|
|
124
|
+
modified: staleDate,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const updated = await models.DroneConnection.findOneAndUpdate({
|
|
129
|
+
departmentId,
|
|
130
|
+
}, {
|
|
131
|
+
$set: {
|
|
132
|
+
active: true,
|
|
133
|
+
},
|
|
134
|
+
}, {
|
|
135
|
+
new: true,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
assert.isNotNull(updated);
|
|
139
|
+
assert.isTrue(updated!.modified > staleDate, "expected modified to advance");
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("enforces a unique (departmentId, provider, label) index", async function() {
|
|
143
|
+
await new models.DroneConnection({
|
|
144
|
+
departmentId,
|
|
145
|
+
provider: "skydio",
|
|
146
|
+
label: "Skydio HQ",
|
|
147
|
+
}).save();
|
|
148
|
+
|
|
149
|
+
let thrownError: unknown = null;
|
|
150
|
+
try {
|
|
151
|
+
await new models.DroneConnection({
|
|
152
|
+
departmentId,
|
|
153
|
+
provider: "skydio",
|
|
154
|
+
label: "Skydio HQ",
|
|
155
|
+
}).save();
|
|
156
|
+
} catch (e) {
|
|
157
|
+
thrownError = e;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
assert.isNotNull(thrownError, "expected a duplicate (departmentId, label) to be rejected");
|
|
161
|
+
assert.equal((thrownError as { code?: number }).code, 11000);
|
|
162
|
+
assert.include(String((thrownError as Error).message), "E11000");
|
|
163
|
+
});
|
|
164
|
+
});
|
package/src/test/user.ts
CHANGED
|
@@ -51,4 +51,15 @@ describe("User", function () {
|
|
|
51
51
|
assert.equal(item.restrictedCommentsEnabled, true);
|
|
52
52
|
assert.isTrue(sut.canBlockIncidents);
|
|
53
53
|
});
|
|
54
|
+
|
|
55
|
+
it("saves and retrieves visibleSources", async function () {
|
|
56
|
+
const item = new models.User({
|
|
57
|
+
...testItem,
|
|
58
|
+
stealthStatus: m.UserStealthStatus.Hidden,
|
|
59
|
+
visibleSources: [m.LocationSource.VehicleModem, m.LocationSource.TCIOS],
|
|
60
|
+
});
|
|
61
|
+
const sut = await item.save();
|
|
62
|
+
assert.equal(sut.stealthStatus, "hidden");
|
|
63
|
+
assert.deepEqual(sut.visibleSources, [m.LocationSource.VehicleModem, m.LocationSource.TCIOS]);
|
|
64
|
+
});
|
|
54
65
|
});
|
package/src/types/department.ts
CHANGED
|
@@ -359,6 +359,10 @@ export interface DroneSenseConfigurationType {
|
|
|
359
359
|
apiKey: string,
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
+
export interface DronesConfigurationType {
|
|
363
|
+
enabled: boolean,
|
|
364
|
+
}
|
|
365
|
+
|
|
362
366
|
export interface FireMapperConfigurationType {
|
|
363
367
|
enabled: boolean,
|
|
364
368
|
auth: FireMapperAuthV2Type,
|
|
@@ -707,6 +711,7 @@ export interface DepartmentType {
|
|
|
707
711
|
usft: USFTConfigurationType,
|
|
708
712
|
onestep: OneStepConfigurationType, // cspell:disable-line
|
|
709
713
|
dronesense: DroneSenseConfigurationType,
|
|
714
|
+
drones: DronesConfigurationType,
|
|
710
715
|
selfAssignmentEnabled: boolean,
|
|
711
716
|
shareAVL: AccountConfigurationShareAVL,
|
|
712
717
|
shareIncident: AccountConfigurationShareIncident,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Types } from "mongoose";
|
|
2
|
+
import { DroneProvider } from "../constants";
|
|
3
|
+
import { EncryptedDataType } from "./common";
|
|
4
|
+
|
|
5
|
+
export interface DroneConnectionOptionsType {
|
|
6
|
+
drones: "all" | "listed",
|
|
7
|
+
serials: string[],
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface DroneConnectionType {
|
|
11
|
+
// The stable id the video gateway diffs on.
|
|
12
|
+
_id: Types.ObjectId,
|
|
13
|
+
departmentId: Types.ObjectId,
|
|
14
|
+
provider: DroneProvider,
|
|
15
|
+
active: boolean,
|
|
16
|
+
label: string,
|
|
17
|
+
authToken: EncryptedDataType, // Skydio token id
|
|
18
|
+
authSecret: EncryptedDataType, // Skydio token secret
|
|
19
|
+
options?: DroneConnectionOptionsType, // omitted means every drone on the account
|
|
20
|
+
modified: Date,
|
|
21
|
+
}
|
package/src/types/user.ts
CHANGED
|
@@ -139,6 +139,7 @@ export interface UserType {
|
|
|
139
139
|
shareWith3rdPartiesEnabled: boolean,
|
|
140
140
|
socketIO: PubNubTokenSchemaType,
|
|
141
141
|
stealthStatus: string, // UserStealthStatus
|
|
142
|
+
visibleSources: string[],
|
|
142
143
|
superuser: boolean,
|
|
143
144
|
superUserReadOnly: boolean
|
|
144
145
|
syncLoggingExpireDate: Date,
|