Adds analysis MapConfig adapter to named maps
This commit is contained in:
parent
efacafaa0d
commit
077c4ab907
@ -2,17 +2,21 @@ var _ = require('underscore');
|
||||
var dot = require('dot');
|
||||
var NamedMapMapConfigProvider = require('../models/mapconfig/named_map_provider');
|
||||
var MapConfigNamedLayersAdapter = require('../models/mapconfig_named_layers_adapter');
|
||||
var AnalysisMapConfigAdapter = require('../models/analysis_mapconfig_adapter');
|
||||
var templateName = require('../backends/template_maps').templateName;
|
||||
var queue = require('queue-async');
|
||||
|
||||
var LruCache = require("lru-cache");
|
||||
|
||||
function NamedMapProviderCache(templateMaps, pgConnection, userLimitsApi, overviewsAdapter, turboCartocssAdapter) {
|
||||
function NamedMapProviderCache(templateMaps, pgConnection, metadataBackend, userLimitsApi, overviewsAdapter,
|
||||
turboCartocssAdapter) {
|
||||
this.templateMaps = templateMaps;
|
||||
this.pgConnection = pgConnection;
|
||||
this.metadataBackend = metadataBackend;
|
||||
this.userLimitsApi = userLimitsApi;
|
||||
|
||||
this.namedLayersAdapter = new MapConfigNamedLayersAdapter(templateMaps);
|
||||
this.analysisMapConfigAdapter = new AnalysisMapConfigAdapter();
|
||||
this.overviewsAdapter = overviewsAdapter;
|
||||
this.turboCartocssAdapter = turboCartocssAdapter;
|
||||
|
||||
@ -30,10 +34,12 @@ NamedMapProviderCache.prototype.get = function(user, templateId, config, authTok
|
||||
namedMapProviders[providerKey] = new NamedMapMapConfigProvider(
|
||||
this.templateMaps,
|
||||
this.pgConnection,
|
||||
this.metadataBackend,
|
||||
this.userLimitsApi,
|
||||
this.namedLayersAdapter,
|
||||
this.overviewsAdapter,
|
||||
this.turboCartocssAdapter,
|
||||
this.analysisMapConfigAdapter,
|
||||
user,
|
||||
templateId,
|
||||
config,
|
||||
|
@ -257,10 +257,12 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
|
||||
mapConfigProvider = new NamedMapMapConfigProvider(
|
||||
self.templateMaps,
|
||||
self.pgConnection,
|
||||
self.metadataBackend,
|
||||
self.userLimitsApi,
|
||||
self.namedLayersAdapter,
|
||||
self.overviewsAdapter,
|
||||
self.turboCartoCssAdapter,
|
||||
self.analysisMapConfigAdapter,
|
||||
cdbuser,
|
||||
req.params.template_id,
|
||||
templateParams,
|
||||
|
@ -11,14 +11,16 @@ var QueryTables = require('cartodb-query-tables');
|
||||
* @constructor
|
||||
* @type {NamedMapMapConfigProvider}
|
||||
*/
|
||||
function NamedMapMapConfigProvider(templateMaps, pgConnection, userLimitsApi,
|
||||
namedLayersAdapter, overviewsAdapter, turboCartoCssAdapter,
|
||||
function NamedMapMapConfigProvider(templateMaps, pgConnection, metadataBackend, userLimitsApi,
|
||||
namedLayersAdapter, overviewsAdapter, turboCartoCssAdapter, analysisMapConfigAdapter,
|
||||
owner, templateId, config, authToken, params) {
|
||||
this.templateMaps = templateMaps;
|
||||
this.pgConnection = pgConnection;
|
||||
this.metadataBackend = metadataBackend;
|
||||
this.userLimitsApi = userLimitsApi;
|
||||
this.namedLayersAdapter = namedLayersAdapter;
|
||||
this.turboCartoCssAdapter = turboCartoCssAdapter;
|
||||
this.analysisMapConfigAdapter = analysisMapConfigAdapter;
|
||||
this.overviewsAdapter = overviewsAdapter;
|
||||
|
||||
this.owner = owner;
|
||||
@ -53,15 +55,29 @@ NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) {
|
||||
var mapConfig = null;
|
||||
var datasource = null;
|
||||
var rendererParams;
|
||||
var apiKey;
|
||||
|
||||
step(
|
||||
function getTemplate() {
|
||||
self.getTemplate(this);
|
||||
},
|
||||
function prepareParams(err, tpl) {
|
||||
function prepareDbParams(err, tpl) {
|
||||
assert.ifError(err);
|
||||
self.template = tpl;
|
||||
|
||||
rendererParams = _.extend({}, self.params, {
|
||||
user: self.owner
|
||||
});
|
||||
self.setDBParams(self.owner, rendererParams, this);
|
||||
},
|
||||
function getUserApiKey(err) {
|
||||
assert.ifError(err);
|
||||
self.metadataBackend.getUserMapKey(self.owner, this);
|
||||
},
|
||||
function prepareParams(err, _apiKey) {
|
||||
assert.ifError(err);
|
||||
|
||||
self.template = tpl;
|
||||
apiKey = _apiKey;
|
||||
|
||||
var templateParams = {};
|
||||
if (self.config) {
|
||||
@ -78,6 +94,34 @@ NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) {
|
||||
assert.ifError(err);
|
||||
return self.templateMaps.instance(self.template, templateParams);
|
||||
},
|
||||
function prepareAnalysisLayers(err, requestMapConfig) {
|
||||
assert.ifError(err);
|
||||
var analysisConfiguration = {
|
||||
db: {
|
||||
host: rendererParams.dbhost,
|
||||
port: rendererParams.dbport,
|
||||
dbname: rendererParams.dbname,
|
||||
user: rendererParams.dbuser,
|
||||
pass: rendererParams.dbpassword
|
||||
},
|
||||
batch: {
|
||||
// TODO load this from configuration
|
||||
endpoint: 'http://127.0.0.1:8080/api/v1/sql/job',
|
||||
username: self.owner,
|
||||
apiKey: apiKey
|
||||
}
|
||||
};
|
||||
|
||||
var filters = {};
|
||||
if (self.params.filters) {
|
||||
try {
|
||||
filters = JSON.parse(self.params.filters);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
self.analysisMapConfigAdapter.getLayers(analysisConfiguration, requestMapConfig, filters, this);
|
||||
},
|
||||
function prepareLayergroup(err, _mapConfig) {
|
||||
assert.ifError(err);
|
||||
var next = this;
|
||||
@ -126,17 +170,10 @@ NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) {
|
||||
return next(null, _mapConfig, datasource);
|
||||
});
|
||||
},
|
||||
function beforeLayergroupCreate(err, _mapConfig, _datasource) {
|
||||
function prepareContextLimits(err, _mapConfig, _datasource) {
|
||||
assert.ifError(err);
|
||||
mapConfig = _mapConfig;
|
||||
datasource = _datasource;
|
||||
rendererParams = _.extend({}, self.params, {
|
||||
user: self.owner
|
||||
});
|
||||
self.setDBParams(self.owner, rendererParams, this);
|
||||
},
|
||||
function prepareContextLimits(err) {
|
||||
assert.ifError(err);
|
||||
self.userLimitsApi.getRenderLimits(self.owner, this);
|
||||
},
|
||||
function cacheAndReturnMapConfig(err, renderLimits) {
|
||||
|
@ -152,6 +152,7 @@ module.exports = function(serverOptions) {
|
||||
var namedMapProviderCache = new NamedMapProviderCache(
|
||||
templateMaps,
|
||||
pgConnection,
|
||||
metadataBackend,
|
||||
userLimitsApi,
|
||||
overviewsAdapter,
|
||||
turboCartocssAdapter
|
||||
|
192
test/acceptance/analysis/named-maps.js
Normal file
192
test/acceptance/analysis/named-maps.js
Normal file
@ -0,0 +1,192 @@
|
||||
var assert = require('../../support/assert');
|
||||
var step = require('step');
|
||||
|
||||
//var mapnik = require('windshaft').mapnik;
|
||||
|
||||
var helper = require('../../support/test_helper');
|
||||
|
||||
var CartodbWindshaft = require('../../../lib/cartodb/server');
|
||||
var serverOptions = require('../../../lib/cartodb/server_options');
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
|
||||
var LayergroupToken = require('../../../lib/cartodb/models/layergroup_token');
|
||||
|
||||
describe('named-maps analysis', function() {
|
||||
|
||||
var IMAGE_TOLERANCE_PER_MIL = 20;
|
||||
|
||||
var username = 'localhost';
|
||||
var widgetsTemplateName = 'widgets-template';
|
||||
|
||||
var layergroupid;
|
||||
var layergroup;
|
||||
var keysToDelete;
|
||||
|
||||
beforeEach(function(done) {
|
||||
keysToDelete = {};
|
||||
|
||||
var widgetsTemplate = {
|
||||
version: '0.0.1',
|
||||
name: widgetsTemplateName,
|
||||
layergroup: {
|
||||
version: '1.5.0',
|
||||
layers: [
|
||||
{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"source": {
|
||||
"id": "HEAD"
|
||||
},
|
||||
"cartocss": '#buffer { polygon-fill: red; }',
|
||||
"cartocss_version": "2.3.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
analyses: [
|
||||
{
|
||||
"id": "HEAD",
|
||||
"type": "buffer",
|
||||
"params": {
|
||||
"source": {
|
||||
"id": "2570e105-7b37-40d2-bdf4-1af889598745",
|
||||
"type": "source",
|
||||
"params": {
|
||||
"query": "select * from populated_places_simple_reduced"
|
||||
}
|
||||
},
|
||||
"radio": 50000
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
var template_params = {};
|
||||
|
||||
step(
|
||||
function createTemplate()
|
||||
{
|
||||
var next = this;
|
||||
assert.response(
|
||||
server,
|
||||
{
|
||||
url: '/api/v1/map/named?api_key=1234',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
host: username,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: JSON.stringify(widgetsTemplate)
|
||||
},
|
||||
{
|
||||
status: 200
|
||||
},
|
||||
function(res, err) {
|
||||
next(err, res);
|
||||
}
|
||||
);
|
||||
},
|
||||
function instantiateTemplate(err, res) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert.deepEqual(JSON.parse(res.body), { template_id: widgetsTemplateName });
|
||||
var next = this;
|
||||
assert.response(
|
||||
server,
|
||||
{
|
||||
url: '/api/v1/map/named/' + widgetsTemplateName,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
host: username,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: JSON.stringify(template_params)
|
||||
},
|
||||
{
|
||||
status: 200
|
||||
},
|
||||
function(res) {
|
||||
next(null, res);
|
||||
}
|
||||
);
|
||||
},
|
||||
function finish(err, res) {
|
||||
assert.ifError(err);
|
||||
|
||||
layergroup = JSON.parse(res.body);
|
||||
assert.ok(layergroup.hasOwnProperty('layergroupid'), "Missing 'layergroupid' from: " + res.body);
|
||||
layergroupid = layergroup.layergroupid;
|
||||
|
||||
keysToDelete['map_cfg|' + LayergroupToken.parse(layergroup.layergroupid).token] = 0;
|
||||
keysToDelete['user:localhost:mapviews:global'] = 5;
|
||||
|
||||
return done();
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
step(
|
||||
function deleteTemplate(err) {
|
||||
assert.ifError(err);
|
||||
var next = this;
|
||||
assert.response(
|
||||
server,
|
||||
{
|
||||
url: '/api/v1/map/named/' + widgetsTemplateName + '?api_key=1234',
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
host: username
|
||||
}
|
||||
},
|
||||
{
|
||||
status: 204
|
||||
},
|
||||
function(res, err) {
|
||||
next(err, res);
|
||||
}
|
||||
);
|
||||
},
|
||||
function deleteRedisKeys(err) {
|
||||
assert.ifError(err);
|
||||
helper.deleteRedisKeys(keysToDelete, done);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to retrieve widgets from all URLs', function(done) {
|
||||
assert.response(
|
||||
server,
|
||||
{
|
||||
url: '/api/v1/map/' + layergroupid + '/6/31/24.png',
|
||||
method: 'GET',
|
||||
encoding: 'binary',
|
||||
headers: {
|
||||
host: username
|
||||
}
|
||||
},
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'image/png'
|
||||
}
|
||||
},
|
||||
function(res, err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
// var image = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
|
||||
// assert.ok(image);
|
||||
var fixturePath = './test/fixtures/analysis/named-map-buffer.png';
|
||||
assert.imageBufferIsSimilarToFile(res.body, fixturePath, IMAGE_TOLERANCE_PER_MIL, function(err) {
|
||||
assert.ok(!err, err);
|
||||
done();
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
});
|
BIN
test/fixtures/analysis/named-map-buffer.png
vendored
Normal file
BIN
test/fixtures/analysis/named-map-buffer.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
Loading…
Reference in New Issue
Block a user