Skip to content
Snippets Groups Projects
Commit c9d1b074 authored by Benoit Lavenier's avatar Benoit Lavenier
Browse files

[enh] ES settings: allow to define a google API key, for address resolution in maps

parent ef9a2b28
Branches
Tags
No related merge requests found
Showing
with 155 additions and 49 deletions
...@@ -198,6 +198,7 @@ ...@@ -198,6 +198,7 @@
<script src="dist/dist_js/plugins/map/js/controllers/wot-controllers.js"></script> <script src="dist/dist_js/plugins/map/js/controllers/wot-controllers.js"></script>
<script src="dist/dist_js/plugins/map/js/controllers/network-controllers.js"></script> <script src="dist/dist_js/plugins/map/js/controllers/network-controllers.js"></script>
<script src="dist/dist_js/plugins/map/js/controllers/user-controllers.js"></script> <script src="dist/dist_js/plugins/map/js/controllers/user-controllers.js"></script>
<script src="dist/dist_js/plugins/map/js/controllers/settings-controllers.js"></script>
<!-- RML9 plugin --> <!-- RML9 plugin -->
<!--<script src="dist/dist_js/plugins/rml9/plugin-01-add_button.js"></script>--> <!--<script src="dist/dist_js/plugins/rml9/plugin-01-add_button.js"></script>-->
......
...@@ -10,7 +10,7 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser ...@@ -10,7 +10,7 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser
}) })
.factory('esGeo', function($q, csConfig, csHttp) { .factory('esGeo', function($rootScope, $q, csConfig, csSettings, csHttp) {
'ngInject'; 'ngInject';
var var
...@@ -22,7 +22,7 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser ...@@ -22,7 +22,7 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser
searchByQuery: csHttp.get('nominatim.openstreetmap.org', 443, '/search.php?format=json') searchByQuery: csHttp.get('nominatim.openstreetmap.org', 443, '/search.php?format=json')
}, },
google: { google: {
apiKey: csConfig.plugins && csConfig.plugins.es && csConfig.plugins.es.googleApiKey, apiKey: undefined,
search: csHttp.get('maps.google.com', 443, '/maps/api/geocode/json') search: csHttp.get('maps.google.com', 443, '/maps/api/geocode/json')
}, },
searchByIP: csHttp.get('freegeoip.net', 80, '/json/:ip') searchByIP: csHttp.get('freegeoip.net', 80, '/json/:ip')
...@@ -126,6 +126,24 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser ...@@ -126,6 +126,24 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser
}); });
} }
// If no google api key in config: get it from settings
that.raw.google.apiKey = csConfig.plugins && csConfig.plugins.es && csConfig.plugins.es.googleApiKey;
if (!that.raw.google.apiKey) {
csSettings.ready()
.then(function() {
// Listen settings changed
function onSettingsChanged(data){
that.raw.google.enable = data.plugins && data.plugins.es && data.plugins.es.enableGoogleApi;
that.raw.google.apiKey = that.raw.google.enable && data.plugins.es.googleApiKey;
}
csSettings.api.data.on.changed($rootScope, onSettingsChanged, this);
onSettingsChanged(csSettings.data);
})
}
return { return {
point: { point: {
current: getCurrentPosition, current: getCurrentPosition,
...@@ -133,8 +151,8 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser ...@@ -133,8 +151,8 @@ angular.module('cesium.es.geo.services', ['cesium.services', 'cesium.es.http.ser
searchByIP: searchPositionByIP searchByIP: searchPositionByIP
}, },
google: { google: {
hasApiKey : function() { isEnable: function() {
return !!that.raw.google.apiKey; return that.raw.google.enable && that.raw.google.apiKey;
}, },
searchByAddress: googleSearchPositionByString searchByAddress: googleSearchPositionByString
} }
......
...@@ -40,7 +40,10 @@ angular.module('cesium.es.settings.services', ['cesium.services', 'cesium.es.htt ...@@ -40,7 +40,10 @@ angular.module('cesium.es.settings.services', ['cesium.services', 'cesium.es.htt
}, },
invitations: { invitations: {
readTime: true readTime: true
} },
defaultCountry: undefined,
enableGoogleApi: false,
googleApiKey: undefined
} }
} }
}, {plugins: {es: csConfig.plugins && csConfig.plugins.es || {}}}), }, {plugins: {es: csConfig.plugins && csConfig.plugins.es || {}}}),
......
...@@ -64,5 +64,10 @@ ...@@ -64,5 +64,10 @@
</div> </div>
</label> </label>
<!-- Allow extension here -->
<cs-extension-point name="common"></cs-extension-point>
</ion-content> </ion-content>
</ion-view> </ion-view>
...@@ -36,6 +36,15 @@ ...@@ -36,6 +36,15 @@
}, },
"ERROR": { "ERROR": {
"LOCALIZE_ME_FAILED": "Impossible de récupérer votre position actuelle" "LOCALIZE_ME_FAILED": "Impossible de récupérer votre position actuelle"
},
"SETTINGS": {
"MAP_DIVIDER": "Cartes",
"ENABLE_GOOGLE_API": "Activer les services Google API ?",
"ENABLE_GOOGLE_API_HELP": "Permet l'affichage dans la <b>carte des membres</b> des comptes ayant une adresse mais aucun positionnement GPS.",
"GOOGLE_API_KEY": "Clé d'API Google",
"BTN_GOOGLE_API": "Obtenir une clé",
"BTN_GOOGLE_API_WARNING": "nécessite d'avoir un compte Google",
"GOOGLE_API_KEY_PLACEHOLDER": "Exemple: AIzaqyAgszvWm0tM81x1sMK_ipDHBI7EowLqR7I"
} }
} }
} }
angular.module('cesium.map.settings.controllers', ['cesium.services'])
// Configure menu items
.config(function(PluginServiceProvider, csConfig) {
'ngInject';
var enable = csConfig.plugins && csConfig.plugins.es;
if (enable) {
// Extend settings via extension points
PluginServiceProvider.extendState('app.es_settings', {
points: {
'common': {
templateUrl: "plugins/map/templates/settings/es_settings_extend.html"
}
}
});
}
})
;
...@@ -102,19 +102,8 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser ...@@ -102,19 +102,8 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser
if ($scope.loading) { if ($scope.loading) {
// Load the map (and init if need) // Load the map (and init if need)
$scope.loadMap().then(function(map) { $scope.loadMap()
.then($scope.load);
// Load indicator
map.fire('dataloading');
// Load data
return $scope.load()
// Hide loading indicator
.then(function() {
map.fire('dataload');
});
});
} }
else { else {
// Make sur to have previous center coordinate defined in the location URL // Make sur to have previous center coordinate defined in the location URL
...@@ -127,16 +116,24 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser ...@@ -127,16 +116,24 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser
return leafletData.getMap($scope.mapId).then(function(map) { return leafletData.getMap($scope.mapId).then(function(map) {
if (!$scope.map.loading) return map; // already loaded if (!$scope.map.loading) return map; // already loaded
// Add a refresh button
if (!UIUtils.screen.isSmall()) {
L.easyButton('icon ion-refresh', function(btn, map){
return $scope.load(map);
},
{position: 'topright'}
).addTo(map);
}
// Add loading control // Add loading control
var loadingControl = L.Control.loading({ L.Control.loading({
position: 'topright', position: 'topright',
separate: true separate: true
}); }).addTo(map);
loadingControl.addTo(map);
// Add localize me control // Add localize me control
var localizeMe = MapUtils.control.localizeMe(); MapUtils.control.localizeMe()
localizeMe.addTo(map); .addTo(map);
// Add search control // Add search control
var searchTip = $interpolate($templateCache.get('plugins/map/templates/wot/item_search_tooltip.html')); var searchTip = $interpolate($templateCache.get('plugins/map/templates/wot/item_search_tooltip.html'));
...@@ -155,25 +152,28 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser ...@@ -155,25 +152,28 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser
}; };
// Load markers data // Load markers data
$scope.load = function() { $scope.load = function(map) {
if (!map) {
return leafletData.getMap($scope.mapId).then(function(map) {
return $scope.load(map); // loop with the map object
});
}
$scope.loading = true; $scope.loading = true;
// Show loading indicator
map.fire('dataloading');
// Load wot data // Load wot data
return mapWot.load() return mapWot.load()
.then(function(res) { .then(function(res) {
var markers = {};
var existingMarkerIds = _.keys($scope.map.markers);
if (res && res.length) { if (res && res.length) {
var formatPubkey = $filter('formatPubkey'); var formatPubkey = $filter('formatPubkey');
var markerTemplate = $templateCache.get('plugins/map/templates/wot/popup_marker.html'); var markerTemplate = $templateCache.get('plugins/map/templates/wot/popup_marker.html');
// Sort with member first
/*res = _.sortBy(res, function(hit) {
var score = 0;
score += (!hit.uid) ? 100 : 0;
return -score;
});*/
_.forEach(res, function (hit) { _.forEach(res, function (hit) {
var type = hit.pending ? 'pending' : (hit.uid ? 'member' : 'wallet'); var type = hit.pending ? 'pending' : (hit.uid ? 'member' : 'wallet');
var shortPubkey = formatPubkey(hit.pubkey); var shortPubkey = formatPubkey(hit.pubkey);
...@@ -193,11 +193,10 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser ...@@ -193,11 +193,10 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser
message: markerTemplate message: markerTemplate
}; };
var id = (hit.uid ? (hit.uid + ':' + hit.pubkey) : hit.pubkey).replace(/-/g, '_'); var id = (hit.uid ? (hit.uid + ':' + hit.pubkey) : hit.pubkey).replace(/-/g, '_');
var wasExisting = !!$scope.map.markers[id]; markers[id] = marker;
$scope.map.markers[id] = marker;
// Create a search marker (will be hide) // Create a search marker (will be hide)
if (!wasExisting) { if (!existingMarkerIds[id]) {
var searchText = hit.name + ((hit.uid && hit.uid != hit.name) ? (' | ' + hit.uid) : '') + ' | ' + shortPubkey; var searchText = hit.name + ((hit.uid && hit.uid != hit.name) ? (' | ' + hit.uid) : '') + ' | ' + shortPubkey;
var searchMarker = angular.merge({ var searchMarker = angular.merge({
type: type, type: type,
...@@ -215,8 +214,11 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser ...@@ -215,8 +214,11 @@ angular.module('cesium.map.wot.controllers', ['cesium.services', 'cesium.map.ser
} }
}); });
} }
$scope.map.markers = markers;
$scope.loading = false; $scope.loading = false;
// hide loading indicator
map.fire('dataload');
}); });
}; };
......
...@@ -6,7 +6,8 @@ angular.module('cesium.map.plugin', [ ...@@ -6,7 +6,8 @@ angular.module('cesium.map.plugin', [
// Controllers // Controllers
'cesium.map.wot.controllers', 'cesium.map.wot.controllers',
'cesium.map.network.controllers', 'cesium.map.network.controllers',
'cesium.map.user.controllers' 'cesium.map.user.controllers',
'cesium.map.settings.controllers'
]) ])
// Configure plugin // Configure plugin
......
...@@ -26,7 +26,7 @@ angular.module('cesium.map.wot.services', ['cesium.services']) ...@@ -26,7 +26,7 @@ angular.module('cesium.map.wot.services', ['cesium.services'])
}; };
// Limit to profile with geo point // Limit to profile with geo point
if (esGeo.google.hasApiKey()) { if (options.searchAddress) {
query.bool.should = [ query.bool.should = [
{exists: {field: "geoPoint"}}, {exists: {field: "geoPoint"}},
{exists: {field: "address"}}, {exists: {field: "address"}},
...@@ -63,6 +63,7 @@ angular.module('cesium.map.wot.services', ['cesium.services']) ...@@ -63,6 +63,7 @@ angular.module('cesium.map.wot.services', ['cesium.services'])
options = options || {}; options = options || {};
options.from = options.from || 0; options.from = options.from || 0;
options.size = options.size || constants.DEFAULT_LOAD_SIZE; options.size = options.size || constants.DEFAULT_LOAD_SIZE;
options.searchAddress = esGeo.google.isEnable() && (angular.isDefined(options.searchAddress) ? options.searchAddress : true);
var request = { var request = {
query: createFilterQuery(options), query: createFilterQuery(options),
...@@ -107,7 +108,7 @@ angular.module('cesium.map.wot.services', ['cesium.services']) ...@@ -107,7 +108,7 @@ angular.module('cesium.map.wot.services', ['cesium.services'])
// Transform profile hits // Transform profile hits
var commaRegexp = new RegExp('[,]'); var commaRegexp = new RegExp('[,]');
var noPositionItems = []; var searchAddressItems = [];
var items = res.hits.hits.reduce(function(res, hit) { var items = res.hits.hits.reduce(function(res, hit) {
var pubkey = hit._id; var pubkey = hit._id;
...@@ -117,13 +118,13 @@ angular.module('cesium.map.wot.services', ['cesium.services']) ...@@ -117,13 +118,13 @@ angular.module('cesium.map.wot.services', ['cesium.services'])
// City & address // City & address
item.city = hit._source.city; item.city = hit._source.city;
item.fullAddress = item.city && ((hit._source.address ? hit._source.address+ ', ' : '') + item.city);
// Set geo point // Set geo point
item.geoPoint = hit._source.geoPoint; item.geoPoint = hit._source.geoPoint;
if (!item.geoPoint || !item.geoPoint.lat || !item.geoPoint.lon) { if (!item.geoPoint || !item.geoPoint.lat || !item.geoPoint.lon) {
if (!item.fullAddress) return res; // no city: exclude this item if (!options.searchAddress || !item.city) return res; // no city: exclude this item
noPositionItems.push(item); item.searchAddress = item.city && ((hit._source.address ? hit._source.address+ ', ' : '') + item.city);
searchAddressItems.push(item);
} }
else { else {
// Convert lat/lon to float (if need) // Convert lat/lon to float (if need)
...@@ -152,24 +153,29 @@ angular.module('cesium.map.wot.services', ['cesium.services']) ...@@ -152,24 +153,29 @@ angular.module('cesium.map.wot.services', ['cesium.services'])
}, []); }, []);
// Resolve missing positions by addresses (only if google API enable) // Resolve missing positions by addresses (only if google API enable)
if (noPositionItems.length && esGeo.google.hasApiKey()) { if (searchAddressItems.length) {
var now = new Date().getTime(); var now = new Date().getTime();
console.log('[map] [wot] Search positions of {0} addresses...'.format(noPositionItems.length)); console.log('[map] [wot] Search positions of {0} addresses...'.format(searchAddressItems.length));
var counter = 0; var counter = 0;
return $q.all(noPositionItems.reduce(function(res, item) { return $q.all(searchAddressItems.reduce(function(res, item) {
return res.concat(esGeo.google.searchByAddress(item.fullAddress) return !item.searchAddress ? res : res.concat(esGeo.google.searchByAddress(item.searchAddress)
.then(function(res) { .then(function(res) {
if (!res || !res.length) return; if (!res || !res.length) return;
item.geoPoint = res[0]; item.geoPoint = res[0];
delete item.fullAddress; // If search on city, add a randomized delta to avoid superposition
if (item.city == item.searchAddress) {
item.geoPoint.lon += Math.random() / 1000;
item.geoPoint.lat += Math.random() / 1000;
}
delete item.searchAddress; // not need anymore
items.push(item); items.push(item);
counter++; counter++;
}) })
.catch(function() {/*silent*/})); .catch(function() {/*silent*/}));
}, [])) }, []))
.then(function(){ .then(function(){
console.log('[map] [wot] Resolved {0}/{1} addresses in {2}ms'.format(counter, noPositionItems.length, new Date().getTime()-now)); console.log('[map] [wot] Resolved {0}/{1} addresses in {2}ms'.format(counter, searchAddressItems.length, new Date().getTime()-now));
return items; return items;
}); });
} }
......
<ion-view left-buttons="leftButtons" class="view-map-network"> <ion-view left-buttons="leftButtons" class="view-map-network">
<ion-nav-title> <ion-nav-title>
<span class="hidden-xs" translate>MAP.NETWORK.VIEW.TITLE</span>
</ion-nav-title> </ion-nav-title>
<ion-nav-buttons side="secondary"> <ion-nav-buttons side="secondary">
......
<span class="item item-divider" translate>MAP.SETTINGS.MAP_DIVIDER</span>
<label class="item item-toggle dark item-text-wrap">
<span translate>MAP.SETTINGS.ENABLE_GOOGLE_API</span>
<h4 class="gray" translate>MAP.SETTINGS.ENABLE_GOOGLE_API_HELP</h4>
<div class="toggle toggle-royal">
<input type="checkbox" ng-model="formData.enableGoogleApi">
<div class="track">
<div class="handle"></div>
</div>
</div>
</label>
<ion-item class="item-input"
ng-if="!$root.config.plugins.es.googleApiKey"
ng-class="{'item-input-error': formData.enableGoogleApi && !formData.googleApiKey}">
<div class="input-label col-33">
<span class="" ng-class="{'gray': !formData.enableGoogleApi}"translate>MAP.SETTINGS.GOOGLE_API_KEY</span>
<h4>
<a href="https://console.developers.google.com/apis/credentials/key" target="_system" translate>MAP.SETTINGS.BTN_GOOGLE_API</a>
<span class="gray"> ({{'MAP.SETTINGS.BTN_GOOGLE_API_WARNING'|translate}})</span>
</h4>
</div>
<input type="text"
placeholder="{{'MAP.SETTINGS.GOOGLE_API_KEY_PLACEHOLDER' | translate}}"
ng-model="formData.googleApiKey"
ng-if="formData.enableGoogleApi">
</ion-item>
<div class="form-errors"
ng-show="formData.enableGoogleApi && !formData.googleApiKey">
<div class="form-error">
<span translate="ERROR.FIELD_REQUIRED"></span>
</div>
</div>
...@@ -18,6 +18,6 @@ ...@@ -18,6 +18,6 @@
</h4> </h4>
</div> </div>
</div> </div>
<div class="item no-border no-padding item-text-wrap" ng-if="::hit.description"> <div class="item no-border no-padding item-text-wrap hidden-xs" ng-if="::hit.description">
<small ng-bind-html="::hit.description"></small> <small ng-bind-html="::hit.description"></small>
</div> </div>
<ion-view left-buttons="leftButtons" class="view-map-wot"> <ion-view left-buttons="leftButtons" class="view-map-wot">
<ion-nav-title> <ion-nav-title>
<span class="hidden-xs" translate>MAP.WOT.VIEW.TITLE</span>
</ion-nav-title> </ion-nav-title>
<ion-nav-buttons side="secondary"> <ion-nav-buttons side="secondary">
<button class="button button-icon button-clear icon ion-loop visible-xs visible-sm" ng-click="load()">
</button>
</ion-nav-buttons> </ion-nav-buttons>
<ion-content data-tap-disabled="true"> <ion-content data-tap-disabled="true">
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment