"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var RoadRefinementController_1; var _a, _b, _c; Object.defineProperty(exports, "__esModule", { value: true }); exports.RoadRefinementController = void 0; const common_1 = require("@nestjs/common"); const swagger_1 = require("@nestjs/swagger"); const typeorm_1 = require("@nestjs/typeorm"); const typeorm_2 = require("typeorm"); const candidate_road_entity_1 = require("./candidate-road.entity"); const road_stat_entity_1 = require("./road-stat.entity"); const api_key_guard_1 = require("../common/guards/api-key.guard"); let RoadRefinementController = RoadRefinementController_1 = class RoadRefinementController { candidateRepo; roadStatRepo; dataSource; logger = new common_1.Logger(RoadRefinementController_1.name); constructor(candidateRepo, roadStatRepo, dataSource) { this.candidateRepo = candidateRepo; this.roadStatRepo = roadStatRepo; this.dataSource = dataSource; } async getSummary() { try { const [cCount] = await this.dataSource.query("SELECT COUNT(*) as total, COUNT(*) FILTER (WHERE status='pending') as pending FROM candidate_roads"); const [clCount] = await this.dataSource.query('SELECT COUNT(*) as count FROM road_segment_stats WHERE "isClosed" = true'); const [rCount] = await this.dataSource.query('SELECT COUNT(*) as count FROM road_segment_stats'); return { roads: { analyzed: parseInt(rCount?.count || '0', 10), closed: parseInt(clCount?.count || '0', 10), }, candidates: { total: parseInt(cCount?.total || '0', 10), pending: parseInt(cCount?.pending || '0', 10), }, }; } catch (e) { this.logger.error(`Error in summary: ${e.message}`); return { roads: { analyzed: 0, closed: 0 }, candidates: { total: 0, pending: 0 }, }; } } async getCandidates(status) { const s = status || 'pending'; try { const rows = await this.dataSource.query(`SELECT id, "uniqueDriverCount", "totalPoints", "averageSpeed", "lengthMeters", confidence, status, source, name, highway, oneway, "discoveredAt", "reviewedAt", ST_AsGeoJSON(geometry) as geojson FROM candidate_roads WHERE status = $1 ORDER BY confidence DESC, "discoveredAt" DESC LIMIT 100`, [s]); return rows.map((r) => ({ ...r, geometry: r.geojson ? JSON.parse(r.geojson) : null, })); } catch (e) { this.logger.error(`Error fetching candidates: ${e.message}`); return []; } } async submitManualCandidate(body) { if (!body.geojson || !body.geojson.coordinates || body.geojson.coordinates.length < 2) { throw new common_1.HttpException('Invalid GeoJSON LineString coordinates', common_1.HttpStatus.BAD_REQUEST); } try { const geojsonStr = JSON.stringify(body.geojson); const name = body.name || 'Unnamed Road'; const highway = body.highway || 'residential'; let result; try { result = await this.dataSource.query(`WITH raw_input AS ( SELECT ST_SetSRID(ST_GeomFromGeoJSON($1), 4326) AS geom ), start_snap AS ( SELECT COALESCE( ( SELECT ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326) FROM raw_input r CROSS JOIN LATERAL (SELECT ST_Transform(ST_StartPoint(r.geom), 3857) AS pt) p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) JOIN planet_osm_ways w ON w.id = l.osm_id CROSS JOIN LATERAL unnest(w.nodes) AS wn(node_id) JOIN planet_osm_nodes n ON n.id = wn.node_id WHERE ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, ST_StartPoint(r.geom)::geography) < 30 ORDER BY ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, ST_StartPoint(r.geom)::geography) ASC LIMIT 1 ), ( SELECT ST_Transform(ST_ClosestPoint(l.way, ST_Transform(ST_StartPoint(r.geom), 3857)), 4326) FROM raw_input r JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(ST_Transform(ST_StartPoint(r.geom), 3857), 60) WHERE ST_Distance(ST_Transform(l.way, 4326)::geography, ST_StartPoint(r.geom)::geography) < 30 ORDER BY ST_Distance(l.way, ST_Transform(ST_StartPoint(r.geom), 3857)) ASC LIMIT 1 ), (SELECT ST_StartPoint(geom) FROM raw_input) ) AS pt ), end_snap AS ( SELECT COALESCE( ( SELECT ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326) FROM raw_input r CROSS JOIN LATERAL (SELECT ST_Transform(ST_EndPoint(r.geom), 3857) AS pt) p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) JOIN planet_osm_ways w ON w.id = l.osm_id CROSS JOIN LATERAL unnest(w.nodes) AS wn(node_id) JOIN planet_osm_nodes n ON n.id = wn.node_id WHERE ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, ST_EndPoint(r.geom)::geography) < 30 ORDER BY ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, ST_EndPoint(r.geom)::geography) ASC LIMIT 1 ), ( SELECT ST_Transform(ST_ClosestPoint(l.way, ST_Transform(ST_EndPoint(r.geom), 3857)), 4326) FROM raw_input r JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(ST_Transform(ST_EndPoint(r.geom), 3857), 60) WHERE ST_Distance(ST_Transform(l.way, 4326)::geography, ST_EndPoint(r.geom)::geography) < 30 ORDER BY ST_Distance(l.way, ST_Transform(ST_EndPoint(r.geom), 3857)) ASC LIMIT 1 ), (SELECT ST_EndPoint(geom) FROM raw_input) ) AS pt ), snapped_input AS ( SELECT ST_SetPoint( ST_SetPoint(r.geom, 0, s.pt), ST_NPoints(r.geom) - 1, e.pt ) AS geom FROM raw_input r, start_snap s, end_snap e ) INSERT INTO candidate_roads ( geometry, "uniqueDriverCount", "totalPoints", "averageSpeed", "lengthMeters", confidence, status, source, name, highway, oneway, "discoveredAt" ) SELECT geom, 1, 10, 30.0, ST_Length(ST_Transform(geom, 3857)), 0.90, 'pending', 'manual', $2, $3, 0, NOW() FROM snapped_input RETURNING id, name, highway, confidence, status`, [geojsonStr, name, highway]); } catch (err) { this.logger.warn(`Complex snapping query failed, falling back to direct insertion: ${err.message}`); result = await this.dataSource.query(`INSERT INTO candidate_roads ( geometry, "uniqueDriverCount", "totalPoints", "averageSpeed", "lengthMeters", confidence, status, source, name, highway, oneway, "discoveredAt" ) VALUES ( ST_SetSRID(ST_GeomFromGeoJSON($1), 4326), 1, 10, 30.0, ST_Length(ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON($1), 4326), 3857)), 0.90, 'pending', 'manual', $2, $3, 0, NOW() ) RETURNING id, name, highway, confidence, status`, [geojsonStr, name, highway]); } this.logger.log(`✍️ Manual candidate road registered: ${result[0]?.id} (${name})`); return { success: true, candidate: result[0] }; } catch (e) { this.logger.error(`Failed to insert manual candidate road: ${e.message}`); throw new common_1.HttpException(`Failed to create candidate road: ${e.message}`, common_1.HttpStatus.INTERNAL_SERVER_ERROR); } } async approveCandidate(id) { try { await this.dataSource.query(` CREATE TABLE IF NOT EXISTS approved_roads ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), candidate_id UUID UNIQUE, geometry GEOMETRY(LineString, 4326), name VARCHAR(255), highway VARCHAR(32), confidence FLOAT, "uniqueDriverCount" INT DEFAULT 1, oneway SMALLINT DEFAULT 0, start_node BIGINT, end_node BIGINT, approved_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS approved_roads_geom_idx ON approved_roads USING GIST(geometry); CREATE UNIQUE INDEX IF NOT EXISTS approved_roads_cand_uidx ON approved_roads(candidate_id) WHERE candidate_id IS NOT NULL; `); await this.candidateRepo.update(id, { status: 'approved', reviewedAt: new Date(), }); await this.dataSource.query(` DO $$ DECLARE cand RECORD; start_pt GEOMETRY; end_pt GEOMETRY; snapped_geom GEOMETRY; s_node BIGINT := NULL; e_node BIGINT := NULL; node_rec RECORD; line_rec RECORD; BEGIN SELECT id, geometry::geometry as geom, name, COALESCE(highway, 'residential') as highway, confidence, "uniqueDriverCount", oneway INTO cand FROM candidate_roads WHERE id = $1; IF FOUND THEN snapped_geom := cand.geom; start_pt := ST_StartPoint(snapped_geom); end_pt := ST_EndPoint(snapped_geom); -- 1. Start node & geometry snapping BEGIN WITH p AS (SELECT ST_Transform(start_pt, 3857) AS pt) SELECT n.id, n.lon/1e7 as lon, n.lat/1e7 as lat INTO node_rec FROM p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) JOIN planet_osm_ways w ON w.id = l.osm_id CROSS JOIN LATERAL unnest(w.nodes) AS wn(node_id) JOIN planet_osm_nodes n ON n.id = wn.node_id WHERE ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, start_pt::geography) < 30 ORDER BY ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, start_pt::geography) ASC LIMIT 1; IF FOUND THEN s_node := node_rec.id; snapped_geom := ST_SetPoint(snapped_geom, 0, ST_SetSRID(ST_MakePoint(node_rec.lon, node_rec.lat), 4326)); ELSE WITH p AS (SELECT ST_Transform(start_pt, 3857) AS pt) SELECT ST_X(ST_Transform(ST_ClosestPoint(l.way, p.pt), 4326)) as lon, ST_Y(ST_Transform(ST_ClosestPoint(l.way, p.pt), 4326)) as lat INTO line_rec FROM p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) WHERE ST_Distance(ST_Transform(l.way, 4326)::geography, start_pt::geography) < 30 ORDER BY ST_Distance(l.way, p.pt) ASC LIMIT 1; IF FOUND THEN snapped_geom := ST_SetPoint(snapped_geom, 0, ST_SetSRID(ST_MakePoint(line_rec.lon, line_rec.lat), 4326)); END IF; END IF; EXCEPTION WHEN OTHERS THEN NULL; END; -- 2. End node & geometry snapping BEGIN WITH p AS (SELECT ST_Transform(end_pt, 3857) AS pt) SELECT n.id, n.lon/1e7 as lon, n.lat/1e7 as lat INTO node_rec FROM p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) JOIN planet_osm_ways w ON w.id = l.osm_id CROSS JOIN LATERAL unnest(w.nodes) AS wn(node_id) JOIN planet_osm_nodes n ON n.id = wn.node_id WHERE ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, end_pt::geography) < 30 ORDER BY ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, end_pt::geography) ASC LIMIT 1; IF FOUND THEN e_node := node_rec.id; snapped_geom := ST_SetPoint(snapped_geom, ST_NPoints(snapped_geom) - 1, ST_SetSRID(ST_MakePoint(node_rec.lon, node_rec.lat), 4326)); ELSE WITH p AS (SELECT ST_Transform(end_pt, 3857) AS pt) SELECT ST_X(ST_Transform(ST_ClosestPoint(l.way, p.pt), 4326)) as lon, ST_Y(ST_Transform(ST_ClosestPoint(l.way, p.pt), 4326)) as lat INTO line_rec FROM p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) WHERE ST_Distance(ST_Transform(l.way, 4326)::geography, end_pt::geography) < 30 ORDER BY ST_Distance(l.way, p.pt) ASC LIMIT 1; IF FOUND THEN snapped_geom := ST_SetPoint(snapped_geom, ST_NPoints(snapped_geom) - 1, ST_SetSRID(ST_MakePoint(line_rec.lon, line_rec.lat), 4326)); END IF; END IF; EXCEPTION WHEN OTHERS THEN NULL; END; -- Update candidate_roads UPDATE candidate_roads SET geometry = snapped_geom WHERE id = cand.id; -- Insert or update approved_roads INSERT INTO approved_roads ( candidate_id, geometry, name, highway, confidence, "uniqueDriverCount", oneway, start_node, end_node ) VALUES ( cand.id, snapped_geom, cand.name, cand.highway, cand.confidence, cand."uniqueDriverCount", cand.oneway, s_node, e_node ) ON CONFLICT (candidate_id) DO UPDATE SET geometry = EXCLUDED.geometry, start_node = EXCLUDED.start_node, end_node = EXCLUDED.end_node; END IF; END $$; `, [id]); try { await this.dataSource.query(` DO $$ DECLARE r RECORD; target_table TEXT := 'places_jordan'; center_lat FLOAT; center_lng FLOAT; BEGIN SELECT name, ST_Y(ST_Centroid(geometry::geometry)) as lat, ST_X(ST_Centroid(geometry::geometry)) as lng INTO r FROM candidate_roads WHERE id = $1 AND name IS NOT NULL AND trim(name) != ''; IF FOUND THEN center_lat := r.lat; center_lng := r.lng; IF center_lat >= 29 AND center_lat <= 37.5 AND center_lng >= 38.7 AND center_lng <= 48.8 THEN target_table := 'places_iraq'; ELSIF center_lat >= 29 AND center_lat <= 37.5 AND center_lng >= 34.5 AND center_lng <= 42.5 THEN IF center_lat > 32.5 AND center_lng > 35.8 THEN target_table := 'places_syria'; ELSE target_table := 'places_jordan'; END IF; ELSIF center_lat >= 22 AND center_lat <= 32 AND center_lng >= 24.5 AND center_lng <= 37 THEN target_table := 'places_egypt'; END IF; EXECUTE format(' INSERT INTO %I (name, name_ar, category, latitude, longitude, location, source) VALUES ($1, $1, $2, $3, $4, ST_SetSRID(ST_MakePoint($4, $3), 4326), $5) ', target_table) USING r.name, 'street', center_lat, center_lng, 'approved_road'; END IF; END $$; `, [id]); } catch (err) { this.logger.warn(`Could not index approved road to places: ${err.message}`); } this.logger.log(`βœ… Road candidate ${id} approved & published.`); return { success: true, id, status: 'approved' }; } catch (e) { this.logger.error(`Failed to approve candidate road: ${e.message}`); throw new common_1.HttpException(e.message, common_1.HttpStatus.INTERNAL_SERVER_ERROR); } } async rejectCandidate(id) { try { await this.candidateRepo.update(id, { status: 'rejected', reviewedAt: new Date(), }); return { success: true, id, status: 'rejected' }; } catch (e) { this.logger.error(`Failed to reject candidate road: ${e.message}`); throw new common_1.HttpException(e.message, common_1.HttpStatus.INTERNAL_SERVER_ERROR); } } async getClosures() { return this.roadStatRepo.find({ where: { isClosed: true }, order: { sampleCount: 'DESC' }, take: 50, }); } async discoverOvertureGaps() { try { const exists = await this.dataSource.query(` SELECT to_regclass('public.overture_transportation') as tbl; `); if (!exists[0]?.tbl) { return { success: true, candidatesFound: 0, message: 'Overture transportation table not loaded yet.' }; } const inserted = await this.dataSource.query(` INSERT INTO candidate_roads (geometry, "uniqueDriverCount", "totalPoints", "averageSpeed", "lengthMeters", confidence, status, source, name, highway, oneway) SELECT o.geometry, 5, 50, 40.0, ST_Length(ST_Transform(o.geometry::geometry, 3857)), 0.85, 'pending', 'overture', o.name, COALESCE(o.class, 'residential'), 0 FROM overture_transportation o WHERE NOT EXISTS ( SELECT 1 FROM planet_osm_line l WHERE ST_DWithin(ST_Transform(o.geometry::geometry, 3857), l.way, 25) ) AND ST_Length(ST_Transform(o.geometry::geometry, 3857)) > 40 LIMIT 50 RETURNING id; `); return { success: true, candidatesFound: inserted.length }; } catch (e) { this.logger.warn(`Overture gap check skipped: ${e.message}`); return { success: true, candidatesFound: 0 }; } } async discoverClosures() { return { success: true, roadsClosed: 0 }; } async snapExistingApprovedRoads() { try { await this.dataSource.query(` DO $$ DECLARE r RECORD; start_pt GEOMETRY; end_pt GEOMETRY; snapped_geom GEOMETRY; s_node BIGINT; e_node BIGINT; node_rec RECORD; line_rec RECORD; BEGIN FOR r IN SELECT id, geometry FROM approved_roads LOOP snapped_geom := r.geometry; s_node := NULL; e_node := NULL; start_pt := ST_StartPoint(snapped_geom); end_pt := ST_EndPoint(snapped_geom); -- Snap start BEGIN WITH p AS (SELECT ST_Transform(start_pt, 3857) AS pt) SELECT n.id, n.lon/1e7 as lon, n.lat/1e7 as lat INTO node_rec FROM p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) JOIN planet_osm_ways w ON w.id = l.osm_id CROSS JOIN LATERAL unnest(w.nodes) AS wn(node_id) JOIN planet_osm_nodes n ON n.id = wn.node_id WHERE ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, start_pt::geography) < 30 ORDER BY ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, start_pt::geography) ASC LIMIT 1; IF FOUND THEN s_node := node_rec.id; snapped_geom := ST_SetPoint(snapped_geom, 0, ST_SetSRID(ST_MakePoint(node_rec.lon, node_rec.lat), 4326)); ELSE WITH p AS (SELECT ST_Transform(start_pt, 3857) AS pt) SELECT ST_X(ST_Transform(ST_ClosestPoint(l.way, p.pt), 4326)) as lon, ST_Y(ST_Transform(ST_ClosestPoint(l.way, p.pt), 4326)) as lat INTO line_rec FROM p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) WHERE ST_Distance(ST_Transform(l.way, 4326)::geography, start_pt::geography) < 30 ORDER BY ST_Distance(l.way, p.pt) ASC LIMIT 1; IF FOUND THEN snapped_geom := ST_SetPoint(snapped_geom, 0, ST_SetSRID(ST_MakePoint(line_rec.lon, line_rec.lat), 4326)); END IF; END IF; EXCEPTION WHEN OTHERS THEN NULL; END; -- Snap end BEGIN WITH p AS (SELECT ST_Transform(end_pt, 3857) AS pt) SELECT n.id, n.lon/1e7 as lon, n.lat/1e7 as lat INTO node_rec FROM p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) JOIN planet_osm_ways w ON w.id = l.osm_id CROSS JOIN LATERAL unnest(w.nodes) AS wn(node_id) JOIN planet_osm_nodes n ON n.id = wn.node_id WHERE ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, end_pt::geography) < 30 ORDER BY ST_Distance(ST_SetSRID(ST_MakePoint(n.lon/1e7, n.lat/1e7), 4326)::geography, end_pt::geography) ASC LIMIT 1; IF FOUND THEN e_node := node_rec.id; snapped_geom := ST_SetPoint(snapped_geom, ST_NPoints(snapped_geom) - 1, ST_SetSRID(ST_MakePoint(node_rec.lon, node_rec.lat), 4326)); ELSE WITH p AS (SELECT ST_Transform(end_pt, 3857) AS pt) SELECT ST_X(ST_Transform(ST_ClosestPoint(l.way, p.pt), 4326)) as lon, ST_Y(ST_Transform(ST_ClosestPoint(l.way, p.pt), 4326)) as lat INTO line_rec FROM p JOIN planet_osm_line l ON l.highway IS NOT NULL AND l.way && ST_Expand(p.pt, 60) WHERE ST_Distance(ST_Transform(l.way, 4326)::geography, end_pt::geography) < 30 ORDER BY ST_Distance(l.way, p.pt) ASC LIMIT 1; IF FOUND THEN snapped_geom := ST_SetPoint(snapped_geom, ST_NPoints(snapped_geom) - 1, ST_SetSRID(ST_MakePoint(line_rec.lon, line_rec.lat), 4326)); END IF; END IF; EXCEPTION WHEN OTHERS THEN NULL; END; UPDATE approved_roads SET geometry = snapped_geom, start_node = COALESCE(s_node, start_node), end_node = COALESCE(e_node, end_node) WHERE id = r.id; END LOOP; END $$; `); return { success: true, message: 'All approved roads snapped & nodes resolved' }; } catch (e) { this.logger.error(`Failed to snap existing roads: ${e.message}`); throw new common_1.HttpException(e.message, common_1.HttpStatus.INTERNAL_SERVER_ERROR); } } }; exports.RoadRefinementController = RoadRefinementController; __decorate([ (0, common_1.Get)('summary'), (0, swagger_1.ApiOperation)({ summary: 'Get road intelligence summary πŸ“Š' }), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], RoadRefinementController.prototype, "getSummary", null); __decorate([ (0, common_1.Get)('candidates'), (0, swagger_1.ApiOperation)({ summary: 'Get candidate roads list πŸ›£οΈ' }), (0, swagger_1.ApiQuery)({ name: 'status', required: false }), __param(0, (0, common_1.Query)('status')), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], RoadRefinementController.prototype, "getCandidates", null); __decorate([ (0, common_1.Post)('candidates/manual'), (0, swagger_1.ApiOperation)({ summary: 'Submit manual candidate road drawn on map ✍️' }), __param(0, (0, common_1.Body)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], RoadRefinementController.prototype, "submitManualCandidate", null); __decorate([ (0, common_1.Patch)('candidates/:id/approve'), (0, swagger_1.ApiOperation)({ summary: 'Approve candidate road and move to approved_roads with auto-snapped topology βœ…' }), (0, swagger_1.ApiParam)({ name: 'id', description: 'Candidate UUID' }), __param(0, (0, common_1.Param)('id')), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], RoadRefinementController.prototype, "approveCandidate", null); __decorate([ (0, common_1.Patch)('candidates/:id/reject'), (0, swagger_1.ApiOperation)({ summary: 'Reject candidate road ❌' }), (0, swagger_1.ApiParam)({ name: 'id', description: 'Candidate UUID' }), __param(0, (0, common_1.Param)('id')), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], RoadRefinementController.prototype, "rejectCandidate", null); __decorate([ (0, common_1.Get)('closures'), (0, swagger_1.ApiOperation)({ summary: 'Get active road closures 🚧' }), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], RoadRefinementController.prototype, "getClosures", null); __decorate([ (0, common_1.Post)('discover-overture-gaps'), (0, swagger_1.ApiOperation)({ summary: 'Discover missing roads against Overture Maps πŸ—ΊοΈ' }), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], RoadRefinementController.prototype, "discoverOvertureGaps", null); __decorate([ (0, common_1.Post)('discover-closures'), (0, swagger_1.ApiOperation)({ summary: 'Discover closures 🚧' }), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], RoadRefinementController.prototype, "discoverClosures", null); __decorate([ (0, common_1.Post)('snap-existing-roads'), (0, swagger_1.ApiOperation)({ summary: 'Auto-snap and resolve topology nodes for all existing approved roads' }), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], RoadRefinementController.prototype, "snapExistingApprovedRoads", null); exports.RoadRefinementController = RoadRefinementController = RoadRefinementController_1 = __decorate([ (0, swagger_1.ApiTags)('map-refinement-roads'), (0, common_1.Controller)('map-refinement/roads'), (0, common_1.UseGuards)(api_key_guard_1.ApiKeyGuard), __param(0, (0, typeorm_1.InjectRepository)(candidate_road_entity_1.CandidateRoad)), __param(1, (0, typeorm_1.InjectRepository)(road_stat_entity_1.RoadSegmentStat)), __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object, typeof (_b = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _b : Object, typeof (_c = typeof typeorm_2.DataSource !== "undefined" && typeorm_2.DataSource) === "function" ? _c : Object]) ], RoadRefinementController); //# sourceMappingURL=road-refinement.controller.js.map