From 78541f88489e7e3348afcb9cfd60d4c35176ff90 Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 16:58:29 +0100 Subject: [PATCH 01/12] Favorites: allow .json file extension Signed-off-by: Simon Spannagel --- lib/Controller/FavoritesController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Controller/FavoritesController.php b/lib/Controller/FavoritesController.php index 287f67a43..aeeaa45f5 100644 --- a/lib/Controller/FavoritesController.php +++ b/lib/Controller/FavoritesController.php @@ -229,7 +229,7 @@ public function importFavorites($path) { if ($file->getType() === \OCP\Files\FileInfo::TYPE_FILE and $file->isReadable()){ $lowerFileName = strtolower($file->getName()); - if ($this->endswith($lowerFileName, '.gpx') or $this->endswith($lowerFileName, '.kml') or $this->endswith($lowerFileName, '.kmz')) { + if ($this->endswith($lowerFileName, '.gpx') or $this->endswith($lowerFileName, '.kml') or $this->endswith($lowerFileName, '.kmz') or $this->endswith($lowerFileName, '.json')) { $result = $this->favoritesService->importFavorites($this->userId, $file); return new DataResponse($result); } From 82543e126fd11045f9120f0464c44c97cdc3a6b2 Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 17:00:23 +0100 Subject: [PATCH 02/12] Favorites: add service for parsing JSOn files from Google Maps Takeout Signed-off-by: Simon Spannagel --- lib/Service/FavoritesService.php | 69 ++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/lib/Service/FavoritesService.php b/lib/Service/FavoritesService.php index 81dba7137..442c25755 100644 --- a/lib/Service/FavoritesService.php +++ b/lib/Service/FavoritesService.php @@ -421,6 +421,9 @@ public function importFavorites($userId, $file) { elseif ($this->endswith($lowerFileName, '.kmz')) { return $this->importFavoritesFromKmz($userId, $file); } + elseif ($this->endswith($lowerFileName, '.json')) { + return $this->importFavoritesFromJSON($userId, $file); + } } public function importFavoritesFromKmz($userId, $file) { @@ -655,6 +658,72 @@ private function gpxDataElement($parser, $data) { } } + public function importFavoritesFromJSON($userId, $file) { + $this->nbImported = 0; + $this->currentFavoritesList = []; + $this->importUserId = $userId; + + // Read file content + $path = $file->getStorage()->getLocalFile($file->getInternalPath()); + $fp = $file->fopen('r'); + $fdata = fread($fp,filesize($path)); + fclose($fp); + + // Decode file content from JSON + $data = json_decode($fdata, true); + + if(!array_key_exists('features', $data)) { + $this->logger->error( + 'Exception parsing '.$file->getName().': no places found to import', + array('app' => 'maps') + ); + } + + // Loop over all favorite entries + foreach($data['features'] as $key => $value) { + // store new favorite + $this->nbImported++; + $this->currentFavorite = []; + + $this->currentFavorite['name'] = $value['properties']['Title']; + $this->currentFavorite['category'] = $this->l10n->t('Personal'); + + $time = new \DateTime($value['properties']['Published']); + $this->currentFavorite['date_created'] = $time->getTimestamp(); + + $time = new \DateTime($value['properties']['Updated']); + $this->currentFavorite['date_modified'] = $time->getTimestamp(); + + if(array_key_exists('Address', $value['properties']['Location'])) { + $this->currentFavorite['comment'] = $value['properties']['Location']['Address']; + } + + $this->currentFavorite['lng'] = floatval($value['geometry']['coordinates'][0]); + $this->currentFavorite['lat'] = floatval($value['geometry']['coordinates'][1]); + + // Store this favorite + array_push($this->currentFavoritesList, $this->currentFavorite); + + // if we have enough favorites, we create them and clean the array + if (count($this->currentFavoritesList) >= 500) { + $this->addMultipleFavoritesToDB($this->importUserId, $this->currentFavoritesList); + unset($this->currentFavoritesList); + $this->currentFavoritesList = []; + } + } + + // Store last set of favorites + if (count($this->currentFavoritesList) > 0) { + $this->addMultipleFavoritesToDB($this->importUserId, $this->currentFavoritesList); + } + unset($this->currentFavoritesList); + + return [ + 'nbImported'=>$this->nbImported, + 'linesFound'=>false + ]; + } + private function endswith($string, $test) { $strlen = strlen($string); $testlen = strlen($test); From 4e3a01c19099cd90ceeb2d4d6401d1d3491bc701 Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 17:00:55 +0100 Subject: [PATCH 03/12] Favorites: allow json mime type in file picker dialogue Signed-off-by: Simon Spannagel --- src/favoritesController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/favoritesController.js b/src/favoritesController.js index f304cab1c..a5d497b05 100644 --- a/src/favoritesController.js +++ b/src/favoritesController.js @@ -207,7 +207,7 @@ FavoritesController.prototype = { that.importFavorites(targetPath); }, false, - ['application/gpx+xml', 'application/vnd.google-earth.kmz', 'application/vnd.google-earth.kml+xml'], + ['application/gpx+xml', 'application/vnd.google-earth.kmz', 'application/vnd.google-earth.kml+xml', 'application/json'], true ); }); From 5319062643ef0e6d254e654a4e2510d850d28551 Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 17:03:24 +0100 Subject: [PATCH 04/12] Navigation: rename menu item to "import from file" Signed-off-by: Simon Spannagel --- templates/navigation/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/navigation/index.php b/templates/navigation/index.php index 086456d2e..78216045c 100644 --- a/templates/navigation/index.php +++ b/templates/navigation/index.php @@ -22,7 +22,7 @@
  • - t('Import from gpx/kml/kmz')); ?> + t('Import from file')); ?>
  • From 7d1a687dd1dc761fb82dd218a27fe892c09cbd47 Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 17:18:48 +0100 Subject: [PATCH 05/12] Favorites: throw when JSON parsing fails Signed-off-by: Simon Spannagel --- lib/Service/FavoritesService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Service/FavoritesService.php b/lib/Service/FavoritesService.php index 442c25755..01d622296 100644 --- a/lib/Service/FavoritesService.php +++ b/lib/Service/FavoritesService.php @@ -670,9 +670,9 @@ public function importFavoritesFromJSON($userId, $file) { fclose($fp); // Decode file content from JSON - $data = json_decode($fdata, true); + $data = json_decode($fdata, true, 512, JSON_THROW_ON_ERROR); - if(!array_key_exists('features', $data)) { + if($data == null or !array_key_exists('features', $data)) { $this->logger->error( 'Exception parsing '.$file->getName().': no places found to import', array('app' => 'maps') From 2b2f6bf89c509f57783d3c86078b3d0bc7e49326 Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 17:29:36 +0100 Subject: [PATCH 06/12] Favorites: read whole JSON file in one go using file_get_contents Signed-off-by: Simon Spannagel --- lib/Service/FavoritesService.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Service/FavoritesService.php b/lib/Service/FavoritesService.php index 01d622296..3c20737a2 100644 --- a/lib/Service/FavoritesService.php +++ b/lib/Service/FavoritesService.php @@ -665,9 +665,7 @@ public function importFavoritesFromJSON($userId, $file) { // Read file content $path = $file->getStorage()->getLocalFile($file->getInternalPath()); - $fp = $file->fopen('r'); - $fdata = fread($fp,filesize($path)); - fclose($fp); + $fdata = file_get_contents($path); // Decode file content from JSON $data = json_decode($fdata, true, 512, JSON_THROW_ON_ERROR); From c24dc643b60e596e09384015ea5eb5bf86ce9910 Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 17:59:59 +0100 Subject: [PATCH 07/12] Favorite import: allow extension .geojson Signed-off-by: Simon Spannagel --- lib/Service/FavoritesService.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Service/FavoritesService.php b/lib/Service/FavoritesService.php index 3c20737a2..36fbceaaa 100644 --- a/lib/Service/FavoritesService.php +++ b/lib/Service/FavoritesService.php @@ -421,8 +421,8 @@ public function importFavorites($userId, $file) { elseif ($this->endswith($lowerFileName, '.kmz')) { return $this->importFavoritesFromKmz($userId, $file); } - elseif ($this->endswith($lowerFileName, '.json')) { - return $this->importFavoritesFromJSON($userId, $file); + elseif ($this->endswith($lowerFileName, '.json') or $this->endswith($lowerFileName, '.geojson')) { + return $this->importFavoritesFromGeoJSON($userId, $file); } } @@ -658,7 +658,7 @@ private function gpxDataElement($parser, $data) { } } - public function importFavoritesFromJSON($userId, $file) { + public function importFavoritesFromGeoJSON($userId, $file) { $this->nbImported = 0; $this->currentFavoritesList = []; $this->importUserId = $userId; From 38ec01c4b8e87ad256b6fa704f992a90b5099979 Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 18:00:29 +0100 Subject: [PATCH 08/12] Favorites import: check proper GeoJSON geometry Signed-off-by: Simon Spannagel --- lib/Service/FavoritesService.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/Service/FavoritesService.php b/lib/Service/FavoritesService.php index 36fbceaaa..9a3b22a04 100644 --- a/lib/Service/FavoritesService.php +++ b/lib/Service/FavoritesService.php @@ -660,6 +660,7 @@ private function gpxDataElement($parser, $data) { public function importFavoritesFromGeoJSON($userId, $file) { $this->nbImported = 0; + $this->linesFound = false; $this->currentFavoritesList = []; $this->importUserId = $userId; @@ -679,10 +680,18 @@ public function importFavoritesFromGeoJSON($userId, $file) { // Loop over all favorite entries foreach($data['features'] as $key => $value) { - // store new favorite - $this->nbImported++; $this->currentFavorite = []; + // Ensure that we have a valid GeoJSON Point geometry + if($value['geometry']['type'] !== "Point") { + $this->linesFound = true; + continue; + } + + // Read geometry + $this->currentFavorite['lng'] = floatval($value['geometry']['coordinates'][0]); + $this->currentFavorite['lat'] = floatval($value['geometry']['coordinates'][1]); + $this->currentFavorite['name'] = $value['properties']['Title']; $this->currentFavorite['category'] = $this->l10n->t('Personal'); @@ -696,11 +705,10 @@ public function importFavoritesFromGeoJSON($userId, $file) { $this->currentFavorite['comment'] = $value['properties']['Location']['Address']; } - $this->currentFavorite['lng'] = floatval($value['geometry']['coordinates'][0]); - $this->currentFavorite['lat'] = floatval($value['geometry']['coordinates'][1]); // Store this favorite array_push($this->currentFavoritesList, $this->currentFavorite); + $this->nbImported++; // if we have enough favorites, we create them and clean the array if (count($this->currentFavoritesList) >= 500) { @@ -718,7 +726,7 @@ public function importFavoritesFromGeoJSON($userId, $file) { return [ 'nbImported'=>$this->nbImported, - 'linesFound'=>false + 'linesFound'=>$this->linesFound ]; } From fe50060dc76d4d795d0acc6b6c542bf6b55ce43c Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 18:04:49 +0100 Subject: [PATCH 09/12] Favorites import: register action for GeoJSON Signed-off-by: Simon Spannagel --- src/filetypes.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/filetypes.js b/src/filetypes.js index 834bbbde6..1bff2c775 100644 --- a/src/filetypes.js +++ b/src/filetypes.js @@ -100,6 +100,15 @@ $(document).ready(function() { iconClass: 'icon-maps-black', actionHandler: importFavoritesFile }); + // import geojson files as favorites + OCA.Files.fileActions.registerAction({ + name: 'importGeoJsonFavoritesMaps', + displayName: t('maps', 'Import as favorites in Maps'), + mime: 'application/geo+json', + permissions: OC.PERMISSION_READ, + iconClass: 'icon-maps-black', + actionHandler: importFavoritesFile + }); // import gpx files as devices OCA.Files.fileActions.registerAction({ From e29515691d587affb355f08b461c2478a55c2fbf Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 18:07:55 +0100 Subject: [PATCH 10/12] Favorites import: also allow .geojson mime type for file picker Signed-off-by: Simon Spannagel --- src/favoritesController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/favoritesController.js b/src/favoritesController.js index a5d497b05..798003faa 100644 --- a/src/favoritesController.js +++ b/src/favoritesController.js @@ -202,12 +202,12 @@ FavoritesController.prototype = { // import favorites $('body').on('click', '#import-favorites', function(e) { OC.dialogs.filepicker( - t('maps', 'Import favorites from gpx (OsmAnd, Nextcloud Maps) or kmz/kml (F-Droid Maps, Maps.me, Marble)'), + t('maps', 'Import favorites from GeoJSON, gpx (OsmAnd, Nextcloud Maps) or kmz/kml (F-Droid Maps, Maps.me, Marble)'), function(targetPath) { that.importFavorites(targetPath); }, false, - ['application/gpx+xml', 'application/vnd.google-earth.kmz', 'application/vnd.google-earth.kml+xml', 'application/json'], + ['application/gpx+xml', 'application/vnd.google-earth.kmz', 'application/vnd.google-earth.kml+xml', 'application/json', 'application/geo+json'], true ); }); From 024f05373cf6bef52a4b4cedfde93dd471fd5d18 Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sat, 21 Mar 2020 18:19:21 +0100 Subject: [PATCH 11/12] FavoritesController: pass on .geojson files Signed-off-by: Simon Spannagel --- lib/Controller/FavoritesController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Controller/FavoritesController.php b/lib/Controller/FavoritesController.php index aeeaa45f5..0478c6405 100644 --- a/lib/Controller/FavoritesController.php +++ b/lib/Controller/FavoritesController.php @@ -229,7 +229,7 @@ public function importFavorites($path) { if ($file->getType() === \OCP\Files\FileInfo::TYPE_FILE and $file->isReadable()){ $lowerFileName = strtolower($file->getName()); - if ($this->endswith($lowerFileName, '.gpx') or $this->endswith($lowerFileName, '.kml') or $this->endswith($lowerFileName, '.kmz') or $this->endswith($lowerFileName, '.json')) { + if ($this->endswith($lowerFileName, '.gpx') or $this->endswith($lowerFileName, '.kml') or $this->endswith($lowerFileName, '.kmz') or $this->endswith($lowerFileName, '.json') or $this->endswith($lowerFileName, '.geojson')) { $result = $this->favoritesService->importFavorites($this->userId, $file); return new DataResponse($result); } From 33c38576affc403b257f365d89beec602d776cec Mon Sep 17 00:00:00 2001 From: Simon Spannagel Date: Sun, 3 May 2020 18:28:35 +0200 Subject: [PATCH 12/12] Mention Google Maps in the file picker Signed-off-by: Simon Spannagel --- src/favoritesController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/favoritesController.js b/src/favoritesController.js index 798003faa..8454adb21 100644 --- a/src/favoritesController.js +++ b/src/favoritesController.js @@ -202,7 +202,7 @@ FavoritesController.prototype = { // import favorites $('body').on('click', '#import-favorites', function(e) { OC.dialogs.filepicker( - t('maps', 'Import favorites from GeoJSON, gpx (OsmAnd, Nextcloud Maps) or kmz/kml (F-Droid Maps, Maps.me, Marble)'), + t('maps', 'Import favorites from GeoJSON (Google Maps), gpx (OsmAnd, Nextcloud Maps) or kmz/kml (F-Droid Maps, Maps.me, Marble)'), function(targetPath) { that.importFavorites(targetPath); },