Merge pull request #594 from CartoDB/resources-url-templates

Allow to set resource URL templates with substitution tokens
This commit is contained in:
Raul Ochoa 2016-11-24 15:37:23 +01:00 committed by GitHub
commit 488698d5e2
5 changed files with 127 additions and 24 deletions

View File

@ -23,6 +23,21 @@ var config = {
// "tiles/layergroup" is for compatibility with versions up to 1.6.x // "tiles/layergroup" is for compatibility with versions up to 1.6.x
,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)' ,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)'
// Resource URLs expose endpoints to request/retrieve metadata associated to Maps: dataviews, analysis node status.
//
// This URLs depend on how `base_url_detached` and `user_from_host` are configured: the application can be
// configured to accept request with the {user} in the header host or in the request path.
// It also might depend on the configured cdn_url via `serverMetadata.cdn_url`.
//
// This template allows to make the endpoints generation more flexible, the template exposes the following params:
// 1. {{=it.cdn_url}}: will be used when `serverMetadata.cdn_url` exists.
// 2. {{=it.user}}: will use the username as extraced from `user_from_host` or `base_url_detached`.
// 3. {{=it.port}}: will use the `port` from this very same configuration file.
,resources_url_templates: {
http: 'http://{{=it.user}}.localhost.lan:{{=it.port}}/api/v1/map',
https: 'http://localhost.lan:{{=it.port}}/user/{{=it.user}}/api/v1/map'
}
// Maximum number of connections for one process // Maximum number of connections for one process
// 128 is a good value with a limit of 1024 open file descriptors // 128 is a good value with a limit of 1024 open file descriptors
,maxConnections:128 ,maxConnections:128

View File

@ -23,6 +23,21 @@ var config = {
// "tiles/layergroup" is for compatibility with versions up to 1.6.x // "tiles/layergroup" is for compatibility with versions up to 1.6.x
,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)' ,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)'
// Resource URLs expose endpoints to request/retrieve metadata associated to Maps: dataviews, analysis node status.
//
// This URLs depend on how `base_url_detached` and `user_from_host` are configured: the application can be
// configured to accept request with the {user} in the header host or in the request path.
// It also might depend on the configured cdn_url via `serverMetadata.cdn_url`.
//
// This template allows to make the endpoints generation more flexible, the template exposes the following params:
// 1. {{=it.cdn_url}}: will be used when `serverMetadata.cdn_url` exists.
// 2. {{=it.user}}: will use the username as extraced from `user_from_host` or `base_url_detached`.
// 3. {{=it.port}}: will use the `port` from this very same configuration file.
,resources_url_templates: {
http: 'http://{{=it.cdn_url}}/{{=it.user}}/api/v1/map',
https: 'https://{{=it.cdn_url}}/{{=it.user}}/api/v1/map'
}
// Maximum number of connections for one process // Maximum number of connections for one process
// 128 is a good value with a limit of 1024 open file descriptors // 128 is a good value with a limit of 1024 open file descriptors
,maxConnections:128 ,maxConnections:128

View File

@ -23,6 +23,21 @@ var config = {
// "/tiles/layergroup" is for compatibility with versions up to 1.6.x // "/tiles/layergroup" is for compatibility with versions up to 1.6.x
,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)' ,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)'
// Resource URLs expose endpoints to request/retrieve metadata associated to Maps: dataviews, analysis node status.
//
// This URLs depend on how `base_url_detached` and `user_from_host` are configured: the application can be
// configured to accept request with the {user} in the header host or in the request path.
// It also might depend on the configured cdn_url via `serverMetadata.cdn_url`.
//
// This template allows to make the endpoints generation more flexible, the template exposes the following params:
// 1. {{=it.cdn_url}}: will be used when `serverMetadata.cdn_url` exists.
// 2. {{=it.user}}: will use the username as extraced from `user_from_host` or `base_url_detached`.
// 3. {{=it.port}}: will use the `port` from this very same configuration file.
,resources_url_templates: {
http: 'http://{{=it.user}}.localhost.lan:{{=it.port}}/api/v1/map',
https: 'https://{{=it.cdn_url}}/{{=it.user}}/api/v1/map'
}
// Maximum number of connections for one process // Maximum number of connections for one process
// 128 is a good value with a limit of 1024 open file descriptors // 128 is a good value with a limit of 1024 open file descriptors
,maxConnections:128 ,maxConnections:128

View File

