Skip to content

Commit 5905e91

Browse files
committed
HPC-9963: WIP Replace leaflet with mapbox gl
1 parent 93f9bd3 commit 5905e91

File tree

82 files changed

+5965
-5733
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+5965
-5733
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<IfModule mod_rewrite.c>
22
RewriteEngine on
33
SSLProxyEngine on
4-
#Add the string and keep hidden from user with [P]
4+
# Add the string and keep hidden from user with [P]
55
RewriteCond %{QUERY_STRING} ^(([^&]*&)*)access_token=token(&.*)?$
66
RewriteRule ^/mapbox/(.*)$ https://api.mapbox.com/$1?%1access_token=${MAPBOX_TOKEN}%3 [P]
77
</IfModule>

composer.json

-5
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,6 @@
135135
"drupal/webp": "^1.0-beta7",
136136
"drush/drush": "^12.4",
137137
"npm-asset/d3": "^7.4",
138-
"npm-asset/leaflet": "^1.7",
139-
"npm-asset/leaflet-modal": "^0.2.0",
140-
"npm-asset/leaflet-providers": "^1.13",
141-
"npm-asset/leaflet-search": "^3",
142-
"npm-asset/leaflet-sidebar": "^0.2.2",
143138
"npm-asset/select2": "^4.0",
144139
"npm-asset/swiper": "^8.1",
145140
"oomphinc/composer-installers-extender": "^2.0",

composer.lock

+1-67
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/ghi_blocks.map_settings.yml

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
mapbox_proxy: true
2+
country_outlines: false

config/seckit.settings.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,25 @@ seckit_xss:
88
webkit: false
99
report-only: true
1010
default-src: "'none'"
11-
script-src: "'self' 'unsafe-inline' https://js-agent.newrelic.com https://static.addtoany.com browser-update.org/update.min.js https://bam.nr-data.net cdn.jsdelivr.net/npm/toastify-js https://unpkg.com/@popperjs/core@2 https://unpkg.com/tippy.js@6"
11+
script-src: "'self' 'unsafe-inline' https://js-agent.newrelic.com https://static.addtoany.com browser-update.org/update.min.js https://bam.nr-data.net cdn.jsdelivr.net/npm/toastify-js https://unpkg.com/@popperjs/core@2 https://unpkg.com/tippy.js@6 https://api.mapbox.com"
1212
object-src: "'none'"
13-
style-src: "'self' 'unsafe-inline' fonts.googleapis.com cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css https://fonts.gstatic.com"
13+
style-src: "'self' 'unsafe-inline' fonts.googleapis.com cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css https://fonts.gstatic.com https://api.mapbox.com"
1414
img-src: "'self' unocha.org hpc.tools content.hpc.tools fts.unocha.org data: api.mapbox.com browser-update.org https://fonts.gstatic.com"
1515
media-src: ''
1616
frame-src: "'self' https://content.hpc.tools https://www.youtube.com https://data.humdata.org https://datawrapper.dwcdn.net"
1717
frame-ancestors: "'none'"
1818
child-src: "'self'"
1919
font-src: "'self' fonts.gstatic.com data:"
20-
connect-src: "'self' https://bam.nr-data.net"
20+
connect-src: "'self' https://bam.nr-data.net https://api.mapbox.com https://events.mapbox.com"
2121
report-uri: /report-csp-violation
2222
upgrade-req: false
2323
policy-uri: ''
2424
x_xss:
25+
select: 0
2526
seckit_x_xss_option_disable: Disabled
2627
seckit_x_xss_option_0: '0'
2728
seckit_x_xss_option_1: 1;
2829
seckit_x_xss_option_1_block: '1; mode=block'
29-
select: 0
3030
seckit_csrf:
3131
origin: false
3232
origin_whitelist: ''

html/modules/custom/ghi_base_objects/assets/geojson/UN_Geodata_simplified.geojson

+1
Large diffs are not rendered by default.

html/modules/custom/ghi_base_objects/assets/geojson/countries.geojson

+261
Large diffs are not rendered by default.

html/modules/custom/ghi_base_objects/ghi_base_objects.deploy.php

