Upgrade system finished

This commit is contained in:
2026-03-22 21:47:09 -06:00
parent a71ba20176
commit bb1935027d
299 changed files with 8067 additions and 2758 deletions

View File

@@ -1 +1 @@
{"version":3,"file":"bulk-geocode.routes.d.ts","sourceRoot":"","sources":["../../../../src/modules/map/locations/bulk-geocode.routes.ts"],"names":[],"mappings":"AAUA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAsCxB,OAAO,EAAE,MAAM,IAAI,iBAAiB,EAAE,CAAC"}
{"version":3,"file":"bulk-geocode.routes.d.ts","sourceRoot":"","sources":["../../../../src/modules/map/locations/bulk-geocode.routes.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAsCxB,OAAO,EAAE,MAAM,IAAI,iBAAiB,EAAE,CAAC"}

View File

@@ -2,17 +2,16 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.bulkGeocodeRouter = void 0;
const express_1 = require("express");
const client_1 = require("@prisma/client");
const geocode_queue_service_1 = require("../../../services/geocode-queue.service");
const bulk_geocode_schemas_1 = require("./bulk-geocode.schemas");
const validate_1 = require("../../../middleware/validate");
const auth_middleware_1 = require("../../../middleware/auth.middleware");
const rbac_middleware_1 = require("../../../middleware/rbac.middleware");
const MAP_ADMIN_ROLES = [client_1.UserRole.SUPER_ADMIN, client_1.UserRole.MAP_ADMIN];
const roles_1 = require("../../../utils/roles");
const router = (0, express_1.Router)();
exports.bulkGeocodeRouter = router;
router.use(auth_middleware_1.authenticate);
router.use((0, rbac_middleware_1.requireRole)(...MAP_ADMIN_ROLES));
router.use((0, rbac_middleware_1.requireRole)(...roles_1.MAP_ROLES));
// POST /api/map/locations/bulk-geocode — start bulk geocoding job
router.post('/', (0, validate_1.validate)(bulk_geocode_schemas_1.bulkGeocodeSchema), async (req, res, next) => {
try {

View File

@@ -1 +1 @@
{"version":3,"file":"bulk-geocode.routes.js","sourceRoot":"","sources":["../../../../src/modules/map/locations/bulk-geocode.routes.ts"],"names":[],"mappings":";;;AAAA,qCAAkE;AAClE,2CAA0C;AAC1C,mFAA8E;AAC9E,iEAA2D;AAC3D,2DAAwD;AACxD,yEAAmE;AACnE,yEAAkE;AAElE,MAAM,eAAe,GAAe,CAAC,iBAAQ,CAAC,WAAW,EAAE,iBAAQ,CAAC,SAAS,CAAC,CAAC;AAE/E,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAsCL,mCAAiB;AArCpC,MAAM,CAAC,GAAG,CAAC,8BAAY,CAAC,CAAC;AACzB,MAAM,CAAC,GAAG,CAAC,IAAA,6BAAW,EAAC,GAAG,eAAe,CAAC,CAAC,CAAC;AAE5C,kEAAkE;AAClE,MAAM,CAAC,IAAI,CACT,GAAG,EACH,IAAA,mBAAQ,EAAC,wCAAiB,CAAC,EAC3B,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACxD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,2CAAmB,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAK,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACjF,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,8DAA8D;AAC9D,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IAC9E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,2CAAmB,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAe,CAAC,CAAC;QAClF,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAa,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IAC9E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,2CAAmB,CAAC,QAAQ,EAAE,CAAC;QACnD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC;AACH,CAAC,CAAC,CAAC"}
{"version":3,"file":"bulk-geocode.routes.js","sourceRoot":"","sources":["../../../../src/modules/map/locations/bulk-geocode.routes.ts"],"names":[],"mappings":";;;AAAA,qCAAkE;AAClE,mFAA8E;AAC9E,iEAA2D;AAC3D,2DAAwD;AACxD,yEAAmE;AACnE,yEAAkE;AAClE,gDAAiD;AAEjD,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AAsCL,mCAAiB;AArCpC,MAAM,CAAC,GAAG,CAAC,8BAAY,CAAC,CAAC;AACzB,MAAM,CAAC,GAAG,CAAC,IAAA,6BAAW,EAAC,GAAG,iBAAS,CAAC,CAAC,CAAC;AAEtC,kEAAkE;AAClE,MAAM,CAAC,IAAI,CACT,GAAG,EACH,IAAA,mBAAQ,EAAC,wCAAiB,CAAC,EAC3B,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IACxD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,2CAAmB,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAK,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACjF,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,8DAA8D;AAC9D,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IAC9E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,2CAAmB,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAe,CAAC,CAAC;QAClF,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAa,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IAC9E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,2CAAmB,CAAC,QAAQ,EAAE,CAAC;QACnD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC;AACH,CAAC,CAAC,CAAC"}

View File

@@ -6,13 +6,13 @@ export declare const bulkGeocodeSchema: z.ZodObject<{
limit: z.ZodOptional<z.ZodNumber>;
}, "strip", z.ZodTypeAny, {
limit?: number | undefined;
buildingType?: "SINGLE_FAMILY" | "MULTI_UNIT" | "MIXED_USE" | "COMMERCIAL" | undefined;
cutId?: string | undefined;
buildingType?: "SINGLE_FAMILY" | "MULTI_UNIT" | "MIXED_USE" | "COMMERCIAL" | undefined;
confidenceThreshold?: number | undefined;
}, {
limit?: number | undefined;
buildingType?: "SINGLE_FAMILY" | "MULTI_UNIT" | "MIXED_USE" | "COMMERCIAL" | undefined;
cutId?: string | undefined;
buildingType?: "SINGLE_FAMILY" | "MULTI_UNIT" | "MIXED_USE" | "COMMERCIAL" | undefined;
confidenceThreshold?: number | undefined;
}>;
export type BulkGeocodeInput = z.infer<typeof bulkGeocodeSchema>;

View File

@@ -1 +1 @@
{"version":3,"file":"locations.routes.d.ts","sourceRoot":"","sources":["../../../../src/modules/map/locations/locations.routes.ts"],"names":[],"mappings":"AAiDA,QAAA,MAAM,WAAW,4CAAW,CAAC;AA4R7B,QAAA,MAAM,YAAY,4CAAW,CAAC;AA4B9B,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,YAAY,IAAI,qBAAqB,EAAE,CAAC"}
{"version":3,"file":"locations.routes.d.ts","sourceRoot":"","sources":["../../../../src/modules/map/locations/locations.routes.ts"],"names":[],"mappings":"AA+CA,QAAA,MAAM,WAAW,4CAAW,CAAC;AA4R7B,QAAA,MAAM,YAAY,4CAAW,CAAC;AA4B9B,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,YAAY,IAAI,qBAAqB,EAAE,CAAC"}

View File

@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.locationsPublicRouter = exports.locationsAdminRouter = void 0;
const express_1 = require("express");
const client_1 = require("@prisma/client");
const multer_1 = __importDefault(require("multer"));
const locations_service_1 = require("./locations.service");
const locations_schemas_1 = require("./locations.schemas");
@@ -14,7 +13,7 @@ const database_1 = require("../../../config/database");
const validate_1 = require("../../../middleware/validate");
const auth_middleware_1 = require("../../../middleware/auth.middleware");
const rbac_middleware_1 = require("../../../middleware/rbac.middleware");
const MAP_ADMIN_ROLES = [client_1.UserRole.SUPER_ADMIN, client_1.UserRole.MAP_ADMIN];
const roles_1 = require("../../../utils/roles");
// Multer config for CSV upload (memory storage, 10MB limit)
const upload = (0, multer_1.default)({
storage: multer_1.default.memoryStorage(),
@@ -45,7 +44,7 @@ const bulkUpload = (0, multer_1.default)({
const adminRouter = (0, express_1.Router)();
exports.locationsAdminRouter = adminRouter;
adminRouter.use(auth_middleware_1.authenticate);
adminRouter.use((0, rbac_middleware_1.requireRole)(...MAP_ADMIN_ROLES));
adminRouter.use((0, rbac_middleware_1.requireRole)(...roles_1.MAP_ROLES));
// GET /api/map/locations — list with pagination + filters
adminRouter.get('/', (0, validate_1.validate)(locations_schemas_1.listLocationsSchema, 'query'), async (req, res, next) => {
try {

File diff suppressed because one or more lines are too long

View File

@@ -25,27 +25,27 @@ export declare const createLocationSchema: z.ZodObject<{
phone?: string | undefined;
latitude?: number | undefined;
longitude?: number | undefined;
buildingNotes?: string | undefined;
unitNumber?: string | undefined;
notes?: string | undefined;
firstName?: string | undefined;
lastName?: string | undefined;
supportLevel?: "LEVEL_1" | "LEVEL_2" | "LEVEL_3" | "LEVEL_4" | undefined;
unitNumber?: string | undefined;
buildingNotes?: string | undefined;
signSize?: string | undefined;
notes?: string | undefined;
}, {
address: string;
email?: string | undefined;
phone?: string | undefined;
latitude?: number | undefined;
longitude?: number | undefined;
buildingNotes?: string | undefined;
unitNumber?: string | undefined;
notes?: string | undefined;
firstName?: string | undefined;
lastName?: string | undefined;
supportLevel?: "LEVEL_1" | "LEVEL_2" | "LEVEL_3" | "LEVEL_4" | undefined;
unitNumber?: string | undefined;
buildingNotes?: string | undefined;
sign?: boolean | undefined;
signSize?: string | undefined;
notes?: string | undefined;
}>;
export declare const updateLocationSchema: z.ZodObject<{
address: z.ZodOptional<z.ZodString>;
@@ -79,35 +79,35 @@ export declare const updateLocationSchema: z.ZodObject<{
phone?: string | null | undefined;
latitude?: number | null | undefined;
longitude?: number | null | undefined;
notes?: string | null | undefined;
firstName?: string | null | undefined;
lastName?: string | null | undefined;
supportLevel?: "LEVEL_1" | "LEVEL_2" | "LEVEL_3" | "LEVEL_4" | null | undefined;
address?: string | undefined;
unitNumber?: string | null | undefined;
postalCode?: string | null | undefined;
province?: string | null | undefined;
buildingType?: "SINGLE_FAMILY" | "MULTI_UNIT" | "MIXED_USE" | "COMMERCIAL" | null | undefined;
buildingNotes?: string | null | undefined;
unitNumber?: string | null | undefined;
firstName?: string | null | undefined;
lastName?: string | null | undefined;
supportLevel?: "LEVEL_1" | "LEVEL_2" | "LEVEL_3" | "LEVEL_4" | null | undefined;
sign?: boolean | undefined;
signSize?: string | null | undefined;
notes?: string | null | undefined;
}, {
email?: string | null | undefined;
phone?: string | null | undefined;
latitude?: number | null | undefined;
longitude?: number | null | undefined;
notes?: string | null | undefined;
firstName?: string | null | undefined;
lastName?: string | null | undefined;
supportLevel?: "LEVEL_1" | "LEVEL_2" | "LEVEL_3" | "LEVEL_4" | null | undefined;
address?: string | undefined;
unitNumber?: string | null | undefined;
postalCode?: string | null | undefined;
province?: string | null | undefined;
buildingType?: "SINGLE_FAMILY" | "MULTI_UNIT" | "MIXED_USE" | "COMMERCIAL" | null | undefined;
buildingNotes?: string | null | undefined;
unitNumber?: string | null | undefined;
firstName?: string | null | undefined;
lastName?: string | null | undefined;
supportLevel?: "LEVEL_1" | "LEVEL_2" | "LEVEL_3" | "LEVEL_4" | null | undefined;
sign?: boolean | undefined;
signSize?: string | null | undefined;
notes?: string | null | undefined;
}>;
export declare const listLocationsSchema: z.ZodObject<{
page: z.ZodDefault<z.ZodNumber>;
@@ -126,21 +126,21 @@ export declare const listLocationsSchema: z.ZodObject<{
}, "strip", z.ZodTypeAny, {
limit: number;
page: number;
sortBy: "createdAt" | "address" | "supportLevel";
sortBy: "createdAt" | "supportLevel" | "address";
sortOrder: "asc" | "desc";
search?: string | undefined;
supportLevel?: "LEVEL_1" | "LEVEL_2" | "LEVEL_3" | "LEVEL_4" | undefined;
hasSign?: boolean | undefined;
confidenceLevel?: "high" | "medium" | "low" | "none" | undefined;
confidenceLevel?: "none" | "low" | "medium" | "high" | undefined;
}, {
search?: string | undefined;
limit?: number | undefined;
page?: number | undefined;
sortBy?: "createdAt" | "supportLevel" | "address" | undefined;
sortOrder?: "asc" | "desc" | undefined;
supportLevel?: "LEVEL_1" | "LEVEL_2" | "LEVEL_3" | "LEVEL_4" | undefined;
hasSign?: boolean | undefined;
confidenceLevel?: "high" | "medium" | "low" | "none" | undefined;
sortBy?: "createdAt" | "address" | "supportLevel" | undefined;
sortOrder?: "asc" | "desc" | undefined;
confidenceLevel?: "none" | "low" | "medium" | "high" | undefined;
}>;
export declare const locationIdSchema: z.ZodObject<{
id: z.ZodString;
@@ -185,7 +185,7 @@ export declare const bulkImportSchema: z.ZodObject<{
batchSize: z.ZodDefault<z.ZodNumber>;
}, "strip", z.ZodTypeAny, {
format: "standard" | "nar";
filterType: "city" | "cut" | "province" | "none" | "mapArea";
filterType: "none" | "city" | "cut" | "province" | "mapArea";
residentialOnly: boolean;
deduplicateRadius: number;
skipGeocoding: boolean;
@@ -194,9 +194,9 @@ export declare const bulkImportSchema: z.ZodObject<{
filterCity?: string | undefined;
filterProvince?: string | undefined;
}, {
cutId?: string | undefined;
format?: "standard" | "nar" | undefined;
filterType?: "city" | "cut" | "province" | "none" | "mapArea" | undefined;
cutId?: string | undefined;
filterType?: "none" | "city" | "cut" | "province" | "mapArea" | undefined;
filterCity?: string | undefined;
filterProvince?: string | undefined;
residentialOnly?: boolean | undefined;

View File

@@ -16,10 +16,10 @@ export declare const locationsService: {
locations: ({
addresses: {
id: string;
unitNumber: string | null;
firstName: string | null;
lastName: string | null;
supportLevel: import(".prisma/client").$Enums.SupportLevel | null;
unitNumber: string | null;
sign: boolean;
}[];
} & {
@@ -28,8 +28,9 @@ export declare const locationsService: {
updatedAt: Date;
latitude: Prisma.Decimal;
longitude: Prisma.Decimal;
address: string;
createdByUserId: string | null;
updatedByUserId: string | null;
address: string;
postalCode: string | null;
province: string | null;
federalDistrict: string | null;
@@ -40,7 +41,6 @@ export declare const locationsService: {
buildingNotes: string | null;
geocodeConfidence: number | null;
geocodeProvider: import(".prisma/client").$Enums.GeocodeProvider | null;
updatedByUserId: string | null;
})[];
pagination: {
page: number;
@@ -54,13 +54,13 @@ export declare const locationsService: {
id: string;
email: string | null;
phone: string | null;
unitNumber: string | null;
notes: string | null;
firstName: string | null;
lastName: string | null;
supportLevel: import(".prisma/client").$Enums.SupportLevel | null;
unitNumber: string | null;
sign: boolean;
signSize: string | null;
notes: string | null;
}[];
} & {
id: string;
@@ -68,8 +68,9 @@ export declare const locationsService: {
updatedAt: Date;
latitude: Prisma.Decimal;
longitude: Prisma.Decimal;
address: string;
createdByUserId: string | null;
updatedByUserId: string | null;
address: string;
postalCode: string | null;
province: string | null;
federalDistrict: string | null;
@@ -80,16 +81,16 @@ export declare const locationsService: {
buildingNotes: string | null;
geocodeConfidence: number | null;
geocodeProvider: import(".prisma/client").$Enums.GeocodeProvider | null;
updatedByUserId: string | null;
}>;
create(data: CreateLocationInput, userId: string): Promise<{
create(data: CreateLocationInput, userId: string | null): Promise<{
id: string;
createdAt: Date;
updatedAt: Date;
latitude: Prisma.Decimal;
longitude: Prisma.Decimal;
address: string;
createdByUserId: string | null;
updatedByUserId: string | null;
address: string;
postalCode: string | null;
province: string | null;
federalDistrict: string | null;
@@ -100,7 +101,6 @@ export declare const locationsService: {
buildingNotes: string | null;
geocodeConfidence: number | null;
geocodeProvider: import(".prisma/client").$Enums.GeocodeProvider | null;
updatedByUserId: string | null;
}>;
update(id: string, data: UpdateLocationInput, userId: string): Promise<{
id: string;
@@ -108,8 +108,9 @@ export declare const locationsService: {
updatedAt: Date;
latitude: Prisma.Decimal;
longitude: Prisma.Decimal;
address: string;
createdByUserId: string | null;
updatedByUserId: string | null;
address: string;
postalCode: string | null;
province: string | null;
federalDistrict: string | null;
@@ -120,7 +121,6 @@ export declare const locationsService: {
buildingNotes: string | null;
geocodeConfidence: number | null;
geocodeProvider: import(".prisma/client").$Enums.GeocodeProvider | null;
updatedByUserId: string | null;
}>;
delete(id: string): Promise<void>;
bulkDelete(ids: string[]): Promise<{
@@ -139,11 +139,11 @@ export declare const locationsService: {
createdAt: Date;
userId: string | null;
action: import(".prisma/client").$Enums.LocationHistoryAction;
metadata: Prisma.JsonValue | null;
locationId: string;
field: string | null;
oldValue: string | null;
newValue: string | null;
metadata: Prisma.JsonValue | null;
})[];
pagination: {
page: number;
@@ -195,13 +195,13 @@ export declare const locationsService: {
id: string;
email: string | null;
phone: string | null;
unitNumber: string | null;
notes: string | null;
firstName: string | null;
lastName: string | null;
supportLevel: import(".prisma/client").$Enums.SupportLevel | null;
unitNumber: string | null;
sign: boolean;
signSize: string | null;
notes: string | null;
}[];
} & {
id: string;
@@ -209,8 +209,9 @@ export declare const locationsService: {
updatedAt: Date;
latitude: Prisma.Decimal;
longitude: Prisma.Decimal;
address: string;
createdByUserId: string | null;
updatedByUserId: string | null;
address: string;
postalCode: string | null;
province: string | null;
federalDistrict: string | null;
@@ -221,7 +222,6 @@ export declare const locationsService: {
buildingNotes: string | null;
geocodeConfidence: number | null;
geocodeProvider: import(".prisma/client").$Enums.GeocodeProvider | null;
updatedByUserId: string | null;
})[]>;
getPublicLocations(bounds?: {
minLat: number;
@@ -232,14 +232,14 @@ export declare const locationsService: {
id: string;
latitude: Prisma.Decimal;
longitude: Prisma.Decimal;
address: string;
addresses: {
id: string;
unitNumber: string | null;
supportLevel: import(".prisma/client").$Enums.SupportLevel | null;
unitNumber: string | null;
sign: boolean;
signSize: string | null;
}[];
address: string;
}[]>;
importFromCsv(buffer: Buffer, userId: string): Promise<{
total: number;

View File

@@ -1 +1 @@
{"version":3,"file":"locations.service.d.ts","sourceRoot":"","sources":["../../../../src/modules/map/locations/locations.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,EAA0C,MAAM,gBAAgB,CAAC;AAU9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAKzH,UAAU,aAAa;IACrB,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAkLD,eAAO,MAAM,gBAAgB;qBACJ,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0FtB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0BN,mBAAmB,UAAU,MAAM;;;;;;;;;;;;;;;;;;;;eA2ErC,MAAM,QAAQ,mBAAmB,UAAU,MAAM;;;;;;;;;;;;;;;;;;;;eA2HjD,MAAM;oBAQD,MAAM,EAAE;;;2BAOD,MAAM,SAAQ,MAAM,UAAa,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;4BA4BtC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAwIR;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,UAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA4C3E;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;0BA0CxE,MAAM,UAAU,MAAM;;;;;;;6BA4GnB,MAAM,aAAa,MAAM;uBAS9C,MAAM,UACN,MAAM,WACL,eAAe,YACd,aAAa;;;;;;;;0BAgUG;QAAE,YAAY,CAAC,EAAE,YAAY,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE;CAiD/E,CAAC"}
{"version":3,"file":"locations.service.d.ts","sourceRoot":"","sources":["../../../../src/modules/map/locations/locations.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,EAA0C,MAAM,gBAAgB,CAAC;AAW9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAKzH,UAAU,aAAa;IACrB,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAkLD,eAAO,MAAM,gBAAgB;qBACJ,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0FtB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0BN,mBAAmB,UAAU,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;eA2E5C,MAAM,QAAQ,mBAAmB,UAAU,MAAM;;;;;;;;;;;;;;;;;;;;eA2HjD,MAAM;oBAQD,MAAM,EAAE;;;2BAOD,MAAM,SAAQ,MAAM,UAAa,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;4BA4BtC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAwIR;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,UAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA4C3E;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;0BA2DxE,MAAM,UAAU,MAAM;;;;;;;6BA4GnB,MAAM,aAAa,MAAM;uBAS9C,MAAM,UACN,MAAM,WACL,eAAe,YACd,aAAa;;;;;;;;0BAgUG;QAAE,YAAY,CAAC,EAAE,YAAY,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE;CAyD/E,CAAC"}

View File

@@ -14,6 +14,7 @@ const geocoding_service_1 = require("../geocoding/geocoding.service");
const logger_1 = require("../../../utils/logger");
const metrics_1 = require("../../../utils/metrics");
const spatial_1 = require("../../../utils/spatial");
const settings_service_1 = require("../settings/settings.service");
// Statistics Canada Lambert Conformal Conic projection (EPSG:3347) → WGS84 (EPSG:4326)
proj4_1.default.defs('EPSG:3347', '+proj=lcc +lat_1=49 +lat_2=77 +lat_0=63.390675 +lon_0=-91.86666666666666 +x_0=6200000 +y_0=3000000 +ellps=GRS80 +units=m +no_defs');
// Map CSV header names to our fields (case-insensitive, flexible)
@@ -685,6 +686,21 @@ exports.locationsService = {
},
take: 5000, // Safety limit
});
// Server-side enforcement: strip sensitive fields based on map visibility settings
const mapSettings = await settings_service_1.mapSettingsService.get();
if (!mapSettings.publicShowSupportLevels || !mapSettings.publicShowSignInfo) {
for (const loc of locations) {
for (const addr of loc.addresses) {
if (!mapSettings.publicShowSupportLevels) {
addr.supportLevel = null;
}
if (!mapSettings.publicShowSignInfo) {
addr.sign = false;
addr.signSize = null;
}
}
}
}
const durationSeconds = (Date.now() - startTime) / 1000;
(0, metrics_1.recordLocationQuery)('public', !!bounds, locations.length, durationSeconds);
return locations;
@@ -1099,6 +1115,14 @@ exports.locationsService = {
include: { addresses: true },
orderBy: { createdAt: 'desc' },
});
// Sanitize a field value against CSV formula injection.
// Spreadsheet apps treat cells starting with =, +, -, @, \t, \r as formulas.
// Prefixing with an apostrophe causes Excel/Sheets to treat the value as plain text.
function sanitizeCsvField(value) {
if (/^[=+\-@\t\r]/.test(value))
return `'${value}`;
return value;
}
// Flatten: one row per address
const rows = [];
for (const loc of locations) {
@@ -1109,16 +1133,16 @@ exports.locationsService = {
if (filters?.hasSign !== undefined && addr.sign !== filters.hasSign)
continue;
rows.push({
address: loc.address || '',
unitNumber: addr.unitNumber || '',
firstName: addr.firstName || '',
lastName: addr.lastName || '',
email: addr.email || '',
phone: addr.phone || '',
address: sanitizeCsvField(loc.address || ''),
unitNumber: sanitizeCsvField(addr.unitNumber || ''),
firstName: sanitizeCsvField(addr.firstName || ''),
lastName: sanitizeCsvField(addr.lastName || ''),
email: sanitizeCsvField(addr.email || ''),
phone: sanitizeCsvField(addr.phone || ''),
supportLevel: addr.supportLevel || '',
sign: addr.sign ? 'Yes' : 'No',
signSize: addr.signSize || '',
notes: addr.notes || '',
notes: sanitizeCsvField(addr.notes || ''),
latitude: loc.latitude?.toString() || '',
longitude: loc.longitude?.toString() || '',
geocodeConfidence: loc.geocodeConfidence?.toString() || '',

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"nar-import.routes.d.ts","sourceRoot":"","sources":["../../../../src/modules/map/locations/nar-import.routes.ts"],"names":[],"mappings":"AAwBA,QAAA,MAAM,eAAe,4CAAW,CAAC;AAoFjC,OAAO,EAAE,eAAe,EAAE,CAAC"}
{"version":3,"file":"nar-import.routes.d.ts","sourceRoot":"","sources":["../../../../src/modules/map/locations/nar-import.routes.ts"],"names":[],"mappings":"AAsBA,QAAA,MAAM,eAAe,4CAAW,CAAC;AAoFjC,OAAO,EAAE,eAAe,EAAE,CAAC"}

View File

@@ -2,7 +2,6 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.narImportRouter = void 0;
const express_1 = require("express");
const client_1 = require("@prisma/client");
const zod_1 = require("zod");
const crypto_1 = require("crypto");
const nar_import_service_1 = require("./nar-import.service");
@@ -11,7 +10,7 @@ const logger_1 = require("../../../utils/logger");
const auth_middleware_1 = require("../../../middleware/auth.middleware");
const rbac_middleware_1 = require("../../../middleware/rbac.middleware");
const validate_1 = require("../../../middleware/validate");
const MAP_ADMIN_ROLES = [client_1.UserRole.SUPER_ADMIN, client_1.UserRole.MAP_ADMIN];
const roles_1 = require("../../../utils/roles");
const serverImportSchema = zod_1.z.object({
provinceCode: zod_1.z.string().min(1).max(2),
filterType: zod_1.z.enum(['none', 'city', 'postalPrefix', 'cut']).default('none'),
@@ -25,7 +24,7 @@ const serverImportSchema = zod_1.z.object({
const narImportRouter = (0, express_1.Router)();
exports.narImportRouter = narImportRouter;
narImportRouter.use(auth_middleware_1.authenticate);
narImportRouter.use((0, rbac_middleware_1.requireRole)(...MAP_ADMIN_ROLES));
narImportRouter.use((0, rbac_middleware_1.requireRole)(...roles_1.MAP_ROLES));
// GET /api/map/nar-import/datasets — list available NAR datasets by province
narImportRouter.get('/datasets', async (_req, res, next) => {
try {

View File

@@ -1 +1 @@
{"version":3,"file":"nar-import.routes.js","sourceRoot":"","sources":["../../../../src/modules/map/locations/nar-import.routes.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"nar-import.routes.js","sourceRoot":"","sources":["../../../../src/modules/map/locations/nar-import.routes.ts"],"names":[],"mappings":"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"}