tabletcommand-location 2.4.0 → 2.4.1
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/audience.js +38 -0
- package/build/audience.js.map +1 -0
- package/build/index.js +38 -20
- package/build/index.js.map +1 -1
- package/build/location.js +3 -0
- package/build/location.js.map +1 -1
- package/build/query.js +373 -0
- package/build/query.js.map +1 -0
- package/build/store.js +2 -0
- package/build/store.js.map +1 -1
- package/build/test/location.js +53 -0
- package/build/test/location.js.map +1 -1
- package/build/test/mock.js +5 -0
- package/build/test/mock.js.map +1 -1
- package/build/test/query.js +174 -0
- package/build/test/query.js.map +1 -0
- package/cspell.json +2 -1
- package/definitions/audience.d.ts +18 -0
- package/definitions/audience.d.ts.map +1 -0
- package/definitions/index.d.ts +1 -0
- package/definitions/index.d.ts.map +1 -1
- package/definitions/location.d.ts.map +1 -1
- package/definitions/query.d.ts +36 -0
- package/definitions/query.d.ts.map +1 -0
- package/definitions/store.d.ts +5 -0
- package/definitions/store.d.ts.map +1 -1
- package/definitions/test/mock.d.ts.map +1 -1
- package/definitions/test/query.d.ts +2 -0
- package/definitions/test/query.d.ts.map +1 -0
- package/package.json +18 -14
- package/src/audience.ts +54 -0
- package/src/index.ts +5 -20
- package/src/location.ts +3 -0
- package/src/query.ts +492 -0
- package/src/store.ts +2 -0
- package/src/test/location.ts +53 -1
- package/src/test/mock.ts +6 -0
- package/src/test/query.ts +209 -0
- package/test.sh +1 -1
package/src/test/mock.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as mongoose from "mongoose";
|
|
2
2
|
import {
|
|
3
3
|
BackendModels,
|
|
4
|
+
AccountIndustry,
|
|
4
5
|
Agency,
|
|
5
6
|
Department,
|
|
6
7
|
convertToObjectId as ObjectId
|
|
@@ -15,11 +16,16 @@ export default function(modelsModule: typeof import("tabletcommand-backend-model
|
|
|
15
16
|
_id: ObjectId(departmentId),
|
|
16
17
|
department: "Test Department",
|
|
17
18
|
accountType: "production",
|
|
19
|
+
industry: AccountIndustry.Utility,
|
|
18
20
|
shareAVL: {
|
|
19
21
|
enabled: true,
|
|
20
22
|
opAreaName: "Test Area",
|
|
21
23
|
opAreaCode: "TEST",
|
|
22
24
|
fadeZoomLevel: 45000,
|
|
25
|
+
area: {
|
|
26
|
+
type: "Polygon",
|
|
27
|
+
coordinates: [],
|
|
28
|
+
},
|
|
23
29
|
},
|
|
24
30
|
signupDomains: [],
|
|
25
31
|
signupKey: "abcd",
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { assert } from "chai";
|
|
2
|
+
import { describe, it, describe as context } from "node:test";
|
|
3
|
+
import {
|
|
4
|
+
adminListLocations,
|
|
5
|
+
adminListPersonLocations,
|
|
6
|
+
adminListUAVLocations,
|
|
7
|
+
adminListAircraftLocations,
|
|
8
|
+
adminListSharedLocations,
|
|
9
|
+
adminListFocusedLocations,
|
|
10
|
+
syncListSharedLocations,
|
|
11
|
+
syncListLocations,
|
|
12
|
+
syncListPersonLocations,
|
|
13
|
+
syncListAircraftLocations,
|
|
14
|
+
syncListUAVLocations,
|
|
15
|
+
metersToRadians,
|
|
16
|
+
} from "../query";
|
|
17
|
+
|
|
18
|
+
const departmentId = "5195426cc4e016a988000969";
|
|
19
|
+
const movedAt = new Date("2024-01-01T00:00:00.000Z");
|
|
20
|
+
const modifiedDate = new Date("2024-01-02T00:00:00.000Z");
|
|
21
|
+
const longitude = -119.0669;
|
|
22
|
+
const latitude = 34.35264;
|
|
23
|
+
const diagonal = 5000;
|
|
24
|
+
|
|
25
|
+
describe("query", () => {
|
|
26
|
+
context("adminListLocations", () => {
|
|
27
|
+
it("Scopes to the department, excludes uav and person/transponder-tracked records", () => {
|
|
28
|
+
const { list } = adminListLocations({ departmentId, movedAt });
|
|
29
|
+
assert.equal(list.active, true);
|
|
30
|
+
assert.equal(list.departmentId, departmentId);
|
|
31
|
+
assert.deepEqual(list.kindType, { $ne: "uav" });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("Drops the active filter when showAll is true", () => {
|
|
35
|
+
const { list } = adminListLocations({ departmentId, movedAt, showAll: true });
|
|
36
|
+
assert.isUndefined(list.active);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("Keeps the active filter when showAll is not set", () => {
|
|
40
|
+
const { list } = adminListLocations({ departmentId, movedAt });
|
|
41
|
+
assert.property(list, "active");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
context("adminListPersonLocations", () => {
|
|
46
|
+
it("Scopes to the department and person kindType", () => {
|
|
47
|
+
const { list } = adminListPersonLocations({ departmentId, movedAt });
|
|
48
|
+
assert.equal(list.active, true);
|
|
49
|
+
assert.equal(list.departmentId, departmentId);
|
|
50
|
+
assert.equal(list.kindType, "person");
|
|
51
|
+
assert.deepEqual(list.movedAt, { $gte: movedAt });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("Drops the active filter when showAll is true", () => {
|
|
55
|
+
const { list } = adminListPersonLocations({ departmentId, movedAt, showAll: true });
|
|
56
|
+
assert.isUndefined(list.active);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
context("adminListUAVLocations", () => {
|
|
61
|
+
it("Scopes to the department and uav kindType", () => {
|
|
62
|
+
const { list } = adminListUAVLocations({ departmentId, movedAt });
|
|
63
|
+
assert.equal(list.active, true);
|
|
64
|
+
assert.equal(list.departmentId, departmentId);
|
|
65
|
+
assert.equal(list.kindType, "uav");
|
|
66
|
+
assert.deepEqual(list.movedAt, { $gte: movedAt });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("Drops the active filter when showAll is true", () => {
|
|
70
|
+
const { list } = adminListUAVLocations({ departmentId, movedAt, showAll: true });
|
|
71
|
+
assert.isUndefined(list.active);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
context("adminListAircraftLocations", () => {
|
|
76
|
+
it("Excludes the caller's department and matches shared ADSB aircraft", () => {
|
|
77
|
+
const { list } = adminListAircraftLocations({ departmentId, movedAt, longitude, latitude, diagonal });
|
|
78
|
+
assert.equal(list.shared, true);
|
|
79
|
+
assert.equal(list.active, true);
|
|
80
|
+
assert.equal(list.source, "ADSB");
|
|
81
|
+
assert.deepEqual(list.kindType, { $in: ["fixed-wing", "helicopter"] });
|
|
82
|
+
assert.deepEqual(list.departmentId, { $ne: departmentId });
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("Sends movedAt as an ISO string", () => {
|
|
86
|
+
const { list } = adminListAircraftLocations({ departmentId, movedAt, longitude, latitude, diagonal });
|
|
87
|
+
assert.deepEqual(list.movedAt, { $gte: movedAt.toISOString() });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("Builds a $centerSphere filter as [longitude, latitude] with the diagonal converted to radians", () => {
|
|
91
|
+
const { list } = adminListAircraftLocations({ departmentId, movedAt, longitude, latitude, diagonal });
|
|
92
|
+
assert.deepEqual(list.locationGeoJSON.$geoWithin.$centerSphere, [
|
|
93
|
+
[longitude, latitude],
|
|
94
|
+
diagonal / metersToRadians,
|
|
95
|
+
]);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
context("adminListSharedLocations", () => {
|
|
100
|
+
it("Excludes the caller's department, ADSB source, and uav kindType", () => {
|
|
101
|
+
const { list } = adminListSharedLocations({ departmentId, movedAt, longitude, latitude, diagonal });
|
|
102
|
+
assert.equal(list.shared, true);
|
|
103
|
+
assert.equal(list.active, true);
|
|
104
|
+
assert.deepEqual(list.source, { $ne: "ADSB" });
|
|
105
|
+
assert.deepEqual(list.kindType, { $ne: "uav" });
|
|
106
|
+
assert.deepEqual(list.departmentId, { $ne: departmentId });
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
context("adminListFocusedLocations", () => {
|
|
111
|
+
it("Scopes to the caller's department with a geo filter", () => {
|
|
112
|
+
const { list } = adminListFocusedLocations({ departmentId, movedAt, longitude, latitude, diagonal });
|
|
113
|
+
assert.equal(list.active, true);
|
|
114
|
+
assert.equal(list.departmentId, departmentId);
|
|
115
|
+
assert.property(list, "locationGeoJSON");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("Drops the geo filter (not active) when showAll is true", () => {
|
|
119
|
+
const { list } = adminListFocusedLocations({ departmentId, movedAt, longitude, latitude, diagonal, showAll: true });
|
|
120
|
+
assert.isUndefined(list.locationGeoJSON);
|
|
121
|
+
assert.equal(list.active, true);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
context("syncListSharedLocations", () => {
|
|
126
|
+
it("Excludes the caller's department and ADSB/DroneSense sources", () => {
|
|
127
|
+
const { list } = syncListSharedLocations({ departmentId, movedAt, modifiedDate, longitude, latitude, diagonal });
|
|
128
|
+
assert.equal(list.shared, true);
|
|
129
|
+
assert.deepEqual(list.source, { $nin: ["ADSB", "DroneSense"] });
|
|
130
|
+
assert.deepEqual(list.departmentId, { $ne: departmentId });
|
|
131
|
+
assert.deepEqual(list.modified, { $gte: modifiedDate.toISOString() });
|
|
132
|
+
assert.deepEqual(list.movedAt, { $gte: movedAt.toISOString() });
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
context("syncListLocations", () => {
|
|
137
|
+
it("Scopes to the department, excludes uav and person/transponder-tracked records", () => {
|
|
138
|
+
const { list } = syncListLocations({ departmentId, movedAt, modifiedDate });
|
|
139
|
+
assert.equal(list.departmentId, departmentId);
|
|
140
|
+
assert.deepEqual(list.kindType, { $ne: "uav" });
|
|
141
|
+
assert.deepEqual(list.modified, { $gte: modifiedDate.toISOString() });
|
|
142
|
+
assert.deepEqual(list.movedAt, { $gte: movedAt.toISOString() });
|
|
143
|
+
assert.deepEqual(list.$and, [
|
|
144
|
+
{ $or: [{ personnelUUID: "" }, { personnelUUID: { $exists: false } }] },
|
|
145
|
+
{ $or: [{ transponderUUID: "" }, { transponderUUID: { $exists: false } }] },
|
|
146
|
+
]);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
context("syncListPersonLocations", () => {
|
|
151
|
+
it("Scopes to the department and person kindType", () => {
|
|
152
|
+
const { list } = syncListPersonLocations({ departmentId, movedAt, modifiedDate });
|
|
153
|
+
assert.equal(list.departmentId, departmentId);
|
|
154
|
+
assert.equal(list.kindType, "person");
|
|
155
|
+
assert.deepEqual(list.modified, { $gte: modifiedDate.toISOString() });
|
|
156
|
+
assert.deepEqual(list.movedAt, { $gte: movedAt.toISOString() });
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
context("syncListUAVLocations", () => {
|
|
161
|
+
it("Scopes to the department and uav kindType", () => {
|
|
162
|
+
const { list } = syncListUAVLocations({ departmentId, movedAt, modifiedDate });
|
|
163
|
+
assert.equal(list.departmentId, departmentId);
|
|
164
|
+
assert.equal(list.kindType, "uav");
|
|
165
|
+
assert.deepEqual(list.modified, { $gte: modifiedDate.toISOString() });
|
|
166
|
+
assert.deepEqual(list.movedAt, { $gte: movedAt.toISOString() });
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
context("syncListAircraftLocations", () => {
|
|
171
|
+
const base = { departmentId, movedAt, modifiedDate };
|
|
172
|
+
|
|
173
|
+
it("Matches shared ADSB aircraft, scoped away from the caller's department", () => {
|
|
174
|
+
const { list } = syncListAircraftLocations({ ...base, longitude, latitude, diagonal });
|
|
175
|
+
assert.equal(list.shared, true);
|
|
176
|
+
assert.equal(list.source, "ADSB");
|
|
177
|
+
assert.deepEqual(list.kindType, { $in: ["fixed-wing", "helicopter"] });
|
|
178
|
+
assert.deepEqual(list.departmentId, { $ne: departmentId });
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("Adds a geo filter when given valid, non-zero coordinates", () => {
|
|
182
|
+
const { list } = syncListAircraftLocations({ ...base, longitude, latitude, diagonal });
|
|
183
|
+
assert.deepEqual(list.locationGeoJSON.$geoWithin.$centerSphere, [
|
|
184
|
+
[longitude, latitude],
|
|
185
|
+
diagonal / metersToRadians,
|
|
186
|
+
]);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it("Omits the geo filter when coordinates are at the origin", () => {
|
|
190
|
+
const { list } = syncListAircraftLocations({ ...base, longitude: 0, latitude: 0, diagonal });
|
|
191
|
+
assert.isUndefined(list.locationGeoJSON);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("Omits the geo filter when coordinates are within the origin (<= 0.01)", () => {
|
|
195
|
+
const { list } = syncListAircraftLocations({ ...base, longitude: 0.01, latitude: 0.01, diagonal });
|
|
196
|
+
assert.isUndefined(list.locationGeoJSON);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("Omits the geo filter when latitude is out of range", () => {
|
|
200
|
+
const { list } = syncListAircraftLocations({ ...base, longitude, latitude: 90, diagonal });
|
|
201
|
+
assert.isUndefined(list.locationGeoJSON);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("Omits the geo filter when longitude is out of range", () => {
|
|
205
|
+
const { list } = syncListAircraftLocations({ ...base, longitude: 180, latitude, diagonal });
|
|
206
|
+
assert.isUndefined(list.locationGeoJSON);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|