+19
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,22 @@ function ghi_base_objects_deploy_base_object_bundles_admin_menu_2() {
3535
])->save();
3636
}
3737
}
38+
39+
/**
40+
* Import country outlines from the fallback source.
41+
*/
42+
function ghi_base_objects_deploy_import_country_outlines_from_fallback(&$sandbox) {
43+
/** @var \Drupal\hpc_api\Query\EndpointQueryManager $endpoint_query_manager */
44+
$endpoint_query_manager = \Drupal::service('plugin.manager.endpoint_query_manager');
45+
/** @var \Drupal\ghi_base_objects\Plugin\EndpointQuery\CountryQuery $country_query */
46+
$country_query = $endpoint_query_manager->createInstance('country_query');
47+
$countries = $country_query->getCountries();
48+
foreach ($countries as $country) {
49+
\Drupal::queue('ghi_base_objects_download_country_geojson')->createItem((object) [
50+
'country_id' => $country->id(),
51+
]);
52+
}
53+
return (string) t('Enqueued @total countries for downloading their GeoJson country outline.', [
54+
'@total' => \Drupal::queue('ghi_base_objects_download_country_geojson')->numberOfItems(),
55+
]);
56+
}

html/modules/custom/ghi_base_objects/src/ApiObjects/Location.php

