feat(server): add KML and KMZ place import pipeline

This commit is contained in:
Yannis Biasutti
2026-04-06 18:31:47 +02:00
parent 96080e8a03
commit 5271463064
9 changed files with 606 additions and 1 deletions
+54
View File
@@ -13,6 +13,8 @@ import {
updatePlace,
deletePlace,
importGpx,
importKmlPlaces,
importKmzPlaces,
importGoogleList,
searchPlaceImage,
} from '../services/placeService';
@@ -72,6 +74,58 @@ router.post('/import/gpx', authenticate, requireTripAccess, gpxUpload.single('fi
}
});
router.post('/import/kml', authenticate, requireTripAccess, gpxUpload.single('file'), (req: Request, res: Response) => {
const authReq = req as AuthRequest;
if (!checkPermission('place_edit', authReq.user.role, authReq.trip!.user_id, authReq.user.id, authReq.trip!.user_id !== authReq.user.id)) {
return res.status(403).json({ error: 'No permission' });
}
const { tripId } = req.params;
const file = (req as any).file;
if (!file) return res.status(400).json({ error: 'No file uploaded' });
try {
const result = importKmlPlaces(tripId, file.buffer);
if (result.count === 0) {
return res.status(400).json({ error: 'No valid Placemarks found in KML file', summary: result.summary });
}
res.status(201).json(result);
for (const place of result.places) {
broadcast(tripId, 'place:created', { place }, req.headers['x-socket-id'] as string);
}
} catch (err: unknown) {
const message = err instanceof Error ? err.message : 'Failed to import KML file';
res.status(400).json({ error: message });
}
});
router.post('/import/kmz', authenticate, requireTripAccess, gpxUpload.single('file'), async (req: Request, res: Response) => {
const authReq = req as AuthRequest;
if (!checkPermission('place_edit', authReq.user.role, authReq.trip!.user_id, authReq.user.id, authReq.trip!.user_id !== authReq.user.id)) {
return res.status(403).json({ error: 'No permission' });
}
const { tripId } = req.params;
const file = (req as any).file;
if (!file) return res.status(400).json({ error: 'No file uploaded' });
try {
const result = await importKmzPlaces(tripId, file.buffer);
if (result.count === 0) {
return res.status(400).json({ error: 'No valid Placemarks found in KMZ file', summary: result.summary });
}
res.status(201).json(result);
for (const place of result.places) {
broadcast(tripId, 'place:created', { place }, req.headers['x-socket-id'] as string);
}
} catch (err: unknown) {
const message = err instanceof Error ? err.message : 'Failed to import KMZ file';
res.status(400).json({ error: message });
}
});
// Import places from a shared Google Maps list URL
router.post('/import/google-list', authenticate, requireTripAccess, async (req: Request, res: Response) => {
const authReq = req as AuthRequest;