@@ -5,8 +5,7 @@ import { AnyPermission } from '../entities/authorization/entities.permissions'
55import fs from 'fs-extra' ;
66import Zip from 'adm-zip' ;
77import { defaultHandler as upload } from '../upload' ;
8- import { DOMParser , Document } from '@xmldom/xmldom' ;
9- import kml from '../utilities/transformKML' ;
8+ import { KmlFeature , kml } from '../utilities/transformKML' ;
109
1110interface SecurityConfig {
1211 authentication : {
@@ -41,78 +40,63 @@ const getMimeType = (filename: string): string => {
4140 return mimeTypes [ ext ] || 'application/octet-stream' ;
4241}
4342
43+ const kmlToGeoJSON = ( kmlPathname : string , isKMZ : boolean ) : KmlFeature [ ] => {
44+ let kmlString : string ;
45+ let images : Record < string , string > = { } ;
46+
47+ if ( isKMZ ) {
48+ // TODO: Update how images are handled in KMZ files to prevent duplication. Move images to a separate directory and store their paths in the KML.
49+ const zip = new Zip ( kmlPathname ) ;
50+ const zipEntries = zip . getEntries ( ) ;
51+ const kmlEntry = zipEntries . find ( entry => entry . entryName . toLowerCase ( ) . endsWith ( '.kml' ) ) ;
52+
53+ if ( ! kmlEntry ) {
54+ throw new Error ( 'No KML file found inside KMZ.' ) ;
55+ }
56+
57+ zipEntries . forEach ( entry => {
58+ const entryName = entry . entryName ;
59+ try {
60+ if ( ! entry . isDirectory && / \. ( p n g | j p g | j p e g | g i f | b m p ) $ / i. test ( entryName ) ) {
61+ const buffer = entry . getData ( ) ;
62+ const base64 = buffer . toString ( 'base64' ) ;
63+ const mimeType = getMimeType ( entryName ) ;
64+ images [ entryName ] = `data:${ mimeType } ;base64,${ base64 } ` ;
65+ }
66+ } catch ( error ) {
67+ console . error ( `Error processing entry ${ entryName } :` , error ) ;
68+ }
69+ } ) ;
70+
71+ kmlString = kmlEntry . getData ( ) . toString ( 'utf8' ) ;
72+ } else {
73+ kmlString = fs . readFileSync ( kmlPathname , 'utf8' ) ;
74+ }
75+
76+ try {
77+ return kml ( kmlString , images ) ;
78+ } catch ( error ) {
79+ throw new Error ( 'Failed to transform KML: ' + error ) ;
80+ }
81+ }
82+
4483const validate = async ( req : Request , res : Response , next : NextFunction ) : Promise < void | Response > => {
4584 const layRequest = req as LayerRequest ;
4685 if ( layRequest . layer . type !== 'Feature' ) {
4786 return res . status ( 400 ) . send ( 'Cannot import data, layer type is not "Static".' ) ;
4887 }
4988
50- if ( ! layRequest . file ) {
51- return res . status ( 400 ) . send ( 'Invalid file, please upload a KML or KMZ file.' ) ;
52- }
53-
54- const fileExtension : string = layRequest . file . originalname . toLowerCase ( ) . split ( '.' ) . pop ( ) || '' ;
89+ const fileExtension : string = layRequest . file ?. originalname ?. toLowerCase ( ) . split ( '.' ) . pop ( ) || '' ;
5590
5691 if ( ! [ 'kml' , 'kmz' ] . includes ( fileExtension ) ) {
5792 return res . status ( 400 ) . send ( 'Invalid file, please upload a KML or KMZ file.' ) ;
5893 }
5994
60- const parser = new DOMParser ( ) ;
61- let geoJson : any ;
62-
63- if ( fileExtension === 'kmz' ) {
64- try {
65- // TODO: Update how images are handled in KMZ files to prevent duplication. Move images to a separate directory and store their paths in the KML.
66- const zip = new Zip ( layRequest . file . path ) ;
67- const zipEntries = zip . getEntries ( ) ;
68- const kmlEntry = zipEntries . find ( entry => entry . entryName . toLowerCase ( ) . endsWith ( '.kml' ) ) ;
69-
70- if ( ! kmlEntry ) {
71- return res . status ( 400 ) . send ( 'No KML file found inside.' ) ;
72- }
73-
74- const images : { [ key : string ] : string } = { } ;
75- zipEntries . forEach ( entry => {
76- const entryName = entry . entryName ;
77- try {
78- if ( ! entry . isDirectory && / \. ( p n g | j p g | j p e g | g i f | b m p ) $ / i. test ( entryName ) ) {
79- const buffer = entry . getData ( ) ;
80- const base64 = buffer . toString ( 'base64' ) ;
81- const mimeType = getMimeType ( entryName ) ;
82- images [ entryName ] = `data:${ mimeType } ;base64,${ base64 } ` ;
83- }
84- } catch ( error ) {
85- console . error ( `Error processing entry ${ entryName } :` , error ) ;
86- }
87- } ) ;
88-
89- const kmlString = kmlEntry . getData ( ) . toString ( 'utf8' ) ;
90-
91- const kmlDocument = parser . parseFromString ( kmlString , 'text/xml' ) ;
92- geoJson = kml ( kmlDocument as any , images ) ;
93-
94- } catch ( err ) {
95- return res . status ( 400 ) . send ( 'Unable to extract contents from KMZ file.' + err ) ;
96- }
97- } else {
98- const fileData = fs . readFileSync ( layRequest . file . path , 'utf8' ) ;
99- const kmlDocument : Document = parser . parseFromString ( fileData , 'application/xml' ) ;
100- const parseError = kmlDocument . getElementsByTagName ( "parsererror" ) ;
101-
102- if ( parseError . length > 0 ) {
103- console . error ( "KML Parsing Error:" , parseError [ 0 ] . textContent ) ;
104- } else {
105- console . log ( "Parsed KML successfully" ) ;
106- }
107-
108- if ( ! kmlDocument || kmlDocument . documentElement ?. nodeName !== 'kml' ) {
109- return res . status ( 400 ) . send ( 'Invalid file, please upload a KML or KMZ file.' ) ;
110- }
111-
112- geoJson = kml ( kmlDocument as any ) ;
95+ try {
96+ layRequest . features = kmlToGeoJSON ( layRequest . file ! . path , fileExtension === 'kmz' ) ;
97+ } catch ( err ) {
98+ return res . status ( 400 ) . send ( 'Unable to extract contents from KMZ file.' + err ) ;
11399 }
114-
115- layRequest . features = geoJson ;
116100 return next ( ) ;
117101}
118102
0 commit comments