@justair/justair-library 4.8.20 → 4.8.22
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/package.json +1 -1
- package/src/index.js +15 -0
- package/src/models/sampleSites.js +126 -72
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -58,6 +58,15 @@ import { NetworkMetrics, networkMetricsSchema } from "./models/networkMetrics.js
|
|
|
58
58
|
import Database from "./config/db.js"; // Import the new Database class
|
|
59
59
|
import CustomLogger from "./config/logger.js";
|
|
60
60
|
|
|
61
|
+
// SampleSites related imports
|
|
62
|
+
import {
|
|
63
|
+
sampleSitesSchema,
|
|
64
|
+
SampleSites,
|
|
65
|
+
sampleSiteAuditSchema,
|
|
66
|
+
SampleSiteAudit,
|
|
67
|
+
sampleParametersEnum,
|
|
68
|
+
} from "./models/sampleSites.js";
|
|
69
|
+
|
|
61
70
|
export function createLoggerInstance({ DATADOG_API_KEY, APPLICATION_NAME }) {
|
|
62
71
|
return new CustomLogger({ DATADOG_API_KEY, APPLICATION_NAME });
|
|
63
72
|
}
|
|
@@ -115,4 +124,10 @@ export {
|
|
|
115
124
|
DataCompleteness,
|
|
116
125
|
networkMetricsSchema,
|
|
117
126
|
NetworkMetrics,
|
|
127
|
+
// SampleSites related exports
|
|
128
|
+
sampleSitesSchema,
|
|
129
|
+
SampleSites,
|
|
130
|
+
sampleSiteAuditSchema,
|
|
131
|
+
SampleSiteAudit,
|
|
132
|
+
sampleParametersEnum,
|
|
118
133
|
};
|
|
@@ -38,12 +38,12 @@ const noteSchema = mongoose.Schema({
|
|
|
38
38
|
// Sample Site Audit Schema
|
|
39
39
|
const sampleSiteAuditSchema = mongoose.Schema(
|
|
40
40
|
{
|
|
41
|
-
|
|
41
|
+
sampleSiteId: { type: mongoose.Types.ObjectId, ref: "SampleSites" },
|
|
42
42
|
orgId: { type: mongoose.Types.ObjectId, ref: "Organizations" },
|
|
43
43
|
timeUpdated: Date,
|
|
44
44
|
deletedAt: { type: Date, default: Date.now }, // Only populated on delete
|
|
45
|
-
|
|
46
|
-
//
|
|
45
|
+
sampleSiteLocation: {
|
|
46
|
+
// Sample Site GPS location (lat, lon)
|
|
47
47
|
type: { type: String, enum: ["Point"], required: true },
|
|
48
48
|
coordinates: { type: [Number], required: true },
|
|
49
49
|
},
|
|
@@ -59,30 +59,48 @@ const SampleSiteAudit = mongoose.model("SampleSiteAudit", sampleSiteAuditSchema)
|
|
|
59
59
|
// Sample Sites Schema
|
|
60
60
|
const sampleSitesSchema = mongoose.Schema(
|
|
61
61
|
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
name: { type: String },
|
|
63
|
+
managedBy: { type: String },
|
|
64
|
+
sponsoredBy: { type: String },
|
|
65
|
+
lastSamplePeriodStartDate: { type: Date },
|
|
66
|
+
lastSamplePeriodEndDate: { type: Date },
|
|
67
67
|
isPrivate: { type: Boolean, default: false, required: true },
|
|
68
68
|
sponsor: { type: mongoose.Types.ObjectId, ref: "Organizations" },
|
|
69
|
-
sponsorName: String,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
sponsorName: { type: String },
|
|
70
|
+
/*
|
|
71
|
+
* Location object: unified structure for all address and geospatial data.
|
|
72
|
+
* - monitorLatitude and monitorLongitude are deprecated and no longer used.
|
|
73
|
+
* - The location object (including location.gps) is now built in config/google.js.
|
|
74
|
+
* - location.gps is a GeoJSON Point used for all geospatial queries (replaces gpsLocation).
|
|
75
|
+
*/
|
|
76
|
+
location: {
|
|
77
|
+
city: { type: String },
|
|
78
|
+
state: { type: String },
|
|
79
|
+
county: { type: String },
|
|
80
|
+
street: { type: String },
|
|
81
|
+
zip_code: { type: String },
|
|
82
|
+
neighborhood: { type: String },
|
|
83
|
+
gps: {
|
|
84
|
+
type: {
|
|
85
|
+
type: String,
|
|
86
|
+
enum: ["Point"],
|
|
87
|
+
required: true,
|
|
88
|
+
},
|
|
89
|
+
coordinates: {
|
|
90
|
+
type: [Number],
|
|
91
|
+
required: true,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
75
94
|
},
|
|
76
|
-
|
|
77
|
-
context: [String],
|
|
95
|
+
context: { type: [String] },
|
|
78
96
|
parameters: [
|
|
79
97
|
{
|
|
80
98
|
type: String,
|
|
81
99
|
enum: sampleParametersEnum,
|
|
82
100
|
},
|
|
83
101
|
],
|
|
84
|
-
notes: [noteSchema],
|
|
85
|
-
image: String,
|
|
102
|
+
notes: { type: [noteSchema] },
|
|
103
|
+
image: { type: String },
|
|
86
104
|
},
|
|
87
105
|
{
|
|
88
106
|
timestamps: true,
|
|
@@ -90,10 +108,10 @@ const sampleSitesSchema = mongoose.Schema(
|
|
|
90
108
|
);
|
|
91
109
|
|
|
92
110
|
// Geographic queries - already exists
|
|
93
|
-
sampleSitesSchema.index({
|
|
111
|
+
sampleSitesSchema.index({ "location.gps": "2dsphere" }); // use location.gps for geospatial queries
|
|
94
112
|
|
|
95
113
|
// Sponsor-based queries
|
|
96
|
-
sampleSitesSchema.index({ sponsor: 1,
|
|
114
|
+
sampleSitesSchema.index({ sponsor: 1, isPrivate: 1 });
|
|
97
115
|
|
|
98
116
|
// Location-based filtering
|
|
99
117
|
sampleSitesSchema.index({ "location.city": 1, "location.state": 1 });
|
|
@@ -109,20 +127,25 @@ sampleSitesSchema.pre("findOneAndDelete", async function () {
|
|
|
109
127
|
const docToDelete = await this.model.findOne(this.getFilter()).lean();
|
|
110
128
|
if (docToDelete) {
|
|
111
129
|
console.log("Logging findOneAndDelete to sample site audit", docToDelete);
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
let coordinates = null;
|
|
131
|
+
if (docToDelete.location && docToDelete.location.gps && Array.isArray(docToDelete.location.gps.coordinates)) {
|
|
132
|
+
coordinates = docToDelete.location.gps.coordinates;
|
|
133
|
+
} else if (docToDelete.gpsLocation && Array.isArray(docToDelete.gpsLocation.coordinates)) {
|
|
134
|
+
coordinates = docToDelete.gpsLocation.coordinates;
|
|
135
|
+
}
|
|
136
|
+
if (coordinates) {
|
|
137
|
+
const auditLog = new SampleSiteAudit({
|
|
138
|
+
sampleSiteId: docToDelete._id,
|
|
139
|
+
orgId: docToDelete.sponsor,
|
|
140
|
+
timeUpdated: docToDelete.updatedAt,
|
|
141
|
+
sampleSiteLocation: {
|
|
142
|
+
type: "Point",
|
|
143
|
+
coordinates,
|
|
144
|
+
},
|
|
145
|
+
deletedAt: new Date(),
|
|
146
|
+
});
|
|
147
|
+
await auditLog.save();
|
|
148
|
+
}
|
|
126
149
|
}
|
|
127
150
|
});
|
|
128
151
|
|
|
@@ -133,18 +156,31 @@ sampleSitesSchema.pre("deleteMany", async function () {
|
|
|
133
156
|
|
|
134
157
|
if (docsToDelete.length) {
|
|
135
158
|
console.log(`Logging ${docsToDelete.length} sample site documents to audit`);
|
|
136
|
-
const auditLogs = docsToDelete.map((doc) =>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
159
|
+
const auditLogs = docsToDelete.map((doc) => {
|
|
160
|
+
let coordinates = null;
|
|
161
|
+
if (doc.location && doc.location.gps && Array.isArray(doc.location.gps.coordinates)) {
|
|
162
|
+
coordinates = doc.location.gps.coordinates;
|
|
163
|
+
} else if (doc.gpsLocation && Array.isArray(doc.gpsLocation.coordinates)) {
|
|
164
|
+
coordinates = doc.gpsLocation.coordinates;
|
|
165
|
+
}
|
|
166
|
+
if (coordinates) {
|
|
167
|
+
return {
|
|
168
|
+
sampleSiteId: doc._id,
|
|
169
|
+
orgId: doc.sponsor,
|
|
170
|
+
timeUpdated: doc.updatedAt,
|
|
171
|
+
sampleSiteLocation: {
|
|
172
|
+
type: "Point",
|
|
173
|
+
coordinates,
|
|
174
|
+
},
|
|
175
|
+
deletedAt: new Date(),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}).filter(Boolean);
|
|
180
|
+
|
|
181
|
+
if (auditLogs.length) {
|
|
182
|
+
await SampleSiteAudit.insertMany(auditLogs);
|
|
183
|
+
}
|
|
148
184
|
}
|
|
149
185
|
});
|
|
150
186
|
|
|
@@ -155,20 +191,25 @@ sampleSitesSchema.pre("deleteOne", async function () {
|
|
|
155
191
|
|
|
156
192
|
if (docToDelete) {
|
|
157
193
|
console.log("Logging deleteOne to sample site audit", docToDelete);
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
194
|
+
let coordinates = null;
|
|
195
|
+
if (docToDelete.location && docToDelete.location.gps && Array.isArray(docToDelete.location.gps.coordinates)) {
|
|
196
|
+
coordinates = docToDelete.location.gps.coordinates;
|
|
197
|
+
} else if (docToDelete.gpsLocation && Array.isArray(docToDelete.gpsLocation.coordinates)) {
|
|
198
|
+
coordinates = docToDelete.gpsLocation.coordinates;
|
|
199
|
+
}
|
|
200
|
+
if (coordinates) {
|
|
201
|
+
const auditLog = new SampleSiteAudit({
|
|
202
|
+
sampleSiteId: docToDelete._id,
|
|
203
|
+
orgId: docToDelete.sponsor,
|
|
204
|
+
timeUpdated: docToDelete.updatedAt,
|
|
205
|
+
sampleSiteLocation: {
|
|
206
|
+
type: "Point",
|
|
207
|
+
coordinates,
|
|
208
|
+
},
|
|
209
|
+
deletedAt: new Date(),
|
|
210
|
+
});
|
|
211
|
+
await auditLog.save();
|
|
212
|
+
}
|
|
172
213
|
}
|
|
173
214
|
});
|
|
174
215
|
|
|
@@ -177,18 +218,31 @@ sampleSitesSchema.pre("updateMany", async function () {
|
|
|
177
218
|
const docsToUpdate = await this.model.find(this.getFilter()).lean();
|
|
178
219
|
if (docsToUpdate.length) {
|
|
179
220
|
console.log(`Logging ${docsToUpdate.length} sample site documents to audit`);
|
|
180
|
-
const auditLogs = docsToUpdate.map((doc) =>
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
221
|
+
const auditLogs = docsToUpdate.map((doc) => {
|
|
222
|
+
let coordinates = null;
|
|
223
|
+
if (doc.location && doc.location.gps && Array.isArray(doc.location.gps.coordinates)) {
|
|
224
|
+
coordinates = doc.location.gps.coordinates;
|
|
225
|
+
} else if (doc.gpsLocation && Array.isArray(doc.gpsLocation.coordinates)) {
|
|
226
|
+
coordinates = doc.gpsLocation.coordinates;
|
|
227
|
+
}
|
|
228
|
+
if (coordinates) {
|
|
229
|
+
return {
|
|
230
|
+
sampleSiteId: doc._id,
|
|
231
|
+
orgId: doc.sponsor,
|
|
232
|
+
timeUpdated: doc.updatedAt,
|
|
233
|
+
sampleSiteLocation: {
|
|
234
|
+
type: "Point",
|
|
235
|
+
coordinates,
|
|
236
|
+
},
|
|
237
|
+
deletedAt: null, // Not a deletion, so this field is null
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
}).filter(Boolean);
|
|
242
|
+
|
|
243
|
+
if (auditLogs.length) {
|
|
244
|
+
await SampleSiteAudit.insertMany(auditLogs);
|
|
245
|
+
}
|
|
192
246
|
}
|
|
193
247
|
});
|
|
194
248
|
|