// import * as uuid from "uuid"; import { Model } from "mongoose"; import { MongooseModule, } from "../helpers"; import EsriAuthModule from "./schema/esri-auth"; import EsriErrorModule from "./schema/esri-error"; import EsriMapModule from "./schema/esri-map"; import { EsriType, MapPropertiesType } from "../types/esri"; export interface Esri extends EsriType { } export function EsriSchema(mongoose: MongooseModule) { const { Schema } = mongoose; const EsriAuth = EsriAuthModule(mongoose); const EsriError = EsriErrorModule(mongoose); const EsriMap = EsriMapModule(mongoose); const MapProperties = new Schema({ // ArcGIS Item id itemId: { type: String, default: "", }, download: { type: Boolean, default: false, }, }, { _id: false, id: false, }); const modelSchema = new Schema({ _id: { type: Schema.Types.ObjectId, auto: true, }, // last time when cron updated maps runAt: { type: Date, default: new Date("1970-01-01T00:00:00.000Z"), }, departmentId: { type: Schema.Types.ObjectId, ref: "Department", required: true }, auth: { type: EsriAuth, default: null, }, authError: { type: EsriError, default: null, }, // Link to ArcGISGroup arcGISGroupIds: { type: [String], default: [], }, // ArcGIS user used for fallback when a new user has no ArcGIS account yet arcGISAuth: { type: EsriAuth, default: null, }, // For new accounts, set the default value to true arcGISMigrated: { type: Boolean, default: true, }, review: { type: Object, default: null, }, // last time when review cron was run // if date is in the past, we should refresh this // at run success, update this date to a date in the future reviewRunAt: { type: Date, default: null, }, // maps maps: { type: [EsriMap], default: [] }, // Properties set by user. // These are applied by the sync on top of the EsriMap properties // saved as { itemId, download, ... } mapsProperties: { type: [MapProperties], default: [], }, // newest modified for EsriMap mapLastUpdated: { type: Date, default: new Date("1970-01-01T00:00:00.000Z"), }, }, { autoIndex: false, toJSON: { versionKey: false, } }); modelSchema.index({ departmentId: 1, }, { name: "departmentId_unique", unique: true, }); // cspell:disable-next-line // arcGISAuth must be set-or-null, never a subdoc with an empty username. // EsriAuth.username defaults to "" and that schema is shared with `auth`, so we // normalize here rather than change the default: an arcGISAuth present without a // username collapses to null, keeping it out of the $exists unique index below. modelSchema.pre("save", function(next) { const arcGISAuth = this.get("arcGISAuth"); if (arcGISAuth && !arcGISAuth.username) { this.set("arcGISAuth", null); } next(); }); // arcGISAuth.username is generated lowercase (cron-maps domain.ts: // name.toLowerCase() -> `tc_`), so this case-sensitive unique index is // sufficient in practice; case-insensitive enforcement is intentionally deferred. // $exists (not $gt: "") is correct because the pre-save hook above guarantees // arcGISAuth is set-or-null, so the username field is present only on real records. modelSchema.index({ "arcGISAuth.username": 1, }, { name: "arcGISAuth.username_1_unique", unique: true, partialFilterExpression: { "arcGISAuth.username": { $exists: true }, }, }); return modelSchema; } export default async function EsriModule(mongoose: MongooseModule) { const modelSchema = EsriSchema(mongoose); return mongoose.model("Esri", modelSchema, "massive_esri", { overwriteModels: true }); } export interface EsriModel extends Model { }