@ -23,6 +23,20 @@ var config = {
// "tiles/layergroup" is for compatibility with versions up to 1.6.x // "tiles/layergroup" is for compatibility with versions up to 1.6.x
,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)' ,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)'
// Resource URLs expose endpoints to request/retrieve metadata associated to Maps: dataviews, analysis node status.
//
// This URLs depend on how `base_url_detached` and `user_from_host` are configured: the application can be
// configured to accept request with the {user} in the header host or in the request path.
// It also might depend on the configured cdn_url via `serverMetadata.cdn_url`.
//
// This template allows to make the endpoints generation more flexible, the template exposes the following params:
// 1. {{=it.cdn_url}}: will be used when `serverMetadata.cdn_url` exists.
// 2. {{=it.user}}: will use the username as extraced from `user_from_host` or `base_url_detached`.
// 3. {{=it.port}}: will use the `port` from this very same configuration file.
,resources_url_templates: {
http: 'http://{{=it.user}}.localhost.lan:{{=it.port}}/api/v1/map'
}
// Maximum number of connections for one process // Maximum number of connections for one process
// 128 is a good value with a limit of 1024 open file descriptors // 128 is a good value with a limit of 1024 open file descriptors
,maxConnections:128 ,maxConnections:128

View File

@ -1,4 +1,6 @@
var _ = require('underscore'); var _ = require('underscore');
var dot = require('dot');
dot.templateSettings.strip = false;
var assert = require('assert'); var assert = require('assert');
var step = require('step'); var step = require('step');
var windshaft = require('windshaft'); var windshaft = require('windshaft');
@ -44,6 +46,20 @@ function MapController(authApi, pgConnection, templateMaps, mapBackend, metadata
this.layergroupAffectedTables = layergroupAffectedTables; this.layergroupAffectedTables = layergroupAffectedTables;
this.mapConfigAdapter = mapConfigAdapter; this.mapConfigAdapter = mapConfigAdapter;
this.resourcesUrlTemplates = null;
if (global.environment.resources_url_templates) {
var templates = global.environment.resources_url_templates;
if (templates.http) {
this.resourcesUrlTemplates = this.resourcesUrlTemplates || {};
this.resourcesUrlTemplates.http = dot.template(templates.http + '/{{=it.resource}}');
}
if (templates.https) {
this.resourcesUrlTemplates = this.resourcesUrlTemplates || {};
this.resourcesUrlTemplates.https = dot.template(templates.https + '/{{=it.resource}}');
}
}
} }
util.inherits(MapController, BaseController); util.inherits(MapController, BaseController);
@ -187,8 +203,8 @@ MapController.prototype.create = function(req, res, prepareConfigFn) {
self.sendError(req, res, err, 'ANONYMOUS LAYERGROUP'); self.sendError(req, res, err, 'ANONYMOUS LAYERGROUP');
} else { } else {
var analysesResults = context.analysesResults || []; var analysesResults = context.analysesResults || [];
addDataviewsAndWidgetsUrls(req.context.user, layergroup, mapConfig.obj()); self.addDataviewsAndWidgetsUrls(req.context.user, layergroup, mapConfig.obj());
addAnalysesMetadata(req.context.user, layergroup, analysesResults, true); self.addAnalysesMetadata(req.context.user, layergroup, analysesResults, true);
addContextMetadata(layergroup, mapConfig.obj(), context); addContextMetadata(layergroup, mapConfig.obj(), context);
res.set('X-Layergroup-Id', layergroup.layergroupid); res.set('X-Layergroup-Id', layergroup.layergroupid);
self.send(req, res, layergroup, 200); self.send(req, res, layergroup, 200);
@ -260,8 +276,8 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
layergroup.layergroupid = cdbuser + '@' + templateHash + '@' + layergroup.layergroupid; layergroup.layergroupid = cdbuser + '@' + templateHash + '@' + layergroup.layergroupid;
var _mapConfig = mapConfig.obj(); var _mapConfig = mapConfig.obj();
addDataviewsAndWidgetsUrls(cdbuser, layergroup, _mapConfig); self.addDataviewsAndWidgetsUrls(cdbuser, layergroup, _mapConfig);
addAnalysesMetadata(cdbuser, layergroup, mapConfigProvider.analysesResults); self.addAnalysesMetadata(cdbuser, layergroup, mapConfigProvider.analysesResults);
addContextMetadata(layergroup, _mapConfig, mapConfigProvider.context); addContextMetadata(layergroup, _mapConfig, mapConfigProvider.context);
res.set('X-Layergroup-Id', layergroup.layergroupid); res.set('X-Layergroup-Id', layergroup.layergroupid);
@ -370,7 +386,7 @@ function getLastUpdatedTime(analysesResults, lastUpdateTime) {
}, lastUpdateTime); }, lastUpdateTime);
} }
function addAnalysesMetadata(username, layergroup, analysesResults, includeQuery) { MapController.prototype.addAnalysesMetadata = function(username, layergroup, analysesResults, includeQuery) {
includeQuery = includeQuery || false; includeQuery = includeQuery || false;
analysesResults = analysesResults || []; analysesResults = analysesResults || [];
layergroup.metadata.analyses = []; layergroup.metadata.analyses = [];
@ -383,7 +399,7 @@ function addAnalysesMetadata(username, layergroup, analysesResults, includeQuery
var nodeResource = layergroup.layergroupid + '/analysis/node/' + node.id(); var nodeResource = layergroup.layergroupid + '/analysis/node/' + node.id();
var nodeRepr = { var nodeRepr = {
status: node.getStatus(), status: node.getStatus(),
url: getUrls(username, nodeResource) url: this.getUrls(username, nodeResource)
}; };
if (includeQuery) { if (includeQuery) {
nodeRepr.query = node.getQuery(); nodeRepr.query = node.getQuery();
@ -395,30 +411,30 @@ function addAnalysesMetadata(username, layergroup, analysesResults, includeQuery
} }
return nodesIdMap; return nodesIdMap;
}, {}) }.bind(this), {})
}); });
}); }.bind(this));
} };
// TODO this should take into account several URL patterns // TODO this should take into account several URL patterns
function addDataviewsAndWidgetsUrls(username, layergroup, mapConfig) { MapController.prototype.addDataviewsAndWidgetsUrls = function(username, layergroup, mapConfig) {
addDataviewsUrls(username, layergroup, mapConfig); this.addDataviewsUrls(username, layergroup, mapConfig);
addWidgetsUrl(username, layergroup, mapConfig); this.addWidgetsUrl(username, layergroup, mapConfig);
} };
function addDataviewsUrls(username, layergroup, mapConfig) { MapController.prototype.addDataviewsUrls = function(username, layergroup, mapConfig) {
layergroup.metadata.dataviews = layergroup.metadata.dataviews || {}; layergroup.metadata.dataviews = layergroup.metadata.dataviews || {};
var dataviews = mapConfig.dataviews || {}; var dataviews = mapConfig.dataviews || {};
Object.keys(dataviews).forEach(function(dataviewName) { Object.keys(dataviews).forEach(function(dataviewName) {
var resource = layergroup.layergroupid + '/dataview/' + dataviewName; var resource = layergroup.layergroupid + '/dataview/' + dataviewName;
layergroup.metadata.dataviews[dataviewName] = { layergroup.metadata.dataviews[dataviewName] = {
url: getUrls(username, resource) url: this.getUrls(username, resource)
}; };
}); }.bind(this));
} };
function addWidgetsUrl(username, layergroup, mapConfig) { MapController.prototype.addWidgetsUrl = function(username, layergroup, mapConfig) {
if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) { if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) {
layergroup.metadata.layers = layergroup.metadata.layers.map(function(layer, layerIndex) { layergroup.metadata.layers = layergroup.metadata.layers.map(function(layer, layerIndex) {
var mapConfigLayer = mapConfig.layers[layerIndex]; var mapConfigLayer = mapConfig.layers[layerIndex];
@ -428,16 +444,19 @@ function addWidgetsUrl(username, layergroup, mapConfig) {
var resource = layergroup.layergroupid + '/' + layerIndex + '/widget/' + widgetName; var resource = layergroup.layergroupid + '/' + layerIndex + '/widget/' + widgetName;
layer.widgets[widgetName] = { layer.widgets[widgetName] = {
type: mapConfigLayer.options.widgets[widgetName].type, type: mapConfigLayer.options.widgets[widgetName].type,
url: getUrls(username, resource) url: this.getUrls(username, resource)
}; };
}); }.bind(this));
} }
return layer; return layer;
}); }.bind(this));
} }
} };
function getUrls(username, resource) { MapController.prototype.getUrls = function(username, resource) {
if (this.resourcesUrlTemplates) {
return this.getUrlsFromTemplate(username, resource);
}
var cdnUrl = global.environment.serverMetadata && global.environment.serverMetadata.cdn_url; var cdnUrl = global.environment.serverMetadata && global.environment.serverMetadata.cdn_url;
if (cdnUrl) { if (cdnUrl) {
return { return {
@ -450,4 +469,29 @@ function getUrls(username, resource) {
http: 'http://' + username + '.' + 'localhost.lan:' + port + '/api/v1/map/' + resource http: 'http://' + username + '.' + 'localhost.lan:' + port + '/api/v1/map/' + resource
}; };
} }
} };
MapController.prototype.getUrlsFromTemplate = function(username, resource) {
var urls = {};
var cdnUrl = global.environment.serverMetadata && global.environment.serverMetadata.cdn_url || {};
if (this.resourcesUrlTemplates.http) {
urls.http = this.resourcesUrlTemplates.http({
cdn_url: cdnUrl.http,
user: username,
port: global.environment.port,
resource: resource
});
}
if (this.resourcesUrlTemplates.https) {
urls.https = this.resourcesUrlTemplates.https({
cdn_url: cdnUrl.https,
user: username,
port: global.environment.port,
resource: resource
});
}
return urls;
};