+118-6
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,42 @@
77
*/
88
class Location extends BaseObject {
99

10+
/**
11+
* Define the paths to the fallback files for geojson country data.
12+
*
13+
* The paths are relative to the module directory.
14+
*
15+
* The UN dataset which unfortunately has quite some issues and renders a lot
16+
* of artefacts. It comes from:
17+
* https://geoportal.un.org/arcgis/apps/sites/#/geohub/datasets/d7caaff3ef4b4f7c82689b7c4694ad92/about.
18+
*/
19+
const GEOJSON_FALLBACK_FILE_UN = 'assets/geojson/UN_Geodata_simplified.geojson';
20+
21+
/**
22+
* An alternative source.
23+
*
24+
* This comes from
25+
* https://github.com/datasets/geo-countries via
26+
* https://datahub.io/core/geo-countries and
27+
* https://www.naturalearthdata.com/downloads/10m-cultural-vectors/.
28+
*/
29+
const GEOJSON_FALLBACK_FILE_OTHER = 'assets/geojson/countries.geojson';
30+
1031
/**
1132
* {@inheritdoc}
1233
*/
1334
protected function map() {
1435
$data = $this->getRawData();
1536
return (object) [
1637
'location_id' => $data->id,
17-
'location_name' => $data->name,
38+
'location_name' => $data->name ?: 'Admin area ' . $data->externalId,
1839
'admin_level' => $data->adminLevel,
1940
'pcode' => $data->pcode,
41+
'iso3' => $data->iso3,
2042
'latLng' => [(string) $data->latitude, (string) $data->longitude],
2143
'filepath' => !empty($data->filepath) ? $data->filepath : NULL,
2244
'parent_id' => $data->parentId,
45+
'children' => $data->children ?? [],
2346
];
2447
}
2548

@@ -34,8 +57,24 @@ protected function map() {
3457
*/
3558
public function getGeoJsonLocalFilePath($refresh = FALSE) {
3659
$geojson_service = self::getGeoJsonService();
37-
$uri = $geojson_service->getGeoJsonLocalFilePath($this->filepath, $refresh);
38-
return $uri ? \Drupal::service('file_url_generator')->generate($uri)->toString() : NULL;
60+
$file_url_generator = self::fileUrlGenerator();
61+
if ($this->filepath && $uri = $geojson_service->getGeoJsonLocalFilePath($this->filepath, $refresh)) {
62+
// If we have a filepath, let's point to it. This comes from the API and
63+
// we store local copies of it.
64+
return $uri ? $file_url_generator->generate($uri)->toString() : NULL;
65+
}
66+
if (!$this->iso3) {
67+
return NULL;
68+
}
69+
// Otherwise let's see if we can get another type of local file that is
70+
// extracted from a static geojson source and fetched via
71+
// self::getGeoJsonFallback().
72+
$local_filename = $this->iso3 . '.json';
73+
if (!$geojson_service->localFileExists($local_filename)) {
74+
$this->getGeoJsonFallback();
75+
}
76+
$filepath = $geojson_service->getLocalFilePath($local_filename);
77+
return $filepath ? $file_url_generator->generate($filepath)->toString() : NULL;
3978
}
4079

4180
/**
@@ -44,12 +83,65 @@ public function getGeoJsonLocalFilePath($refresh = FALSE) {
4483
* @param bool $refresh
4584
* Whether to refresh stored data.
4685
*
47-
* @return object
48-
* The geo json data object.
86+
* @return object|false
87+
* The geo json data object or FALSE.
4988
*/
5089
public function getGeoJson($refresh = FALSE) {
5190
$geojson_service = self::getGeoJsonService();
52-
return $geojson_service->getGeoJson($this->filepath, $refresh);
91+
$geojson = $this->filepath ? $geojson_service->getGeoJson($this->filepath, $refresh) : FALSE;
92+
if (!$geojson) {
93+
$geojson = $this->getGeoJsonFallback();
94+
}
95+
return $geojson;
96+
}
97+
98+
/**
99+
* Use a fallback to retrieve geojson polygon data for a location.
100+
*
101+
* @return object|false
102+
* The geo json data object or FALSE.
103+
*/
104+
private function getGeoJsonFallback() {
105+
if ($this->admin_level > 0) {
106+
// The fallback is available only for admin level 0 locations.
107+
return FALSE;
108+
}
109+
$geojson_service = self::getGeoJsonService();
110+
$local_filename = $this->iso3 . '.json';
111+
if ($geojson_service->localFileExists($local_filename)) {
112+
return $geojson_service->getLocalFileContent($local_filename);
113+
}
114+
115+
$geojson_file = self::moduleHandler()->getModule('ghi_base_objects')->getPath() . '/' . self::GEOJSON_FALLBACK_FILE_OTHER;
116+
if (!file_exists($geojson_file)) {
117+
return FALSE;
118+
}
119+
// Extract the features for the current location based on the iso3 code.
120+
$content = json_decode(file_get_contents($geojson_file));
121+
$features = array_filter($content->features, function ($item) {
122+
return property_exists($item->properties, 'iso3cd') && $item->properties->iso3cd == $this->iso3 || property_exists($item->properties, 'ISO_A3') && $item->properties->ISO_A3 == $this->iso3;
123+
});
124+
if (empty($features)) {
125+
return FALSE;
126+
}
127+
$features = array_values(array_map(function ($feature) {
128+
unset($feature->properties);
129+
return $feature;
130+
}, $features));
131+
$geojson = (object) [
132+
'type' => 'Feature',
133+
'geometry' => (object) [
134+
'type' => 'GeometryCollection',
135+
'geometries' => array_map(function ($feature) {
136+
return $feature->geometry;
137+
}, $features),
138+
],
139+
'properties' => (object) [
140+
'location_id' => $this->id(),
141+
],
142+
];
143+
$geojson_service->writeGeoJsonFile($local_filename, json_encode($geojson));
144+
return $geojson;
53145
}
54146

55147
/**
@@ -71,4 +163,24 @@ public static function getGeoJsonService() {
71163
return \Drupal::service('hpc_api.geojson');
72164
}
73165

166+
/**
167+
* Get the file url generator service.
168+
*
169+
* @return \Drupal\Core\File\FileUrlGeneratorInterface
170+
* The file url generator service.
171+
*/
172+
public static function fileUrlGenerator() {
173+
return \Drupal::service('file_url_generator');
174+
}
175+
176+
/**
177+
* Get the module handler service.
178+
*
179+
* @return \Drupal\Core\Extension\ModuleHandlerInterface
180+
* The module handler service.
181+
*/
182+
public static function moduleHandler() {
183+
return \Drupal::service('module_handler');
184+
}
185+
74186
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
namespace Drupal\ghi_base_objects\Plugin\EndpointQuery;
4+
5+
use Drupal\Core\StringTranslation\StringTranslationTrait;
6+
use Drupal\ghi_base_objects\ApiObjects\Location;
7+
use Drupal\hpc_api\Query\EndpointQueryBase;
8+
9+
/**
10+
* Provides a query plugin for country locations.
11+
*
12+
* @EndpointQuery(
13+
* id = "country_query",
14+
* label = @Translation("Country query"),
15+
* endpoint = {
16+
* "api_key" = "location",
17+
* "version" = "v2",
18+
* }
19+
* )
20+
*/
21+
class CountryQuery extends EndpointQueryBase {
22+
23+
use StringTranslationTrait;
24+
25+
/**
26+
* Get country location objects for all countries.
27+
*
28+
* @return \Drupal\ghi_base_objects\ApiObjects\Location[]
29+
* An array of country locations.
30+
*/
31+
public function getCountries() {
32+
$cache_key = 'locations';
33+
$countries = $this->cache($cache_key);
34+
if ($countries) {
35+
return $countries;
36+
}
37+
$data = $this->getData();
38+
if (empty($data)) {
39+
return [];
40+
}
41+
42+
$countries = [];
43+
foreach ($data as $item) {
44+
$countries[$item->id] = new Location($item);
45+
}
46+
$this->cache($cache_key, $countries);
47+
return $countries;
48+
}
49+
50+
/**
51+
* Get country location objects for all countries.
52+
*
53+
* @return \Drupal\ghi_base_objects\ApiObjects\Location|null
54+
* A location object or NULL.
55+
*/
56+
public function getCountry($country_id) {
57+
$countries = $this->getCountries();
58+
return array_key_exists($country_id, $countries) ? $countries[$country_id] : NULL;
59+
}
60+
61+
}

0 commit comments

Comments
 (0)